UsePeakCan.h
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of FZIs ic_workspace.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
12 //
13 // -- END LICENSE BLOCK ------------------------------------------------
14 
15 //----------------------------------------------------------------------
27 //----------------------------------------------------------------------
28 #ifndef _icl_hardware_can_UsePeakCan_h_
29 #define _icl_hardware_can_UsePeakCan_h_
30 
31 #ifdef _SYSTEM_LINUX_
32 # include <fcntl.h>
33 # include <unistd.h>
34 # include <sys/ioctl.h>
35 # include <string.h>
36 # include <errno.h>
37 # include <libpcan.h>
38 #endif
39 
42 #include "Logging.h"
43 
44 namespace icl_hardware {
45 namespace can {
46 
47 typedef HANDLE tCanDescriptor;
48 inline bool CanDescriptorValid(tCanDescriptor can_device)
49 {
50  return can_device != 0;
51 }
52 inline tCanDescriptor InvalidCanDescriptor()
53 {
54  return 0;
55 }
56 inline const char* CanDriverName()
57 {
58  return "PEAK-CAN";
59 }
60 
61 inline WORD BaudRateSpecifier( unsigned int baud_rate )
62 {
63  switch( baud_rate )
64  {
65  case 1000:
66  return CAN_BAUD_1M;
67  case 500:
68  return CAN_BAUD_500K;
69  case 250:
70  return CAN_BAUD_250K;
71  case 100:
72  return CAN_BAUD_100K;
73  case 50:
74  return CAN_BAUD_50K;
75  case 20:
76  return CAN_BAUD_20K;
77  case 10:
78  return CAN_BAUD_10K;
79  case 5:
80  return CAN_BAUD_5K;
81 
82  default:
83  LOGGING_ERROR( CAN, "Peak Can baud rate " << baud_rate << " not valid. Setting the baud rate to 1MB " << endl);
84  return CAN_BAUD_1M;
85  }
86 }
88 
107 inline tCanDescriptor CanDeviceOpen(const char * device_name, int flags,
108  unsigned char acceptance_code, unsigned char acceptance_mask, unsigned int baud_rate,
109  unsigned send_fifo_size, unsigned receive_fifo_size)
110 {
111  printf("flags:%i\n",flags);
112  HANDLE handle;
113  handle = LINUX_CAN_Open((char*) device_name, flags);
114 
115  // Timing problems when CAN_Init is called too early
116  sleep(1);
117 
118  WORD br = BaudRateSpecifier( baud_rate );
119 
120  if ( CAN_Init(handle, br , CAN_INIT_TYPE_ST ))
121  {
122  printf("Invalid CanDescriptor!\n");
123  return InvalidCanDescriptor();
124  }
125  else
126  {
127  printf("Can Init successful!\n");
128  return handle;
129  }
130 }
131 
132 inline int CanDeviceClose(tCanDescriptor _can_device)
133 {
134  return CAN_Close(_can_device);
135 }
136 
137 inline int CanDeviceSend(tCanDescriptor _can_device, const tCanMessage &msg)
138 {
139  if (!_can_device)
140  return -ENODEV;
141 
142  // return write(_can_device,&msg,sizeof(tCanMessage));
143 
144  TPCANMsg pmsg;
145  pmsg.ID = msg.id;
146  pmsg.MSGTYPE = MSGTYPE_STANDARD;
147  // pmsg.MSGTYPE = msg.rtr;
148  pmsg.LEN = msg.dlc;
149  memcpy(pmsg.DATA, msg.data, pmsg.LEN);
150 
151  // INFOMSG( "writing can msg: id:%d (0x%02x), type:%d, len:%d, data: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", pmsg.ID, pmsg.ID, pmsg.MSGTYPE, pmsg.LEN, pmsg.DATA[ 0 ], pmsg.DATA[ 1 ], pmsg.DATA[ 2 ], pmsg.DATA[ 3 ], pmsg.DATA[ 4 ], pmsg.DATA[ 5 ], pmsg.DATA[ 6 ], pmsg.DATA[ 7 ] );
152 
153  return CAN_Write(_can_device, &pmsg);
154 }
155 
156 inline int CanDeviceReceive(tCanDescriptor _can_device, tCanMessage &msg)
157 {
158  if (!_can_device)
159  return -ENODEV;
160 
161  // Raw Can Message
162  TPCANRdMsg pmsg;
163 
164 
165 
166  // DM("reading can msg.\n");
173  int ret = LINUX_CAN_Read_Timeout(_can_device, &pmsg, 0);
174  // DM("done\n");
175  //DM("recieved msg\n");
176 
177  // In Case of an IOCTL or SELECT Error we could not even open the hardware itself. We will immediately terminate and retun a generic IO Error
178  // It should only be -1 as error code but in case it isnt we will print it out here.
179  if (ret < 0)
180  {
181  LOGGING_ERROR( CAN, "CAN DEVICE HANDLE CRITICAL ERROR. COULD NOT READ PROPERLY FROM DEVICE. Error Code: " << ret << endl);
182  return -EIO; // Generic IO error
183  }
184 
185  // Buffer is empty is the only return value still given as ret. all other errors need to be handled differently
186  if (ret == CAN_ERR_QRCVEMPTY)
187  {
188  // As "no data" is actually no error we will just stop the read here"
189  return -ENODATA;
190  }
191 
192  // since pcan 6.x the error handling is changed and facilitates the Data field for error messages
193  if (pmsg.Msg.MSGTYPE == MSGTYPE_STATUS )
194  {
195  // All 8 Data bytes are always present in the message so it is save to just read any of them without checking the lenght.
196  // Hoever, it might contain garbage.
197 
198  // This should not happen but just to be save
199  if (pmsg.Msg.DATA[3] == CAN_ERR_QRCVEMPTY)
200  {
201  return -ENODATA;
202  }
203 
204  LOGGING_ERROR( CAN, "CAN ERROR DETECTED: ");
205  // Error Values are stored in data[3]!
206  switch (pmsg.Msg.DATA[3])
207  {
208  case CAN_ERR_OK: // no error
209  LOGGING_ERROR( CAN, "no error code given in an error message....check protocol" << endl);
210  break;
211  case CAN_ERR_XMTFULL: // transmit buffer full
212  LOGGING_ERROR( CAN, "transmit Buffer is full" << endl);
213  return -ENOBUFS;
214  break;
215  case CAN_ERR_OVERRUN: // overrun in receive buffer
216  LOGGING_ERROR( CAN, "ovverrun in receive buffer" << endl);
217  return -ENOBUFS;
218  break;
219  case CAN_ERR_BUSLIGHT: // bus error, errorcounter limit reached
220  LOGGING_ERROR( CAN, "BUSLIGHT, errorcounter limit reached, please check your cable setup" << endl);
221  return -EIO;
222  break;
223  case CAN_ERR_BUSHEAVY: // bus error, errorcounter limit reached
224  LOGGING_ERROR( CAN, "BUSHEAVY, errorcounter limit reached, please check your cable setup" << endl);
225  return -EIO;
226  break;
227  case CAN_ERR_BUSOFF: // bus error, 'bus off' state entered
228  LOGGING_ERROR( CAN, "BUSOFF, 'bus off' state entered" << endl);
229  return -EIO;
230  break;
231  case CAN_ERR_QOVERRUN: // receive queue overrun
232  LOGGING_ERROR( CAN, "receive queue overrun" << endl);
233  return -ENOBUFS;
234  break;
235  case CAN_ERR_QXMTFULL: // transmit queue full
236  LOGGING_ERROR( CAN, "transmit queue full" << endl);
237  return -ENOBUFS;
238  break;
239 // TODO: These error codes are defined by the API, but they can never be reached using a one-byte value
240 // case CAN_ERR_REGTEST: // test of controller registers failed
241 // LOGGING_ERROR( CAN, "test of controller registers failed" << endl);
242 // return -EPROTO;
243 // break;
244 // case CAN_ERR_NOVXD: // Win95/98/ME only
245 // LOGGING_ERROR( CAN, "NO VXD (win95 issue...)" << endl);
246 // return -EPROTO;
247 // break;
248 // case CAN_ERR_RESOURCE : // can't create resource
249 // LOGGING_ERROR( CAN, "can't create resoursce" << endl);
250 // return -EPROTO;
251 // break;
252 // case CAN_ERR_ILLPARAMTYPE: // illegal parameter
253 // LOGGING_ERROR( CAN, "illegal parameter" << endl);
254 // return -EPROTO;
255 // break;
256 // case CAN_ERR_ILLPARAMVAL: // value out of range
257 // LOGGING_ERROR( CAN, "value out of range" << endl);
258 // return -EPROTO;
259 // break;
260 // case CAN_ERRMASK_ILLHANDLE: // wrong handle, handle error
261 // LOGGING_ERROR( CAN, "wrong handle, handle error" << endl);
262 // return -EPROTO;
263 // break;
264  default:
265  LOGGING_ERROR( CAN, "Unknown error : "<< pmsg.Msg.DATA[3] << endl);
266  // TODO:
267  // do something usefull herer
268  return -ENODATA;
269  break;
270  }
271  }
272 
273  // At this point we have Extended, RTR and Standard messages left.
274  // Standard can just be parsed, extended too, but we need to check the RTR
275  // As this is only 0x01 in case of an RTR type message
276 
277 
278  /* DM( "reading can msg: id:%d (0x%02x), type:%d, len:%d,
279  data: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
280  pmsg.Msg.ID, pmsg.Msg.ID, pmsg.Msg.MSGTYPE, pmsg.Msg.LEN,
281  pmsg.Msg.DATA[ 0 ], pmsg.Msg.DATA[ 1 ], pmsg.Msg.DATA[ 2 ], pmsg.Msg.DATA[ 3 ],
282  pmsg.Msg.DATA[ 4 ], pmsg.Msg.DATA[ 5 ], pmsg.Msg.DATA[ 6 ], pmsg.Msg.DATA[ 7 ] );*/
283 
284  msg.id = pmsg.Msg.ID;
285  msg.dlc = pmsg.Msg.LEN;
286  if (pmsg.Msg.MSGTYPE == MSGTYPE_EXTENDED || pmsg.Msg.MSGTYPE == MSGTYPE_STATUS)
287  {
288  msg.rtr = 0;
289  }
290  else
291  {
292  // MSG Type Standard = 0x00 ,RTR = 0x01
293  msg.rtr = pmsg.Msg.MSGTYPE;
294  }
295 
296  memcpy(msg.data, pmsg.Msg.DATA, pmsg.Msg.LEN);
297 
298  // As all the errors have been captured before we just need to return something >0 in case of a succesfull read. This should be the case with msg.len
299  return pmsg.Msg.LEN;
300 }
301 
302 inline int CanDeviceReset(tCanDescriptor _can_device)
303 {
304  if (!_can_device)
305  return -ENODEV;
306  return 0;
307 }
308 
309 }
310 }
311 
312 #endif
int CanDeviceClose(tCanDescriptor)
Definition: UseDummyCan.h:62
WORD BaudRateSpecifier(unsigned int baud_rate)
Definition: UsePeakCan.h:61
Implements a struct representing a can message.
Definition: tCanMessage.h:43
void * memcpy(void *dest, void *src, size_t count)
bool CanDescriptorValid(tCanDescriptor can_device)
Definition: UseDummyCan.h:38
int CanDeviceReset(tCanDescriptor)
Definition: UseDummyCan.h:77
#define LOGGING_ERROR(streamname, arg)
unsigned int sleep(unsigned int seconds)
const char * CanDriverName()
Definition: UseDummyCan.h:48
Contains CAN driver interface functions.
ThreadStream & endl(ThreadStream &stream)
tCanDescriptor InvalidCanDescriptor()
Definition: UseDummyCan.h:43
Contains CAN driver interface functions.
tCanDescriptor CanDeviceOpen(const char *, int, unsigned char, unsigned char, unsigned int, unsigned, unsigned)
Open a can device and set parameters.
Definition: UseDummyCan.h:53
int CanDeviceSend(tCanDescriptor, const tCanMessage &)
Definition: UseDummyCan.h:67
int CanDeviceReceive(tCanDescriptor, tCanMessage &)
Definition: UseDummyCan.h:72


fzi_icl_can
Author(s):
autogenerated on Mon Jun 10 2019 13:17:02