This is the second post in a 3-part series about CANlib development:
In the last video, we established how to add the CANlib SDK resources to your own Visual Studio project. In this video we will walk through the minimum CANlib function calls for configuring and reading messages from the CAN bus through a Kvaser unit. We have already added the necessary code to the example project from our last video. This code will configure the unit or a virtual channel for 250 kbps and then loop, reading every CAN frame on the bus until the user presses the escape button.
To accomplish this, the first step as we described in the previous video, is to import the canlibCLSNET types with the “using” directive.
Our first CANlib function call must be canInitalizeLibrary. Calling this function causes the necessary DLLs to be loaded into memory and all connected Kvaser hardware is assigned a channel number.
We now need to get a handle to a Kvaser CAN circuit using the canOpenChannel function. The handle returned is necessary for subsequent calls to the library. The first parameter specifies the desired CAN circuit. The second parameter allows for additional qualifying flags. In this case, we are accepting handles to virtual channels.
Now that we have a handle, we can configure the circuit to the appropriate bitrate for the CAN bus that we’re connecting to. The canSetBusParams function supports setting each of the bus parameter values or using one of Kvaser’s predefined bitrates. We are using the predefined bitrate of 250 kbps.
Once you have configured the bitrate, you can make the circuit active on the CAN bus by calling canBusOn. Once this function has executed, the CAN circuit is actively participating in CAN traffic.
You may have noticed that we call DisplayError after each call to a CANlib function. For cleaner code, we are processing the error status returned from CANlib in a separate function. If there is an error condition, we translate the error code to a string description using the canGetErrorText function. Checking the status returned by CANlib functions is essential to understanding where problems are occurring.
Back in Main, we have finished configuring and activating the circuit, so we can loop reading the CAN frames from the bus. We will use canReadWait to retrieve the CAN frames. A CAN frame consists of an identifier (id), 0 to 8 data bytes (data), a data length code (dlc), message attributes (flags), and a time stamp (time). The final parameter in canReadWait specifies how long to wait in milliseconds for a CAN frame if the receive buffer is empty. So, when the canReadWait returns we need to check a couple of things before assuming we have a message. If the returned status value is canOK, we know we have something to process. If the returned status is canERR_NOMSG, then we simply need to loop again. But if the returned status is any other value, the handle to the circuit can no longer be used for reading CAN data.
Again, to make the code easier to read we have placed the data processing code in a separate function called DisplayMessage which is executed when canReadWait returns a status of canOK. DisplayMessage shows many pieces of information that can be extracted from the CAN frame data returned. But most importantly, the function checks the second indicator of whether an actual CAN data frame was received. This is done by checking for the canMSG_ERROR_FRAME bit in the flags parameter. If the bit is set, you received an error frame and you do not process the identifier, data length code, or data parameters. If the bit is not set, you have received a CAN data frame and should process the frame as desired.
Once you are finished, you should gracefully close your program by making the CAN circuit inactive on the bus using the canBusOff function and then freeing the handle with the canClose function.
Now let’s run our new console application and see it work in real time. As you can see, the app was able to connect to a device, begin receiving can frames, and process them until we pressed Escape to exit.