drivers/can_ixxat_win32/ixxat.cpp
changeset 787 e13fa74d169c
parent 785 b72a88dbc7c3
child 788 6121ebff4da6
equal deleted inserted replaced
785:b72a88dbc7c3 787:e13fa74d169c
     1 /*
       
     2 This file is part of CanFestival, a library implementing CanOpen Stack.
       
     3 
       
     4 CanFestival Copyright (C): Edouard TISSERANT and Francis DUPIN
       
     5 CanFestival Win32 port Copyright (C) 2007 Leonid Tochinski, ChattenAssociates, Inc.
       
     6 
       
     7 See COPYING file for copyrights details.
       
     8 
       
     9 This library is free software; you can redistribute it and/or
       
    10 modify it under the terms of the GNU Lesser General Public
       
    11 License as published by the Free Software Foundation; either
       
    12 version 2.1 of the License, or (at your option) any later version.
       
    13 
       
    14 This library is distributed in the hope that it will be useful,
       
    15 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    17 Lesser General Public License for more details.
       
    18 
       
    19 You should have received a copy of the GNU Lesser General Public
       
    20 License along with this library; if not, write to the Free Software
       
    21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    22 */
       
    23 // pragma based message
       
    24 // http://www.codeproject.com/macro/location_pragma.asp
       
    25 #define __STR2__(x) #x
       
    26 #define __STR1__(x) __STR2__(x)
       
    27 #define __LOC2__ __FILE__ "("__STR1__(__LINE__)") : "
       
    28 
       
    29 
       
    30 #pragma message("*********************************************************************************")
       
    31 #pragma message("  NOTE: IXXAT Win32 drivers and API should be installed in order to build this project!")
       
    32 #pragma message(__LOC2__ "See IXXAT.Cpp header for details.")
       
    33 #pragma message("*********************************************************************************")
       
    34 
       
    35 
       
    36 // IXXAT adapter driver for CanFestival-3 Win32 port
       
    37 //
       
    38 // Notes
       
    39 //--------------------------------------------
       
    40 // For building of this project you will need 
       
    41 // the following IXXAT API files
       
    42 // Vci2.h
       
    43 // Vci11un6.lib
       
    44 //
       
    45 // IXXAT Win32 drivers and API can be downloaded from
       
    46 // http://www.ixxat.com/download_vci_en,7547,5873.html
       
    47 //
       
    48 // Copy Vci2.h & Vci11un6.lib files to can_ixxat_win32 folder of add path to them in Project settings.
       
    49 
       
    50 
       
    51 #include <stdio.h>
       
    52 extern "C" {
       
    53 #include "applicfg.h"
       
    54 #include "can_driver.h"
       
    55 #include "def.h"
       
    56 }
       
    57 #include "VCI2.h"
       
    58 #include "async_access_que.h"
       
    59 
       
    60 #define CAN_NUM 0
       
    61 
       
    62 class IXXAT
       
    63    {
       
    64    public:
       
    65       class error
       
    66         {
       
    67         };
       
    68       IXXAT(s_BOARD *board);
       
    69       ~IXXAT();
       
    70       bool send(const Message *m);
       
    71       bool receive(Message *m);
       
    72 
       
    73 	  static bool isDriverClosed() {return m_driverClosed;}
       
    74    private:
       
    75       bool open(int board_number, const char* baud_rate);
       
    76       bool close();
       
    77       void receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj);
       
    78       // VCI2 handler      
       
    79       static void VCI_CALLBACKATTR message_handler(char *msg_str);
       
    80       static void VCI_CALLBACKATTR receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj);
       
    81       static void VCI_CALLBACKATTR exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str);
       
    82       
       
    83       static void CALLBACK canBusWatchdog(HWND hwnd, UINT msg, UINT_PTR idEvent, DWORD dwTime);
       
    84       void watchdog();
       
    85    private:
       
    86       UINT16 m_BoardHdl;
       
    87       UINT16 m_TxQueHdl;
       
    88       UINT16 m_RxQueHdl;
       
    89       async_access_que<VCI_CAN_OBJ> m_RX_Que;
       
    90       static IXXAT* m_callbackPtr;
       
    91 
       
    92 	  static bool m_driverClosed;
       
    93       static UINT_PTR m_watchdogTimerId;
       
    94       static const unsigned int CAN_BUS_WATCHDOG_INTERVAL_MSEC = 10000;
       
    95 
       
    96       /** Bitmask inside sts from VCI_ReadCanStatus() that defines the can bus off state.*/
       
    97       static const unsigned char STS_CAN_BUS_OFF = 0x80;
       
    98 
       
    99       /** Bitmask inside sts from VCI_ReadCanStatus() that defines the can data overrun state.*/
       
   100       static const unsigned char STS_CAN_DATA_OVERRUN = 0x20;
       
   101 
       
   102       /** Bitmask inside sts from VCI_ReadCanStatus() that defines the remote queue overrun state.*/
       
   103       static const unsigned char STS_REMOTE_QUEUE_OVERRUN = 0x04;
       
   104    };
       
   105 
       
   106 IXXAT *IXXAT::m_callbackPtr = NULL;
       
   107 
       
   108 UINT_PTR IXXAT::m_watchdogTimerId = 0;
       
   109 
       
   110 bool IXXAT::m_driverClosed = false;
       
   111 
       
   112 IXXAT::IXXAT(s_BOARD *board) : m_BoardHdl(0xFFFF),
       
   113                                m_TxQueHdl(0xFFFF),
       
   114                                m_RxQueHdl(0xFFFF)
       
   115                                
       
   116    {
       
   117    if (!board)
       
   118       {
       
   119       close();
       
   120       throw error();
       
   121       }
       
   122 
       
   123    long board_number = 0;
       
   124 
       
   125    if (board->busname)
       
   126       {
       
   127       board_number = atol(board->busname);
       
   128       }
       
   129 
       
   130    if (!open(board_number, board->baudrate))
       
   131       {
       
   132       close();
       
   133       throw error();
       
   134       }
       
   135    m_callbackPtr = this;
       
   136    }
       
   137 
       
   138 IXXAT::~IXXAT()
       
   139    {
       
   140    close();
       
   141    m_callbackPtr = 0;
       
   142    }
       
   143 
       
   144 bool IXXAT::send(const Message *m)
       
   145    {
       
   146    if (m_BoardHdl == 0xFFFF)
       
   147       return true; // true -> NOT OK
       
   148    long res = VCI_ERR;
       
   149    if (m->rtr == NOT_A_REQUEST)
       
   150       res = VCI_TransmitObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len, const_cast<unsigned char*>(m->data));
       
   151    else
       
   152       res = VCI_RequestObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len);
       
   153 
       
   154    return (res == VCI_OK);
       
   155    }
       
   156 
       
   157 
       
   158 bool IXXAT::receive(Message *m)
       
   159    {
       
   160    if (m_BoardHdl == 0xFFFF)
       
   161       return false;
       
   162    VCI_CAN_OBJ obj;
       
   163    if (m_RX_Que.extract_top(obj))
       
   164       {
       
   165       m->cob_id = static_cast<UNS16>(obj.id); //valid for 11Bit ids
       
   166       m->len = obj.len;
       
   167       m->rtr = (obj.rtr == VCI_RX_BUF) ? NOT_A_REQUEST : REQUEST;
       
   168       if (m->rtr == NOT_A_REQUEST)
       
   169          ::memcpy(m->data, obj.a_data, m->len);
       
   170       return true;
       
   171       }
       
   172    return false;
       
   173    }
       
   174 
       
   175 bool IXXAT::open(int board_number, const char* baud_rate)
       
   176    {
       
   177    // check, if baudrate is supported
       
   178    struct IXXAT_baud_rate_param 
       
   179      { 
       
   180      UINT8  bt0; 
       
   181      UINT8  bt1;
       
   182      };
       
   183    struct IXXAT_look_up_table
       
   184      {
       
   185      char baud_rate[20];
       
   186      IXXAT_baud_rate_param bt;
       
   187      };
       
   188    static const IXXAT_look_up_table br_lut[] = {
       
   189                {"10K",{VCI_10KB}},
       
   190                {"20K",{VCI_20KB}},
       
   191                {"50K",{VCI_50KB}},
       
   192                {"100K",{VCI_100KB}},
       
   193                {"125K",{VCI_125KB}},
       
   194                {"250K",{VCI_250KB}},
       
   195                {"500K",{VCI_500KB}},
       
   196                {"800K",{VCI_800KB}},
       
   197                {"1M",{VCI_1000KB}}
       
   198                };
       
   199    static const long br_lut_size = sizeof (br_lut)/sizeof(IXXAT_look_up_table);
       
   200    int index;
       
   201    for (index = 0; index < br_lut_size; ++index)
       
   202        {
       
   203        if (::strcmp(br_lut[index].baud_rate,baud_rate)==0)
       
   204           break;
       
   205        }
       
   206    if (index == br_lut_size)
       
   207    {
       
   208       MSG_ERR_DRV("IXXAT::open: The given baudrate %S is invalid.", baud_rate);
       
   209       return false;
       
   210    }
       
   211    // close existing board   
       
   212    close();
       
   213    // init IXXAT board
       
   214    long res = VCI2_PrepareBoard(   0,                         // board type, unused in VCI2
       
   215                                    board_number,              // unique board index, see XAT_EnumHwEntry() and XAT_GetConfig()
       
   216                                    NULL,                      // pointer to buffer for additional info 
       
   217                                    0,                         // length of additional info buffer
       
   218                                    message_handler,           // pointer to msg-callbackhandler
       
   219                                    receive_queuedata_handler, // pointer to receive-callbackhandler
       
   220                                    exception_handler);        // pointer to exception-callbackhandler
       
   221    if (res < 0)
       
   222    {
       
   223       MSG_ERR_DRV("IXXAT::open: VCI2_PrepareBoard failed with code '%d'.", res);
       
   224       return false;
       
   225    }
       
   226    m_BoardHdl = (UINT16)res;
       
   227 
       
   228    VCI_ResetBoard(m_BoardHdl);
       
   229    
       
   230    // init CAN parameters
       
   231    
       
   232    // initialize CAN-Controller
       
   233    res = VCI_InitCan(m_BoardHdl, CAN_NUM, br_lut[index].bt.bt0,br_lut[index].bt.bt1, VCI_11B);
       
   234    
       
   235    //  definition of Acceptance-Mask (define to receive all IDs)
       
   236    res = VCI_SetAccMask(m_BoardHdl, CAN_NUM, 0x0UL, 0x0UL);
       
   237 
       
   238    // definition of Transmit Queue
       
   239    res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_TX_QUE, 100 , 0, 0, 0,  &m_TxQueHdl);
       
   240    
       
   241    //  definition of Receive Queue (interrupt mode)
       
   242    res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_RX_QUE, 500, 1, 0, 100,  &m_RxQueHdl);
       
   243 
       
   244    //  assign the all IDs to the Receive Queue
       
   245    res = VCI_AssignRxQueObj(m_BoardHdl, m_RxQueHdl ,VCI_ACCEPT, 0, 0);
       
   246 
       
   247    //  And now start the CAN
       
   248    res = VCI_StartCan(m_BoardHdl, CAN_NUM);
       
   249 
       
   250    //Start CAN Bus-Off watchdog
       
   251    m_watchdogTimerId = SetTimer(NULL, NULL, IXXAT::CAN_BUS_WATCHDOG_INTERVAL_MSEC, IXXAT::canBusWatchdog);
       
   252    
       
   253    m_driverClosed = false;
       
   254 
       
   255    return true;
       
   256    }
       
   257 
       
   258 bool IXXAT::close()
       
   259    {
       
   260 	m_driverClosed = true;
       
   261    if (m_BoardHdl == 0xFFFF)
       
   262       return true;
       
   263    VCI_ResetBoard(m_BoardHdl);   
       
   264    VCI_CancelBoard(m_BoardHdl);
       
   265    m_BoardHdl = 
       
   266    m_TxQueHdl = 
       
   267    m_RxQueHdl = 0xFFFF;
       
   268    return true;
       
   269    }
       
   270 
       
   271 void IXXAT::receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj)
       
   272    {
       
   273    for (int i = 0; i < count; ++i)
       
   274        m_RX_Que.append(p_obj[i]); // can packet
       
   275    }
       
   276 
       
   277 void VCI_CALLBACKATTR IXXAT::receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj)
       
   278   {
       
   279    if (m_callbackPtr != NULL)
       
   280       m_callbackPtr->receive_queuedata(que_hdl, count, p_obj);
       
   281   }
       
   282 
       
   283 void VCI_CALLBACKATTR IXXAT::message_handler(char *msg_str)
       
   284   {
       
   285   MSG_ERR_DRV("IXXAT Message: [%S]", msg_str);
       
   286   }
       
   287 
       
   288 void VCI_CALLBACKATTR IXXAT::exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str)
       
   289   {
       
   290   static const char* Num2Function[] =
       
   291     {
       
   292     "VCI_Init",
       
   293     "VCI_Searchboard",
       
   294     "VCI_Prepareboard",
       
   295     "VCI_Cancel_board",
       
   296     "VCI_Testboard",
       
   297     "VCI_ReadBoardInfo",
       
   298     "VCI_ReadBoardStatus",
       
   299     "VCI_Resetboard",
       
   300     "VCI_ReadCANInfo",
       
   301     "VCI_ReadCANStatus",
       
   302     "VCI_InitCAN",
       
   303     "VCI_SetAccMask",
       
   304     "VCI_ResetCAN",
       
   305     "VCI_StartCAN",
       
   306     "VCI_ResetTimeStamps",
       
   307     "VCI_ConfigQueue",
       
   308     "VCI_AssignRxQueObj",
       
   309     "VCI_ConfigBuffer",
       
   310     "VCI_ReconfigBuffer",
       
   311     "VCI_ConfigTimer",
       
   312     "VCI_ReadQueStatus",
       
   313     "VCI_ReadQueObj",
       
   314     "VCI_ReadBufStatus",
       
   315     "VCI_ReadBufData",
       
   316     "VCI_TransmitObj",
       
   317     "VCI_RequestObj",
       
   318     "VCI_UpdateBufObj",
       
   319     "VCI_CciReqData"
       
   320     };
       
   321 
       
   322   MSG_ERR_DRV("IXXAT Exception: %S (%i / %u) [%S]", Num2Function[func_num], err_code, ext_err, err_str);
       
   323   }
       
   324 
       
   325   void IXXAT::watchdog()
       
   326   {
       
   327     VCI_CAN_STS sts;
       
   328     long res = VCI_ReadCanStatus(m_BoardHdl, CAN_NUM, &sts);
       
   329 
       
   330     if (res < 0)
       
   331     {
       
   332       MSG_ERR_DRV("IXXAT canBusWatchdog: ERROR: Reading the can state failed!");
       
   333     }
       
   334     else
       
   335     {
       
   336       if (sts.sts & (STS_CAN_BUS_OFF | STS_CAN_DATA_OVERRUN | STS_REMOTE_QUEUE_OVERRUN))
       
   337       {
       
   338         if (sts.sts & STS_CAN_BUS_OFF)
       
   339         {
       
   340           MSG_ERR_DRV("IXXAT canBusWatchdog: CAN bus off detected!");
       
   341         }
       
   342         if (sts.sts & STS_CAN_DATA_OVERRUN)
       
   343         {
       
   344           MSG_ERR_DRV("IXXAT canBusWatchdog: CAN data overrun detected!");
       
   345         }
       
   346         if (sts.sts & STS_REMOTE_QUEUE_OVERRUN)
       
   347         {
       
   348           MSG_ERR_DRV("IXXAT canBusWatchdog: Remote queue overrun detected!");
       
   349         }
       
   350 
       
   351         res = VCI_ResetCan(m_BoardHdl, CAN_NUM);
       
   352         if (res <= 0)
       
   353         {
       
   354           MSG_ERR_DRV("IXXAT canBusWatchdog: ERROR: Resetting the can module failed with code '%d'!", res);
       
   355         }
       
   356 
       
   357         res = VCI_StartCan(m_BoardHdl, CAN_NUM);
       
   358         if (res <= 0)
       
   359         {
       
   360           MSG_ERR_DRV("IXXAT canBusWatchdog: ERROR: Restaring the can module failed with code '%d'!", res);
       
   361         }
       
   362       }
       
   363     }
       
   364 
       
   365     if (SetTimer(NULL, m_watchdogTimerId, IXXAT::CAN_BUS_WATCHDOG_INTERVAL_MSEC, IXXAT::canBusWatchdog) == 0)
       
   366     {
       
   367       MSG_ERR_DRV("IXXAT canBusWatchdog: ERROR: Creation of the watchdog timer failed!");
       
   368     }
       
   369   }
       
   370 
       
   371 void CALLBACK IXXAT::canBusWatchdog(HWND hwnd, UINT msg, UINT_PTR idEvent, DWORD dwTime)
       
   372 {
       
   373    if (m_callbackPtr != NULL)
       
   374       m_callbackPtr->watchdog();
       
   375 }
       
   376 
       
   377 //------------------------------------------------------------------------
       
   378 extern "C"
       
   379    UNS8 __stdcall canReceive_driver(CAN_HANDLE inst, Message *m)
       
   380    {
       
   381 	 if (IXXAT::isDriverClosed()) return 0;
       
   382      return reinterpret_cast<IXXAT*>(inst)->receive(m) ? 0 : 1;
       
   383    }
       
   384                             
       
   385 extern "C"
       
   386    UNS8 __stdcall canSend_driver(CAN_HANDLE inst, Message const *m)
       
   387    {
       
   388 	 if (IXXAT::isDriverClosed()) return 0;
       
   389      return reinterpret_cast<IXXAT*>(inst)->send(m) ? 0 : 1;
       
   390    }
       
   391 
       
   392 extern "C"
       
   393    CAN_HANDLE __stdcall canOpen_driver(s_BOARD *board)
       
   394    {
       
   395    try
       
   396       {
       
   397       return new IXXAT(board);
       
   398       }
       
   399    catch (IXXAT::error&)
       
   400       {
       
   401       return 0;
       
   402       }
       
   403    }
       
   404 
       
   405 extern "C"
       
   406    int __stdcall canClose_driver(CAN_HANDLE inst)
       
   407    {
       
   408    delete reinterpret_cast<IXXAT*>(inst);
       
   409    return 1;
       
   410    }
       
   411    
       
   412 extern "C"
       
   413    UNS8 __stdcall canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
       
   414 	{
       
   415 	//printf("canChangeBaudRate not yet supported by this driver\n");
       
   416 	return 0;
       
   417 	}