Send and Receive

Bus On / Bus Off

When the CAN controller is on bus, it is receiving messages and is sending acknowledge bits in response to all correctly received messages. A controller that is off bus is not taking part in the bus communication at all.

Use canBusOn() to go on bus and canBusOff() to go off bus.

If you have multiple handles to the same controller, the controller will go off bus when the last of the handles go off bus (i.e. all handles must be off bus for the controller to be off bus). You can use canReadStatus() and watch the flag canSTAT_BUS_OFF to see if the controller has gone off bus.

If you would like to reset a CAN bus controller by taking the channel off bus and then on bus again, you can use canResetBus().

You can set a channel to silent mode by using the canDRIVER_SILENT mode if you want it to be on-bus without interfering with the traffic in any way, see CAN Driver Modes

Example. This example takes an open channel off-bus and then takes it on-bus again, for what purpose it may serve.

canStatus stat;
.
.
.
stat = canBusOff(hnd);
if (stat < 0) {
printf("canBusOff failed, status=%d\n", stat);
exit(1);
}
stat = canBusOn(hnd);
if (stat < 0) {
printf("canBusOn failed, status=%d\n", stat);
exit(1);
}

Reading Messages

Incoming messages are placed in a queue in the driver. In most cases the hardware does message buffering as well. You can read the first message in the queue by calling canRead(); it will return canERR_NOMSG if there was no message available.

The flag parameter of canRead() contains a combination of the message flags canMSG_xxx, including canFDMSG_xxx if the CAN FD protocol is enabled, and error flags canMSGERR_xxx which provides you with more information about the message; for example, a frame with a 29-bit identifier will have the canMSG_EXT bit set, and a remote frame will have the canMSG_RTR bit set. Note that the flag argument is a combination of the canMSG_xxx flags, so more than one bit might be set.

See CAN Frame Types Different for more detailed information.

The size of the queues in the driver and hardware is described in Message Queue and Buffer Sizes.

Sometimes it is desirable to have a peek into the more remote parts of the queue. Is there, for example, any message waiting that has a certain identifier?

  • canReadSpecific() - You can call canReadSpecific() to read that message. Messages not matching the specified identifier will be kept in the queue and will be returned on the next call to canRead().
  • canReadSpecificSkip() - If you want to read just a message with a specified identifier, and throw all others away, you can call canReadSpecificSkip(). This routine will return the first message with the specified identifier, discarding any other message in front of the desired one.
  • canReadWait() - If you want to wait until a message arrives (or a timeout occurs) and then read it, call canReadWait().
  • canReadSync() - If you want just to wait for an arbitrary message to arrive, but you don't want to read the message, call canReadSync().
  • canReadSyncSpecific() - If you want to wait until there is at least one message in the queue with a certain identifier, but you don't want to read it, call canReadSyncSpecific().

You can specify a timeout (in milliseconds) for those routines that wait for messages.

Example. Input Queue Handling

As an illustration of the abovementioned routines, consider the case where CAN messages with the following identifiers have arrived to the input queue:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

  1. canRead(hnd, &id, …) returns canOK and id == 1.
  2. canRead(hnd, &id, …) returns canOK and id == 2.
  3. canReadSpecific(hnd, 7, …) returns canOK and the message with id 7.
  4. canReadSpecific(hnd, 7, …) returns canERR_NOMSG.
  5. canRead(hnd, &id, …) returns canOK and id == 3.
  6. canReadSpecificSkip(hnd, 5, …) returns canOK and the message with id 5.
  7. canRead(hnd, &id, …) returns canOK and id == 6.
  8. canReadSyncSpecific(hnd, 7, …, 500) will wait for the next message with id=7 (or 500 ms have elapsed) and return canOK or canERR_TIMEOUT.
  9. canRead(hnd, &id, …) returns canOK and id == 8.
  10. canReadSpecific(hnd, 7, …) returns canOK and the message with id = 7, if the previous call to canReadSyncSpecific() returned canOK.

Example. The following code fragment reads the next available CAN message, if any.

long id;
unsigned char data[8];
unsigned int dlc, flags;
unsigned long timestamp;
stat = canRead(hnd, &id, data, &dlc, &flags, &timestamp);
if (stat != canERR_NOMSG) {
printf("Failed, status == %d\n", stat);
}

Acceptance Filters

You can set filters to reduce the number of received messages. CANlib supports setting of the hardware filters on the CAN interface board. This is done either with the canAccept() function or with the canSetAcceptanceFilter() function.

Note that both functions distinguish between 11-bit (std) and 29-bit (ext) identifiers since these are handled by two separate filters. Both of these filters default to OFF (mask == 0).

You set an acceptance code and an acceptance mask which together determine which CAN identifiers are accepted or rejected.

If you want to remove a filter, call canAccept() with the mask set to 0.

Example. To set the mask to 0xF0 and the code to 0x60:

stat = canAccept(hnd1, 0x0F0L, canFILTER_SET_MASK_STD);
if (stat < 0) printf("canAccept failed, stat = %d\n", stat);
stat = canAccept(hnd1, 0x060L, canFILTER_SET_CODE_STD);
if (stat < 0) printf("canAccept failed, stat = %d\n", stat);

or, alternatively,

stat = canSetAcceptanceFilter(hnd1, 0x060, 0x0F0, FALSE);
if (stat < 0) printf("canSetAcceptanceFilter failed, stat = %d\n", stat);

This code snippet will cause all messages having a standard (11-bit) identifier with bit7-bit4 in the identifier equal to 0110 (binary) will pass through. Other messages with standard identifiers will be rejected.

