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 <stdio.h>
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: #pragma warning(disable:4996)
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:       
leonid@252:    private:
leonid@252:       UINT16 m_BoardHdl;
leonid@252:       UINT16 m_TxQueHdl;
leonid@252:       UINT16 m_RxQueHdl;
leonid@252:       async_access_que<VCI_CAN_OBJ> m_RX_Que;
leonid@252:       static IXXAT* m_callbackPtr;
leonid@252:    };
leonid@252: 
leonid@252: IXXAT *IXXAT::m_callbackPtr = NULL;
leonid@252: 
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<unsigned char*>(m->data));
leonid@252:    else
etisserant@365:       res = VCI_RequestObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len);
greg@267:    return (res == false); // false -> 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:       {
etisserant@365:       m->cob_id = obj.id;
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:        }
leonid@252:    if (index == br_lut_size)    
leonid@252:       return false;
leonid@252:    // close existing board   
leonid@252:    close();
leonid@252:    // init IXXAT board
leonid@252:    unsigned long board_type = VCI_GetBrdTypeByName(const_cast<char*>(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)
leonid@252:       return false;
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)
leonid@252:    res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_RX_QUE, 50, 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);
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:   {
leonid@252:   char buf[200];
leonid@252:   ::sprintf(buf,"IXXAT Message: [%s]\n", msg_str);
leonid@252:   ::OutputDebugString(buf);
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:     };
leonid@252:   char buf[200];
leonid@252:   ::sprintf(buf, "IXXAT Exception: %s (%i / %u) [%s]\n", Num2Function[func_num], err_code, ext_err, err_str);
leonid@252:   ::OutputDebugString(buf);
leonid@252:   }
leonid@252: 
leonid@252: //------------------------------------------------------------------------
leonid@252: extern "C"
leonid@252:    UNS8 canReceive_driver(CAN_HANDLE inst, Message *m)
leonid@252:    {
leonid@252:    return (UNS8)reinterpret_cast<IXXAT*>(inst)->receive(m);
leonid@252:    }
leonid@252:                             
leonid@252: extern "C"
leonid@252:    UNS8 canSend_driver(CAN_HANDLE inst, Message *m)
leonid@252:    {
leonid@252:    return (UNS8)reinterpret_cast<IXXAT*>(inst)->send(m);
leonid@252:    }
leonid@252: 
leonid@252: extern "C"
leonid@252:    CAN_HANDLE 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"
leonid@252:    int canClose_driver(CAN_HANDLE inst)
leonid@252:    {
leonid@252:    delete reinterpret_cast<IXXAT*>(inst);
leonid@252:    return 1;
leonid@252:    }
groke6@384:    
groke6@384: extern "C"
groke6@384:    UNS8 canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
groke6@384: 	{
groke6@384: 	//printf("canChangeBaudRate not yet supported by this driver\n");
groke6@384: 	return 0;
groke6@384: 	}