iCub-main
Loading...
Searching...
No Matches
SharedCanBus.cpp
Go to the documentation of this file.
1// -*- Mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
2
3/*
4 * Copyright (C) 2012 RobotCub Consortium
5 * Author: Alessandro Scalzo
6 * CopyPolicy: Released under the terms of the GNU GPL v2.0.
7 *
8 */
9
10#include <mutex>
11#include <string>
12#include <vector>
13
14#include <yarp/os/Time.h>
15#include <yarp/os/Log.h>
16#include <yarp/os/Property.h>
17#include <yarp/os/PeriodicThread.h>
18#include <yarp/dev/PolyDriver.h>
19
20#include "SharedCanBus.h"
21
22const int CAN_DRIVER_BUFFER_SIZE = 500;
23const int DEFAULT_THREAD_PERIOD = 10;
24
25class SharedCanBus : public yarp::os::PeriodicThread
26{
27public:
28 SharedCanBus() : PeriodicThread((double)DEFAULT_THREAD_PERIOD/1000.0)
29 {
30 mBufferSize=0;
31 mCanDeviceNum=-1;
32 mDevice="";
33
34 reqIdsUnion=new char[0x800];
35
36 for (int i=0; i<0x800; ++i) reqIdsUnion[i]=UNREQ;
37 }
38
40 {
41 stop();
42
43 polyDriver.close();
44
45 delete [] reqIdsUnion;
46 }
47
49 {
50 return mBufferSize;
51 }
52
54 {
55 return mCanDeviceNum;
56 }
57
58 bool IloveUmom(yarp::os::Searchable &config)
59 {
60 if (!config.check("physDevice"))
61 {
62 yError("SharedCanBus could not find low level can driver specification\n");
63 return false;
64 }
65
66 if (mDevice!=config.find("physDevice").asString()) return false;
67
68 if (config.findGroup("CAN").check("sharedCanPeriod"))
69 {
70 int sharedCanPeriod = config.findGroup("CAN").find("sharedCanPeriod").asInt32();
71 int currentCanPeriod = (int)(1000.0 * this->getPeriod());
72 if (currentCanPeriod != sharedCanPeriod && currentCanPeriod != DEFAULT_THREAD_PERIOD)
73 {
74 yWarning("SharedCanBus: Requested a different sharedCanPeriod (%d ms) respect to previous instance (%d ms). Using: %d ms\n", sharedCanPeriod, currentCanPeriod, currentCanPeriod);
75 }
76 }
77
78 if (!config.check("canDeviceNum")) return true;
79
80 return mCanDeviceNum==config.find("canDeviceNum").asInt32();
81 }
82
84 {
85 std::lock_guard<std::mutex> lck(configMutex);
86 accessPoints.push_back(ap);
87 }
88
90 {
91 if (!ap) return;
92
93 std::lock_guard<std::mutex> lck(configMutex);
94
95 int n=accessPoints.size();
96
97 for (int i=0; i<n; ++i)
98 {
99 if (ap==accessPoints[i])
100 {
101 for (int id=0; id<0x800; ++id)
102 {
103 if (ap->hasId(id)) canIdDeleteUnsafe(id);
104 }
105
106 accessPoints[i]=accessPoints[n-1];
107
108 accessPoints.pop_back();
109
110 break;
111 }
112 }
113
114 if (accessPoints.size()==0)
115 {
116 // should close the driver here?
117 }
118 }
119
120 void run()
121 {
122 static const bool NOWAIT=false;
123 unsigned int msgsNum=0;
124
125 std::lock_guard<std::mutex> lck(configMutex);
126
127 bool ret=theCanBus->canRead(readBufferUnion,mBufferSize,&msgsNum,NOWAIT);
128
129 if (ret)
130 {
131 for (unsigned int i=0; i<msgsNum; ++i)
132 {
133 unsigned int id=readBufferUnion[i].getId();
134
135 for (unsigned int p=0; p<accessPoints.size(); ++p)
136 {
137 if (accessPoints[p]->hasId(id))
138 {
139 if (accessPoints[p]->pushReadMsg(readBufferUnion[i])==false)
140 {
141 yError("run()-pushReadMsg() failed on CAN bus %d", mCanDeviceNum);
142 }
143 }
144 }
145 }
146 }
147 }
148
149 bool canWrite(const yarp::dev::CanBuffer &msgs, unsigned int size, unsigned int *sent, bool wait,yarp::dev::CanBusAccessPoint* pFrom)
150 {
151 std::lock_guard<std::mutex> lck(writeMutex);
152 bool ret=theCanBus->canWrite(msgs,size,sent,wait);
153
154 //this allows other istances to read back the sent message (echo)
155 yarp::dev::CanBuffer buff=msgs;
156 for (unsigned int m=0; m<size; ++m)
157 {
158 unsigned int id=buff[m].getId();
159 if (reqIdsUnion[id])
160 {
161 for (unsigned int p=0; p<accessPoints.size(); ++p)
162 {
163 if (accessPoints[p]!=pFrom && accessPoints[p]->hasId(id))
164 {
165 if (accessPoints[p]->pushReadMsg(buff[m])==false)
166 {
167 yError("canWrite()-pushReadMsg() failed on CAN bus %d", mCanDeviceNum);
168 }
169 }
170 }
171 }
172 }
173
174 return ret;
175 }
176
177 void canIdAdd(unsigned int id)
178 {
179 std::lock_guard<std::mutex> lck(configMutex);
180 if (reqIdsUnion[id]==UNREQ)
181 {
182 reqIdsUnion[id]=REQST;
183 theCanBus->canIdAdd(id);
184 }
185 }
186
187 void canIdDelete(unsigned int id)
188 {
189 std::lock_guard<std::mutex> lck(configMutex);
190 canIdDeleteUnsafe(id);
191 }
192
193 yarp::dev::ICanBus* getCanBus()
194 {
195 return theCanBus;
196 }
197
198 yarp::dev::ICanBufferFactory* getCanBufferFactory()
199 {
200 if (!theBufferFactory)
201 {
202 yError("SharedCanBus error: no buffer factory\n");
203 }
204
205 return theBufferFactory;
206 }
207
208 yarp::dev::ICanBusErrors* getCanBusErrors()
209 {
210 return theCanBusErrors;
211 }
212
213 bool open(yarp::os::Searchable &config)
214 {
215 std::lock_guard<std::mutex> lck(configMutex);
216
217 //fprintf(stderr, "sharedCanBus::open() using the following configuration parameters: \n%s\n",config.toString().c_str());
218 if (!config.check("physDevice"))
219 {
220 yError("SharedCanBus::open() could not find low level can driver specification\n");
221 return false;
222 }
223
224 std::string device=config.find("physDevice").asString();
225
226 yarp::os::Property prop;
227 prop.fromString(config.toString().c_str());
228
229 prop.unput("device");
230 prop.unput("subdevice");
231 prop.unput("physDevice");
232
233 prop.put("device",device.c_str());
234
235 // low level driver
236 polyDriver.open(prop);
237
238 if (!polyDriver.isValid())
239 {
240 yError("SharedCanBus: could not instantiate can device\n");
241 return false;
242 }
243
244 polyDriver.view(theCanBus);
245
246 if (theCanBus==NULL)
247 {
248 yError("SharedCanBus: could not get ICanBus interface\n");
249 return false;
250 }
251
252 polyDriver.view(theBufferFactory);
253
254 if (theBufferFactory==NULL)
255 {
256 yError("SharedCanBus: could not get ICanBufferFactory interface\n");
257 return false;
258 }
259
260 polyDriver.view(theCanBusErrors);
261
262 mBufferSize=CAN_DRIVER_BUFFER_SIZE;
263
264 if (config.check("canRxQueueSize"))
265 {
266 mBufferSize=config.find("canRxQueueSize").asInt32();
267 }
268
269 readBufferUnion=theBufferFactory->createBuffer(mBufferSize);
270
271 bool started=start();
272
273 mDevice=device;
274
275 if (config.check("canDeviceNum"))
276 {
277 mCanDeviceNum=config.find("canDeviceNum").asInt32();
278 }
279
280 return started;
281 }
282
283private:
284 void canIdDeleteUnsafe(unsigned int id)
285 {
286 if (reqIdsUnion[id]==REQST)
287 {
288 for (int i=0; i<(int)accessPoints.size(); ++i)
289 {
290 if (accessPoints[i]->hasId(id))
291 {
292 return;
293 }
294 }
295
296 reqIdsUnion[id]=UNREQ;
297
298 theCanBus->canIdDelete(id);
299 }
300 }
301
302 int mBufferSize;
303
304 std::mutex writeMutex;
305 std::mutex configMutex;
306
307 std::string mDevice;
308 int mCanDeviceNum;
309
310 yarp::dev::PolyDriver polyDriver;
311
312 yarp::dev::ICanBus *theCanBus;
313 yarp::dev::ICanBufferFactory *theBufferFactory;
314 yarp::dev::ICanBusErrors *theCanBusErrors;
315
316 std::vector<yarp::dev::CanBusAccessPoint*> accessPoints;
317
318 yarp::dev::CanBuffer readBufferUnion;
319
320 char *reqIdsUnion; //[0x800];
321};
322
323class SharedCanBusManager // singleton
324{
325public:
327 {
328 for (unsigned int i=0; i<mDevices.size(); ++i)
329 {
330 if (mDevices[i]) delete mDevices[i];
331 }
332
333 mDevices.clear();
334 }
335
337 {
338 static SharedCanBusManager instance;
339
340 return instance;
341 }
342
343 SharedCanBus* open(yarp::os::Searchable &config)
344 {
345 for (unsigned int i=0; i<mDevices.size(); ++i)
346 {
347 if (mDevices[i]->IloveUmom(config))
348 {
349 return mDevices[i];
350 }
351 }
352
353 SharedCanBus *scb=new SharedCanBus();
354
355 if (!scb->open(config))
356 {
357 delete scb;
358 return NULL;
359 }
360
361 if (config.findGroup("CAN").check("sharedCanPeriod"))
362 {
363 int sharedCanPeriod = config.findGroup("CAN").find("sharedCanPeriod").asInt32();
364 scb->setPeriod((double)sharedCanPeriod/1000.0);
365 //yDebug("SharedCanBus [%d] using custom thread period = %dms\n", scb->getCanDeviceNum(), sharedCanPeriod);///TOBEREMOVED
366 }
367 else
368 {
369 yWarning("SharedCanBus [%d] using default thread period = %dms\n", scb->getCanDeviceNum(), DEFAULT_THREAD_PERIOD);
370 }
371
372 mDevices.push_back(scb);
373
374 return scb;
375 }
376
377private:
379 {
380 mDevices.clear();
381 }
382
383 std::vector<SharedCanBus*> mDevices;
384};
385
387// CanBusAccessPoint methods
389
390bool yarp::dev::CanBusAccessPoint::open(yarp::os::Searchable& config)
391{
393
394 if (!mSharedPhysDevice) return false;
395
397
399
401
402 return true;
403}
404
406{
407 if (!mSharedPhysDevice) return false;
408
409 mSharedPhysDevice->detachAccessPoint(this);
410
411 return true;
412}
413
414bool yarp::dev::CanBusAccessPoint::canWrite(const CanBuffer &msgs, unsigned int size, unsigned int *sent, bool wait)
415{
416 if (!mSharedPhysDevice) return false;
417
418 return mSharedPhysDevice->canWrite(msgs,size,sent,wait,this);
419}
420
422{
423 if (!mSharedPhysDevice) return false;
424
425 return mSharedPhysDevice->getCanBus()->canGetBaudRate(rate);
426}
427
429{
430 if (!mSharedPhysDevice) return false;
431
432 if (id>=0x800)
433 {
434 yError("SharedCanBus: Id=%d is out of 11 bit address range\n",id);
435 return false;
436 }
437
438 reqIds[id]=REQST;
439
440 mSharedPhysDevice->canIdAdd(id);
441
442 return true;
443}
444
446{
447 if (!mSharedPhysDevice) return false;
448
449 if (id>=0x800)
450 {
451 yError("SharedCanBus: Id=%d is out of 11 bit address range\n",id);
452 return false;
453 }
454
455 reqIds[id]=UNREQ;
456
457 mSharedPhysDevice->canIdDelete(id);
458
459 return true;
460}
461
462yarp::dev::CanBuffer yarp::dev::CanBusAccessPoint::createBuffer(int nmessage)
463{
464 yarp::dev::CanBuffer cb;
465
466 if (mSharedPhysDevice) cb = mSharedPhysDevice->getCanBufferFactory()->createBuffer(nmessage);
467
468 return cb;
469}
470
472{
473 if (!mSharedPhysDevice) return;
474
475 yarp::dev::ICanBufferFactory* tmp = mSharedPhysDevice->getCanBufferFactory();
476
477 if (tmp) tmp->destroyBuffer(msgs);
478}
const int DEFAULT_THREAD_PERIOD
const int CAN_DRIVER_BUFFER_SIZE
#define REQST
#define UNREQ
Copyright (C) 2012 RobotCub Consortium.
static SharedCanBusManager & getInstance()
SharedCanBus * open(yarp::os::Searchable &config)
bool open(yarp::os::Searchable &config)
void canIdAdd(unsigned int id)
bool canWrite(const yarp::dev::CanBuffer &msgs, unsigned int size, unsigned int *sent, bool wait, yarp::dev::CanBusAccessPoint *pFrom)
yarp::dev::ICanBusErrors * getCanBusErrors()
void attachAccessPoint(yarp::dev::CanBusAccessPoint *ap)
int getCanDeviceNum()
void detachAccessPoint(yarp::dev::CanBusAccessPoint *ap)
yarp::dev::ICanBus * getCanBus()
yarp::dev::ICanBufferFactory * getCanBufferFactory()
bool IloveUmom(yarp::os::Searchable &config)
void canIdDelete(unsigned int id)
sharedcan : implements ICanBus interface for multiple access from a single access can driver (for exa...
virtual void destroyBuffer(CanBuffer &msgs)
virtual bool open(yarp::os::Searchable &config)
virtual bool canGetBaudRate(unsigned int *rate)
bool hasId(unsigned int id)
virtual bool canIdAdd(unsigned int id)
virtual bool canWrite(const CanBuffer &msgs, unsigned int size, unsigned int *sent, bool wait=false)
virtual bool canIdDelete(unsigned int id)
virtual CanBuffer createBuffer(int nmessage)
int n