example/cpp/candemo/candemo.cpp
/*
** This software is furnished as Redistributable under the Kvaser Software Licence
** https://www.kvaser.com/canlib-webhelp/page_license_and_copyright.html
**
** Description:
** Demo program for CANLIB.
** This program can send and receive CAN messages on all CAN channels installed
** in your computer. Start it, and press 'h' to get a list of available commands.
** ---------------------------------------------------------------------------
*/
#include <canlib.h>
#include "candemo.h"
#include "stdio.h"
// module globals
unsigned int m_usedBaudRate = 0;
canHandle m_usedChannel;
unsigned int m_usedId;
unsigned int m_usedFlags = 0;
unsigned int m_Verbose = 1;
driverData m_channelData;
driverData *m_DriverConfig = &m_channelData;
//Function that prints the "help- menu"
void help(void)
{
printf("\n********************************************\n*\n");
printf("* Keyboard commands:\n");
printf("* t Transmit a Message\n");
printf("* b Transmit a Message Burst\n");
printf("* r Select Remote Message\n");
printf("* S Request chip status\n");
printf("* s Read chip status\n");
printf("* o On/Off Bus\n");
printf("* c/C/1-9 Select Channel\n");
printf("* i/I Select Transmit Id (Up/Down)\n");
printf("* x Select Extended Id\n");
printf("* m Toggle Output Mode\n");
printf("* v Toggle Logging to Screen\n");
printf("* T Toggle transmission acknowledges for the current channel\n");
printf("* k Read the clock (call kvReadTimer)\n");
printf("* h Help\n");
printf("* d Print Driver Configuration\n");
printf("* e Clear Screen\n");
printf("* y Clear Error Status and Counters\n");
printf("* ESC Exit\n*\n*");
printf("\n********************************************\n");
}
//Function that prints channel data
void printDriverConfig( void )
{
unsigned int i;
printf("\nDriver Configuration:\n ChannelCount=%u\n", m_DriverConfig->channelCount);
for (i = 0; i < m_DriverConfig->channelCount; i++) {
printf(" %s : Channel %d, isOnBus=%d, Baudrate=%u",
m_DriverConfig->channel[i].name,
m_DriverConfig->channel[i].channel,
m_DriverConfig->channel[i].isOnBus,
m_usedBaudRate);
switch(m_usedBaudRate) {
printf("canBITRATE_1M");
break;
printf("canBITRATE_500K");
break;
printf("canBITRATE_250K");
break;
printf("canBITRATE_125K");
break;
printf("canBITRATE_100K");
break;
printf("canBITRATE_62K");
break;
printf("canBITRATE_50K");
break;
default:
printf("UNKNOWN");
}
printf("\n ");
if (m_DriverConfig->channel[i].driverMode == canDRIVER_NORMAL) {
printf("Drivermode=canDRIVER_NORMAL\n");
} else {
printf ("Drivermode=canDRIVER_SILENT\n");
}
}
printf("\n\n");
}
// Open one handle to each channel present in the system.
// Set bus parameters
void InitDriver(void)
{
int i;
canStatus stat;
// Initialize ChannelData.
memset(m_channelData.channel, 0, sizeof(m_channelData.channel));
for (i = 0; i < MAX_CHANNELS; i++) {
m_channelData.channel[i].isOnBus = 0;
m_channelData.channel[i].driverMode = canDRIVER_NORMAL;
m_channelData.channel[i].channel = -1;
m_channelData.channel[i].hnd = canINVALID_HANDLE;
m_channelData.channel[i].txAck = 0; // Default is TxAck off
}
m_channelData.channelCount = 0;
//
// Enumerate all installed channels in the system and obtain their names
// and hardware types.
//
//initialize CANlib
//get number of present channels
stat = canGetNumberOfChannels((int*)&m_channelData.channelCount);
for (i = 0; (unsigned int)i < m_channelData.channelCount; i++) {
canHandle hnd;
//obtain some hardware info from CANlib
m_channelData.channel[i].channel = i;
m_channelData.channel[i].name,
sizeof(m_channelData.channel[i].name));
&m_channelData.channel[i].hwType,
sizeof(DWORD));
//open CAN channel
if (hnd < 0) {
// error
PRINTF_ERR(("ERROR canOpenChannel() in initDriver() FAILED Err= %d. <line: %d>\n",
hnd, __LINE__));
}
else {
m_channelData.channel[i].hnd = hnd;
if ((stat = canIoCtl(hnd, canIOCTL_FLUSH_TX_BUFFER, NULL, NULL)) != canOK)
PRINTF_ERR(("ERROR canIoCtl(canIOCTL_FLUSH_TX_BUFFER) FAILED, Err= %d <line: %d>\n",
stat, __LINE__));
}
//set up the bus
if (i == 0) {
switch(m_usedBaudRate) {
case 1000000:
m_usedBaudRate = canBITRATE_1M;
break;
case 500000:
m_usedBaudRate = canBITRATE_500K;
break;
case 250000:
m_usedBaudRate = canBITRATE_250K;
break;
case 125000:
m_usedBaudRate = canBITRATE_125K;
break;
case 100000:
m_usedBaudRate = canBITRATE_100K;
break;
case 62500:
m_usedBaudRate = canBITRATE_62K;
break;
case 50000:
m_usedBaudRate = canBITRATE_50K;
break;
default:
printf("Baudrate set to 125 kbit/s. \n");
m_usedBaudRate = canBITRATE_125K;
break;
}
}
//set the channels busparameters
stat = canSetBusParams(hnd, m_usedBaudRate, 0, 0, 0, 0, 0);
if (stat < 0) {
PRINTF_ERR(("ERROR canSetBusParams() in InitDriver(). Err = %d <line: %d>\n",
stat, __LINE__));
}
}
printf("\n");
}
// Go off bus and close all open handles.
void Cleanup(void)
{
unsigned int i;
for (i = 0; i < m_channelData.channelCount; i++) {
canStatus stat;
if ((stat = canBusOff(m_channelData.channel[i].hnd)) != canOK)
PRINTF_ERR(("ERROR canBusOff() FAILED Err= %d. <line: %d>\n", stat, __LINE__));
if ((stat = canClose(m_channelData.channel[i].hnd)) != canOK) {
PRINTF_ERR(("ERROR canClose() in Cleanup() FAILED Err= %d. <line: %d>\n",
stat, __LINE__));
}
}
}
// CheckAbort()
//
// check at transmission of a message burst, if key pressed
// if key pressed -> stop transmission
int CheckAbort(void)
{
INPUT_RECORD ir;
unsigned long n;
GetNumberOfConsoleInputEvents(GetStdHandle(STD_INPUT_HANDLE), &n);
while (n > 0) {
ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &n);
if ((n == 1) && (ir.EventType == KEY_EVENT)) {
if (ir.Event.KeyEvent.bKeyDown)
return TRUE;
}
n--;
}
return FALSE;
}
// Transmit a message using channel, id and flags from the global variables
// If print is TRUE the transmitted msg will be printed
canStatus TransmitMessage(BOOL print)
{
unsigned char msg[8];
int i;
if (!m_Verbose) print = FALSE;
if (print) {
// The time stamp is not available when we call canWrite so it's
// omitted here. (If we want to see when the message was sent, we
// first need to enable transmission acknowledges with canIoCtl.
// Then all sent messages will appear also as received messages,
// but with the canMSG_TXACK flag set.
printf("Ch:%u ID:%08x DLC:%zu Flg:%02x Data:",
m_usedChannel, m_usedId, sizeof(msg), m_usedFlags);
}
for (i = 0; i < 8; i++) {
msg[i] = (unsigned char) i;
if (print) printf("%02x ", msg[i]);
}
if (print) printf("\n");
return canWrite(m_DriverConfig->channel[m_usedChannel].hnd, m_usedId,
msg, sizeof(msg), m_usedFlags);
}
/*************************************************************/
/*************************************************************/
// MAIN
int main(int argc, char **argv)
{
HANDLE th[MAX_CHANNELS + 1];
static int running = 1;
DWORD active_handle;
char c;
canStatus stat;
unsigned int i;
m_usedId = 0;
m_usedChannel = 0;
system("cls");
printf("\n\nWelcome to yet another CANLIB Test Application, compiled at " __DATE__ "\n"
"(Check out http://www.kvaser.com for more info.)\n\n"
"Usage:\n"
" CANdemo [baudrate] [identifier]\n"
"Press h for help\n\n\n -----------------------------------------------------------------\n\n");
// Commandline can contain baudrate and an identifier, both optional.
if (argc > 1) {
m_usedBaudRate = atoi(argv[1]);
if (m_usedBaudRate) {
printf("Baudrate = %u\n\n", m_usedBaudRate);
argc--;
argv++;
}
}
if (argc > 1) {
sscanf (argv[1], "%x", &m_usedId );
if (m_usedId) {
printf("Identifier = 0x%x\n\n", m_usedId);
}
}
// open channel and set busparams, etc...
InitDriver();
//get std_input event handle
th[0] = GetStdHandle(STD_INPUT_HANDLE);
if (th[0] == INVALID_HANDLE_VALUE)
PRINTF_ERR(("ERROR inv handle (std_input). <line: %d>\n", __LINE__));
for (i = 1; i < (m_channelData.channelCount + 1); i++) {
HANDLE tmp;
//go on bus (every channel)
stat = canBusOn(m_channelData.channel[i-1].hnd);
if (stat < 0) {
PRINTF_ERR(("ERROR canBusOn(). Err = %d <line: %d>\n", stat, __LINE__));
}
else {
m_DriverConfig->channel[i-1].isOnBus = 1;
}
//get CAN - eventHandles
stat = canIoCtl(m_channelData.channel[i-1].hnd,
&tmp,
sizeof(tmp));
if (stat < 0) {
PRINTF_ERR(("canIoCtl(canIOCTL_GET_EVENTHANDLE) FAILED. Err = %d <line: %d>\n",
stat, __LINE__));
}
th[i] = tmp;
}
printDriverConfig();
printf("\n");
//Main LOOP
while (running) {
active_handle = WaitForMultipleObjects(m_channelData.channelCount + 1,
th,
FALSE /*any*/,
INFINITE);
//
// CAN hardware event?
//
if (((active_handle - WAIT_OBJECT_0) > 0) &&
((active_handle - WAIT_OBJECT_0) <= m_channelData.channelCount))
{
unsigned int j;
long id;
unsigned char data[8];
unsigned int dlc;
unsigned int flags;
DWORD time;
int moreDataExist;
do {
moreDataExist = 0;
for (i = 0; i < m_channelData.channelCount; i++) {
stat = canRead(m_channelData.channel[i].hnd, &id, &data[0], &dlc, &flags, &time);
switch (stat) {
case canOK:
if (m_Verbose) {
printf("RxMsg: Ch:%d ID:%08lx DLC:%u Flg:%02x T:%08lx Data:",
m_channelData.channel[i].channel, id, dlc, flags, time);
if ((flags & canMSG_RTR) == 0) {
for (j = 0; j < dlc; j++) {
printf("%02x ", data[j]);
}
}
printf("\n");
}
moreDataExist = 1;
break;
// No more data on this handle
break;
default:
PRINTF_ERR(("ERROR canRead() FAILED, Err= %d <line: %d>\n", stat, __LINE__));
break;
}
}
} while (moreDataExist);
}
//STD_INPUT event
else if (active_handle == WAIT_OBJECT_0)
{
unsigned long n;
INPUT_RECORD ir;
ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &n);
if ((n == 1) && (ir.EventType == KEY_EVENT)) {
if (ir.Event.KeyEvent.bKeyDown) {
//pressed key switch
switch ((c = ir.Event.KeyEvent.uChar.AsciiChar)) {
//==================================================
case 'V':
case 'v':
m_Verbose = !m_Verbose;
if (m_Verbose) printf("Logging to screen ON. \n");
else printf("Logging to screen OFF. \n");
break;
//==================================================
case 't':
{
canStatus stat;
if (m_Verbose) {
printf("TxMsg: ");
}
if (m_DriverConfig->channel[m_usedChannel].isOnBus == 0) {
printf("Cannot transmit message. \n");
printf("Channel %d is OFF bus. \n", m_usedChannel);
break;
}
stat = TransmitMessage(TRUE);
if (stat < 0) {
PRINTF_ERR(("ERROR TransmitMessage() FAILED Err= %d <line: %d>\n",
stat, __LINE__));
}
}
break;
//==================================================
case 'T':
{
canStatus stat;
int tmp;
if (m_Verbose) {
printf("Toggling TxAcks on channel %d", m_usedChannel);
}
tmp = m_DriverConfig->channel[m_usedChannel].txAck? 0 : 1;
stat = canIoCtl(m_DriverConfig->channel[m_usedChannel].hnd,
&tmp,
sizeof(tmp));
if (stat == canOK) {
m_DriverConfig->channel[m_usedChannel].txAck = tmp;
printf(" - now %s\n", tmp? "on" : "off");
} else {
printf(" failed with error %d on line %d\n", stat, __LINE__);
}
}
break;
//==================================================
case 'k':
{
unsigned int can_time;
stat = kvReadTimer(m_DriverConfig->channel[m_usedChannel].hnd, &can_time);
if (stat == canOK) {
printf("Time on channel %d: 0x%08x\n", m_usedChannel, can_time);
} else {
printf("kvReadTimer() failed with error %d on line %d\n", stat, __LINE__);
}
}
break;
//==================================================
case 'B':
case 'b':
{
if (m_Verbose) printf("Transmit message BURST. \n");
// transmit a message burst
unsigned char msg[8];
int i;
canStatus stat;
if (m_DriverConfig->channel[m_usedChannel].isOnBus == 0) {
printf("Cannot transmit burst. \n");
printf("Channel %d is OFF bus. \n", m_usedChannel);
break;
}
for (i = 0; i < 8; i++) {
msg[i] = (unsigned char) i;
}
printf("Press any key to stop.\n");
for (i = 0; ; i++) {
//Send bursts of 250 messages
for (int j = 0; j < 250; j++) {
stat = TransmitMessage(FALSE);
if (stat != canOK) {
char err[100];
canGetErrorText((canStatus)stat, err, 100);
printf("ERROR: %s\n", err);
break;
}
}
if(stat != canOK)
break;
//Wait until all the messages are sent
stat = canWriteSync(m_DriverConfig->channel[m_usedChannel].hnd, 2000);
if (stat != canOK) {
char err[100];
canGetErrorText((canStatus)stat, err, 100);
printf("ERROR: %s\n", err);
break;
}
if ((i % 20) == 0) {
printf("*");
if (CheckAbort()) {
printf("\nTransmission finished\n");
break;
}
}
}
//flush transmit buffer
stat = canIoCtl(m_DriverConfig->channel[m_usedChannel].hnd,
NULL,
NULL);
if (stat != canOK) {
PRINTF_ERR(("ERROR canIoCtl() in 'b' FAILED. Err = %d <line: %d>\n", stat, __LINE__));
}
break;
}
//==================================================
case 'R':
case 'r':
// Toggle sending of remote frames.
m_usedFlags ^= canMSG_RTR;
if (m_Verbose) {
printf("Now sending %s frames.\n", (m_usedFlags & canMSG_RTR) ? "remote" : "data");
}
break;
//==================================================
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
m_usedChannel = c - '1';
goto select;
//==================================================
case 'C': // channel selection
m_usedChannel--;
if (m_usedChannel < 0)
m_usedChannel = m_channelData.channelCount - 1;
if (m_Verbose)
printf("Current channel = %d \n", m_usedChannel);
break;
//==================================================
case 'c': // channel selection
m_usedChannel++;
select:
if (m_usedChannel >= (int)m_channelData.channelCount)
m_usedChannel = 0;
if (m_Verbose)
printf("Current channel = %d \n", m_usedChannel);
break;
//==================================================
case 'X': // id-type selection
case 'x':
// Toggle sending of extended frames.
m_usedFlags ^= canMSG_EXT;
if (m_Verbose) {
printf("Now sending %s frames.\n",
(m_usedFlags & canMSG_EXT) ? "extended" : "standard");
}
break;
case 'i': // id selection
m_usedId++;
if (m_Verbose)
printf("Id set to 0x%08x\n", m_usedId);
break;
//==================================================
case 'I':
if (m_usedId > 0) m_usedId--;
if (m_Verbose)
printf("Id set to 0x%08x\n", m_usedId);
break;
//==================================================
case 'S':
if ((stat = canRequestChipStatus(m_DriverConfig->channel[m_usedChannel].hnd)) != canOK) {
PRINTF_ERR(("ERROR canRequestChipStatus() FAILED. Err= %d <line: %d>\n", stat, __LINE__));
}
break;
//==================================================
case 's':
// print chip status here
if (m_Verbose) {
printf("Channel %d is ", m_usedChannel);
if (m_DriverConfig->channel[m_usedChannel].isOnBus)
printf("ON bus. \n");
else printf("OFF bus. \n");
}
if (m_Verbose) {
DWORD flags;
if ((stat = canReadStatus(m_DriverConfig->channel[m_usedChannel].hnd, &flags)) != canOK) {
PRINTF_ERR(("ERROR canReadStatus() FAILED. Err= %d <line: %d>\n", stat, __LINE__));
}
else {
printf("Bus status : ");
if (flags & canSTAT_ERROR_PASSIVE)
printf("canSTAT_ERROR_PASSIVE ");
if (flags & canSTAT_BUS_OFF)
printf("canSTAT_BUS_OFF ");
if (flags & canSTAT_ERROR_WARNING)
printf("canSTAT_ERROR_WARNING ");
if (flags & canSTAT_ERROR_ACTIVE)
printf("canSTAT_ERROR_ACTIVE ");
if (flags & canSTAT_TX_PENDING)
printf("canSTAT_TX_PENDING ");
if (flags & canSTAT_RX_PENDING)
printf("canSTAT_RX_PENDING ");
if (flags & canSTAT_TXERR)
printf("canSTAT_TXERR ");
if (flags & canSTAT_RXERR)
printf("canSTAT_RXERR ");
if (flags & canSTAT_HW_OVERRUN)
printf("canSTAT_HW_OVERRUN ");
if (flags & canSTAT_SW_OVERRUN)
printf("canSTAT_SW_OVERRUN ");
printf("\n");
}
}
break;
//==================================================
case 'M':
case 'm':
// change output mode normal / silent
{
canStatus stat;
if (m_DriverConfig->channel[m_usedChannel].driverMode == canDRIVER_NORMAL) {
stat = canSetBusOutputControl(m_DriverConfig->channel[m_usedChannel].hnd, canDRIVER_SILENT);
if (stat < 0) {
PRINTF_ERR(("ERROR canSetBusOutputControl(). Err = %d <line: %d>\n", stat, __LINE__));
}
else {
if (m_Verbose) printf("Channel %d Drivermode set to canDRIVER_SILENT. \n", m_usedChannel);
m_DriverConfig->channel[m_usedChannel].driverMode = canDRIVER_SILENT;
}
}
else {
stat = canSetBusOutputControl(m_DriverConfig->channel[m_usedChannel].hnd, canDRIVER_NORMAL);
if (stat < 0) {
PRINTF_ERR(("ERROR canBusOn(). Err = %d <line: %d>\n", stat, __LINE__));
}
else {
if (m_Verbose) printf("Channel %d Drivermode set to canDRIVER_NORMAL. \n", m_usedChannel);
m_DriverConfig->channel[m_usedChannel].driverMode = canDRIVER_NORMAL;
}
}
}
break;
//==================================================
case 'O':
case 'o':
{
canStatus stat;
// Go on bus/off bus here for currentChannel
if (m_DriverConfig->channel[m_usedChannel].isOnBus) {
stat = canBusOff(m_DriverConfig->channel[m_usedChannel].hnd);
if (stat < 0) {
PRINTF_ERR(("ERROR canBusOff(). Err = %d <line: %d>\n", stat, __LINE__));
}
else {
if (m_Verbose) printf("Channel %d Off bus. \n", m_usedChannel);
m_DriverConfig->channel[m_usedChannel].isOnBus = 0;
}
}
else {
stat = canBusOn(m_DriverConfig->channel[m_usedChannel].hnd);
if (stat < 0) {
PRINTF_ERR(("ERROR canBusOn(). Err = %d <line: %d>\n", stat, __LINE__));
}
else {
if (m_Verbose) printf("Channel %d On bus. \n", m_usedChannel);
m_DriverConfig->channel[m_usedChannel].isOnBus = 1;
}
}
}
break;
//==================================================
case 27: // Esccape
case 'q':
case 'Q':
running = FALSE;
break;
//==================================================
case 'H':
case 'h':
help();
break;
//==================================================
case 'E':
case 'e':
system("cls");
break;
//==================================================
case 'D':
case 'd':
printDriverConfig();
break;
//==================================================
case 'y':
case 'Y':
{
canStatus stat;
stat = canIoCtl(m_DriverConfig->channel[m_usedChannel].hnd,
NULL,
NULL);
if (stat < 0) {
PRINTF_ERR(("ERROR canIoCtl(). Err = %d <line: %d>\n", stat, __LINE__));
}
else {
printf("Error counters cleared successfully.\n");
}
}
break;
//==================================================
default:
break;
} //switch
}
}
} //event type
} // while
// Go off bus & close channels.
Cleanup();
return NULL;
}