Sending and Receiving

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.

You can set a channel to silent mode if you want it to be on-bus without interfering with the traffic in any way. A channel in silent mode will receive everything on the bus but will not transmit anything, not even ACK bits. Use canSetBusOutputControl() to set a channel to silent mode.

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 canMSG_xxx flags and 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.

The size of the queues in the driver and hardware is descibed 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? 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.

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.

If you want to wait until a message arrives (or a timeout occurs) and then read it, call canReadWait().

If you want just to wait for an arbitrary message to arrive, but you don't want to read the message, call canReadSync().

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.

Sending Messages

Outgoing CAN messages are buffered in a transmit queue and sent on a First-In First-Out basis. Use canWrite() to send a message on the bus.

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.

Note
Not all CAN controllers support CAN 2.0B.

Example. Sending a CAN message using extended CAN.

char msg[8];
...
stat = canWrite(hnd, 23456, msg, 8, canMSG_EXT);

Asynchronous Notification

Receiving Asynchronous Notification

You can receive an asynchronous notification when certain events occur in CANlib, for example, when a message arrives or when the CAN controller goes "error passive" due to bus errors. Use canSetNotify() to tell CANlib what events you want notifications for. The different kinds of events are described below.

When the specified kind of event occur, a WM__CANLIB message is posted (using the Win32 PostMessage API) to the window whose handle was specified in the call to canSetNotify(). Like all Windows messages, this particular message carries two parameters, WPARAM and LPARAM; their contents vary depending on the kind of event and are described below.

Receive Events
A receive event occurs when a CAN message arrives to a previously empty queue. In other words, there will be a receive event when the queue needs servicing but you will not receive an event for every received CAN message. The WPARAM parameter will be set to the handle of the circuit that received the message. The lowest two bytes of the LPARAM parameter will be set to canEVENT_RX, and the two most significant bytes will be zero.

Transmit Events
A transmit event occurs whenever a CAN message has been transmitted. The WPARAM parameter will be set to the handle of the circuit that transmitted the message. The lowest two bytes of the LPARAM parameter will be set to canEVENT_TX, and the two most significant bytes will be zero.

Status Events
A status event occurs when the bus status of the CAN controller has changed, for example, if the controller goes "error passive" due to bus errors. The WPARAM parameter will be set to the handle of the circuit for which the status has changed. The lowest two bytes of the LPARAM parameter will be set to canEVENT_STATUS, and the two most significant bytes will be zero.

Error Events
An error frame has been received. The WPARAM parameter will be set to the handle of the circuit where the error frame was received. The lowest two bytes of the LPARAM parameter will be set to canEVENT_ERROR, and the two most significant bytes will be zero.

Receiving Asynchronous Notification Using a Callback Function

You can call the kvSetNotifyCallback() function to register a callback that is called by CANlib when certain events occur. The callback function is called in the context of a high-priority thread created by CANlib. You should be careful not to perform any time consuming tasks within the callback function, and you must also arrange for the synchronization between the callback function and the rest of your code.

Receiving Asynchronous Notification Using an Event Handle

You can call canIoCtl() to get a handle to a Win32 event that you can send to the Win32 API functions WaitForSingleObject or WaitForMultipleObjects. The event will be set when "something" happens.

Passing this handle to WaitForXXX is the only supported operation. Don't try to set and or reset the event yourself.

You can also call canWaitForEvent(); the calling thread will sleep inside CANlib and return when "something" has happened. There is no more information available as to what really happened.

Be sure to read canRead() until it returns canERR_NOMSG to empty the receive queue when you have called canWaitForEvent or waited on the event. If you fail to do this, the event might not be set in the future. This is because the event is set only when an driver internal receive queue goes from empty to not empty. Calling canRead() until it returns canERR_NOMSG will drain this queue and the event will be set next time an event arrives to the driver internal queue.

Message Filters

Setting 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 with the canAccept() function.

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

Example. Setting the acceptance filters.

stat = canAccept(hnd, 0xE7, canFILTER_SET_CODE_STD);
stat = canAccept(hnd, 0xFF, canFILTER_SET_MASK_STD);

This code snippet will cause all messages with 11-bit identifiers with the lower 8 bits not equalling 0xe7 to be rejected.

Message Mailboxes

Some other CAN driver libraries in the market feature what usually is called "mailboxes", "message objects", "user buffers" etc. CANlib, on the other hand, focuses on message queues because we feel this imposes fewer restrictions on the CAN system.

For example, a higher layer protocol that uses a sequence of CAN messages with the same identifier is hard to implement using mailboxes: when the next message arrives it overwrites the previous one. You can, in a way, simulate the behavior of mailboxes by using canReadSpecific(). You will have to call canRead() periodically in order to clear out messages not read by canReadSpecific().

