Developer Blog

31/10/2023 by Troy Via

Using the benefits of MagiSync

MagiSync is a feature provided in our SemiPro, Professional, and Precision products that automatically synchronises the clock ticks on Kvaser USB devices that are attached to the same USB root hub. This synchronisation occurs when the units are plugged in and powered on and does not require any configuration to activate this feature.

You can tell which units are synchronised by looking in the Kvaser Device Guide if you check menu item View -> Synchronized Hardware.

MagiSync DevBlog 1

As you can see, the Kvaser Hybrid Pro and Kvaser Memorator Pro are synchronised into MagiSync Group 1. The Leaf Light v2 that is also attached is not included because the Leaf Light v2 does not support MagiSync. So, the clock ticks on the Hybrid Pro and Memorator Pro channels are synchronised while the Leaf Light HS v2 channel is not.

With the clock ticks synchronised, we now need to place the clocks within the same time domain, so the time stamps returned from each channel are the same for the same moment in time. This will make analyzing the data received on multiple channels easier. This is done by using the kvTimeDomain*** functions in the CANlib SDK.

The first step is to create a time domain to be used by all handles you wish to have synchronised time stamps.

Canlib.canStatus status = Canlib.kvTimeDomainCreate(out object myTimeDomain);

The next step happens during the configuration of the handle to each channel. So, get your channel handles and set their bitrate. For my example code, I am using channels enumerations 1 and 3 to correspond to the first channel on the Kvaser Hybrid Pro and the first channel of the Kvaser Memorator Pro as shown below:

magisync devblog 2
int hybridHnd = Canlib.canOpenChannel(1, 0);
int memoHnd = Canlib.canOpenChannel(3, 0);
status = Canlib.canSetBusParams(hybridHnd, Canlib.canBITRATE_250K, 0, 0, 0, 1);
status = Canlib.canSetBusParams(memoHnd, Canlib.canBITRATE_250K, 0, 0, 0, 1);

Normally the time stamp is reset to zero when the channel handle is set to bus on. When using a time domain, we want the time stamp to only be reset to zero when the time domain is reset. So, we need to turn the normal behavior off using the canIoCtl function.

object autoResetOff = (UInt32)0;
status = Canlib.canIoCtl(hybridHnd, Canlib.canIOCTL_SET_BUSON_TIME_AUTO_RESET, ref autoResetOff);
status = Canlib.canIoCtl(memoHnd, Canlib.canIOCTL_SET_BUSON_TIME_AUTO_RESET, ref autoResetOff);

Then we add the handles to the time domain with the kvTimeDomainAddHandle function.

status = Canlib.kvTimeDomainAddHandle(myTimeDomain, hybridHnd);
status = Canlib.kvTimeDomainAddHandle(myTimeDomain, memoHnd);

Before going bus on, we need to reset the time domain to zero.

status = Canlib.kvTimeDomainResetTime(myTimeDomain);

We are now ready to place the channel handles bus on.

status = canBusOn(hybridHnd);
status = canBusOn(memoHnd);

At this point, the time stamps on the frames received on both channels will be synchronised. Here is the output from the complete example program where the columns are channel, identifier, flags, dlc, data bytes and time stamp from left to right.

Magisync DevBlog 3

**** Screen grab of program running showing the same message received on both channels with the same time stamp ****

As the final steps when using the kvTimeDomain*** functions, you should perform proper cleanup of the handles and time domain by using the kvTimeDomainRemoveHandle and kvTimeDomainDelete functions.

status = Canlib.canBusOff(hybridHnd);
status = Canlib.canBusOff(memoHnd);
status = Canlib.kvTimeDomainRemoveHandle(myTimeDomain, hybridHnd);
status = Canlib.kvTimeDomainRemoveHandle(myTimeDomain, memoHnd);
status = Canlib.canClose(hybridHnd);
status = Canlib.canClose(memoHnd);
status = Canlib.kvTimeDomainDelete(myTimeDomain);

If you enjoy getting all your time stamps in the same time domain, you may also want to adjust the scale on the time stamps. The default time stamp resolution reported is 1 millisecond. But you can use the canIoCtl function to adjust the resolution on each handles time stamps.

object timerScale = (UInt32)1;  // set resolution to 1 microsecond
status = Canlib.canIoCtl(hybridHnd, Canlib.canIOCTL_SET_TIMER_SCALE, ref timerScale);
status = Canlib.canIoCtl(memoHnd, Canlib.canIOCTL_SET_TIMER_SCALE, ref timerScale);

This change should be made before resetting the time domain and making the handle active on the bus.


Additional information can be found in the CANlib help documentation. You can also contact support@kvaser.com with any questions or if you would like a copy of the example application in this article.

Author Image

Troy Via

Troy Via is a software and support engineer at Kvaser Inc. Troy has authored several training videos for Kvaser and is a key member of the product development team. He also participates in NMEA discussions on behalf of Kvaser. When he’s not working, he’s an avid gamer.