CANtegrity API (kvDiag)

Table of Contents

The CANtegrity API can be used to obtain detailed information about the traffic on a CAN bus. To use the CANtegrity API, a device that supports it is needed, such as the Kvaser USBcan Pro 2xHS v2.

If a device supports CANtegrity, it will have the canCHANNEL_CAP_CANTEGRITY flag set in its channel capabilities. To check whether the flag is set or not, use the canGetChannelData API call with the canCHANNELDATA_CHANNEL_CAP item as follows.

uint32_t capabilities;
canGetChannelData(channel, canCHANNELDATA_CHANNEL_CAP, &capabilities, sizeof(capabilities));
if (capabilities & canCHANNEL_CAP_CANTEGRITY) {
// Device has CANtegrity support.
}

Setting up an analyzer

To use the API, both the "canlib.h" and "kvDiag.h" header files need to be included in the program.

First, a CAN channel must be opened on the CANtegrity device to obtain a canHandle.

Then, attach an analyzer to the open channel.

Decide which analyzer program to run. Currently there are two analyzer programs, DIAG_PROGRAM_TYPE_NORMAL and DIAG_PROGRAM_TYPE_AUTOBAUD. The former samples CAN frames from the bus and gives detailed information about the timing characteristics, while the latter can be used to find out the bitrate of a running CAN bus.

Choosing an analyzer program is done through the kvDiagSetProgram API call, which requires a JSON configuration as an argument. For DIAG_PROGRAM_TYPE_AUTOBAUD, no configuration is needed so pass an empty JSON string, "{}". DIAG_PROGRAM_TYPE_NORMAL needs bus parameters in the configuration, the details of which can be found in the kvDiagSetProgram reference.

kvDiagSetProgram(hnd, DIAG_PROGRAM_TYPE_NORMAL, "{\"tseg1\" : 59, \"tseg2\" : 20, \"sjw\" : 16, \"brp\" : 2}");

Now, the analyzer program can be started by calling kvDiagStart.

There are different functions available for interacting with a running analyzer program. kvDiagReadSample and kvDiagReadSampleWait are used with DIAG_PROGRAM_TYPE_NORMAL , kvDiagCalculateBitrate and kvDiagResetBitrateCalculation are used with DIAG_PROGRAM_TYPE_AUTOBAUD, and kvDiagCalculateClockOffset and kvDiagResetClockOffsetCalculation can be used with both analyzer programs. For details on their usage, see the API reference.

When finished, call kvDiagStop, kvDiagDetachAnalyzer and canClose in that order to stop the CANtegrity device.

Below, two complete sample programs are provided showcasing how the CANtegrity API is used.

Samples


Example: Continuously read samples from the CAN bus using DIAG_PROGRAM_TYPE_NORMAL and print some information about the samples.

