leonid@255: /* leonid@255: This file is part of CanFestival, a library implementing CanOpen Stack. leonid@255: leonid@255: CanFestival Copyright (C): Edouard TISSERANT and Francis DUPIN leonid@255: CanFestival Win32 port Copyright (C) 2007 Leonid Tochinski, ChattenAssociates, Inc. leonid@255: leonid@255: See COPYING file for copyrights details. leonid@255: leonid@255: This library is free software; you can redistribute it and/or leonid@255: modify it under the terms of the GNU Lesser General Public leonid@255: License as published by the Free Software Foundation; either leonid@255: version 2.1 of the License, or (at your option) any later version. leonid@255: leonid@255: This library is distributed in the hope that it will be useful, leonid@255: but WITHOUT ANY WARRANTY; without even the implied warranty of leonid@255: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU leonid@255: Lesser General Public License for more details. leonid@255: leonid@255: You should have received a copy of the GNU Lesser General Public leonid@255: License along with this library; if not, write to the Free Software leonid@255: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA leonid@255: */ leonid@255: // pragma based message leonid@255: // http://www.codeproject.com/macro/location_pragma.asp leonid@255: #define __STR2__(x) #x leonid@255: #define __STR1__(x) __STR2__(x) leonid@255: #define __LOC2__ __FILE__ "("__STR1__(__LINE__)") : " leonid@255: leonid@255: leonid@255: #pragma message("*********************************************************************************") leonid@255: #pragma message(" NOTE: IXXAT Win32 drivers and API should be installed in order to build this project!") leonid@255: #pragma message(__LOC2__ "See IXXAT.Cpp header for details.") leonid@255: #pragma message("*********************************************************************************") leonid@255: leonid@255: leonid@252: // IXXAT adapter driver for CanFestival-3 Win32 port leonid@252: // leonid@252: // Notes leonid@252: //-------------------------------------------- leonid@252: // For building of this project you will need leonid@252: // the following IXXAT API files leonid@252: // Vci2.h leonid@252: // Vci11un6.lib leonid@252: // leonid@252: // IXXAT Win32 drivers and API can be downloaded from leonid@252: // http://www.ixxat.com/download_vci_en,7547,5873.html leonid@252: // leonid@252: // Copy Vci2.h & Vci11un6.lib files to can_ixxat_win32 folder of add path to them in Project settings. leonid@252: leonid@255: leonid@252: #include leonid@252: extern "C" { leonid@252: #include "applicfg.h" leonid@252: #include "can_driver.h" leonid@252: #include "def.h" leonid@252: } leonid@252: #include "VCI2.h" leonid@252: #include "async_access_que.h" leonid@252: leonid@252: #define CAN_NUM 0 leonid@252: leonid@252: class IXXAT leonid@252: { leonid@252: public: leonid@252: class error leonid@252: { leonid@252: }; leonid@252: IXXAT(s_BOARD *board); leonid@252: ~IXXAT(); leonid@252: bool send(const Message *m); leonid@252: bool receive(Message *m); leonid@252: private: leonid@252: bool open(const char* board_name, int board_number, const char* baud_rate); leonid@252: bool close(); leonid@252: void receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj); leonid@252: // VCI2 handler leonid@252: static void VCI_CALLBACKATTR message_handler(char *msg_str); leonid@252: static void VCI_CALLBACKATTR receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj); leonid@252: static void VCI_CALLBACKATTR exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str); leonid@252: Christian@655: static void CALLBACK canBusWatchdog(HWND hwnd, UINT msg, UINT_PTR idEvent, DWORD dwTime); Christian@655: void watchdog(); leonid@252: private: leonid@252: UINT16 m_BoardHdl; leonid@252: UINT16 m_TxQueHdl; leonid@252: UINT16 m_RxQueHdl; leonid@252: async_access_que m_RX_Que; leonid@252: static IXXAT* m_callbackPtr; Christian@655: static UINT_PTR m_watchdogTimerId; Christian@655: static const unsigned int CAN_BUS_WATCHDOG_INTERVAL_MSEC = 10000; Christian@655: Christian@655: /** Bitmask inside sts from VCI_ReadCanStatus() that defines the can bus off state.*/ Christian@655: static const unsigned char STS_CAN_BUS_OFF = 0x80; Christian@655: Christian@655: /** Bitmask inside sts from VCI_ReadCanStatus() that defines the can data overrun state.*/ Christian@655: static const unsigned char STS_CAN_DATA_OVERRUN = 0x20; Christian@655: Christian@655: /** Bitmask inside sts from VCI_ReadCanStatus() that defines the remote queue overrun state.*/ Christian@655: static const unsigned char STS_REMOTE_QUEUE_OVERRUN = 0x04; leonid@252: }; leonid@252: leonid@252: IXXAT *IXXAT::m_callbackPtr = NULL; leonid@252: Christian@655: UINT_PTR IXXAT::m_watchdogTimerId = 0; Christian@655: leonid@252: IXXAT::IXXAT(s_BOARD *board) : m_BoardHdl(0xFFFF), leonid@252: m_TxQueHdl(0xFFFF), leonid@252: m_RxQueHdl(0xFFFF) leonid@252: leonid@252: { leonid@252: char busname[100]; leonid@252: ::strcpy(busname,board->busname); leonid@252: char board_name[100]; leonid@252: long board_number = 0; leonid@252: char *ptr = ::strrchr(busname,':'); leonid@252: if (ptr != 0) leonid@252: { leonid@252: *ptr = 0; leonid@252: ::strcpy(board_name,busname); leonid@252: if (++ptr - busname < (int)::strlen(board->busname)) leonid@252: board_number = ::atoi(ptr); leonid@252: } leonid@252: if (!open(board_name,board_number,board->baudrate)) leonid@252: { leonid@252: close(); leonid@252: throw error(); leonid@252: } leonid@252: m_callbackPtr = this; leonid@252: } leonid@252: leonid@252: IXXAT::~IXXAT() leonid@252: { leonid@252: close(); leonid@252: m_callbackPtr = 0; leonid@252: } leonid@252: leonid@252: bool IXXAT::send(const Message *m) leonid@252: { leonid@252: if (m_BoardHdl == 0xFFFF) greg@267: return true; // true -> NOT OK leonid@252: long res = VCI_ERR; leonid@252: if (m->rtr == NOT_A_REQUEST) etisserant@365: res = VCI_TransmitObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len, const_cast(m->data)); leonid@252: else etisserant@365: res = VCI_RequestObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len); Christian@647: Christian@647: return (res == VCI_OK); leonid@252: } leonid@252: leonid@252: leonid@252: bool IXXAT::receive(Message *m) leonid@252: { leonid@252: if (m_BoardHdl == 0xFFFF) leonid@252: return false; leonid@252: VCI_CAN_OBJ obj; leonid@252: if (m_RX_Que.extract_top(obj)) leonid@252: { Christian@646: m->cob_id = static_cast(obj.id); //valid for 11Bit ids leonid@252: m->len = obj.len; leonid@252: m->rtr = (obj.rtr == VCI_RX_BUF) ? NOT_A_REQUEST : REQUEST; leonid@252: if (m->rtr == NOT_A_REQUEST) leonid@252: ::memcpy(m->data, obj.a_data, m->len); leonid@252: return true; leonid@252: } leonid@252: return false; leonid@252: } leonid@252: leonid@252: bool IXXAT::open(const char* board_name, int board_number, const char* baud_rate) leonid@252: { leonid@252: // check, if baudrate is supported leonid@252: struct IXXAT_baud_rate_param leonid@252: { leonid@252: UINT8 bt0; leonid@252: UINT8 bt1; leonid@252: }; leonid@252: struct IXXAT_look_up_table leonid@252: { leonid@252: char baud_rate[20]; leonid@252: IXXAT_baud_rate_param bt; leonid@252: }; leonid@252: static const IXXAT_look_up_table br_lut[] = { leonid@252: {"10K",{VCI_10KB}}, leonid@252: {"20K",{VCI_20KB}}, leonid@252: {"50K",{VCI_50KB}}, leonid@252: {"100K",{VCI_100KB}}, leonid@252: {"125K",{VCI_125KB}}, leonid@252: {"250K",{VCI_250KB}}, leonid@252: {"500K",{VCI_500KB}}, leonid@252: {"800K",{VCI_800KB}}, leonid@252: {"1M",{VCI_1000KB}} leonid@252: }; leonid@252: static const long br_lut_size = sizeof (br_lut)/sizeof(IXXAT_look_up_table); leonid@252: int index; leonid@252: for (index = 0; index < br_lut_size; ++index) leonid@252: { leonid@252: if (::strcmp(br_lut[index].baud_rate,baud_rate)==0) leonid@252: break; leonid@252: } hacking@685: if (index == br_lut_size) hacking@685: { hacking@687: MSG_ERR_DRV("IXXAT::open: The given baudrate %S is invalid.", baud_rate); leonid@252: return false; hacking@685: } leonid@252: // close existing board leonid@252: close(); leonid@252: // init IXXAT board leonid@252: unsigned long board_type = VCI_GetBrdTypeByName(const_cast(board_name)); leonid@252: long res = VCI2_PrepareBoard( board_type, // board type leonid@252: board_number, // unique board index leonid@252: NULL, // pointer to buffer for additional info leonid@252: 0, // length of additional info buffer leonid@252: message_handler, // pointer to msg-callbackhandler leonid@252: receive_queuedata_handler, // pointer to receive-callbackhandler leonid@252: exception_handler); // pointer to exception-callbackhandler leonid@252: if (res < 0) hacking@685: { hacking@685: MSG_ERR_DRV("IXXAT::open: VCI2_PrepareBoard failed with code '%d'.", res); leonid@252: return false; hacking@685: } leonid@252: m_BoardHdl = (UINT16)res; leonid@252: leonid@252: VCI_ResetBoard(m_BoardHdl); leonid@252: leonid@252: // init CAN parameters leonid@252: leonid@252: // initialize CAN-Controller leonid@252: res = VCI_InitCan(m_BoardHdl, CAN_NUM, br_lut[index].bt.bt0,br_lut[index].bt.bt1, VCI_11B); leonid@252: leonid@252: // definition of Acceptance-Mask (define to receive all IDs) leonid@252: res = VCI_SetAccMask(m_BoardHdl, CAN_NUM, 0x0UL, 0x0UL); leonid@252: leonid@252: // definition of Transmit Queue leonid@252: res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_TX_QUE, 100 , 0, 0, 0, &m_TxQueHdl); leonid@252: leonid@252: // definition of Receive Queue (interrupt mode) Christian@655: res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_RX_QUE, 500, 1, 0, 100, &m_RxQueHdl); leonid@252: leonid@252: // assign the all IDs to the Receive Queue leonid@252: res = VCI_AssignRxQueObj(m_BoardHdl, m_RxQueHdl ,VCI_ACCEPT, 0, 0) ; leonid@252: leonid@252: // And now start the CAN leonid@252: res = VCI_StartCan(m_BoardHdl, CAN_NUM); Christian@655: Christian@655: //Start CAN Bus-Off watchdog Christian@655: m_watchdogTimerId = SetTimer(NULL, NULL, IXXAT::CAN_BUS_WATCHDOG_INTERVAL_MSEC, IXXAT::canBusWatchdog); leonid@252: leonid@252: return true; leonid@252: } leonid@252: leonid@252: bool IXXAT::close() leonid@252: { leonid@252: if (m_BoardHdl == 0xFFFF) leonid@252: return true; leonid@252: VCI_ResetBoard(m_BoardHdl); leonid@252: VCI_CancelBoard(m_BoardHdl); leonid@252: m_BoardHdl = leonid@252: m_TxQueHdl = leonid@252: m_RxQueHdl = 0xFFFF; leonid@252: return true; leonid@252: } leonid@252: leonid@252: void IXXAT::receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj) leonid@252: { leonid@252: for (int i = 0; i < count; ++i) leonid@252: m_RX_Que.append(p_obj[i]); // can packet leonid@252: } leonid@252: leonid@252: void VCI_CALLBACKATTR IXXAT::receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj) leonid@252: { leonid@252: if (m_callbackPtr != NULL) leonid@252: m_callbackPtr->receive_queuedata(que_hdl, count, p_obj); leonid@252: } leonid@252: leonid@252: void VCI_CALLBACKATTR IXXAT::message_handler(char *msg_str) leonid@252: { hacking@687: MSG_ERR_DRV("IXXAT Message: [%S]\n", msg_str); leonid@252: } leonid@252: leonid@252: void VCI_CALLBACKATTR IXXAT::exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str) leonid@252: { leonid@252: static const char* Num2Function[] = leonid@252: { leonid@252: "VCI_Init", leonid@252: "VCI_Searchboard", leonid@252: "VCI_Prepareboard", leonid@252: "VCI_Cancel_board", leonid@252: "VCI_Testboard", leonid@252: "VCI_ReadBoardInfo", leonid@252: "VCI_ReadBoardStatus", leonid@252: "VCI_Resetboard", leonid@252: "VCI_ReadCANInfo", leonid@252: "VCI_ReadCANStatus", leonid@252: "VCI_InitCAN", leonid@252: "VCI_SetAccMask", leonid@252: "VCI_ResetCAN", leonid@252: "VCI_StartCAN", leonid@252: "VCI_ResetTimeStamps", leonid@252: "VCI_ConfigQueue", leonid@252: "VCI_AssignRxQueObj", leonid@252: "VCI_ConfigBuffer", leonid@252: "VCI_ReconfigBuffer", leonid@252: "VCI_ConfigTimer", leonid@252: "VCI_ReadQueStatus", leonid@252: "VCI_ReadQueObj", leonid@252: "VCI_ReadBufStatus", leonid@252: "VCI_ReadBufData", leonid@252: "VCI_TransmitObj", leonid@252: "VCI_RequestObj", leonid@252: "VCI_UpdateBufObj", leonid@252: "VCI_CciReqData" leonid@252: }; hacking@685: hacking@687: MSG_ERR_DRV("IXXAT Exception: %S (%i / %u) [%S]\n", Num2Function[func_num], err_code, ext_err, err_str); leonid@252: } leonid@252: Christian@655: void IXXAT::watchdog() Christian@655: { Christian@655: VCI_CAN_STS sts; Christian@655: long res = VCI_ReadCanStatus(m_BoardHdl, CAN_NUM, &sts); Christian@655: Christian@655: if (res < 0) Christian@655: { hacking@685: MSG_ERR_DRV("\nIXXAT canBusWatchdog: ERROR: Reading the can state failed!\n"); Christian@655: } Christian@655: else Christian@655: { Christian@655: if (sts.sts & (STS_CAN_BUS_OFF | STS_CAN_DATA_OVERRUN | STS_REMOTE_QUEUE_OVERRUN)) Christian@655: { Christian@655: if (sts.sts & STS_CAN_BUS_OFF) Christian@655: { hacking@685: MSG_ERR_DRV("\nIXXAT canBusWatchdog: CAN bus off detected!\n"); Christian@655: } Christian@655: if (sts.sts & STS_CAN_DATA_OVERRUN) Christian@655: { hacking@685: MSG_ERR_DRV("\nIXXAT canBusWatchdog: CAN data overrun detected!\n"); Christian@655: } Christian@655: if (sts.sts & STS_REMOTE_QUEUE_OVERRUN) Christian@655: { hacking@685: MSG_ERR_DRV("\nIXXAT canBusWatchdog: Remote queue overrun detected!\n"); Christian@655: } Christian@655: hacking@683: res = VCI_ResetCan(m_BoardHdl, CAN_NUM); hacking@683: if (res <= 0) hacking@683: { hacking@685: MSG_ERR_DRV("\nIXXAT canBusWatchdog: ERROR: Resetting the can module failed with code '%d'!\n", res); Christian@655: } Christian@655: hacking@683: res = VCI_StartCan(m_BoardHdl, CAN_NUM); hacking@683: if (res <= 0) hacking@683: { hacking@685: MSG_ERR_DRV("\nIXXAT canBusWatchdog: ERROR: Restaring the can module failed with code '%d'!\n", res); Christian@655: } Christian@655: } Christian@655: } Christian@655: Christian@655: if (SetTimer(NULL, m_watchdogTimerId, IXXAT::CAN_BUS_WATCHDOG_INTERVAL_MSEC, IXXAT::canBusWatchdog) == 0) Christian@655: { hacking@685: MSG_ERR_DRV("\nIXXAT canBusWatchdog: ERROR: Creation of the watchdog timer failed!\n"); Christian@655: } Christian@655: } Christian@655: Christian@655: void CALLBACK IXXAT::canBusWatchdog(HWND hwnd, UINT msg, UINT_PTR idEvent, DWORD dwTime) Christian@655: { Christian@655: if (m_callbackPtr != NULL) Christian@655: m_callbackPtr->watchdog(); Christian@655: } Christian@655: leonid@252: //------------------------------------------------------------------------ leonid@252: extern "C" Christian@645: UNS8 __stdcall canReceive_driver(CAN_HANDLE inst, Message *m) leonid@252: { Christian@647: return reinterpret_cast(inst)->receive(m) ? 0 : 1; leonid@252: } leonid@252: leonid@252: extern "C" Christian@645: UNS8 __stdcall canSend_driver(CAN_HANDLE inst, Message const *m) leonid@252: { Christian@647: return reinterpret_cast(inst)->send(m) ? 0 : 1; leonid@252: } leonid@252: leonid@252: extern "C" Christian@645: CAN_HANDLE __stdcall canOpen_driver(s_BOARD *board) leonid@252: { leonid@252: try leonid@252: { leonid@252: return new IXXAT(board); leonid@252: } leonid@252: catch (IXXAT::error&) leonid@252: { leonid@252: return 0; leonid@252: } leonid@252: } leonid@252: leonid@252: extern "C" Christian@645: int __stdcall canClose_driver(CAN_HANDLE inst) leonid@252: { leonid@252: delete reinterpret_cast(inst); leonid@252: return 1; leonid@252: } groke6@384: groke6@384: extern "C" Christian@645: UNS8 __stdcall canChangeBaudRate_driver( CAN_HANDLE fd, char* baud) groke6@384: { groke6@384: //printf("canChangeBaudRate not yet supported by this driver\n"); groke6@384: return 0; edouard@631: }