Asynchronous Notification

Asynchronous Notifications

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.

Example

hnd = canOpenChannel(...);
...
stat = canSetNotify(hnd, wndHandle, canNOTIFY_RX);

When a CAN message is received and the receive queue is empty, a WM__CANLIB message will be sent to the window whose handle is wndHandle. The WM__CANLIB message will have

wParam == hnd
HIWORD(lParam) == 0
LOWORD(lParam) == canEVENT_RX

In the routine that handles WM__CANLIB, you should call canRead() repeatedly, using the handle found in wParam, until it returns canERR_NOMSG or some other error code.

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 Using 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 Using 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.

Example. Sample code using canWaitForEvent()

while (!ready) {
if (canWaitForEvent(hnd, 100) == canOK) {
while (canRead(hnd, ...) == canOK) {
// Handle incoming messages here
}
canReadStatus(hnd, &can_status);
}
}