Example. How to simulate a mailbox-style CAN interface.

Assume you take special interest in CAN messages with identifiers 530, 540 and 550. Your message-handling loop could then look something like this:

while (..) {
if (canReadSpecific(hnd, 530, buf, ...) == canOK) {
// Process msg 530
}
if (canReadSpecific(hnd, 540, buf, ...) == canOK) {
// Process msg 540
}
if (canReadSpecific(hnd, 550, buf, ...) == canOK) {
// Process msg 550
}
while (canRead(hnd, &id, buf, ...) == canOK) {
// Handle other messages
}
}

You can call this message-processing routine from your WM__CANLIB handler or make it the main routine in your program.

Overruns

If the CAN interface or the driver runs out of buffer space, or if the bus load is so high that the CAN controller can't keep up with the traffic, an overload condition is flagged to the application.

The driver will set the canMSGERR_HW_OVERRUN and/or canMSGERR_SW_OVERRUN flags in the flag argument of canRead and its relatives. The flag(s) will be set in the first message read from the driver after the overrun or overload condition happened.

Your application should test for both these flags. You can use the constant canMSGERR_OVERRUN for doing this.

Message Queue and Buffer Sizes

Incoming and outgoing CAN messages can be buffered in three different places:

  • In the CAN controller
  • On the CAN board
  • In the CAN driver (i.e. CANlib)

The sizes of the first two buffers are clearly hardware dependent. You might find the following information useful.

Many CAN boards from KVASER uses the SJA1000 CAN controller. This chip can buffer somewhere between 5 and 19 incoming messages. It does not buffer outgoing messages.

CAN boards with an on-board microcontroller (LAPcan, LAPcan II, USBcan) typically buffer something like 500 incoming and outgoing messages.

CAN boards using the M16C microcontroller (USBcan Rugged, USBcan II, PCIcan II) typically buffer some 100 incoming messages and around 50 outgoing messages.

CANlib drivers will, by default, buffer 256 outgoing messages per channel and 1024 incoming messages per channel. You can use canIoCtl() to adjust the size of the receive buffer.

Object Buffers

CANlib supports object buffers for special purposes. You don't need these object buffers when transmitting and receiving regular messages. Instead, the object buffers allows you to

  • define auto response messages; that is, when a message meeting a certain condition is received, CANlib will respond automatically with a message you define,
  • define auto transmit messages; that is, messages that are transmitted periodically.

The object buffers are implemented by the firmware and hardware of certain devices, e.g. the Kvaser Leaf Professional. The number of buffers in a device is limited. Typically around 10 buffers are available.

Using the object buffers
To use the object buffers, you start with allocating a buffer with a call to canObjBufAllocate(). For an auto response buffer, you define which messages to respond to by calling canObjBufSetFilter(), and the contents of the response is set with canObjBufWrite().

To enable a buffer, call canObjBufEnable(), and call canObjBufDisable() to disable it.

For an auto transmit buffer, call canObjBufSetPeriod() to set the frequency of the message, call canObjBufSetMsgCount() to set the number of messages to send from the buffer, and call canObjBufWrite() to define the contents of the message.

If you want to send a burst of messages at the highest possible pace, use canObjBufSendBurst().

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

See also
canObjBufFreeAll()
canObjBufAllocate()
canObjBufFree()
canObjBufWrite()
canObjBufSetFilter()
canObjBufSetFlags()
canObjBufEnable()
canObjBufDisable()
canObjBufSendBurst()
canObjBufSetPeriod()
canObjBufSetMsgCount()

Different CAN Frame Types

Remote Requests

You can send remote requests by passing the canMSG_RTR flag to canWrite(). Received remote frames are reported by canRead et al using the same flag.

Error Frames

Nearly all hardware platforms support detection of error frames. If an error frame arrives, the flag canMSG_ERROR_FRAME is set in the flag argument of canRead(). The identifier is garbage if an error frame is received, but for LAPcan it happens to be 2048 plus the error code from the SJA1000.

Many platforms (for example, LAPcan, Leaf, and USBcan II) support transmission of error frames as well. To send error frames, set the canMSG_ERROR_FRAME flag in the flag argument to canWrite().

Overload Frames

These aren't used nowadays. Certain old CAN controllers (Intel 82526) used them to delay frame processing in certain cases.

Other frame features of interest

  • You can send wakeup frames (used for Single-Wire CAN) if your hardware supports it, for example, a LAPcan plus a DRVcan S. Just set the canMSG_WAKEUP flag when calling canWrite().
  • For "low-speed CAN" (1053/1054 type transceivers), the canMSG_NERR flag is set if a frame is received in "fault-tolerant" mode.