OpcUaCanOpen
CANopen OPC-UA server
pkcan.cpp
Go to the documentation of this file.
1 
26 #include <time.h>
27 #include <string.h>
28 #include <boost/thread/thread.hpp>
29 
30 #include <LogIt.h>
31 
32 #include "pkcan.h"
33 #include "CanModuleUtils.h"
34 
35 /* static */ std::map<string, string> PKCanScan::m_busMap;
36 
37 #define MLOGPK(LEVEL,THIS) LOG(Log::LEVEL, THIS->logItHandle()) << __FUNCTION__ << " " << " peak bus= " << THIS->getBusName() << " "
38 
39 boost::mutex peakReconnectMutex; // protect m_busMap
40 
41 
42 bool initLibarary = false;
43 extern "C" __declspec(dllexport) CCanAccess *getCanBusAccess()
44 {
45  CCanAccess *cc;
46  cc = new PKCanScan;
47  return cc;
48 }
49 
51  m_busStatus(0),
52  m_baudRate(0),
53  m_idCanScanThread(0),
54  m_CanScanThreadRunEnableFlag(false)
55 {
56  m_statistics.beginNewRun();
57 }
58 
60 {
61  stopBus();
62 }
63 
68 {
70  MLOGPK(TRC, this) << " try finishing thread...calling CAN_Uninitialize";
71  TPCANStatus tpcanStatus = CAN_Uninitialize(m_canObjHandler);
72  MLOGPK(TRC, this) << "CAN_Uninitialize returns " << (int) tpcanStatus;
73 
74  {
75  peakReconnectMutex.lock();
76  std::map<string, string>::iterator it = PKCanScan::m_busMap.find( m_busName );
77  if (it != PKCanScan::m_busMap.end()) {
79  PKCanScan::m_busMap.erase ( it );
80  m_busName = "nobus";
81  MLOGPK(TRC,this) << " bus " << m_busName << " erased from map, OK";
82  } else {
83  MLOGPK(DBG,this) << " bus " << m_busName << " does not exist";
84  }
85  peakReconnectMutex.unlock();
86  }
87  Sleep(2); // and wait a bit for the thread to die
88  MLOGPK(DBG,this) << "stopBus() finished";
89 }
90 
91 
96 {
97  PKCanScan *pkCanScanPointer = reinterpret_cast<PKCanScan *>(pCanScan);
98  TPCANHandle tpcanHandler = pkCanScanPointer->m_canObjHandler;
99  MLOGPK(DBG,pkCanScanPointer) << "CanScanControlThread Started. m_CanScanThreadShutdownFlag = [" << pkCanScanPointer->m_CanScanThreadRunEnableFlag <<"]";
100  pkCanScanPointer->m_CanScanThreadRunEnableFlag = true;
101  while ( pkCanScanPointer->m_CanScanThreadRunEnableFlag ) {
102  TPCANMsg tpcanMessage;
103  TPCANTimestamp tpcanTimestamp;
104  TPCANStatus tpcanStatus = CAN_Read(tpcanHandler,&tpcanMessage,&tpcanTimestamp);
105  if (tpcanStatus == PCAN_ERROR_OK) {
107  for(int i=0; i < 8; i++)
108  {
109  canMessage.c_data[i] = tpcanMessage.DATA[i];
110  }
111  canMessage.c_dlc = tpcanMessage.LEN;
112  canMessage.c_id = tpcanMessage.ID;
113  canMessage.c_ff = tpcanMessage.MSGTYPE;
114 
115  unsigned long long mmsec = 0xFFFFFFFFUL;
116  mmsec = mmsec * 1000;
117  mmsec = mmsec * tpcanTimestamp.millis_overflow;
118  mmsec = mmsec + tpcanTimestamp.micros;
119  mmsec = mmsec + 1000 * tpcanTimestamp.millis;
120 
121  canMessage.c_time.tv_usec = mmsec % 1000000UL;
122  canMessage.c_time.tv_sec = long(mmsec / 1000000UL);
123  pkCanScanPointer->canMessageCame(canMessage);
124  pkCanScanPointer->m_statistics.onReceive( canMessage.c_dlc );
125  } else {
126  if (tpcanStatus & PCAN_ERROR_QRCVEMPTY) {
127  continue;
128  }
129  pkCanScanPointer->sendErrorCode(tpcanStatus);
130  if (tpcanStatus | PCAN_ERROR_ANYBUSERR) {
131  CAN_Initialize(tpcanHandler,pkCanScanPointer->m_baudRate);
132  Sleep(100);
133  }
134  }
135  }
136  MLOGPK(TRC, pkCanScanPointer) << "exiting thread...";
137  ExitThread(0);
138  return 0;
139 }
140 
159 bool PKCanScan::createBus(const string name ,const string parameters )
160 {
161  m_busName = name;
162  m_busParameters = parameters;
163 
164  LogItInstance* logItInstance = CCanAccess::getLogItInstance(); // actually calling instance method, not class
165  if (!LogItInstance::setInstance(logItInstance))
166  std::cout << __FILE__ << " " << __LINE__ << " " << __FUNCTION__
167  << " could not set LogIt instance" << std::endl;
168 
170  std::cout << __FILE__ << " " << __LINE__ << " " << __FUNCTION__
171  << " could not get LogIt component handle for " << LogItComponentName << std::endl;
172 
173  MLOGPK(DBG, this) << " name= " << name << " parameters= " << parameters << ", configuring CAN board";
174 
175  m_sBusName = name; // maybe this can be cleaned up: we have m_busName already
176  if ( !configureCanboard(name,parameters) ) {
177  MLOGPK( ERR, this ) << " name= " << name << " parameters= " << parameters << ", failed to configure CAN board";
178  return false;
179  }
180 
181  bool skipMainThreadCreation = false;
182  {
183  peakReconnectMutex.lock();
184  // dont create a main thread for the same bus twice
185  std::map<string, string>::iterator it = PKCanScan::m_busMap.find( name );
186  if (it == PKCanScan::m_busMap.end()) {
187  PKCanScan::m_busMap.insert ( std::pair<string, string>(name, parameters) );
188  m_busName = name;
189  } else {
190  LOG(Log::WRN) << __FUNCTION__ << " bus exists already [" << name << ", " << parameters << "], not creating another main thread";
191  skipMainThreadCreation = true;
192  }
193  peakReconnectMutex.unlock();
194  }
195  if ( skipMainThreadCreation ){
196  MLOGPK(TRC, this) << "Re-using main thread m_idCanScanThread= " << m_idCanScanThread;
197  } else {
198  MLOGPK(TRC, this) << "creating main thread m_idCanScanThread= " << m_idCanScanThread;
199  CAN_FilterMessages(m_canObjHandler,0,0x7FF,PCAN_MESSAGE_STANDARD);
200  m_hCanScanThread = CreateThread(NULL, 0, CanScanControlThread, this, 0, &m_idCanScanThread);
201  if ( NULL == m_hCanScanThread ) {
202  DebugBreak();
203  return false;
204  }
205  }
206  return true;
207 }
208 
209 
214 bool PKCanScan::configureCanboard(const string name,const string parameters)
215 {
216  m_sBusName = name;
217  m_baudRate = PCAN_BAUD_125K;
218 
219  // for FD modules
220  //unsigned int parametersTseg1 = 0;
221  //unsigned int parametersTseg2 = 0;
222  //unsigned int parametersSjw = 0;
223  //unsigned int parametersNoSamp = 0;
224  //unsigned int parametersSyncmode = 0;
225  //long parametersBaudRate;
226  //int numPar;
227  //Process the parameters
228  vector<string> vectorString;
229  vectorString = parseNameAndParameters(name, parameters);
230  MLOGPK(DBG, this) << " calling getHandle vectorString[1]= " << vectorString[1] << std::endl;
231 
232  // peak guys start counting from 1, we start counting from 0. ugh.
233  int ich = atoi(vectorString[1].c_str());
234  stringstream channel;
235  channel << ich + 1;
236 
237  string interface = "USB";
238  string humanReadableCode = interface + channel.str();
239  m_canObjHandler = getHandle( humanReadableCode.c_str() );
240  MLOGPK( DBG, this ) << "PEAK handle for vectorString[1]= " << vectorString[1]
241  << " is code= 0x" <<hex << m_canObjHandler << dec
242  << " human readable code= " << humanReadableCode << std::endl;
243 
244 
245  if (strcmp(parameters.c_str(), "Unspecified") != 0)
246  {
247  //numPar = sscanf_s(canpars, "%d %d %d %d %d %d", &parametersBaudRate, &parametersTseg1, &parametersTseg2, &parametersSjw, &parametersNoSamp, &parametersSyncmode);
248  //Get the can object handler
249  m_canObjHandler = getHandle( humanReadableCode.c_str() /* vectorString[1].c_str() */ );
250  //Process the baudRate if needed
252  {
253  MLOGPK(DBG, this) << " m_CanParameters.m_lBaudRate= " << m_CanParameters.m_lBaudRate << std::endl;
255  {
256  case 50000:
257  m_baudRate = PCAN_BAUD_50K;
258  break;
259  case 100000:
260  m_baudRate = PCAN_BAUD_100K;
261  break;
262  case 125000:
263  m_baudRate = PCAN_BAUD_125K;
264  break;
265  case 250000:
266  m_baudRate = PCAN_BAUD_250K;
267  break;
268  case 500000:
269  m_baudRate = PCAN_BAUD_500K;
270  break;
271  case 1000000:
272  m_baudRate = PCAN_BAUD_1M;
273  break;
274  default:
276  }
277  } else {
280  } else {
281  MLOGPK(ERR, this) << "Error while parsing parameters: this syntax is incorrect: [" << parameters << "]";
282  return false;
283  }
284  }
285  } else {
286  MLOGPK(DBG, this) << "Unspecified parameters, default values will be used.";
287  }
288  MLOGPK(DBG, this) << " m_baudRate= " << m_baudRate << std::endl;
289 
298  //TPCANBitrateFD br = "f_clock_mhz=20, nom_brp=5, nom_tseg1=2, nom_tseg2=1, nom_sjw=1";
299  //TPCANStatus tpcanStatus = CAN_InitializeFD(m_canObjHandler, br );
300 
301 
306  MLOGPK(TRC, this) << "calling CAN_Initialize";
307  TPCANStatus tpcanStatus = 99;
308  int counter = 10;
309  while ( tpcanStatus != 0 && counter > 0 ){
310  tpcanStatus = CAN_Initialize(m_canObjHandler, m_baudRate );
311  MLOGPK(TRC, this) << "CAN_Initialize returns " << (int) tpcanStatus << " counter= " << counter;
312  if ( tpcanStatus == 0 ) {
313  MLOGPK(TRC, this) << "CAN_Initialize returns " << (int) tpcanStatus << " OK";
314  break;
315  }
316  Sleep( 1000 ); // 1000 ms
317  MLOGPK(TRC, this) << "try again... calling Can_Uninitialize " ;
318  tpcanStatus = CAN_Uninitialize( m_canObjHandler );
319  Sleep( 1000 ); // 1000 ms
320  counter--;
321  }
322 
331  // TPCANStatus tpcanStatus = CAN_Initialize(m_canObjHandler, m_baudRate,256,3); // one param missing ?
332  return tpcanStatus == PCAN_ERROR_OK;
333 }
334 
335 
336 bool PKCanScan::sendErrorCode(long status)
337 {
338  if (status != m_busStatus)
339  {
340  timeval ftTimeStamp = convertTimepointToTimeval(currentTimeTimeval());
341  char *errorMessage;
342  getErrorMessage(status, &errorMessage);
343  canMessageError(status, errorMessage, ftTimeStamp );
344  m_busStatus = (TPCANStatus)status;
345  }
346  if (status != PCAN_ERROR_OK)
347  {
348  status = CAN_Reset(m_canObjHandler);
349  return false;
350  }
351  return true;
352 }
353 
359 bool PKCanScan::sendMessage(short cobID, unsigned char len, unsigned char *message, bool rtr)
360 {
361  MLOGPK(DBG,this) << "Sending message: [" << ( message == 0 ? "" : (const char *) message) << "], cobID: [" << cobID << "], Message Length: [" << static_cast<int>(len) << "]";
362 
363  TPCANStatus tpcanStatus;
364  TPCANMsg tpcanMessage;
365  tpcanMessage.ID = cobID;
366  tpcanMessage.MSGTYPE = PCAN_MESSAGE_STANDARD;
367  if(rtr) {
368  tpcanMessage.MSGTYPE = PCAN_MESSAGE_RTR;
369  }
370  int lengthOfUnsentData, lengthToBeSent;
371  lengthOfUnsentData = len;
372  do {
373  //In every iteration of this loop a piece of message is sent of maximun 8 chars
374  //To keep track of how much message is left we use vars lengthOfUnsentData and lengthToBeSent
375  if (lengthOfUnsentData > 8) {
376  lengthToBeSent = 8;
377  lengthOfUnsentData = lengthOfUnsentData - 8;
378  } else {
379  lengthToBeSent = lengthOfUnsentData;
380  }
381  tpcanMessage.LEN = lengthToBeSent;
382 
383  memcpy(tpcanMessage.DATA,message,lengthToBeSent);
384  tpcanStatus = CAN_Write(m_canObjHandler, &tpcanMessage);
385  if (tpcanStatus != PCAN_ERROR_OK) {
386  return sendErrorCode(tpcanStatus);
387  }
388  m_statistics.onTransmit( tpcanMessage.LEN );
389  message = message + lengthToBeSent;
390  }
391  while (lengthOfUnsentData > 8);
392  return sendErrorCode(tpcanStatus);
393 }
394 
395 bool PKCanScan::sendRemoteRequest(short cobID)
396 {
397  TPCANMsg tpcanMessage;
398  tpcanMessage.ID = cobID;
399  tpcanMessage.MSGTYPE = PCAN_MESSAGE_RTR;
400  TPCANStatus tpcanStatus = CAN_Write(m_canObjHandler, &tpcanMessage);
401  return sendErrorCode(tpcanStatus);
402 }
403 
404 bool PKCanScan::getErrorMessage(long error, char **message)
405 {
406  char tmp[300];
407  CAN_GetErrorText((TPCANStatus)error,0, tmp);
408  *message = new char[strlen(tmp)+1];
409  strcpy(*message,tmp);
410  return true;
411 }
412 
418 TPCANHandle PKCanScan::getHandle(const char *name)
419 {
420  const char *channelNameArray[] = {
421  "ISA1","ISA2","ISA3","ISA4","ISA5","ISA6","ISA7","ISA8",
422  "DNG1",
423  "PCI1","PCI2","PCI3","PCI4","PCI5","PCI6","PCI7","PCI8",
424  "USB1","USB2","USB3","USB4","USB5","USB6","USB7","USB8",
425  "PCC1","PCC2"
426  };
427 
428  const TPCANHandle handlerArray[] = {
429  0x21, // PCAN-ISA interface, channel 1
430  0x22, // PCAN-ISA interface, channel 2
431  0x23, // PCAN-ISA interface, channel 3
432  0x24, // PCAN-ISA interface, channel 4
433  0x25, // PCAN-ISA interface, channel 5
434  0x26, // PCAN-ISA interface, channel 6
435  0x27, // PCAN-ISA interface, channel 7
436  0x28, // PCAN-ISA interface, channel 8
437 
438  0x31, // PCAN-Dongle/LPT interface, channel 1
439 
440  0x41, // PCAN-PCI interface, channel 1
441  0x42, // PCAN-PCI interface, channel 2
442  0x43, // PCAN-PCI interface, channel 3
443  0x44, // PCAN-PCI interface, channel 4
444  0x45, // PCAN-PCI interface, channel 5
445  0x46, // PCAN-PCI interface, channel 6
446  0x47, // PCAN-PCI interface, channel 7
447  0x48, // PCAN-PCI interface, channel 8
448 
449  0x51, // PCAN-USB interface, channel 1
450  0x52, // PCAN-USB interface, channel 2
451  0x53, // PCAN-USB interface, channel 3
452  0x54, // PCAN-USB interface, channel 4
453  0x55, // PCAN-USB interface, channel 5
454  0x56, // PCAN-USB interface, channel 6
455  0x57, // PCAN-USB interface, channel 7
456  0x58, // PCAN-USB interface, channel 8
457 
458  0x61, // PCAN-PC Card interface, channel 1
459  0x62 // PCAN-PC Card interface, channel 2
460  };
461  int chn = sizeof(channelNameArray)/sizeof(channelNameArray[0]);
462  char tmpName[] = "temp";//The previous method didn't work because of excessive string size in tmpName. Since all the names are 4 character long I just changed the size to 4
463  for (unsigned int j=0; j < 4; j++) {
464  tmpName[j] = toupper(name[j]);
465  }
466  for (int i = 0; i < chn; i++) {
467  if (strcmp(channelNameArray[i],tmpName) == 0) {
468  return handlerArray[i];
469  }
470  }
471  return 0;
472 }
473 
475 {
477  result = m_statistics; // copy whole structure
479 }
480