CAN DragonEmSA

Threading and Concurrency

The EmSACAN API supports multiple connected CAN Dragon devices and multi-threaded applications when you follow the rules below. These rules apply equally to the C API and the C# wrapper (which calls the same native library).

Multiple Devices

More than one CAN Dragon may be connected simultaneously. Each successful EmSACAN_Connect / CanDragonDevice.Connect returns an independent session handle. Use one handle (or CanDragonDevice instance) per physical device.

using (CanDragonDevice a = CanDragonDevice.Connect(serialA, false))
using (CanDragonDevice b = CanDragonDevice.Connect(serialB, false))
{
    /* each device has its own handle and port state */
    a.OpenChannel(0);
    b.OpenChannel(0);
}

What Is Supported

ScenarioSupported
Read, Write, GetStatus, OpenChannel, CloseChannel, ResetChannel on different handles from different threadsYes
One dedicated thread per device for ongoing CAN I/OYes (recommended)
EmSACAN_CalculateTiming / EmSACANLibrary.CalculateTiming from any threadYes (no session handle)

What Is Not Supported

ScenarioSupported
Calling any function on the same handle from multiple threads without your own lockNo
Concurrent Startup, Shutdown, EnumerateInterfaces, Connect, or Disconnect without coordinationNo
More than one firmware update active in the processNo
Calling EmSACAN functions on a handle from that handle’s firmware-update callbackNo
Calling EmSACAN functions on a handle from that handle’s port connection callbackNo

::caution Sharing one CanDragonDevice or emsacan_handle_t across threads without a mutex can cause intermittent failures or corrupted state. Assign one owner thread per device, or guard all calls with a lock. ::

Per-Handle Limitations

Firmware update: While an update is active on a handle, other calls on that handle may return EMSACAN_ERR_FWUPDATE_ACTIVE or EMSACAN_ERR_BUSY. Only one update may run in the entire process.

Parameter read/write: EmSACAN_ReadParameter and EmSACAN_WriteParameter block until the device responds. Do not overlap read and write parameter calls on the same handle from different threads unless you serialize them.

Error reporting: EmSACAN_GetLastError(NULL) / EmSACANLibrary.GetLastError() reports the last process-wide error. With a non-null handle it reports the last error for that session only.

Single-threaded application

The simplest approach: all API calls run on the main thread. Poll Read in your main loop or use SetCANEvents to wake a single thread.

One thread per device

For multiple CAN Dragon units, dedicate one thread to each CanDragonDevice:

EmSACANLibrary.Startup();
var list = EmSACANLibrary.EnumerateInterfaces(2);
CanDragonDevice devA = CanDragonDevice.Connect(list[0].SerialNumber, false);
CanDragonDevice devB = CanDragonDevice.Connect(list[1].SerialNumber, false);

Task txA = Task.Run(() => { /* only devA calls here */ });
Task txB = Task.Run(() => { /* only devB calls here */ });
Task.WaitAll(txA, txB);

devA.Dispose();
devB.Dispose();
EmSACANLibrary.Shutdown();

Connection and firmware callbacks

USB presence callbacks (ChannelConnectionChanged in C#, emsacan_channel_connection_callback_fn in C) run on a native monitor thread. Keep callback bodies short—set a flag or signal an event, but do not call back into EmSACAN on the same handle from within the callback.

Firmware progress callbacks may run on a worker thread. Update UI via Invoke / a thread-safe queue, and do not call EmSACAN on that handle from inside the callback.

Startup and Shutdown Coordination

Call Startup once before spawning worker threads that use the API. Call Shutdown only after all worker threads have finished and all devices are disconnected.

::note The C# wrapper serializes Startup and Shutdown internally with a lock, but you must still avoid calling Connect or EnumerateInterfaces concurrently from multiple threads without your own coordination. ::

Summary

RuleAction
One handle per deviceConnect each CAN Dragon separately
One owner per handleSingle thread or mutex per session
Lifecycle on main threadStartup, enumerate, connect, shutdown
Callbacks are lightweightSignal events; no re-entrant API calls
One firmware update at a timeWait for completion before starting another