#include "stdio.h"
#include "signal.h"
#include "canlib.h"
#include "kvDiag.h"
static void check(const char *name, canStatus status); /* Checks for errors */
static void intHandler(int unused); /* Handle Ctrl-C */
static void printSample(kvDiagSample *sample); /* Print sampled frame */
static void usage(); /* Print usage */
static int interrupt = 0;
static const char *CONF_500KBIT = "{"
"\"tseg1\" : 59,"
"\"tseg2\" : 20,"
"\"sjw\" : 16,"
"\"brp\" : 2"
"}";
int main(int argc, char *argv[])
{
int channel = -1;
/* Parse command-line parameters. */
for (int i=1; i<argc; i++) {
if (sscanf(argv[i], "-ch=%d", &channel) == 1);
else {
usage();
exit(1);
}
}
if (channel == -1) {
usage();
exit(1);
}
canHandle hnd;
/* We open the channel with the EXCLUSIVE flag to not let any other
* application interfere with the CANtegrity channel */
canStatus stat;
/* Attach an analyzer to an open CAN channel. */
check("kvDiagAttachAnalyzer", stat);
/* We want to run DIAG_PROGRAM_TYPE_NORMAL. It needs a JSON configuration
* specifying bus parameters. */
stat = kvDiagSetProgram(hnd, DIAG_PROGRAM_TYPE_NORMAL, CONF_500KBIT);
check("kvDiagSetProgram", stat);
/* Start the analyzer. */
stat = kvDiagStart(hnd);
check("kvDiagStart", stat);
/* Continuously read samples and print until Ctrl-C is pressed. */
signal(SIGINT, intHandler);
kvDiagSample sample;
while (1) {
/* Wait at most 100 ms for a new sample. */
stat = kvDiagReadSampleWait(hnd, &sample, 100);
if (stat == canOK) {
printSample(&sample);
}
/* Check Ctrl-C. */
if (interrupt) {
break;
}
}
/* Stop the analyzer. */
stat = kvDiagStop(hnd);
check("kvDiagStop", stat);
/* Detach the analyzer, since we're not going to restart it. */
stat = kvDiagDetachAnalyzer(hnd);
check("kvDiagDetachAnalyzer", stat);
/* Close the CAN channel. */
stat = canClose(hnd);
check("canClose", stat);
return 0;
}
static void check(const char *name, canStatus status)
{
if (status != canOK) {
printf("%s returned %d\n", name, status);
exit(1);
}
}
static void intHandler(int unused)
{
interrupt = 1;
}
static void printEdges(kvDiagSample *sample)
{
uint64_t time = sample->sample.startTime;
int value = sample->sample.startValue;
int i = 0;
printf("Start \t End \t Length (microseconds) \t Value\n");
printf("-----------------------------------------------\n");
do {
printf("%6llu \t %6llu \t %2.2f \t\t %u\n",
time,
time + sample->sample.edgeTimes[i],
(1.0 * sample->sample.edgeTimes[i]) / (1.0 * sample->sample.sampleFreq),
value);
time += sample->sample.edgeTimes[i];
value = !value;
i++;
} while (i < sample->sample.edgeCount);
printf("-----------------------------------------------\n\n");
}
static void printSample(kvDiagSample *sample)
{
printf("CAN ID: 0x%x SEQ: %u. DLC: %u, flags: 0x%x, data:",
sample->msg.id,
sample->header.seqno,
sample->msg.dlc,
sample->msg.flag);
if (sample->msg.dlc > 0) {
for (int i=0; i < sample->msg.dlc; i++) {
printf(" %02X", (unsigned char)sample->msg.data[i]);
}
}
printf("\n\n");
printEdges(sample);
}
static void usage()
{
printf(
"Usage: 'normal_example -ch=n', "
"where 'n' is a CANlib channel with analyzer capability.\n\n"
"Note: This program requires a working CAN bus with traffic to function properly.\n");
}


Example: Continuously measure bitrate of a CAN bus using DIAG_PROGRAM_TYPE_AUTOBAUD .

#include "stdio.h"
#include "signal.h"
#include "canlib.h"
#include "kvDiag.h"
static void check(const char *name, canStatus status); /* Checks for errors */
static void intHandler(int unused); /* Handle Ctrl-C */
static void usage(); /* Print usage */
static int interrupt = 0;
int main(int argc, char *argv[])
{
int channel = -1;
/* Parse command-line parameters. */
for (int i=1; i<argc; i++) {
if (sscanf(argv[i], "-ch=%d", &channel) == 1);
else {
usage();
exit(1);
}
}
if (channel == -1) {
usage();
exit(1);
}
canHandle hnd;
/* We open the channel with the EXCLUSIVE flag to not let any other
* application interfere with the CANtegrity channel */
canStatus stat;
/* Attach an analyzer to an open CAN channel. */
check("kvDiagAttachAnalyzer", stat);
/* We want to run DIAG_PROGRAM_TYPE_AUTOBAUD. It doesn't need a configuration,
* so we pass an empty JSON string. */
check("kvDiagSetProgram", stat);
/* Start the analyzer. */
stat = kvDiagStart(hnd);
check("kvDiagStart", stat);
/* Continuously measure bitrate until Ctrl-C is pressed. */
signal(SIGINT, intHandler);
bitrates_t btrs;
while (1) {
Sleep(100); /* Wait for samples to accumulate. */
stat = kvDiagCalculateBitrate(hnd, &btrs);
if (stat == canOK) {
printf("Estimated CAN bitrate to %.0f KBit/s with quality %d %%.\n",
}
/* Reset bitrate calculation to get a fresh measurement. */
check("kvDiagResetBitrateCalculation", stat);
/* Check Ctrl-C. */
if (interrupt) {
break;
}
}
/* Stop the analyzer. */
stat = kvDiagStop(hnd);
check("kvDiagStop", stat);
/* Detach the analyzer, since we're not going to restart it. */
stat = kvDiagDetachAnalyzer(hnd);
check("kvDiagDetachAnalyzer", stat);
/* Close the CAN channel. */
stat = canClose(hnd);
check("canClose", stat);
return 0;
}
static void check(const char *name, canStatus status)
{
if (status != canOK) {
printf("%s returned %d\n", name, status);
exit(1);
}
}
static void intHandler(int unused)
{
interrupt = 1;
}
static void usage()
{
printf(
"Usage: 'autobaud_example -ch=n', "
"where 'n' is a CANlib channel with analyzer capability.\n\n"
"Note: This program requires a working CAN bus with traffic to function properly.\n");
}