UsePeakCan.h
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 
00003 // -- BEGIN LICENSE BLOCK ----------------------------------------------
00004 // This file is part of FZIs ic_workspace.
00005 //
00006 // This program is free software licensed under the LGPL
00007 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
00008 // You can find a copy of this license in LICENSE folder in the top
00009 // directory of the source code.
00010 //
00011 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
00012 //
00013 // -- END LICENSE BLOCK ------------------------------------------------
00014 
00015 //----------------------------------------------------------------------
00027 //----------------------------------------------------------------------
00028 #ifndef _icl_hardware_can_UsePeakCan_h_
00029 #define _icl_hardware_can_UsePeakCan_h_
00030 
00031 #ifdef _SYSTEM_LINUX_
00032 # include <fcntl.h>
00033 # include <unistd.h>
00034 # include <sys/ioctl.h>
00035 # include <string.h>
00036 # include <errno.h>
00037 # include <libpcan.h>
00038 #endif
00039 
00040 #include "icl_hardware_can/tCanMessage.h"
00041 #include "icl_hardware_can/UseCanNoLxrt.h"
00042 #include "Logging.h"
00043 
00044 namespace icl_hardware {
00045 namespace can {
00046 
00047 typedef HANDLE tCanDescriptor;
00048 inline bool CanDescriptorValid(tCanDescriptor can_device)
00049 {
00050   return can_device != 0;
00051 }
00052 inline tCanDescriptor InvalidCanDescriptor()
00053 {
00054   return 0;
00055 }
00056 inline const char* CanDriverName()
00057 {
00058   return "PEAK-CAN";
00059 }
00060 
00061 inline WORD BaudRateSpecifier( unsigned int baud_rate )
00062 {
00063   switch( baud_rate )
00064   {
00065     case 1000:
00066      return CAN_BAUD_1M;
00067     case 500:
00068      return CAN_BAUD_500K;
00069     case 250:
00070       return CAN_BAUD_250K;
00071     case 100:
00072       return CAN_BAUD_100K;
00073     case 50:
00074       return CAN_BAUD_50K;
00075     case 20:
00076       return CAN_BAUD_20K;
00077     case 10:
00078       return CAN_BAUD_10K;
00079     case 5:
00080       return CAN_BAUD_5K;
00081 
00082     default:
00083       LOGGING_ERROR( CAN, "Peak Can baud rate " << baud_rate << " not valid. Setting the baud rate to 1MB " << endl);
00084       return CAN_BAUD_1M;
00085   }
00086 }
00088 
00107 inline tCanDescriptor CanDeviceOpen(const char * device_name, int flags,
00108                                     unsigned char acceptance_code, unsigned char acceptance_mask, unsigned int baud_rate,
00109                                     unsigned send_fifo_size, unsigned receive_fifo_size)
00110 {
00111   printf("flags:%i\n",flags);
00112   HANDLE handle;
00113   handle = LINUX_CAN_Open((char*) device_name, flags);
00114 
00115   // Timing problems when CAN_Init is called too early
00116   sleep(1);
00117 
00118   WORD br = BaudRateSpecifier( baud_rate );
00119 
00120   if ( CAN_Init(handle, br  , CAN_INIT_TYPE_ST ))
00121   {
00122     printf("Invalid CanDescriptor!\n");
00123     return InvalidCanDescriptor();
00124   }
00125   else
00126   {
00127     printf("Can Init successful!\n");
00128     return handle;
00129   }
00130 }
00131 
00132 inline int CanDeviceClose(tCanDescriptor _can_device)
00133 {
00134   return CAN_Close(_can_device);
00135 }
00136 
00137 inline int CanDeviceSend(tCanDescriptor _can_device, const tCanMessage &msg)
00138 {
00139   if (!_can_device)
00140     return -ENODEV;
00141 
00142   // return write(_can_device,&msg,sizeof(tCanMessage));
00143 
00144   TPCANMsg pmsg;
00145   pmsg.ID = msg.id;
00146   pmsg.MSGTYPE = MSGTYPE_STANDARD;
00147   // pmsg.MSGTYPE = msg.rtr;
00148   pmsg.LEN = msg.dlc;
00149   memcpy(pmsg.DATA, msg.data, pmsg.LEN);
00150 
00151   //   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 ] );
00152 
00153   return CAN_Write(_can_device, &pmsg);
00154 }
00155 
00156 inline int CanDeviceReceive(tCanDescriptor _can_device, tCanMessage &msg)
00157 {
00158   if (!_can_device)
00159     return -ENODEV;
00160 
00161   // Raw Can Message
00162   TPCANRdMsg pmsg;
00163 
00164 
00165 
00166   // DM("reading can msg.\n");
00173   int ret = LINUX_CAN_Read_Timeout(_can_device, &pmsg, 0);
00174   // DM("done\n");
00175   //DM("recieved msg\n");
00176 
00177   // 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
00178   // It should only be -1 as error code but in case it isnt we will print it out here.
00179   if (ret < 0)
00180   {
00181     LOGGING_ERROR( CAN, "CAN DEVICE HANDLE CRITICAL ERROR. COULD NOT READ PROPERLY FROM DEVICE. Error Code: " << ret << endl);
00182     return -EIO; // Generic IO error
00183   }
00184 
00185   // Buffer is empty is the only return value still given as ret. all other errors need to be handled differently
00186   if (ret == CAN_ERR_QRCVEMPTY)
00187   {
00188     // As "no data" is actually no error we will just stop the read here"
00189     return -ENODATA;
00190   }
00191 
00192   // since pcan 6.x the error handling is changed and facilitates the Data field for error messages
00193   if (pmsg.Msg.MSGTYPE == MSGTYPE_STATUS )
00194   {
00195     // All 8 Data bytes are always present in the message so it is save to just read any of them without checking the lenght.
00196     // Hoever, it might contain garbage.
00197 
00198     // This should not happen but just to be save
00199     if (pmsg.Msg.DATA[3] == CAN_ERR_QRCVEMPTY)
00200     {
00201       return -ENODATA;
00202     }
00203 
00204     LOGGING_ERROR( CAN, "CAN ERROR DETECTED:  ");
00205     // Error Values are stored in data[3]!
00206     switch (pmsg.Msg.DATA[3])
00207     {
00208       case CAN_ERR_OK:            // no error
00209           LOGGING_ERROR( CAN, "no error code given in an error message....check protocol" << endl);
00210         break;
00211       case CAN_ERR_XMTFULL:       // transmit buffer full
00212         LOGGING_ERROR( CAN, "transmit Buffer is full" << endl);
00213         return -ENOBUFS;
00214         break;
00215       case CAN_ERR_OVERRUN:       // overrun in receive buffer
00216         LOGGING_ERROR( CAN, "ovverrun in receive buffer" << endl);
00217         return -ENOBUFS;
00218         break;
00219       case CAN_ERR_BUSLIGHT:      // bus error, errorcounter limit reached
00220         LOGGING_ERROR( CAN, "BUSLIGHT, errorcounter limit reached, please check your cable setup" << endl);
00221         return -EIO;
00222         break;
00223       case CAN_ERR_BUSHEAVY:      // bus error, errorcounter limit reached
00224         LOGGING_ERROR( CAN, "BUSHEAVY, errorcounter limit reached, please check your cable setup" << endl);
00225         return -EIO;
00226         break;
00227       case CAN_ERR_BUSOFF:        // bus error, 'bus off' state entered
00228         LOGGING_ERROR( CAN, "BUSOFF, 'bus off' state entered" << endl);
00229         return -EIO;
00230         break;
00231       case CAN_ERR_QOVERRUN:      // receive queue overrun
00232         LOGGING_ERROR( CAN, "receive queue overrun" << endl);
00233         return -ENOBUFS;
00234         break;
00235       case CAN_ERR_QXMTFULL:      // transmit queue full
00236         LOGGING_ERROR( CAN, "transmit queue full" << endl);
00237         return -ENOBUFS;
00238         break;
00239 // TODO: These error codes are defined by the API, but they can never be reached using a one-byte value
00240 //       case CAN_ERR_REGTEST:       // test of controller registers failed
00241 //         LOGGING_ERROR( CAN, "test of controller registers failed" << endl);
00242 //         return -EPROTO;
00243 //         break;
00244 //       case CAN_ERR_NOVXD:         // Win95/98/ME only
00245 //         LOGGING_ERROR( CAN, "NO VXD (win95 issue...)" << endl);
00246 //         return -EPROTO;
00247 //         break;
00248 //       case CAN_ERR_RESOURCE :     // can't create resource
00249 //         LOGGING_ERROR( CAN, "can't create resoursce" << endl);
00250 //         return -EPROTO;
00251 //         break;
00252 //       case CAN_ERR_ILLPARAMTYPE:  // illegal parameter
00253 //         LOGGING_ERROR( CAN, "illegal parameter" << endl);
00254 //         return -EPROTO;
00255 //         break;
00256 //       case CAN_ERR_ILLPARAMVAL:   // value out of range
00257 //         LOGGING_ERROR( CAN, "value out of range" << endl);
00258 //         return -EPROTO;
00259 //         break;
00260 //       case CAN_ERRMASK_ILLHANDLE: // wrong handle, handle error
00261 //         LOGGING_ERROR( CAN, "wrong handle, handle error" << endl);
00262 //         return -EPROTO;
00263 //         break;
00264       default:
00265         LOGGING_ERROR( CAN, "Unknown error : "<< pmsg.Msg.DATA[3]  << endl);
00266         // TODO:
00267         // do something usefull herer
00268         return -ENODATA;
00269         break;
00270     }
00271   }
00272 
00273   // At this point we have Extended, RTR and Standard messages left.
00274   // Standard can just be parsed, extended too, but we need to check the RTR
00275   // As this is only 0x01 in case of an RTR type message
00276 
00277 
00278   /* DM( "reading can msg: id:%d (0x%02x), type:%d, len:%d,
00279                 data: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
00280                 pmsg.Msg.ID, pmsg.Msg.ID, pmsg.Msg.MSGTYPE, pmsg.Msg.LEN,
00281                 pmsg.Msg.DATA[ 0 ], pmsg.Msg.DATA[ 1 ], pmsg.Msg.DATA[ 2 ], pmsg.Msg.DATA[ 3 ],
00282                 pmsg.Msg.DATA[ 4 ], pmsg.Msg.DATA[ 5 ], pmsg.Msg.DATA[ 6 ], pmsg.Msg.DATA[ 7 ] );*/
00283 
00284   msg.id = pmsg.Msg.ID;
00285   msg.dlc = pmsg.Msg.LEN;
00286   if (pmsg.Msg.MSGTYPE == MSGTYPE_EXTENDED || pmsg.Msg.MSGTYPE == MSGTYPE_STATUS)
00287   {
00288     msg.rtr = 0;
00289   }
00290   else
00291   {
00292     // MSG Type Standard = 0x00 ,RTR = 0x01
00293     msg.rtr = pmsg.Msg.MSGTYPE;
00294   }
00295 
00296   memcpy(msg.data, pmsg.Msg.DATA, pmsg.Msg.LEN);
00297 
00298   // 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
00299   return pmsg.Msg.LEN;
00300 }
00301 
00302 inline int CanDeviceReset(tCanDescriptor _can_device)
00303 {
00304   if (!_can_device)
00305     return -ENODEV;
00306   return 0;
00307 }
00308 
00309 }
00310 }
00311 
00312 #endif


fzi_icl_can
Author(s):
autogenerated on Thu Jun 6 2019 20:26:01