Example. How acceptance filters can be used in a smaller project.

long id;
unsigned char data[8];
unsigned int dlc, flags;
unsigned long timestamp;
// The acceptance filter only have to be called once for each handle.
stat = canSetAcceptanceFilter(hnd, 0x060, 0x0F0, FALSE);
if (stat < 0) printf("canSetAcceptanceFilter failed, stat = %d\n", stat);
// We can now run the rest of the program and the acceptance filter will reject unwanted CAN messages.
while (true){
stat = canRead(hnd, &id, data, &dlc, &flags, &timestamp);
if (stat != canERR_NOMSG) {
printf("Failed, status == %d\n", stat);
}
}

Code and Mask Format

Explanation of the code and mask format used by the canAccept(), canSetAcceptanceFilter(), and canObjBufSetFilter() functions:

  • A binary 1 in a mask means "the corresponding bit in the code is relevant"
  • A binary 0 in a mask means "the corresponding bit in the code is not relevant"
  • A relevant binary 1 in a code means "the corresponding bit in the identifier must be 1"
  • A relevant binary 0 in a code means "the corresponding bit in the identifier must be 0"

In other words, the message is accepted if ((code XOR id) AND mask) == 0.

Note
You can set the extended code and mask only on CAN boards that support extended identifiers.
Not all CAN boards support different masks for standard and extended CAN identifiers.
On some boards the acceptance filtering is done by the CAN hardware; on other boards (typically those with an embedded CPU,) the acceptance filtering is done by software. canAccept() behaves in the same way for all boards, however.

canSetAcceptanceFilter() and canAccept() both serve the same purpose but the former can set the code and mask in just one call.

Sending Messages

You transmit messages by calling canWrite(). Outgoing CAN messages are buffered in a transmit queue and sent on a First-In First-Out basis. You can use canWriteSync() to wait until the messages in the queue have been sent.

Example. Sending a CAN message.

char msg[8];
...
stat = canWrite(hnd, 234, msg, 8, 0);

Using Extended CAN (CAN 2.0B)

"Standard" CAN has 11-bit identifiers in the range 0 - 2047. "Extended" CAN, also called CAN 2.0B, has 29-bit identifiers. You specify which kind of identifiers you want to use in your call to canWrite(): if you set the canMSG_EXT flag in the flag argument, the message will be transmitted with a 29-bit identifier. Conversely, received 29-bit-identifier messages have the canMSG_EXT flag set.

Example. The following code fragment sends a CAN message on an already open channel. The CAN message will have identifier 1234 (extended) and DLC = 8. The contents of the data bytes will be whatever the data array happens to contain.

canStatus stat;
unsigned char data[8];
:
:
stat = canWrite(hnd, 1234, data, 8, canMSG_EXT);
if (stat < 0) {
printf("Failed, status == %d\n", stat);
}

There are more (but not all) of the message flags canMSG_xxx, including canFDMSG_xxx if the CAN FD protocol is enabled, that are meaningful to set when sending messages.

Object Buffers

Some of the Kvaser interfaces are equiped with hardware buffers for automatic sending and responding to messages. They can be used when the timing conditions are strict, and might not be possible to fulfill on the application level.

There are two types of buffers, auto response and auto transmit.

  • Auto response sends a defined message immediately upon receiving a message meeting your conditions.
  • Auto transmit sends a message periodically, with higher timing accuracy than can be achieved by an application working through driver and operating system.
Note
The object buffers are implemented by the firmware and hardware of certain devices, e.g. the Kvaser Leaf Professional. The number of buffers are, depending on the device, typically limited to around 8 buffers.

Using the object buffers
To use the object buffers, start by allocating buffer with a call to canObjBufAllocate() and set the content of the buffer with canObjBufWrite().

For auto response you define which messages to respond to by calling canObjBufSetFilter(). The filter uses a code and mask, which means it can be set to respond to a range of CAN ids.

For automatic transmission the delay between each message sent is set by calling canObjBufSetPeriod(). To limit the number of messages sent by the buffer make a call to canObjBufSetMsgCount().

To enable the buffer make a call to canObjBufEnable(). The buffer can be disabled by canObjBufDisable().

You can deallocate a buffer that you don't want to use any longer by a call to canObjBufFree(), or to deallocate all buffers in one call use canObjBufFreeAll().

See also
canObjBufSetFlags()

Example Auto Response.
This example responds with "1 2 3 4 5 6" with id "200" when a message with the id "100" is recieved.

// Allocate buffer for auto response
// Define message
char msg[] = { 1,2,3,4,5,6 };
int status;
// Write to buffer.
status = canObjBufWrite(handle, bufIndex, 200, msg, 0, 0);
// Only match message with id 100, match all bits.
status = canObjBufSetFilter(handle, bufIndex, 100, 0xFFFF);
// Activate the buffer
status = canObjBufEnable(handle, bufIndex);
canBusOn(handle);

Example Auto Transmit.
This example transmit "1 2 3 4 5 6" with id "300" every second.

//Allocate buffer
//define message
char msg[] = { 1, 2, 3, 4, 5, 6 };
int status;
//Write to buffer
status = canObjBufWrite(handle, bufIndex, 300, msg, 0, 0);
//Set period to 1 second (1000000 microseconds)
status = canObjBufSetPeriod(handle, bufIndex, 1000000);
//Limit the transmition to 5 messages
canObjBufSetMsgCount(handle, bufIndex, 5);
//activate the buffer
status = canObjBufEnable(handle, bufIndex);
canBusOn(handle);