📄 can_kvaser.cpp
字号:
/************************************************************/
/* */
/* Copley Motion Libraries */
/* */
/* Author: Stephen Glow & Chris Jones */
/* */
/* Copyright (c) 2002-2005 Copley Controls Corp. */
/* http://www.copleycontrols.com */
/* */
/************************************************************/
/*
CAN object for KVASER CAN driver
(see http://www.kvaser.com for more information on the KVASER driver for the PCIcanS card)
*/
#include <cstdio>
#include <errno.h>
#include <canlib.h>
#include "can_kvaser.h"
#include "CML.h"
/* external functions */
extern void CheckWindowsThreadStop( void );
/* Types used to define functions contained in the Kvaser .dll files */
typedef canStatus (CANLIBAPI *canBusOnType)( int );
typedef canStatus (CANLIBAPI *canSetBusParamsType)( int, long, uint, uint, uint, uint, uint );
typedef canStatus (CANLIBAPI *canIoCtlType)( int, uint, void*, uint );
typedef canStatus (CANLIBAPI *canOpenChannelType)( int, int );
typedef canStatus (CANLIBAPI *canInitLibraryType)( void );
typedef canStatus (CANLIBAPI *canCloseType)( int );
typedef canStatus (CANLIBAPI *canBusOffType)( int );
typedef canStatus (CANLIBAPI *canReadWaitType)( int, long*, void*, uint*, uint*, ulong*, ulong );
typedef canStatus (CANLIBAPI *canReadType)( int, long*, void*, uint*, uint*, ulong* );
typedef canStatus (CANLIBAPI *canWriteType)( int, long, void*, uint, uint );
CML_NAMESPACE_USE();
/* local functions */
static const Error *InitLibrary( void );
static void UninitLibrary( void );
/* local data */
static const char *dllName = "canlib32.dll";
static HMODULE hDLL = 0;
static int openCards = 0;
static Mutex libraryMutex;
static canBusOnType LPcanBusOn;
static canSetBusParamsType LPcanSetBusParams;
static canIoCtlType LPcanIoCtl;
static canOpenChannelType LPcanOpenChannel;
static canInitLibraryType LPcanInitLibrary;
static canCloseType LPcanClose;
static canBusOffType LPcanBusOff;
static canReadWaitType LPcanReadWait;
static canReadType LPcanRead;
static canWriteType LPcanWrite;
/***************************************************************************/
/**
Construct a default CAN object.
The CAN interface is closed initially, and no port name is selected.
*/
/***************************************************************************/
KvaserCAN::KvaserCAN( void ) : CanInterface()
{
// Default baud to 1,000,000 bps
SetBaud( 1000000 );
// Default to not open
open = 0;
readCount = 0;
}
/***************************************************************************/
/**
Construct a CAN object with a specified port name.
The port name should be of the form CANx or KVASERx 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.
*/
/***************************************************************************/
KvaserCAN::KvaserCAN( const char *port ) : CanInterface(port)
{
// Default baud to 1,000,000 bps
SetBaud( 1000000 );
// Default to not open
open = 0;
readCount = 0;
}
/***************************************************************************/
/**
Destructor. This closes the CAN port and frees the .dll
*/
/***************************************************************************/
KvaserCAN::~KvaserCAN( void )
{
Close();
}
/***************************************************************************/
/**
Open the Kvaser CAN port. Before Open is called, the desired baud rate must
have been specified by calling SetBaud, and the port name must have been
set. If the baud was not specified, it will default to 1,000,000 BPS. If
the port name is not set, it will default to CAN0.
@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *KvaserCAN::Open( void )
{
int port;
mutex.Lock();
if( open )
{
mutex.Unlock();
return &CanError::AlreadyOpen;
}
/**************************************************
* Find the port number to open.
**************************************************/
port = FindPortNumber( "CAN" );
if( port < 0 ) port = FindPortNumber( "KVASER" );
if( port < 0 )
{
mutex.Unlock();
return &CanError::BadPortName;
}
const Error *err = InitLibrary();
if( err )
{
mutex.Unlock();
cml.Error( "KvaserCAN::InitLibrary failed with error: %s\n", err->toString() );
return err;
}
LPcanInitLibrary();
Handle = LPcanOpenChannel( port, canWANT_EXCLUSIVE);
int status = LPcanIoCtl(Handle, canIOCTL_FLUSH_RX_BUFFER, NULL, NULL);
// Set the baud rate
if( status == canOK ) status = LPcanSetBusParams(Handle, kvBaud, 0, 0, 0, 0, 0 );
// Set the acceptance mask (not yet supported) ?
if( status == canOK ) status = LPcanBusOn(Handle);
open = 1;
// Set the acceptance mask (not yet supported) ?
mutex.Unlock();
return ConvertError( status );
}
/***************************************************************************/
/**
Close the CAN interface.
@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *KvaserCAN::Close( void )
{
mutex.Lock();
int wasOpen = open;
open = 0;
mutex.Unlock();
if( !wasOpen )
return 0;
// Wait for reading threads to time out.
WaitReadCount();
mutex.Lock();
canStatus status = LPcanBusOff(Handle);
status = LPcanClose(Handle);
mutex.Unlock();
// Free the DLL if no longer in use.
UninitLibrary();
return ConvertError(status);
}
/***************************************************************************/
/**
Set the CAN interface baud rate.
@param b The baud rate to set.
@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *KvaserCAN::SetBaud( int32 b )
{
switch( b )
{
case 1000000: kvBaud = BAUD_1M; break;
case 500000: kvBaud = BAUD_500K; break;
case 250000: kvBaud = BAUD_250K; break;
case 125000: kvBaud = BAUD_125K; break;
case 100000: kvBaud = BAUD_100K; break;
case 62000: kvBaud = BAUD_62K; break;
case 50000: kvBaud = BAUD_50K; 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, NULL on success.
*/
/***************************************************************************/
const Error *KvaserCAN::RecvFrame( CanFrame &frame, int32 timeout )
{
canStatus status;
uint dlc, flags;
ulong time;
if( !open )
return &CanError::NotOpen;
// Do an immediate read if no timeout is requested
if( timeout == 0 )
{
IncReadCount( 1 );
try {
status = LPcanRead( Handle, (long*)&frame.id, frame.data, &dlc, &flags, &time );
}
catch( ... ) {
IncReadCount( -1 );
throw;
}
IncReadCount( -1 );
}
// For reading with a timeout, do a bunch of reads with a max timeout of 100 ms.
// This allows me to check to make sure the thread wasn't stopped (Thread::stop)
// while I was waiting. This is kind of ugly, but it seems to be the only way
// to allow the thread to be stopped using this driver.
else
{
while( timeout )
{
if( !open )
return &CanError::NotOpen;
// Check for Thread::stop.
CheckWindowsThreadStop();
// Wait for up to 100 ms
int32 to = timeout;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -