can_ixxat.cpp

来自「美国COPLEY驱动器,程序开发工具之一.」· C++ 代码 · 共 571 行 · 第 1/2 页

CPP
571
字号
{
	mutex.Lock();
	if( open )
	{
		lpVCI_CancelBoard( handle );
		boardMutex.Lock();
		for( int i=0; i<MAX_BOARDS; i++ )
		{
			if( board[i] == this )
				board[i] = NULL;
		}
		boardMutex.Unlock();

		open = 0;
		UninitLibrary();
	}
	mutex.Unlock();
	return 0;
}

/***************************************************************************/
/**
Set the CAN interface baud rate.
@param b The baud rate to set.
@return A pointer to an error object on failure, or NULL on success.
*/
/***************************************************************************/
const Error *IxxatCAN::SetBaud( int32 b )
{
	switch( b )
	{
		case   10000: bt0=0x31; bt1=0x1C; break;
		case   20000: bt0=0x18; bt1=0x1C; break;
		case   50000: bt0=0x09; bt1=0x1C; break;
		case  100000: bt0=0x04; bt1=0x1C; break;
		case  125000: bt0=0x03; bt1=0x1C; break;
		case  250000: bt0=0x01; bt1=0x1C; break;
		case  500000: bt0=0x00; bt1=0x1C; break;
		case  800000: bt0=0x00; bt1=0x16; break;
		case 1000000: bt0=0x00; bt1=0x14; break;
		default: return &CanError::BadParam;
	}

	baud = b;
	return 0;
}

/***************************************************************************/
/**
Receive the next CAN frame.  
@param frame A reference to the frame object that will be filled by the read.
@param timeout The timeout (ms) to wait for the frame.  A timeout of 0 will
       return immediately if no data is available.  A timeout of < 0 will 
		 wait forever.
@return A pointer to an error object on failure, or NULL on success.
*/
/***************************************************************************/
const Error *IxxatCAN::RecvFrame( CanFrame &frame, int32 timeout )
{
	if( !open )
		return &CanError::NotOpen;

	const Error *err = rxSem.Get( timeout );
	if( err ) return err;

	mutex.Lock();
	frame = rx[rxTail];

	int newTail = rxTail+1;
	if( newTail >= IXXAT_RX_QUEUE_SZ )
		newTail = 0;

	rxTail = newTail;
	mutex.Unlock();

	return 0;
}

/***************************************************************************/
/**
Write a CAN frame to the CAN network.
@param frame A reference to the frame to write.
@param timeout The time to wait for the frame to be successfully sent.
       If the timeout is 0, the frame is written to the output queue and
		 the function returns without waiting for it to be sent.
		 If the timeout is <0 then the function will delay forever.
@return A pointer to an error object on failure, or NULL on success.
*/
/***************************************************************************/
const Error *IxxatCAN::XmitFrame( CanFrame &frame, int32 timeout )
{
   // don't allow frame lengths longer than 8
	if( frame.length > 8 )
		return &CanError::BadParam;

	mutex.Lock();

	if( !open )
	{
		mutex.Unlock();
		return &CanError::NotOpen;
	}

	int ret;

	switch( frame.type )
	{
		case CAN_FRAME_DATA:
			ret = lpVCI_TransmitObj( handle, txQueue, frame.id, frame.length, frame.data );
			break;
		case CAN_FRAME_REMOTE:
			ret = lpVCI_RequestObj( handle, txQueue, frame.id, frame.length );
			break;
		default:
			mutex.Unlock();
			return &CanError::BadParam;
	}

	mutex.Unlock();

	return ConvertError( ret );
}


/***************************************************************************/
/**
Convert error codes defined by the Vector CAN library into 
the standard error codes used by the motion library.
@param err The Vector style status code
@return A pointer to an error object, or NULL if no error is indicated
*/
/***************************************************************************/
const Error *IxxatCAN::ConvertError( int err )
{
	switch( err )
	{
		case VCI_OK:          return 0;
		case VCI_ERR:         return &CanError::Driver;
		case VCI_HWSW_ERR:    return &CanError::Driver;
		case VCI_SUPP_ERR:    return &CanError::Driver;
		case VCI_PARA_ERR:    return &CanError::Driver;
		case VCI_RES_ERR:     return &CanError::Driver;
		case VCI_QUE_ERR:     return &CanError::Driver;
		case VCI_TX_ERR:      return &CanError::Driver;
		default:              return &CanError::Unknown;
	}
}

/***************************************************************************/
/**
Receive interrupt handler.  This is an internal function that should not 
be called except by the driver.  It's used to add one or more CAN frames
to the receive buffer when they are received.

@param ct The number of frames to add
@param ptr Points to an array of ct VCI_CAN_OBJ structures.
*/
/***************************************************************************/
void IxxatCAN::rxInt( int16 ct, void *ptr )
{
	VCI_CAN_OBJ *frame = (VCI_CAN_OBJ*)ptr;

	for( int i=0; i<ct; i++ )
	{
		int newHead = rxHead+1;
		if( newHead >= IXXAT_RX_QUEUE_SZ )
			newHead = 0;
	
		if( newHead == rxTail )
			return;
	
		rx[ rxHead ].id       = frame[i].id;
		rx[ rxHead ].length   = frame[i].len;

		if( frame[i].rtr )
			rx[ rxHead ].type = CAN_FRAME_REMOTE;
		else
			rx[ rxHead ].type = CAN_FRAME_DATA;

		for( int j=0; j<8; j++ )
			rx[ rxHead ].data[j] = frame[i].a_data[j];

		rxHead = newHead;
		rxSem.Put();
	}
}

/***************************************************************************/
/**
Local interrupt handlers.  These just call the member function for the
CAN object.
*/
/***************************************************************************/
#define RX_INT(x)  static void VCI_CALLBACKATTR rxInt##x( UINT16 q, UINT16 ct, VCI_CAN_OBJ *p ) \
                   { if( board[x] ) board[x]->rxInt( ct, p ); }

RX_INT(0);
RX_INT(1);
RX_INT(2);
RX_INT(3);

/***************************************************************************/
/**
Initialize the Ixxat .dll function pointers.  This internal method is called
at startup and used to initialize some local pointers to functions in the 
Ixxat supplied .dll files.
@return A pointer to an error object or NULL on success.
*/
/***************************************************************************/
static const Error *InitLibrary( void )
{
	const Error *err = 0;
	libraryMutex.Lock();

	if( !openCards )
	{
		// Load the Ixxat .dll files
		hReg = LoadLibrary("xat11reg.dll");
		if( !hReg )
		{
			cml.Error( "Unable to load library file: xat11reg.dll\n" );
			err = &CanError::NoDriver;
			goto done;
		}

		hVCI = LoadLibrary("vci11un6.dll");
		if( !hVCI )
		{
			FreeLibrary( hReg );
			cml.Error( "Unable to load library file: vci11un6.dll\n" );
			err = &CanError::NoDriver;
			goto done;
		}

		lpXAT_SelectHardware    = (XAT_SelectHardwareType)   GetProcAddress( hReg, "XAT_SelectHardware"    );
		lpXAT_GetConfig         = (XAT_GetConfigType)        GetProcAddress( hReg, "XAT_GetConfig"         );
		lpXAT_GetDefaultHwEntry = (XAT_GetDefaultHwEntryType)GetProcAddress( hReg, "XAT_GetDefaultHwEntry" );
		lpVCI_StartCan          = (VCI_StartCanType)         GetProcAddress( hVCI, "VCI_StartCan"          );
		lpVCI_AssignRxQueObj    = (VCI_AssignRxQueObjType)   GetProcAddress( hVCI, "VCI_AssignRxQueObj"    );
		lpVCI_ConfigQueue       = (VCI_ConfigQueueType)      GetProcAddress( hVCI, "VCI_ConfigQueue"       );
		lpVCI_SetAccMask        = (VCI_SetAccMaskType)       GetProcAddress( hVCI, "VCI_SetAccMask"        );
		lpVCI_InitCan           = (VCI_InitCanType)          GetProcAddress( hVCI, "VCI_InitCan"           );
		lpVCI2_PrepareBoard     = (VCI2_PrepareBoardType)    GetProcAddress( hVCI, "VCI2_PrepareBoard"     );
		lpVCI_CancelBoard       = (VCI_CancelBoardType)      GetProcAddress( hVCI, "VCI_CancelBoard"       );
		lpVCI_TransmitObj       = (VCI_TransmitObjType)      GetProcAddress( hVCI, "VCI_TransmitObj"       );
		lpVCI_RequestObj        = (VCI_RequestObjType)       GetProcAddress( hVCI, "VCI_RequestObj"        );


		if( !lpXAT_SelectHardware || !lpXAT_GetConfig || !lpXAT_GetDefaultHwEntry || 
			 !lpVCI_StartCan || !lpVCI_AssignRxQueObj || !lpVCI_ConfigQueue || 
			 !lpVCI_SetAccMask || !lpVCI_InitCan || !lpVCI2_PrepareBoard || 
			 !lpVCI_CancelBoard || !lpVCI_TransmitObj || !lpVCI_RequestObj )
		{
			err = &CanError::NoDriver;
			FreeLibrary( hVCI );
			FreeLibrary( hReg );
		}
	}

	if( !err )
		openCards++;

done:
	libraryMutex.Unlock();
	return err;
}

/***************************************************************************/
/**
Free the library pointers if they are no longer accessed.
@return A pointer to an error object or NULL on success
*/
/***************************************************************************/
static void UninitLibrary( void )
{
	libraryMutex.Lock();
	if( --openCards == 0 )
	{
		FreeLibrary( hVCI );
		FreeLibrary( hReg );
	}
	libraryMutex.Unlock();
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?