📄 can_ixxat.cpp
字号:
/************************************************************/
/* */
/* Copley Motion Libraries */
/* */
/* Author: Stephen Glow & Chris Jones */
/* */
/* Copyright (c) 2002-2005 Copley Controls Corp. */
/* http://www.copleycontrols.com */
/* */
/************************************************************/
/*
CAN object for IXXAT CAN driver
(see http://www.ixxat.com for more information on the IXXAT VCI driver for the VCI series cards)
*/
#include <cstdio>
#include <cstring>
#include <windows.h>
#include "CML.h"
#include "can_ixxat.h"
#include "XatXXReg.h"
#include "VCI2.h"
CML_NAMESPACE_USE();
/* local functions */
static void VCI_CALLBACKATTR rxInt0( UINT16 q, UINT16 ct, VCI_CAN_OBJ *p );
static void VCI_CALLBACKATTR rxInt1( UINT16 q, UINT16 ct, VCI_CAN_OBJ *p );
static void VCI_CALLBACKATTR rxInt2( UINT16 q, UINT16 ct, VCI_CAN_OBJ *p );
static void VCI_CALLBACKATTR rxInt3( UINT16 q, UINT16 ct, VCI_CAN_OBJ *p );
/* Types used to define functions contained in the Ixxat .dll files */
typedef HRESULT (XATREG_CALLATTR *XAT_SelectHardwareType)( HWND , XAT_BoardCFG * );
typedef HRESULT (XATREG_CALLATTR *XAT_GetConfigType)( DWORD , XAT_BoardCFG * );
typedef HRESULT (XATREG_CALLATTR *XAT_GetDefaultHwEntryType)( DWORD * );
typedef INT32 (VCI_CALLATTR *VCI_StartCanType)( UINT16 , UINT8 );
typedef INT32 (VCI_CALLATTR *VCI_AssignRxQueObjType)( UINT16, UINT16, UINT8, UINT32, UINT32 );
typedef INT32 (VCI_CALLATTR *VCI_ConfigQueueType)( UINT16, UINT8, UINT8, UINT16, UINT16, UINT16, UINT16, UINT16* );
typedef INT32 (VCI_CALLATTR *VCI_SetAccMaskType)( UINT16, UINT8, UINT32, UINT32 );
typedef INT32 (VCI_CALLATTR *VCI_InitCanType)( UINT16, UINT8, UINT8, UINT8, UINT8 );
typedef INT32 (VCI_CALLATTR *VCI2_PrepareBoardType)( VCI_BOARD_TYPE, UINT16, char*, UINT8, VCI_t_PutS, VCI_t_UsrRxIntHdlr, VCI_t_UsrExcHdlr );
typedef INT32 (VCI_CALLATTR *VCI_CancelBoardType)( UINT16 );
typedef INT32 (VCI_CALLATTR *VCI_TransmitObjType)( UINT16, UINT16, UINT32, UINT8, UINT8* );
typedef INT32 (VCI_CALLATTR *VCI_RequestObjType)( UINT16, UINT16, UINT32, UINT8 );
/* local functions */
static const Error *InitLibrary( void );
static void UninitLibrary( void );
/* local data */
static VCI_t_UsrRxIntHdlr rxIntPtr[] = { rxInt0, rxInt1, rxInt2, rxInt3 };
#define MAX_BOARDS sizeof(rxIntPtr)/sizeof(rxIntPtr[0])
static IxxatCAN *board[ MAX_BOARDS ] = {0};
static Mutex boardMutex;
static Mutex libraryMutex;
static int openCards = 0;
static HMODULE hReg;
static HINSTANCE hVCI;
static XAT_SelectHardwareType lpXAT_SelectHardware;
static XAT_GetConfigType lpXAT_GetConfig;
static XAT_GetDefaultHwEntryType lpXAT_GetDefaultHwEntry;
static VCI_StartCanType lpVCI_StartCan;
static VCI_AssignRxQueObjType lpVCI_AssignRxQueObj;
static VCI_ConfigQueueType lpVCI_ConfigQueue;
static VCI_SetAccMaskType lpVCI_SetAccMask;
static VCI_InitCanType lpVCI_InitCan;
static VCI2_PrepareBoardType lpVCI2_PrepareBoard;
static VCI_CancelBoardType lpVCI_CancelBoard;
static VCI_TransmitObjType lpVCI_TransmitObj;
static VCI_RequestObjType lpVCI_RequestObj;
/***************************************************************************/
/**
Construct a new Ixxat CAN interface object.
This simply sets the default baud rate and
marks the card as not open.
*/
/***************************************************************************/
IxxatCAN::IxxatCAN( void ) : CanInterface()
{
// Default baud to 1,000,000 bps
IxxatCAN::SetBaud( 1000000 );
// Default to not open
open = 0;
}
/***************************************************************************/
/**
Construct a new Ixxat CAN interface object for the specified port.
The port name should be of the form CANx or IXXATx where x is the port number.
The port numbers start at 0, so the first port would be identified by
the port name CAN0.
@param port The port name string identifying the CAN device.
*/
/***************************************************************************/
IxxatCAN::IxxatCAN( const char *port ) : CanInterface(port)
{
// Default baud to 1,000,000 bps
IxxatCAN::SetBaud( 1000000 );
// Default to not open
open = 0;
}
/***************************************************************************/
/**
Destructor for Ixxat card. Closes the interface and unloads the library.
*/
/***************************************************************************/
IxxatCAN::~IxxatCAN(void)
{
Close();
}
/***************************************************************************/
/**
Open the Ixxat CAN card.
The card should have been identified by setting it's name either
in the constructor, or by using the method CanInterface::SetName.
If no port name was set, then the default Ixxat card will be used.
If the port name is set to "select", then a dialog box will be shown
allowing the card to be selected from any installed Ixxat cards.
Otherwise, the port name should be of the form "CANx" where x is the
Ixxat hardware key number (i.e. CAN1 for hardware key 1).
@return A pointer to an error object on failure, or NULL on success.
*/
/***************************************************************************/
const Error *IxxatCAN::Open( void )
{
int port;
int ret = 0;
mutex.Lock();
if( open )
{
mutex.Unlock();
return &CanError::AlreadyOpen;
}
/**************************************************
* Find the port number to open.
**************************************************/
port = FindPortNumber( "CAN" );
if( port < 0 )
port = FindPortNumber( "IXXAT" );
if( port < 0 )
{
mutex.Unlock();
return &CanError::BadPortName;
}
const Error *err = InitLibrary();
if( err )
{
cml.Error( "IxxatCAN::InitLibrary failed with error %s\n", err->toString() );
mutex.Unlock();
return err;
}
// Reset local variables
rxHead = rxTail = 0;
while( rxSem.Get(0) == 0 );
/**************************************************
* Find the board configuration info based on the
* port name specified
**************************************************/
XAT_BoardCFG cfg;
HRESULT res;
DWORD key = port;
int i = -1;
if( port == 0 )
{
lpXAT_GetDefaultHwEntry( &key );
res = lpXAT_GetConfig( key, &cfg );
}
else
res = lpXAT_GetConfig( key, &cfg );
if( res )
{
err = &CanError::BadPortName;
goto done;
}
/**************************************************
* Find an empty slot in the board array.
**************************************************/
boardMutex.Lock();
for( i=0; i<MAX_BOARDS; i++ )
{
if( board[i] == NULL )
{
board[i] = this;
break;
}
}
boardMutex.Unlock();
if( i == MAX_BOARDS )
{
i = -1;
err = &CanError::Driver;
goto done;
}
// For now, we always use channel 0.
channel = 0;
handle = lpVCI2_PrepareBoard( cfg.board_type, cfg.board_no, NULL, 0, 0, rxIntPtr[i], 0 );
if( handle < 0 )
{
err = &CanError::Driver;
goto done;
}
// initialize CAN-Controller
ret = lpVCI_InitCan( handle, channel, bt0, bt1, VCI_11B );
// definition of Acceptance-Mask (define to receive all IDs)
if( ret == VCI_OK )
ret = lpVCI_SetAccMask( handle, channel, 0, 0 );
// definition of Transmit Queue
if( ret == VCI_OK )
ret = lpVCI_ConfigQueue( handle, channel, VCI_TX_QUE, 200, 0, 0, 0, &txQueue );
// definition of Receive Queue (interrupt mode)
if( ret == VCI_OK )
ret = lpVCI_ConfigQueue( handle, channel, VCI_RX_QUE, 20, 1, 0, 100, &rxQueue );
// assign all ID's to the Receive Queue
if( ret == VCI_OK )
ret = lpVCI_AssignRxQueObj( handle, rxQueue, VCI_ACCEPT, 0, 0 );
// And now start the CAN
if( ret == VCI_OK )
ret = lpVCI_StartCan( handle, channel );
if( ret != VCI_OK )
err = ConvertError( ret );
done:
if( err )
{
if( i >= 0 )
{
boardMutex.Lock();
board[i] = NULL;
boardMutex.Unlock();
}
UninitLibrary();
}
else
open = 1;
mutex.Unlock();
return err;
}
/***************************************************************************/
/**
Close the CAN interface.
@return A pointer to an error object on failure, or NULL on success.
*/
/***************************************************************************/
const Error *IxxatCAN::Close( void )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -