Lely core libraries  2.2.5
ixxat.c
Go to the documentation of this file.
1 
24 #include "io.h"
25 
26 #if _WIN32 && LELY_HAVE_IXXAT
27 
28 // Rename error flags to avoid conflicts with definitions in <cantype.h>.
29 #define CAN_ERROR_BIT LELY_IO_CAN_ERROR_BIT
30 #define CAN_ERROR_STUFF LELY_IO_CAN_ERROR_STUFF
31 #define CAN_ERROR_CRC LELY_IO_CAN_ERROR_CRC
32 #define CAN_ERROR_FORM LELY_IO_CAN_ERROR_FORM
33 #define CAN_ERROR_ACK LELY_IO_CAN_ERROR_ACK
34 #define CAN_ERROR_OTHER LELY_IO_CAN_ERROR_OTHER
35 
36 #include "../can.h"
37 #include <lely/io2/ctx.h>
38 #include <lely/io2/win32/ixxat.h>
39 #include <lely/util/diag.h>
40 #include <lely/util/endian.h>
41 #include <lely/util/util.h>
42 
43 #undef CAN_ERROR_OTHER
44 #undef CAN_ERROR_ACK
45 #undef CAN_ERROR_FORM
46 #undef CAN_ERROR_CRC
47 #undef CAN_ERROR_STUFF
48 #undef CAN_ERROR_BIT
49 
50 #include <assert.h>
51 #include <stdlib.h>
52 #include <string.h>
53 
54 #include <processthreadsapi.h>
55 #include <windows.h>
56 
57 #ifdef __MINGW32__
58 #pragma GCC diagnostic push
59 #pragma GCC diagnostic ignored "-Wpedantic"
60 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
61 #define _MSC_VER 1900
62 #endif
63 
64 #if LELY_NO_CANFD
65 #include <vcinpl.h>
66 #else
67 #include <vcinpl2.h>
68 #endif
69 #ifdef __MINGW32__
70 #undef _MSC_VER
71 #pragma GCC diagnostic pop
72 #endif
73 
74 #ifndef LELY_IO_IXXAT_RX_FIFO_SIZE
75 
79 #define LELY_IO_IXXAT_RX_FIFO_SIZE 1024
80 #endif
81 
82 #ifndef LELY_IO_IXXAT_TX_FIFO_SIZE
83 
87 #define LELY_IO_IXXAT_TX_FIFO_SIZE 128
88 #endif
89 
90 static size_t io_ixxat_init_refcnt = 0;
91 
92 static HMODULE hLibModule;
93 
94 #define LELY_IO_DEFINE_IXXAT(name) static PF_##name p_##name;
95 #include "ixxat.inc"
96 #undef LELY_IO_DEFINE_IXXAT
97 
98 static int io_ixxat_read(HANDLE hCanChn, struct can_msg *msg,
99  struct can_err *err, PUINT32 pdwTime, PUINT32 pdwTimeOvr,
100  int timeout);
101 static int io_ixxat_write(
102  HANDLE hCanChn, const struct can_msg *msg, int timeout);
103 static DWORD io_ixxat_error(HRESULT hResult);
104 static int io_ixxat_state(UINT32 dwStatus);
105 static struct timespec io_ixxat_time(
106  UINT64 qwTime, UINT32 dwTscClkFreq, UINT32 dwTscDivisor);
107 
108 static int io_ixxat_ctrl_stop(io_can_ctrl_t *ctrl);
109 static int io_ixxat_ctrl_stopped(const io_can_ctrl_t *ctrl);
110 static int io_ixxat_ctrl_restart(io_can_ctrl_t *ctrl);
111 static int io_ixxat_ctrl_get_bitrate(
112  const io_can_ctrl_t *ctrl, int *pnominal, int *pdata);
113 static int io_ixxat_ctrl_set_bitrate(
114  io_can_ctrl_t *ctrl, int nominal, int data);
115 static int io_ixxat_ctrl_get_state(const io_can_ctrl_t *ctrl);
116 
117 // clang-format off
118 static const struct io_can_ctrl_vtbl io_ixxat_ctrl_vtbl = {
119  &io_ixxat_ctrl_stop,
120  &io_ixxat_ctrl_stopped,
121  &io_ixxat_ctrl_restart,
122  &io_ixxat_ctrl_get_bitrate,
123  &io_ixxat_ctrl_set_bitrate,
124  &io_ixxat_ctrl_get_state
125 };
126 // clang-format on
127 
128 struct io_ixxat_ctrl {
129  const struct io_can_ctrl_vtbl *ctrl_vptr;
130  HANDLE hDevice;
131  UINT32 dwCanNo;
132  HANDLE hCanCtl;
133  int flags;
134  UINT32 dwTscClkFreq;
135  UINT32 dwTscDivisor;
136 };
137 
138 static inline struct io_ixxat_ctrl *io_ixxat_ctrl_from_ctrl(
139  const io_can_ctrl_t *ctrl);
140 
141 static io_ctx_t *io_ixxat_chan_dev_get_ctx(const io_dev_t *dev);
142 static ev_exec_t *io_ixxat_chan_dev_get_exec(const io_dev_t *dev);
143 static size_t io_ixxat_chan_dev_cancel(io_dev_t *dev, struct ev_task *task);
144 static size_t io_ixxat_chan_dev_abort(io_dev_t *dev, struct ev_task *task);
145 
146 // clang-format off
147 static const struct io_dev_vtbl io_ixxat_chan_dev_vtbl = {
148  &io_ixxat_chan_dev_get_ctx,
149  &io_ixxat_chan_dev_get_exec,
150  &io_ixxat_chan_dev_cancel,
151  &io_ixxat_chan_dev_abort
152 };
153 // clang-format on
154 
155 static io_dev_t *io_ixxat_chan_get_dev(const io_can_chan_t *chan);
156 static int io_ixxat_chan_get_flags(const io_can_chan_t *chan);
157 static int io_ixxat_chan_read(io_can_chan_t *chan, struct can_msg *msg,
158  struct can_err *err, struct timespec *tp, int timeout);
159 static void io_ixxat_chan_submit_read(
160  io_can_chan_t *chan, struct io_can_chan_read *read);
161 static int io_ixxat_chan_write(
162  io_can_chan_t *chan, const struct can_msg *msg, int timeout);
163 static void io_ixxat_chan_submit_write(
164  io_can_chan_t *chan, struct io_can_chan_write *write);
165 
166 // clang-format off
167 static const struct io_can_chan_vtbl io_ixxat_chan_vtbl = {
168  &io_ixxat_chan_get_dev,
169  &io_ixxat_chan_get_flags,
170  &io_ixxat_chan_read,
171  &io_ixxat_chan_submit_read,
172  &io_ixxat_chan_write,
173  &io_ixxat_chan_submit_write
174 };
175 // clang-format on
176 
177 static void io_ixxat_chan_svc_shutdown(struct io_svc *svc);
178 
179 // clang-format off
180 static const struct io_svc_vtbl io_ixxat_chan_svc_vtbl = {
181  NULL,
182  &io_ixxat_chan_svc_shutdown
183 };
184 // clang-format on
185 
186 struct io_ixxat_chan {
187  const struct io_dev_vtbl *dev_vptr;
188  const struct io_can_chan_vtbl *chan_vptr;
189  struct io_svc svc;
190  io_ctx_t *ctx;
191  ev_exec_t *exec;
192  int rxtimeo;
193  int txtimeo;
194  struct ev_task read_task;
195  struct ev_task write_task;
196 #if !LELY_NO_THREADS
197  CRITICAL_SECTION CriticalSection;
198 #endif
199  HANDLE hCanChn;
200  int flags;
201  UINT32 dwTscClkFreq;
202  UINT32 dwTscDivisor;
203  UINT32 dwTimeOvr;
204  unsigned shutdown : 1;
205  unsigned read_posted : 1;
206  unsigned write_posted : 1;
207  struct sllist read_queue;
208  struct sllist write_queue;
209  struct io_can_chan_read *current_read;
210  struct io_can_chan_write *current_write;
211 };
212 
213 static void io_ixxat_chan_read_task_func(struct ev_task *task);
214 static void io_ixxat_chan_write_task_func(struct ev_task *task);
215 
216 static inline struct io_ixxat_chan *io_ixxat_chan_from_dev(const io_dev_t *dev);
217 static inline struct io_ixxat_chan *io_ixxat_chan_from_chan(
218  const io_can_chan_t *chan);
219 static inline struct io_ixxat_chan *io_ixxat_chan_from_svc(
220  const struct io_svc *svc);
221 
222 static int io_ixxat_chan_read_impl(struct io_ixxat_chan *ixxat,
223  struct can_msg *msg, struct can_err *err, struct timespec *tp,
224  int timeout);
225 static int io_ixxat_chan_write_impl(struct io_ixxat_chan *ixxat,
226  const struct can_msg *msg, int timeout);
227 
228 static void io_ixxat_chan_pop(struct io_ixxat_chan *ixxat,
229  struct sllist *read_queue, struct sllist *write_queue,
230  struct ev_task *task);
231 
232 static size_t io_ixxat_chan_do_abort_tasks(struct io_ixxat_chan *ixxat);
233 
234 static HANDLE io_ixxat_chan_set_handle(struct io_ixxat_chan *ixxat,
235  HANDLE hCanChn, int flags, UINT32 dwTscClkFreq,
236  UINT32 dwTscDivisor);
237 
238 int
239 io_ixxat_init(void)
240 {
241  if (io_ixxat_init_refcnt++)
242  return 0;
243 
244  DWORD dwErrCode = 0;
245 
246 #if LELY_NO_CANFD
247  hLibModule = LoadLibraryA("vcinpl.dll");
248 #else
249  hLibModule = LoadLibraryA("vcinpl2.dll");
250 #endif
251  if (!hLibModule) {
252  dwErrCode = GetLastError();
253  goto error_LoadLibrary;
254  }
255 
256 #if defined(__MINGW32__) && __GNUC__ >= 8
257 #pragma GCC diagnostic push
258 #pragma GCC diagnostic ignored "-Wcast-function-type"
259 #endif
260 #define LELY_IO_DEFINE_IXXAT(name) \
261  if (!(p_##name = (PF_##name)GetProcAddress(hLibModule, #name))) { \
262  dwErrCode = GetLastError(); \
263  goto error_GetProcAddress; \
264  }
265 #include "ixxat.inc"
266 #undef LELY_IO_DEFINE_IXXAT
267 #if defined(__MINGW32__) && __GNUC__ >= 8
268 #pragma GCC diagnostic pop
269 #endif
270 
271  return 0;
272 
273 error_GetProcAddress:
274 #define LELY_IO_DEFINE_IXXAT(name) p_##name = NULL;
275 #include "ixxat.inc"
276 #undef LELY_IO_DEFINE_IXXAT
277  FreeLibrary(hLibModule);
278  hLibModule = NULL;
279 error_LoadLibrary:
280  SetLastError(dwErrCode);
281  io_ixxat_init_refcnt--;
282  return -1;
283 }
284 
285 void
286 io_ixxat_fini(void)
287 {
288  assert(io_ixxat_init_refcnt);
289 
290  if (--io_ixxat_init_refcnt)
291  return;
292 
293 #define LELY_IO_DEFINE_IXXAT(name) p_##name = NULL;
294 #include "ixxat.inc"
295 #undef LELY_IO_DEFINE_IXXAT
296 
297  FreeLibrary(hLibModule);
298  hLibModule = NULL;
299 }
300 
301 void *
302 io_ixxat_ctrl_alloc(void)
303 {
304  struct io_ixxat_ctrl *ixxat = malloc(sizeof(*ixxat));
305  if (!ixxat) {
306  set_errc(errno2c(errno));
307  return NULL;
308  }
309  return &ixxat->ctrl_vptr;
310 }
311 
312 void
313 io_ixxat_ctrl_free(void *ptr)
314 {
315  if (ptr)
316  free(io_ixxat_ctrl_from_ctrl(ptr));
317 }
318 
320 io_ixxat_ctrl_init(io_can_ctrl_t *ctrl, const LUID *lpLuid, UINT32 dwCanNo,
321  int flags, int nominal, int data)
322 {
323  struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
324  assert(lpLuid);
325 
326  DWORD dwErrCode = 0;
327  HRESULT hResult = VCI_OK;
328 
329  ixxat->ctrl_vptr = &io_ixxat_ctrl_vtbl;
330 
331  VCIID VciObjectId = { .AsLuid = *lpLuid };
332  ixxat->hDevice = NULL;
333  if ((hResult = p_vciDeviceOpen(&VciObjectId, &ixxat->hDevice))
334  != VCI_OK) {
335  if (hResult == VCI_E_INVALIDARG)
336  dwErrCode = ERROR_DEV_NOT_EXIST;
337  else
338  dwErrCode = io_ixxat_error(hResult);
339  goto error_vciDeviceOpen;
340  }
341 
342  ixxat->dwCanNo = dwCanNo;
343  ixxat->hCanCtl = NULL;
344  // clang-format off
345  if ((hResult = p_canControlOpen(ixxat->hDevice, ixxat->dwCanNo,
346  &ixxat->hCanCtl)) != VCI_OK) {
347  // clang-format on
348  if (hResult == VCI_E_INVALID_INDEX)
349  dwErrCode = ERROR_DEV_NOT_EXIST;
350  else
351  dwErrCode = io_ixxat_error(hResult);
352  goto error_canControlOpen;
353  }
354 
355 #if LELY_NO_CANFD
356  CANCAPABILITIES sCanCaps;
357 #else
358  CANCAPABILITIES2 sCanCaps;
359 #endif
360  if ((hResult = p_canControlGetCaps(ixxat->hCanCtl, &sCanCaps))
361  != VCI_OK) {
362  dwErrCode = io_ixxat_error(hResult);
363  goto error_canControlGetCaps;
364  }
365  if (!(sCanCaps.dwFeatures & CAN_FEATURE_STDANDEXT)) {
366  dwErrCode = io_ixxat_error(hResult);
367  goto error_canControlGetCaps;
368  }
369 
370  ixxat->flags = flags;
371  if (ixxat->flags & ~IO_CAN_BUS_FLAG_MASK) {
372  dwErrCode = ERROR_INVALID_PARAMETER;
373  goto error_flags;
374  }
375  if ((ixxat->flags & IO_CAN_BUS_FLAG_ERR)
376  && !(sCanCaps.dwFeatures & CAN_FEATURE_ERRFRAME)) {
377  dwErrCode = ERROR_INVALID_PARAMETER;
378  goto error_flags;
379  }
380 #if !LELY_NO_CANFD
381  if ((ixxat->flags & IO_CAN_BUS_FLAG_FDF)
382  && !(sCanCaps.dwFeatures & CAN_FEATURE_EXTDATA)) {
383  dwErrCode = ERROR_INVALID_PARAMETER;
384  goto error_flags;
385  }
386  if ((ixxat->flags & IO_CAN_BUS_FLAG_BRS)
387  && !(sCanCaps.dwFeatures & CAN_FEATURE_FASTDATA)) {
388  dwErrCode = ERROR_INVALID_PARAMETER;
389  goto error_flags;
390  }
391 #endif
392 
393 #if LELY_NO_CANFD
394  ixxat->dwTscClkFreq = sCanCaps.dwClockFreq;
395 #else
396  ixxat->dwTscClkFreq = sCanCaps.dwTscClkFreq;
397 #endif
398  ixxat->dwTscDivisor = sCanCaps.dwTscDivisor;
399 
400  if (io_can_ctrl_set_bitrate(ctrl, nominal, data) == -1) {
401  dwErrCode = GetLastError();
402  goto error_set_bitrate;
403  }
404 
405  return ctrl;
406 
407 error_set_bitrate:
408 error_flags:
409 error_canControlGetCaps:
410  p_canControlClose(ixxat->hCanCtl);
411 error_canControlOpen:
412  p_vciDeviceClose(ixxat->hDevice);
413 error_vciDeviceOpen:
414  SetLastError(dwErrCode);
415  return NULL;
416 }
417 
418 void
419 io_ixxat_ctrl_fini(io_can_ctrl_t *ctrl)
420 {
421  struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
422 
423  p_canControlClose(ixxat->hCanCtl);
424  p_vciDeviceClose(ixxat->hDevice);
425 }
426 
428 io_ixxat_ctrl_create_from_index(UINT32 dwIndex, UINT32 dwCanNo, int flags,
429  int nominal, int data)
430 {
431  HRESULT hResult = VCI_OK;
432 
433  HANDLE hEnum = NULL;
434  if ((hResult = p_vciEnumDeviceOpen(&hEnum)) != VCI_OK) {
435  SetLastError(io_ixxat_error(hResult));
436  return NULL;
437  }
438 
439  VCIDEVICEINFO sInfo = { .VciObjectId = { .AsLuid = { 0, 0 } } };
440  do {
441  if ((hResult = p_vciEnumDeviceNext(hEnum, &sInfo)) != VCI_OK) {
442  p_vciEnumDeviceClose(hEnum);
443  if (hResult == VCI_E_NO_MORE_ITEMS)
444  SetLastError(ERROR_DEV_NOT_EXIST);
445  else
446  SetLastError(io_ixxat_error(hResult));
447  return NULL;
448  }
449  } while (dwIndex-- > 0);
450 
451  p_vciEnumDeviceClose(hEnum);
452 
453  return io_ixxat_ctrl_create_from_luid(&sInfo.VciObjectId.AsLuid,
454  dwCanNo, flags, nominal, data);
455 }
456 
458 io_ixxat_ctrl_create_from_luid(const LUID *lpLuid, UINT32 dwCanNo, int flags,
459  int nominal, int data)
460 {
461  DWORD dwErrCode = 0;
462 
463  io_can_ctrl_t *ctrl = io_ixxat_ctrl_alloc();
464  if (!ctrl) {
465  dwErrCode = GetLastError();
466  goto error_alloc;
467  }
468 
469  io_can_ctrl_t *tmp = io_ixxat_ctrl_init(
470  ctrl, lpLuid, dwCanNo, flags, nominal, data);
471  if (!tmp) {
472  dwErrCode = GetLastError();
473  goto error_init;
474  }
475  ctrl = tmp;
476 
477  return ctrl;
478 
479 error_init:
480  io_ixxat_ctrl_free((void *)ctrl);
481 error_alloc:
482  SetLastError(dwErrCode);
483  return NULL;
484 }
485 
486 void
488 {
489  if (ctrl) {
490  io_ixxat_ctrl_fini(ctrl);
491  io_ixxat_ctrl_free((void *)ctrl);
492  }
493 }
494 
495 HANDLE
497 {
498  const struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
499 
500  return ixxat->hCanCtl;
501 }
502 
503 void *
504 io_ixxat_chan_alloc(void)
505 {
506  struct io_ixxat_chan *ixxat = malloc(sizeof(*ixxat));
507  if (!ixxat) {
508  set_errc(errno2c(errno));
509  return NULL;
510  }
511  return &ixxat->chan_vptr;
512 }
513 
514 void
515 io_ixxat_chan_free(void *ptr)
516 {
517  if (ptr)
518  free(io_ixxat_chan_from_chan(ptr));
519 }
520 
522 io_ixxat_chan_init(io_can_chan_t *chan, io_ctx_t *ctx, ev_exec_t *exec,
523  int rxtimeo, int txtimeo)
524 {
525  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
526  assert(ctx);
527 
528  if (!rxtimeo)
529  rxtimeo = LELY_IO_RX_TIMEOUT;
530  if (!txtimeo)
531  txtimeo = LELY_IO_TX_TIMEOUT;
532 
533  ixxat->dev_vptr = &io_ixxat_chan_dev_vtbl;
534  ixxat->chan_vptr = &io_ixxat_chan_vtbl;
535 
536  ixxat->svc = (struct io_svc)IO_SVC_INIT(&io_ixxat_chan_svc_vtbl);
537  ixxat->ctx = ctx;
538 
539  ixxat->exec = exec;
540 
541  ixxat->rxtimeo = rxtimeo;
542  ixxat->txtimeo = txtimeo;
543 
544  ixxat->read_task = (struct ev_task)EV_TASK_INIT(
545  ixxat->exec, &io_ixxat_chan_read_task_func);
546  ixxat->write_task = (struct ev_task)EV_TASK_INIT(
547  ixxat->exec, &io_ixxat_chan_write_task_func);
548 
549 #if !LELY_NO_THREADS
550  InitializeCriticalSection(&ixxat->CriticalSection);
551 #endif
552 
553  ixxat->hCanChn = NULL;
554 
555  ixxat->flags = 0;
556  ixxat->dwTscClkFreq = 0;
557  ixxat->dwTscDivisor = 0;
558  ixxat->dwTimeOvr = 0;
559 
560  ixxat->shutdown = 0;
561  ixxat->read_posted = 0;
562  ixxat->write_posted = 0;
563 
564  sllist_init(&ixxat->read_queue);
565  sllist_init(&ixxat->write_queue);
566 
567  ixxat->current_read = NULL;
568  ixxat->current_write = NULL;
569 
570  io_ctx_insert(ixxat->ctx, &ixxat->svc);
571 
572  return chan;
573 }
574 
575 void
576 io_ixxat_chan_fini(io_can_chan_t *chan)
577 {
578  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
579 
580  io_ctx_remove(ixxat->ctx, &ixxat->svc);
581  // Cancel all pending operations.
582  io_ixxat_chan_svc_shutdown(&ixxat->svc);
583 
584  // Deactivate the channel.
585  if (ixxat->hCanChn)
586  p_canChannelActivate(ixxat->hCanChn, FALSE);
587 
588 #if !LELY_NO_THREADS
589  int warning = 0;
590  EnterCriticalSection(&ixxat->CriticalSection);
591  // If necessary, busy-wait until io_ixxat_chan_read_task_func() and
592  // io_ixxat_chan_write_task_func() complete.
593  while (ixxat->read_posted || ixxat->write_posted) {
594  if (io_ixxat_chan_do_abort_tasks(ixxat))
595  continue;
596  LeaveCriticalSection(&ixxat->CriticalSection);
597  if (!warning) {
598  warning = 1;
599  diag(DIAG_WARNING, 0,
600  "io_ixxat_chan_fini() invoked with pending operations");
601  }
602  SwitchToThread();
603  EnterCriticalSection(&ixxat->CriticalSection);
604  }
605  LeaveCriticalSection(&ixxat->CriticalSection);
606 #endif
607 
608  // Close the channel.
609  if (ixxat->hCanChn)
610  p_canChannelClose(ixxat->hCanChn);
611 
612 #if !LELY_NO_THREADS
613  DeleteCriticalSection(&ixxat->CriticalSection);
614 #endif
615 }
616 
618 io_ixxat_chan_create(io_ctx_t *ctx, ev_exec_t *exec, int rxtimeo, int txtimeo)
619 {
620  DWORD dwErrCode = 0;
621 
622  io_can_chan_t *chan = io_ixxat_chan_alloc();
623  if (!chan) {
624  dwErrCode = GetLastError();
625  goto error_alloc;
626  }
627 
628  io_can_chan_t *tmp =
629  io_ixxat_chan_init(chan, ctx, exec, rxtimeo, txtimeo);
630  if (!tmp) {
631  dwErrCode = GetLastError();
632  goto error_init;
633  }
634  chan = tmp;
635 
636  return chan;
637 
638 error_init:
639  io_ixxat_chan_free((void *)chan);
640 error_alloc:
641  SetLastError(dwErrCode);
642  return NULL;
643 }
644 
645 void
647 {
648  if (chan) {
649  io_ixxat_chan_fini(chan);
650  io_ixxat_chan_free((void *)chan);
651  }
652 }
653 
654 HANDLE
656 {
657  const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
658 
659 #if !LELY_NO_THREADS
660  EnterCriticalSection((LPCRITICAL_SECTION)&ixxat->CriticalSection);
661 #endif
662  HANDLE hCanChn = ixxat->hCanChn;
663 #if !LELY_NO_THREADS
664  LeaveCriticalSection((LPCRITICAL_SECTION)&ixxat->CriticalSection);
665 #endif
666  return hCanChn;
667 }
668 
669 int
671  UINT16 wRxFifoSize, UINT16 wTxFifoSize)
672 {
673  struct io_ixxat_chan *ixxat_chan = io_ixxat_chan_from_chan(chan);
674  struct io_ixxat_ctrl *ixxat_ctrl = io_ixxat_ctrl_from_ctrl(ctrl);
675 
676  if (!wRxFifoSize)
677  wRxFifoSize = LELY_IO_IXXAT_RX_FIFO_SIZE;
678  if (!wTxFifoSize)
679  wTxFifoSize = LELY_IO_IXXAT_TX_FIFO_SIZE;
680 
681  DWORD dwErrCode = 0;
682  HRESULT hResult;
683 
684  HANDLE hCanChn = NULL;
685  // clang-format off
686  if ((hResult = p_canChannelOpen(ixxat_ctrl->hDevice,
687  ixxat_ctrl->dwCanNo, FALSE, &hCanChn)) != VCI_OK) {
688  // clang-format on
689  dwErrCode = io_ixxat_error(hResult);
690  goto error_canChannelOpen;
691  }
692 
693  // clang-format off
694 #if LELY_NO_CANFD
695  if ((hResult = p_canChannelInitialize(hCanChn, wRxFifoSize, 1,
696  wTxFifoSize, 1)) != VCI_OK) {
697 #else
698  if ((hResult = p_canChannelInitialize(hCanChn, wRxFifoSize, 1,
699  wTxFifoSize, 1, 0, CAN_FILTER_PASS)) != VCI_OK) {
700 #endif
701  // clang-format on
702  dwErrCode = io_ixxat_error(hResult);
703  goto error_canChannelInitialize;
704  }
705 
706  if ((hResult = p_canChannelActivate(hCanChn, TRUE)) != VCI_OK) {
707  dwErrCode = io_ixxat_error(hResult);
708  goto error_canChannelActivate;
709  }
710 
711  hCanChn = io_ixxat_chan_set_handle(ixxat_chan, hCanChn,
712  ixxat_ctrl->flags, ixxat_ctrl->dwTscClkFreq,
713  ixxat_ctrl->dwTscDivisor);
714  if (hCanChn)
715  p_canChannelClose(hCanChn);
716 
717  return 0;
718 
719 error_canChannelActivate:
720 error_canChannelInitialize:
721  p_canChannelClose(hCanChn);
722 error_canChannelOpen:
723  SetLastError(dwErrCode);
724  return -1;
725 }
726 
727 int
728 io_ixxat_chan_assign(io_can_chan_t *chan, HANDLE hCanChn, UINT32 dwTscClkFreq,
729  UINT32 dwTscDivisor)
730 {
731  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
732 
733  HRESULT hResult;
734 
735  if (!hCanChn) {
736  SetLastError(ERROR_INVALID_HANDLE);
737  return -1;
738  }
739 
740 #if LELY_NO_CANFD
741  CANCHANSTATUS sStatus;
742 #else
743  CANCHANSTATUS2 sStatus;
744 #endif
745  if ((hResult = p_canChannelGetStatus(hCanChn, &sStatus)) != VCI_OK) {
746  SetLastError(io_ixxat_error(hResult));
747  return -1;
748  }
749 
750  int flags = 0;
751  if (sStatus.sLineStatus.bOpMode & CAN_OPMODE_ERRFRAME)
752  flags |= IO_CAN_BUS_FLAG_ERR;
753 #if !LELY_NO_CANFD
754  if (sStatus.sLineStatus.bExMode & CAN_EXMODE_EXTDATA)
755  flags |= IO_CAN_BUS_FLAG_FDF;
756  if (sStatus.sLineStatus.bExMode & CAN_EXMODE_FASTDATA)
757  flags |= IO_CAN_BUS_FLAG_BRS;
758 #endif
759 
760  if (!sStatus.fActivated
761  && (hResult = p_canChannelActivate(hCanChn, TRUE))
762  != VCI_OK) {
763  SetLastError(io_ixxat_error(hResult));
764  return -1;
765  }
766 
767  hCanChn = io_ixxat_chan_set_handle(
768  ixxat, hCanChn, flags, dwTscClkFreq, dwTscDivisor);
769  if (hCanChn)
770  p_canChannelClose(hCanChn);
771 
772  return 0;
773 }
774 
775 HANDLE
777 {
778  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
779 
780  return io_ixxat_chan_set_handle(ixxat, NULL, 0, 0, 0);
781 }
782 
783 int
785 {
786  return io_ixxat_chan_get_handle(chan) != NULL;
787 }
788 
789 int
791 {
792  HANDLE hCanChn = io_ixxat_chan_release(chan);
793  if (hCanChn) {
794  HRESULT hResult = p_canChannelClose(hCanChn);
795  if (hResult != VCI_OK) {
796  SetLastError(io_ixxat_error(hResult));
797  return -1;
798  }
799  }
800  return 0;
801 }
802 
803 static int
804 io_ixxat_read(HANDLE hCanChn, struct can_msg *msg, struct can_err *err,
805  PUINT32 pdwTime, PUINT32 pdwTimeOvr, int timeout)
806 {
807  if (pdwTimeOvr)
808  *pdwTimeOvr = 0;
809 
810  if (!hCanChn) {
811  SetLastError(ERROR_INVALID_HANDLE);
812  return -1;
813  }
814 
815 #if LELY_NO_CANFD
816  CANMSG CanMsg = { .dwMsgId = 0 };
817 #else
818  CANMSG2 CanMsg = { .dwMsgId = 0 };
819 #endif
820  UINT32 type = 0;
821  DWORD dwTimeout = timeout < 0 ? INFINITE : (DWORD)timeout;
822  for (;;) {
823  HRESULT hResult = p_canChannelReadMessage(
824  hCanChn, dwTimeout, &CanMsg);
825  if (hResult != VCI_OK) {
826  SetLastError(io_ixxat_error(hResult));
827  return -1;
828  }
829  type = CanMsg.uMsgInfo.Bits.type;
830  if (type == CAN_MSGTYPE_DATA || type == CAN_MSGTYPE_ERROR
831  || type == CAN_MSGTYPE_STATUS) {
832  break;
833  } else {
834  if (type == CAN_MSGTYPE_TIMEOVR && pdwTimeOvr)
835  // The number of occurred time stamp counter
836  // overflows is stored in the CAN ID.
837  *pdwTimeOvr += CanMsg.dwMsgId;
838  if (dwTimeout != INFINITE) {
839  SetLastError(ERROR_TIMEOUT);
840  return -1;
841  }
842  }
843  }
844 
845  int result = 1;
846  if (type == CAN_MSGTYPE_ERROR) {
847  result = 0;
848 
849  enum can_error error = err ? err->error : 0;
850  switch (CanMsg.abData[0]) {
851  case CAN_ERROR_STUFF: error |= LELY_IO_CAN_ERROR_STUFF; break;
852  case CAN_ERROR_FORM: error |= LELY_IO_CAN_ERROR_FORM; break;
853  case CAN_ERROR_ACK: error |= LELY_IO_CAN_ERROR_ACK; break;
854  case CAN_ERROR_BIT: error |= LELY_IO_CAN_ERROR_BIT; break;
855  case CAN_ERROR_CRC: error |= LELY_IO_CAN_ERROR_CRC; break;
856  default: error |= LELY_IO_CAN_ERROR_OTHER; break;
857  }
858 
859  enum can_state state = io_ixxat_state(CanMsg.abData[1]);
860 
861  if (err) {
862  err->state = state;
863  err->error = error;
864  }
865  } else if (type == CAN_MSGTYPE_STATUS) {
866  result = 0;
867 
868  if (err)
869  err->state = io_ixxat_state(CanMsg.abData[0]);
870  } else if (msg) {
871  assert(type == CAN_MSGTYPE_DATA);
872 
873  *msg = (struct can_msg)CAN_MSG_INIT;
874  if (CanMsg.uMsgInfo.Bits.ext) {
875  msg->id = letoh32(CanMsg.dwMsgId) & CAN_MASK_EID;
876  msg->flags |= CAN_FLAG_IDE;
877  } else {
878  msg->id = letoh32(CanMsg.dwMsgId) & CAN_MASK_BID;
879  }
880  if (CanMsg.uMsgInfo.Bits.rtr)
881  msg->flags |= CAN_FLAG_RTR;
882 #if !LELY_NO_CANFD
883  if (CanMsg.uMsgInfo.Bits.edl)
884  msg->flags |= CAN_FLAG_FDF;
885  if (CanMsg.uMsgInfo.Bits.fdr)
886  msg->flags |= CAN_FLAG_BRS;
887  if (CanMsg.uMsgInfo.Bits.esi)
888  msg->flags |= CAN_FLAG_ESI;
889 #endif
890 #if !LELY_NO_CANFD
891  if (CanMsg.uMsgInfo.Bits.edl) {
892  if (CanMsg.uMsgInfo.Bits.dlc <= 8) {
893  msg->len = CanMsg.uMsgInfo.Bits.dlc;
894  } else {
895  switch (CanMsg.uMsgInfo.Bits.dlc) {
896  case 0x9: msg->len = 12; break;
897  case 0xa: msg->len = 16; break;
898  case 0xb: msg->len = 20; break;
899  case 0xc: msg->len = 24; break;
900  case 0xd: msg->len = 32; break;
901  case 0xe: msg->len = 48; break;
902  case 0xf: msg->len = 64; break;
903  }
904  }
905  } else
906 #endif
907  msg->len = CanMsg.uMsgInfo.Bits.dlc;
908  memcpy(msg->data, CanMsg.abData, msg->len);
909  }
910 
911  if (pdwTime)
912  *pdwTime = CanMsg.dwTime;
913 
914  return result;
915 }
916 
917 static int
918 io_ixxat_write(HANDLE hCanChn, const struct can_msg *msg, int timeout)
919 {
920  assert(msg);
921 
922  if (!hCanChn) {
923  SetLastError(ERROR_INVALID_HANDLE);
924  return -1;
925  }
926 
927 #if LELY_NO_CANFD
928  CANMSG CanMsg = { .dwMsgId = 0 };
929 #else
930  CANMSG2 CanMsg = { .dwMsgId = 0 };
931 #endif
932  if (msg->flags & CAN_FLAG_IDE) {
933  CanMsg.dwMsgId = htole32(msg->id & CAN_MASK_EID);
934  CanMsg.uMsgInfo.Bits.ext = 1;
935  } else {
936  CanMsg.dwMsgId = htole32(msg->id & CAN_MASK_BID);
937  }
938  CanMsg.uMsgInfo.Bits.type = CAN_MSGTYPE_DATA;
939  if (msg->flags & CAN_FLAG_RTR)
940  CanMsg.uMsgInfo.Bits.rtr = 1;
941 #if !LELY_NO_CANFD
942  if (msg->flags & CAN_FLAG_FDF)
943  CanMsg.uMsgInfo.Bits.edl = 1;
944  if (msg->flags & CAN_FLAG_BRS)
945  CanMsg.uMsgInfo.Bits.fdr = 1;
946  if (msg->flags & CAN_FLAG_ESI)
947  CanMsg.uMsgInfo.Bits.esi = 1;
948 #endif
949  int len;
950 #if !LELY_NO_CANFD
951  if (msg->flags & CAN_FLAG_FDF) {
952  len = MIN(msg->len, CANFD_MAX_LEN);
953  if (len <= 8)
954  CanMsg.uMsgInfo.Bits.dlc = len;
955  else if (len <= 12)
956  CanMsg.uMsgInfo.Bits.dlc = 0x9;
957  else if (len <= 16)
958  CanMsg.uMsgInfo.Bits.dlc = 0xa;
959  else if (len <= 20)
960  CanMsg.uMsgInfo.Bits.dlc = 0xb;
961  else if (len <= 24)
962  CanMsg.uMsgInfo.Bits.dlc = 0xc;
963  else if (len <= 32)
964  CanMsg.uMsgInfo.Bits.dlc = 0xd;
965  else if (len <= 48)
966  CanMsg.uMsgInfo.Bits.dlc = 0xe;
967  else
968  CanMsg.uMsgInfo.Bits.dlc = 0xf;
969  } else
970 #endif
971  len = CanMsg.uMsgInfo.Bits.dlc = MIN(msg->len, CAN_MAX_LEN);
972  memcpy(CanMsg.abData, msg->data, len);
973 
974  DWORD dwTimeout = timeout < 0 ? INFINITE : (DWORD)timeout;
975  HRESULT hResult = p_canChannelSendMessage(hCanChn, dwTimeout, &CanMsg);
976  if (hResult != VCI_OK) {
977  SetLastError(io_ixxat_error(hResult));
978  return -1;
979  }
980 
981  return 0;
982 }
983 
984 static DWORD
985 io_ixxat_error(HRESULT hResult)
986 {
987  if (GETSEVERITY(hResult) != SEV_ERROR)
988  return 0;
989 
990  switch (GETSCODE(hResult)) {
991  case 0x0001: // VCI_E_UNEXPECTED
992  return ERROR_UNEXP_NET_ERR;
993  case 0x0002: // VCI_E_NOT_IMPLEMENTED
994  return ERROR_CALL_NOT_IMPLEMENTED;
995  case 0x0003: // VCI_E_OUTOFMEMORY
996  return ERROR_NOT_ENOUGH_MEMORY;
997  case 0x0004: // VCI_E_INVALIDARG
998  return ERROR_BAD_ARGUMENTS;
999  case 0x0005: // VCI_E_NOINTERFACE
1000 #ifndef ERROR_NOINTERFACE
1001 #define ERROR_NOINTERFACE 632
1002 #endif
1003  return ERROR_NOINTERFACE;
1004  case 0x0006: // VCI_E_INVPOINTER
1005  return ERROR_INVALID_ADDRESS;
1006  case 0x0007: // VCI_E_INVHANDLE
1007  return ERROR_INVALID_HANDLE;
1008  case 0x0008: // VCI_E_ABORT
1009  return ERROR_OPERATION_ABORTED;
1010  case 0x0009: // VCI_E_FAIL
1011  return ERROR_GEN_FAILURE;
1012  case 0x000a: // VCI_E_ACCESSDENIED
1013  return ERROR_ACCESS_DENIED;
1014  case 0x000b: // VCI_E_TIMEOUT
1015  return ERROR_TIMEOUT;
1016  case 0x000c: // VCI_E_BUSY
1017  return ERROR_BUSY;
1018  case 0x000d: // VCI_E_PENDING
1019  return ERROR_IO_PENDING;
1020  case 0x000e: // VCI_E_NO_DATA
1021  return ERROR_NO_DATA;
1022  case 0x000f: // VCI_E_NO_MORE_ITEMS
1023  return ERROR_NO_MORE_ITEMS;
1024  case 0x0010: // VCI_E_NOT_INITIALIZED
1025 #ifndef PEERDIST_ERROR_NOT_INITIALIZED
1026 #define PEERDIST_ERROR_NOT_INITIALIZED 4054
1027 #endif
1028  return PEERDIST_ERROR_NOT_INITIALIZED;
1029  case 0x0011: // VCI_E_ALREADY_INITIALIZED
1030 #ifndef PEERDIST_ERROR_ALREADY_INITIALIZED
1031 #define PEERDIST_ERROR_ALREADY_INITIALIZED 4055
1032 #endif
1033  return PEERDIST_ERROR_ALREADY_INITIALIZED;
1034  case 0x0012: // VCI_E_RXQUEUE_EMPTY
1035  case 0x0013: // VCI_E_TXQUEUE_FULL
1036  return ERROR_RETRY;
1037  case 0x0014: // VCI_E_BUFFER_OVERFLOW
1038  return ERROR_BUFFER_OVERFLOW;
1039  case 0x0015: // VCI_E_INVALID_STATE
1040 #ifndef PEERDIST_ERROR_INVALIDATED
1041 #define PEERDIST_ERROR_INVALIDATED 4057
1042 #endif
1043  return PEERDIST_ERROR_INVALIDATED;
1044  case 0x0016: // VCI_E_OBJECT_ALREADY_EXISTS
1045  return ERROR_ALREADY_EXISTS;
1046  case 0x0017: // VCI_E_INVALID_INDEX
1047  return ERROR_INVALID_INDEX;
1048  case 0x0018: // VCI_E_END_OF_FILE
1049  return ERROR_HANDLE_EOF;
1050  case 0x0019: // VCI_E_DISCONNECTED
1051  return ERROR_GRACEFUL_DISCONNECT;
1052  case 0x001a: // VCI_E_INVALID_FIRMWARE
1053 #ifndef PEERDIST_ERROR_VERSION_UNSUPPORTED
1054 #define PEERDIST_ERROR_VERSION_UNSUPPORTED 4062
1055 #endif
1056  return PEERDIST_ERROR_VERSION_UNSUPPORTED;
1057  case 0x001b: // VCI_E_INVALID_LICENSE
1058  case 0x001c: // VCI_E_NO_SUCH_LICENSE
1059  case 0x001d: // VCI_E_LICENSE_EXPIRED
1060 #ifndef PEERDIST_ERROR_NOT_LICENSED
1061 #define PEERDIST_ERROR_NOT_LICENSED 4064
1062 #endif
1063  return PEERDIST_ERROR_NOT_LICENSED;
1064  case 0x001e: // VCI_E_LICENSE_QUOTA_EXCEEDED
1065  return ERROR_LICENSE_QUOTA_EXCEEDED;
1066  case 0x001f: // VCI_E_INVALID_TIMING
1067  return ERROR_INVALID_PARAMETER;
1068  case 0x0020: // VCI_E_IN_USE
1069  return ERROR_DEVICE_IN_USE;
1070  case 0x0021: // VCI_E_NO_SUCH_DEVICE
1071  return ERROR_DEV_NOT_EXIST;
1072  case 0x0022: // VCI_E_DEVICE_NOT_CONNECTED
1073  return ERROR_NOT_CONNECTED;
1074  case 0x0023: // VCI_E_DEVICE_NOT_READY
1075  return ERROR_NOT_READY;
1076  case 0x0024: // VCI_E_TYPE_MISMATCH
1077  return ERROR_BAD_DEV_TYPE;
1078  case 0x0025: // VCI_E_NOT_SUPPORTED
1079  return ERROR_NOT_SUPPORTED;
1080  case 0x0026: // VCI_E_DUPLICATE_OBJECTID
1081  return ERROR_ALREADY_ASSIGNED;
1082  case 0x0027: // VCI_E_OBJECTID_NOT_FOUND
1083  return ERROR_NOT_FOUND;
1084  case 0x0028: // VCI_E_WRONG_LEVEL
1085  return ERROR_INVALID_LEVEL;
1086  case 0x0029: // VCI_E_WRONG_DRV_VERSION
1087  return PEERDIST_ERROR_VERSION_UNSUPPORTED;
1088  case 0x002a: // VCI_E_LUIDS_EXHAUSTED
1089  return ERROR_LUIDS_EXHAUSTED;
1090  default: return ERROR_UNEXP_NET_ERR;
1091  }
1092 }
1093 
1094 static int
1095 io_ixxat_state(UINT32 dwStatus)
1096 {
1097  if (dwStatus & CAN_STATUS_BUSOFF)
1098  return CAN_STATE_BUSOFF;
1099  if (dwStatus & CAN_STATUS_ERRLIM)
1100  return CAN_STATE_PASSIVE;
1101  return CAN_STATE_ACTIVE;
1102 }
1103 
1104 static struct timespec
1105 io_ixxat_time(UINT64 qwTime, UINT32 dwTscClkFreq, UINT32 dwTscDivisor)
1106 {
1107  struct timespec ts = { 0, 0 };
1108  if (dwTscClkFreq && dwTscDivisor) {
1109  qwTime *= dwTscDivisor;
1110  ts.tv_sec = qwTime / dwTscClkFreq;
1111  qwTime -= ts.tv_sec * dwTscClkFreq;
1112  ts.tv_nsec = (qwTime * 1000000000ul) / dwTscClkFreq;
1113  }
1114  return ts;
1115 }
1116 
1117 static int
1118 io_ixxat_ctrl_stop(io_can_ctrl_t *ctrl)
1119 {
1120  struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1121 
1122  HRESULT hResult = p_canControlStart(ixxat->hCanCtl, FALSE);
1123  if (hResult != VCI_OK) {
1124  SetLastError(io_ixxat_error(hResult));
1125  return -1;
1126  }
1127  return 0;
1128 }
1129 
1130 static int
1131 io_ixxat_ctrl_stopped(const io_can_ctrl_t *ctrl)
1132 {
1133  const struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1134 
1135 #if LELY_NO_CANFD
1136  CANLINESTATUS sStatus;
1137 #else
1138  CANLINESTATUS2 sStatus;
1139 #endif
1140  HRESULT hResult = p_canControlGetStatus(ixxat->hCanCtl, &sStatus);
1141  if (hResult != VCI_OK) {
1142  SetLastError(io_ixxat_error(hResult));
1143  return -1;
1144  }
1145  return !!(sStatus.dwStatus & CAN_STATUS_ININIT);
1146 }
1147 
1148 static int
1149 io_ixxat_ctrl_restart(io_can_ctrl_t *ctrl)
1150 {
1151  struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1152 
1153  HRESULT hResult = p_canControlStart(ixxat->hCanCtl, TRUE);
1154  if (hResult != VCI_OK) {
1155  SetLastError(io_ixxat_error(hResult));
1156  return -1;
1157  }
1158  return 0;
1159 }
1160 
1161 static int
1162 io_ixxat_ctrl_get_bitrate(const io_can_ctrl_t *ctrl, int *pnominal, int *pdata)
1163 {
1164  struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1165 
1166 #if LELY_NO_CANFD
1167  CANLINESTATUS sStatus;
1168 #else
1169  CANLINESTATUS2 sStatus;
1170 #endif
1171  HRESULT hResult = p_canControlGetStatus(ixxat->hCanCtl, &sStatus);
1172  if (hResult != VCI_OK) {
1173  SetLastError(io_ixxat_error(hResult));
1174  return -1;
1175  }
1176 
1177 #if LELY_NO_CANFD
1178  if (pnominal) {
1179  UINT8 bBtr0 = sStatus.bBtReg0;
1180  UINT8 bBtr1 = sStatus.bBtReg1;
1181  if (bBtr0 == CAN_BT0_5KB && bBtr1 == CAN_BT1_5KB) {
1182  *pnominal = 5000;
1183  } else if (bBtr0 == CAN_BT0_10KB && bBtr1 == CAN_BT1_10KB) {
1184  *pnominal = 10000;
1185  } else if (bBtr0 == CAN_BT0_20KB && bBtr1 == CAN_BT1_20KB) {
1186  *pnominal = 20000;
1187  } else if (bBtr0 == CAN_BT0_50KB && bBtr1 == CAN_BT1_50KB) {
1188  *pnominal = 50000;
1189  } else if (bBtr0 == CAN_BT0_100KB && bBtr1 == CAN_BT1_100KB) {
1190  *pnominal = 100000;
1191  } else if (bBtr0 == CAN_BT0_125KB && bBtr1 == CAN_BT1_125KB) {
1192  *pnominal = 125000;
1193  } else if (bBtr0 == CAN_BT0_250KB && bBtr1 == CAN_BT1_250KB) {
1194  *pnominal = 250000;
1195  } else if (bBtr0 == CAN_BT0_500KB && bBtr1 == CAN_BT1_500KB) {
1196  *pnominal = 500000;
1197  } else if (bBtr0 == CAN_BT0_800KB && bBtr1 == CAN_BT1_800KB) {
1198  *pnominal = 800000;
1199  } else if (bBtr0 == CAN_BT0_1000KB && bBtr1 == CAN_BT1_1000KB) {
1200  *pnominal = 1000000;
1201  } else {
1202  *pnominal = 0;
1203  }
1204  }
1205  if (pdata)
1206  *pdata = 0;
1207 #else
1208  if (pnominal)
1209  *pnominal = sStatus.sBtpSdr.dwBPS;
1210  if (pdata)
1211  *pdata = (sStatus.bExMode & CAN_FEATURE_FASTDATA)
1212  ? sStatus.sBtpFdr.dwBPS
1213  : 0;
1214 #endif
1215 
1216  return 0;
1217 }
1218 
1219 static int
1220 io_ixxat_ctrl_set_bitrate(io_can_ctrl_t *ctrl, int nominal, int data)
1221 {
1222  struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1223 #if LELY_NO_CANFD
1224  (void)data;
1225 #endif
1226 
1227  UINT8 bOpMode = CAN_OPMODE_STANDARD | CAN_OPMODE_EXTENDED;
1228  if (ixxat->flags & IO_CAN_BUS_FLAG_ERR)
1229  bOpMode |= CAN_OPMODE_ERRFRAME;
1230 #if LELY_NO_CANFD
1231  UINT8 bBtr0 = 0;
1232  UINT8 bBtr1 = 0;
1233  switch (nominal) {
1234  case 5000:
1235  bBtr0 = CAN_BT0_5KB;
1236  bBtr1 = CAN_BT1_5KB;
1237  break;
1238  case 10000:
1239  bBtr0 = CAN_BT0_10KB;
1240  bBtr1 = CAN_BT1_10KB;
1241  break;
1242  case 20000:
1243  bBtr0 = CAN_BT0_20KB;
1244  bBtr1 = CAN_BT1_20KB;
1245  break;
1246  case 50000:
1247  bBtr0 = CAN_BT0_50KB;
1248  bBtr1 = CAN_BT1_50KB;
1249  break;
1250  case 100000:
1251  bBtr0 = CAN_BT0_100KB;
1252  bBtr1 = CAN_BT1_100KB;
1253  break;
1254  case 125000:
1255  bBtr0 = CAN_BT0_125KB;
1256  bBtr1 = CAN_BT1_125KB;
1257  break;
1258  case 250000:
1259  bBtr0 = CAN_BT0_250KB;
1260  bBtr1 = CAN_BT1_250KB;
1261  break;
1262  case 500000:
1263  bBtr0 = CAN_BT0_500KB;
1264  bBtr1 = CAN_BT1_500KB;
1265  break;
1266  case 800000:
1267  bBtr0 = CAN_BT0_800KB;
1268  bBtr1 = CAN_BT1_800KB;
1269  break;
1270  case 1000000:
1271  bBtr0 = CAN_BT0_1000KB;
1272  bBtr1 = CAN_BT1_1000KB;
1273  break;
1274  default: SetLastError(ERROR_INVALID_PARAMETER); return -1;
1275  }
1276  HRESULT hResult = p_canControlInitialize(
1277  ixxat->hCanCtl, bOpMode, bBtr0, bBtr1);
1278 #else
1279  UINT8 bExMode = CAN_EXMODE_DISABLED;
1280  if (ixxat->flags & IO_CAN_BUS_FLAG_FDF)
1281  bExMode |= CAN_EXMODE_EXTDATA;
1282  if (ixxat->flags & IO_CAN_BUS_FLAG_BRS)
1283  bExMode |= CAN_EXMODE_FASTDATA;
1284  CANBTP sBtpSDR, sBtpFDR;
1285  switch (nominal) {
1286  case 5000: sBtpSDR = (CANBTP)CAN_BTP_5KB; break;
1287  case 10000: sBtpSDR = (CANBTP)CAN_BTP_10KB; break;
1288  case 20000: sBtpSDR = (CANBTP)CAN_BTP_20KB; break;
1289  case 50000: sBtpSDR = (CANBTP)CAN_BTP_50KB; break;
1290  case 100000: sBtpSDR = (CANBTP)CAN_BTP_100KB; break;
1291  case 125000: sBtpSDR = (CANBTP)CAN_BTP_125KB; break;
1292  case 250000: sBtpSDR = (CANBTP)CAN_BTP_250KB; break;
1293  case 500000: sBtpSDR = (CANBTP)CAN_BTP_500KB; break;
1294  case 800000: sBtpSDR = (CANBTP)CAN_BTP_800KB; break;
1295  case 1000000: sBtpSDR = (CANBTP)CAN_BTP_1000KB; break;
1296  default: SetLastError(ERROR_INVALID_PARAMETER); return -1;
1297  }
1298  if (ixxat->flags & IO_CAN_BUS_FLAG_BRS) {
1299  switch (data) {
1300  case 5000: sBtpFDR = (CANBTP)CAN_BTP_5KB; break;
1301  case 10000: sBtpFDR = (CANBTP)CAN_BTP_10KB; break;
1302  case 20000: sBtpFDR = (CANBTP)CAN_BTP_20KB; break;
1303  case 50000: sBtpFDR = (CANBTP)CAN_BTP_50KB; break;
1304  case 100000: sBtpFDR = (CANBTP)CAN_BTP_100KB; break;
1305  case 125000: sBtpFDR = (CANBTP)CAN_BTP_125KB; break;
1306  case 250000: sBtpFDR = (CANBTP)CAN_BTP_250KB; break;
1307  case 500000: sBtpFDR = (CANBTP)CAN_BTP_500KB; break;
1308  case 800000: sBtpFDR = (CANBTP)CAN_BTP_800KB; break;
1309  case 1000000: sBtpFDR = (CANBTP)CAN_BTP_1000KB; break;
1310  default: SetLastError(ERROR_INVALID_PARAMETER); return -1;
1311  }
1312  }
1313  HRESULT hResult = p_canControlInitialize(ixxat->hCanCtl, bOpMode,
1314  bExMode, CAN_FILTER_PASS, CAN_FILTER_PASS, 0, 0,
1315  &sBtpSDR,
1316  (ixxat->flags & IO_CAN_BUS_FLAG_BRS) ? &sBtpFDR : NULL);
1317 #endif
1318  if (hResult != VCI_OK) {
1319  SetLastError(io_ixxat_error(hResult));
1320  return -1;
1321  }
1322 
1323  return 0;
1324 }
1325 
1326 static int
1327 io_ixxat_ctrl_get_state(const io_can_ctrl_t *ctrl)
1328 {
1329  const struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1330 
1331 #if LELY_NO_CANFD
1332  CANLINESTATUS sStatus;
1333 #else
1334  CANLINESTATUS2 sStatus;
1335 #endif
1336  HRESULT hResult = p_canControlGetStatus(ixxat->hCanCtl, &sStatus);
1337  if (hResult != VCI_OK) {
1338  SetLastError(io_ixxat_error(hResult));
1339  return -1;
1340  }
1341 
1342  return io_ixxat_state(sStatus.dwStatus);
1343 }
1344 
1345 static inline struct io_ixxat_ctrl *
1346 io_ixxat_ctrl_from_ctrl(const io_can_ctrl_t *ctrl)
1347 {
1348  assert(ctrl);
1349 
1350  return structof(ctrl, struct io_ixxat_ctrl, ctrl_vptr);
1351 }
1352 
1353 static io_ctx_t *
1354 io_ixxat_chan_dev_get_ctx(const io_dev_t *dev)
1355 {
1356  const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1357 
1358  return ixxat->ctx;
1359 }
1360 
1361 static ev_exec_t *
1362 io_ixxat_chan_dev_get_exec(const io_dev_t *dev)
1363 {
1364  const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1365 
1366  return ixxat->exec;
1367 }
1368 
1369 static size_t
1370 io_ixxat_chan_dev_cancel(io_dev_t *dev, struct ev_task *task)
1371 {
1372  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1373 
1374  struct sllist read_queue, write_queue;
1375  sllist_init(&read_queue);
1376  sllist_init(&write_queue);
1377 
1378  io_ixxat_chan_pop(ixxat, &read_queue, &write_queue, task);
1379 
1380  size_t nread = io_can_chan_read_queue_post(
1381  &read_queue, -1, ERROR_OPERATION_ABORTED);
1382  size_t nwrite = io_can_chan_write_queue_post(
1383  &write_queue, ERROR_OPERATION_ABORTED);
1384  return nwrite < SIZE_MAX - nread ? nread + nwrite : SIZE_MAX;
1385 }
1386 
1387 static size_t
1388 io_ixxat_chan_dev_abort(io_dev_t *dev, struct ev_task *task)
1389 {
1390  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1391 
1392  struct sllist queue;
1393  sllist_init(&queue);
1394 
1395  io_ixxat_chan_pop(ixxat, &queue, &queue, task);
1396 
1397  return ev_task_queue_abort(&queue);
1398 }
1399 
1400 static io_dev_t *
1401 io_ixxat_chan_get_dev(const io_can_chan_t *chan)
1402 {
1403  const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1404 
1405  return &ixxat->dev_vptr;
1406 }
1407 
1408 static int
1409 io_ixxat_chan_get_flags(const io_can_chan_t *chan)
1410 {
1411  const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1412 
1413 #if !LELY_NO_THREADS
1414  EnterCriticalSection((CRITICAL_SECTION *)&ixxat->CriticalSection);
1415 #endif
1416  int flags = ixxat->flags;
1417 #if !LELY_NO_THREADS
1418  LeaveCriticalSection((CRITICAL_SECTION *)&ixxat->CriticalSection);
1419 #endif
1420  return flags;
1421 }
1422 
1423 static int
1424 io_ixxat_chan_read(io_can_chan_t *chan, struct can_msg *msg,
1425  struct can_err *err, struct timespec *tp, int timeout)
1426 {
1427  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1428 
1429  return io_ixxat_chan_read_impl(ixxat, msg, err, tp, timeout);
1430 }
1431 
1432 static void
1433 io_ixxat_chan_submit_read(io_can_chan_t *chan, struct io_can_chan_read *read)
1434 {
1435  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1436  assert(read);
1437  struct ev_task *task = &read->task;
1438 
1439  if (!task->exec)
1440  task->exec = ixxat->exec;
1441  assert(task->exec);
1442  ev_exec_on_task_init(task->exec);
1443 
1444 #if !LELY_NO_THREADS
1445  EnterCriticalSection(&ixxat->CriticalSection);
1446 #endif
1447  if (ixxat->shutdown) {
1448 #if !LELY_NO_THREADS
1449  LeaveCriticalSection(&ixxat->CriticalSection);
1450 #endif
1451  io_can_chan_read_post(read, -1, ERROR_OPERATION_ABORTED);
1452  } else {
1453  int post_read = !ixxat->read_posted
1454  && sllist_empty(&ixxat->read_queue);
1455  sllist_push_back(&ixxat->read_queue, &task->_node);
1456  if (post_read)
1457  ixxat->read_posted = 1;
1458 #if !LELY_NO_THREADS
1459  LeaveCriticalSection(&ixxat->CriticalSection);
1460 #endif
1461  assert(ixxat->read_task.exec);
1462  if (post_read)
1463  ev_exec_post(ixxat->read_task.exec, &ixxat->read_task);
1464  }
1465 }
1466 
1467 static int
1468 io_ixxat_chan_write(io_can_chan_t *chan, const struct can_msg *msg, int timeout)
1469 {
1470  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1471 
1472  return io_ixxat_chan_write_impl(ixxat, msg, timeout);
1473 }
1474 
1475 static void
1476 io_ixxat_chan_submit_write(io_can_chan_t *chan, struct io_can_chan_write *write)
1477 {
1478  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1479  assert(write);
1480  assert(write->msg);
1481  struct ev_task *task = &write->task;
1482 
1483 #if !LELY_NO_CANFD
1484  int flags = 0;
1485  if (write->msg->flags & CAN_FLAG_FDF)
1486  flags |= IO_CAN_BUS_FLAG_FDF;
1487  if (write->msg->flags & CAN_FLAG_BRS)
1488  flags |= IO_CAN_BUS_FLAG_BRS;
1489 #endif
1490 
1491  if (!task->exec)
1492  task->exec = ixxat->exec;
1493  assert(task->exec);
1494  ev_exec_on_task_init(task->exec);
1495 
1496 #if !LELY_NO_THREADS
1497  EnterCriticalSection(&ixxat->CriticalSection);
1498 #endif
1499  if (ixxat->shutdown) {
1500 #if !LELY_NO_THREADS
1501  LeaveCriticalSection(&ixxat->CriticalSection);
1502 #endif
1503  io_can_chan_write_post(write, ERROR_OPERATION_ABORTED);
1504 #if !LELY_NO_CANFD
1505  } else if ((flags & ixxat->flags) != flags) {
1506 #if !LELY_NO_THREADS
1507  LeaveCriticalSection(&ixxat->CriticalSection);
1508 #endif
1509  io_can_chan_write_post(write, ERROR_INVALID_PARAMETER);
1510 #endif
1511  } else {
1512  int post_write = !ixxat->write_posted
1513  && sllist_empty(&ixxat->write_queue);
1514  sllist_push_back(&ixxat->write_queue, &task->_node);
1515  if (post_write)
1516  ixxat->write_posted = 1;
1517 #if !LELY_NO_THREADS
1518  LeaveCriticalSection(&ixxat->CriticalSection);
1519 #endif
1520  assert(ixxat->write_task.exec);
1521  if (post_write)
1522  ev_exec_post(ixxat->write_task.exec,
1523  &ixxat->write_task);
1524  }
1525 }
1526 
1527 static void
1528 io_ixxat_chan_svc_shutdown(struct io_svc *svc)
1529 {
1530  struct io_ixxat_chan *ixxat = io_ixxat_chan_from_svc(svc);
1531  io_dev_t *dev = &ixxat->dev_vptr;
1532 
1533 #if !LELY_NO_THREADS
1534  EnterCriticalSection(&ixxat->CriticalSection);
1535 #endif
1536  int shutdown = !ixxat->shutdown;
1537  ixxat->shutdown = 1;
1538  if (shutdown)
1539  // Try to abort io_ixxat_chan_read_task_func() and
1540  // io_ixxat_chan_write_task_func().
1541  io_ixxat_chan_do_abort_tasks(ixxat);
1542 #if !LELY_NO_THREADS
1543  LeaveCriticalSection(&ixxat->CriticalSection);
1544 #endif
1545 
1546  if (shutdown)
1547  // Cancel all pending operations.
1548  io_ixxat_chan_dev_cancel(dev, NULL);
1549 }
1550 
1551 static void
1552 io_ixxat_chan_read_task_func(struct ev_task *task)
1553 {
1554  assert(task);
1555  struct io_ixxat_chan *ixxat =
1556  structof(task, struct io_ixxat_chan, read_task);
1557 
1558  DWORD dwErrCode = GetLastError();
1559 
1560  HANDLE hCanChn = NULL;
1561  struct io_can_chan_read *read = NULL;
1562 
1563 #if !LELY_NO_THREADS
1564  EnterCriticalSection(&ixxat->CriticalSection);
1565 #endif
1566  if (!ixxat->shutdown)
1567  hCanChn = ixxat->hCanChn;
1568  UINT32 dwTscClkFreq = ixxat->dwTscClkFreq;
1569  UINT32 dwTscDivisor = ixxat->dwTscDivisor;
1570  UINT64 qwTime = (UINT64)ixxat->dwTimeOvr << 32;
1571  if ((task = ev_task_from_node(sllist_pop_front(&ixxat->read_queue))))
1572  read = ixxat->current_read = io_can_chan_read_from_task(task);
1573 #if !LELY_NO_THREADS
1574  LeaveCriticalSection(&ixxat->CriticalSection);
1575 #endif
1576 
1577  int result = 0;
1578  int errc = 0;
1579  UINT32 dwTime = 0;
1580  UINT32 dwTimeOvr = 0;
1581  if (read) {
1582  result = io_ixxat_read(hCanChn, read->msg, read->err, &dwTime,
1583  &dwTimeOvr, ixxat->rxtimeo);
1584  if (result >= 0 && read->tp) {
1585  qwTime += ((UINT64)dwTimeOvr << 32) + dwTime;
1586  *read->tp = io_ixxat_time(
1587  qwTime, dwTscClkFreq, dwTscDivisor);
1588  }
1589  if (result == -1) {
1590  errc = GetLastError();
1591  if (errc == ERROR_TIMEOUT)
1592  errc = ERROR_RETRY;
1593  }
1594  }
1595 
1596 #if !LELY_NO_THREADS
1597  EnterCriticalSection(&ixxat->CriticalSection);
1598 #endif
1599  if (hCanChn == ixxat->hCanChn)
1600  ixxat->dwTimeOvr += dwTimeOvr;
1601  // Put the read operation back on the queue if it would block, unless
1602  // it was canceled.
1603  if (result == -1 && errc == ERROR_RETRY
1604  && read == ixxat->current_read) {
1605  assert(read);
1606  sllist_push_front(&ixxat->read_queue, &task->_node);
1607  read = NULL;
1608  }
1609  ixxat->current_read = NULL;
1610  int post_read = ixxat->read_posted =
1611  !sllist_empty(&ixxat->read_queue) && !ixxat->shutdown;
1612 #if !LELY_NO_THREADS
1613  LeaveCriticalSection(&ixxat->CriticalSection);
1614 #endif
1615  if (read) {
1616  if (result == -1 && errc == ERROR_RETRY)
1617  errc = ERROR_OPERATION_ABORTED;
1618  io_can_chan_read_post(read, result, errc);
1619  }
1620 
1621  if (post_read)
1622  ev_exec_post(ixxat->read_task.exec, &ixxat->read_task);
1623 
1624  SetLastError(dwErrCode);
1625 }
1626 
1627 static void
1628 io_ixxat_chan_write_task_func(struct ev_task *task)
1629 {
1630  assert(task);
1631  struct io_ixxat_chan *ixxat =
1632  structof(task, struct io_ixxat_chan, write_task);
1633 
1634  DWORD dwErrCode = GetLastError();
1635 
1636  HANDLE hCanChn = NULL;
1637  struct io_can_chan_write *write = NULL;
1638 
1639 #if !LELY_NO_THREADS
1640  EnterCriticalSection(&ixxat->CriticalSection);
1641 #endif
1642  if (!ixxat->shutdown)
1643  hCanChn = ixxat->hCanChn;
1644  if ((task = ev_task_from_node(sllist_pop_front(&ixxat->write_queue))))
1645  write = ixxat->current_write =
1647 #if !LELY_NO_THREADS
1648  LeaveCriticalSection(&ixxat->CriticalSection);
1649 #endif
1650 
1651  int result = 0;
1652  int errc = 0;
1653  if (write) {
1654  result = io_ixxat_write(hCanChn, write->msg, ixxat->txtimeo);
1655  if (result == -1) {
1656  errc = GetLastError();
1657  if (errc == ERROR_TIMEOUT)
1658  errc = ERROR_RETRY;
1659  }
1660  }
1661 
1662 #if !LELY_NO_THREADS
1663  EnterCriticalSection(&ixxat->CriticalSection);
1664 #endif
1665  // Put the write operation back on the queue if it would block, unless
1666  // it was canceled.
1667  if (result == -1 && errc == ERROR_RETRY
1668  && write == ixxat->current_write) {
1669  assert(write);
1670  sllist_push_front(&ixxat->write_queue, &task->_node);
1671  write = NULL;
1672  }
1673  ixxat->current_write = NULL;
1674  int post_write = ixxat->write_posted =
1675  !sllist_empty(&ixxat->write_queue) && !ixxat->shutdown;
1676 #if !LELY_NO_THREADS
1677  LeaveCriticalSection(&ixxat->CriticalSection);
1678 #endif
1679 
1680  if (write) {
1681  if (result == -1 && errc == ERROR_RETRY)
1682  errc = ERROR_OPERATION_ABORTED;
1683  io_can_chan_write_post(write, errc);
1684  }
1685 
1686  if (post_write)
1687  ev_exec_post(ixxat->write_task.exec, &ixxat->write_task);
1688 
1689  SetLastError(dwErrCode);
1690 }
1691 
1692 static inline struct io_ixxat_chan *
1693 io_ixxat_chan_from_dev(const io_dev_t *dev)
1694 {
1695  assert(dev);
1696 
1697  return structof(dev, struct io_ixxat_chan, dev_vptr);
1698 }
1699 
1700 static inline struct io_ixxat_chan *
1701 io_ixxat_chan_from_chan(const io_can_chan_t *chan)
1702 {
1703  assert(chan);
1704 
1705  return structof(chan, struct io_ixxat_chan, chan_vptr);
1706 }
1707 
1708 static inline struct io_ixxat_chan *
1709 io_ixxat_chan_from_svc(const struct io_svc *svc)
1710 {
1711  assert(svc);
1712 
1713  return structof(svc, struct io_ixxat_chan, svc);
1714 }
1715 
1716 static int
1717 io_ixxat_chan_read_impl(struct io_ixxat_chan *ixxat, struct can_msg *msg,
1718  struct can_err *err, struct timespec *tp, int timeout)
1719 {
1720  assert(ixxat);
1721 
1722 #if !LELY_NO_THREADS
1723  EnterCriticalSection(&ixxat->CriticalSection);
1724 #endif
1725  HANDLE hCanChn = ixxat->hCanChn;
1726  UINT32 dwTscClkFreq = ixxat->dwTscClkFreq;
1727  UINT32 dwTscDivisor = ixxat->dwTscDivisor;
1728  UINT64 qwTime = (UINT64)ixxat->dwTimeOvr << 32;
1729 #if !LELY_NO_THREADS
1730  LeaveCriticalSection(&ixxat->CriticalSection);
1731 #endif
1732 
1733  UINT32 dwTime = 0;
1734  UINT32 dwTimeOvr = 0;
1735  int result = io_ixxat_read(
1736  hCanChn, msg, err, &dwTime, &dwTimeOvr, timeout);
1737  if (result >= 0 && tp) {
1738  qwTime += ((UINT64)dwTimeOvr << 32) + dwTime;
1739  *tp = io_ixxat_time(qwTime, dwTscClkFreq, dwTscDivisor);
1740  }
1741 
1742 #if !LELY_NO_THREADS
1743  EnterCriticalSection(&ixxat->CriticalSection);
1744 #endif
1745  if (hCanChn == ixxat->hCanChn)
1746  ixxat->dwTimeOvr += dwTimeOvr;
1747 #if !LELY_NO_THREADS
1748  LeaveCriticalSection(&ixxat->CriticalSection);
1749 #endif
1750 
1751  return result;
1752 }
1753 
1754 static int
1755 io_ixxat_chan_write_impl(struct io_ixxat_chan *ixxat, const struct can_msg *msg,
1756  int timeout)
1757 {
1758  assert(ixxat);
1759  assert(msg);
1760 
1761 #if !LELY_NO_CANFD
1762  int flags = 0;
1763  if (msg->flags & CAN_FLAG_FDF)
1764  flags |= IO_CAN_BUS_FLAG_FDF;
1765  if (msg->flags & CAN_FLAG_BRS)
1766  flags |= IO_CAN_BUS_FLAG_BRS;
1767 #endif
1768 
1769 #if !LELY_NO_THREADS
1770  EnterCriticalSection(&ixxat->CriticalSection);
1771 #endif
1772 #if !LELY_NO_CANFD
1773  if ((flags & ixxat->flags) != flags) {
1774 #if !LELY_NO_THREADS
1775  LeaveCriticalSection(&ixxat->CriticalSection);
1776 #endif
1777  SetLastError(ERROR_INVALID_PARAMETER);
1778  return -1;
1779  }
1780 #endif
1781  HANDLE hCanChn = ixxat->hCanChn;
1782 #if !LELY_NO_THREADS
1783  LeaveCriticalSection(&ixxat->CriticalSection);
1784 #endif
1785 
1786  return io_ixxat_write(hCanChn, msg, timeout);
1787 }
1788 
1789 static void
1790 io_ixxat_chan_pop(struct io_ixxat_chan *ixxat, struct sllist *read_queue,
1791  struct sllist *write_queue, struct ev_task *task)
1792 {
1793  assert(ixxat);
1794  assert(read_queue);
1795  assert(write_queue);
1796 
1797 #if !LELY_NO_THREADS
1798  EnterCriticalSection(&ixxat->CriticalSection);
1799 #endif
1800  if (!task) {
1801  sllist_append(read_queue, &ixxat->read_queue);
1802  sllist_append(write_queue, &ixxat->write_queue);
1803  } else if (sllist_remove(&ixxat->read_queue, &task->_node)) {
1804  sllist_push_back(read_queue, &task->_node);
1805  } else if (sllist_remove(&ixxat->write_queue, &task->_node)) {
1806  sllist_push_back(write_queue, &task->_node);
1807  }
1808 #if !LELY_NO_THREADS
1809  LeaveCriticalSection(&ixxat->CriticalSection);
1810 #endif
1811 }
1812 
1813 static size_t
1814 io_ixxat_chan_do_abort_tasks(struct io_ixxat_chan *ixxat)
1815 {
1816  assert(ixxat);
1817 
1818  size_t n = 0;
1819 
1820  // Try to abort io_ixxat_chan_read_task_func().
1821  // clang-format off
1822  if (ixxat->read_posted && ev_exec_abort(ixxat->read_task.exec,
1823  &ixxat->read_task)) {
1824  // clang-format on
1825  ixxat->read_posted = 0;
1826  n++;
1827  }
1828 
1829  // Try to abort io_ixxat_chan_write_task_func().
1830  // clang-format off
1831  if (ixxat->write_posted && ev_exec_abort(ixxat->write_task.exec,
1832  &ixxat->write_task)) {
1833  // clang-format on
1834  ixxat->write_posted = 0;
1835  n++;
1836  }
1837 
1838  return n;
1839 }
1840 
1841 static HANDLE
1842 io_ixxat_chan_set_handle(struct io_ixxat_chan *ixxat, HANDLE hCanChn, int flags,
1843  UINT32 dwTscClkFreq, UINT32 dwTscDivisor)
1844 {
1845  assert(ixxat);
1846  assert(!(flags & ~IO_CAN_BUS_FLAG_MASK));
1847 
1848  struct sllist read_queue, write_queue;
1849  sllist_init(&read_queue);
1850  sllist_init(&write_queue);
1851 
1852 #if !LELY_NO_THREADS
1853  EnterCriticalSection(&ixxat->CriticalSection);
1854 #endif
1855 
1856  HANDLE tmp = ixxat->hCanChn;
1857  ixxat->hCanChn = hCanChn;
1858  hCanChn = tmp;
1859 
1860  ixxat->flags = flags;
1861  ixxat->dwTscClkFreq = dwTscClkFreq;
1862  ixxat->dwTscDivisor = dwTscDivisor;
1863  ixxat->dwTimeOvr = 0;
1864 
1865  sllist_append(&read_queue, &ixxat->read_queue);
1866  sllist_append(&write_queue, &ixxat->write_queue);
1867 
1868  ixxat->current_read = NULL;
1869  ixxat->current_write = NULL;
1870 
1871 #if !LELY_NO_THREADS
1872  LeaveCriticalSection(&ixxat->CriticalSection);
1873 #endif
1874 
1875  io_can_chan_read_queue_post(&read_queue, -1, ERROR_OPERATION_ABORTED);
1876  io_can_chan_write_queue_post(&write_queue, ERROR_OPERATION_ABORTED);
1877 
1878  return hCanChn;
1879 }
1880 
1881 #endif // _WIN32 && LELY_HAVE_IXXAT
LELY_IO_RX_TIMEOUT
#define LELY_IO_RX_TIMEOUT
The default timeout (in milliseconds) for I/O read operations.
Definition: io2.h:31
ctx.h
can_msg::flags
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_FDF, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition: msg.h:94
io_ixxat_ctrl_get_handle
HANDLE io_ixxat_ctrl_get_handle(const io_can_ctrl_t *ctrl)
Returns the native handle of the CAN controller.
ev_task_from_node
struct ev_task * ev_task_from_node(struct slnode *node)
Converts a pointer to a node in a queue to the address of the task containing the node.
Definition: task.c:32
ev_exec_t
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
can_msg::data
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:102
sllist_remove
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
Definition: sllist.c:46
CAN_STATE_BUSOFF
@ CAN_STATE_BUSOFF
The bus off state (TX/RX error count >= 256).
Definition: err.h:34
io_can_ctrl_vtbl
Definition: can.h:139
CAN_FLAG_ESI
@ CAN_FLAG_ESI
The Error State Indicator (ESI) flag (only available in CAN FD format frames).
Definition: msg.h:67
CAN_MASK_EID
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition: msg.h:34
CAN_FLAG_BRS
@ CAN_FLAG_BRS
The Bit Rate Switch (BRS) flag (only available in CAN FD format frames).
Definition: msg.h:62
io_can_chan_read_from_task
struct io_can_chan_read * io_can_chan_read_from_task(struct ev_task *task)
Obtains a pointer to a CAN channel read operation from a pointer to its completion task.
Definition: can.c:91
CAN_STATE_ACTIVE
@ CAN_STATE_ACTIVE
The error active state (TX/RX error count < 128).
Definition: err.h:30
IO_CAN_BUS_FLAG_ERR
@ IO_CAN_BUS_FLAG_ERR
Reception of error frames is enabled.
Definition: can.h:39
letoh32
uint_least32_t letoh32(uint_least32_t x)
Converts a 32-bit unsigned integer from little-endian to host byte order.
Definition: endian.h:396
io_svc_vtbl
The virtual table of an I/O service.
Definition: ctx.h:67
CAN_MASK_BID
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
Definition: msg.h:31
CAN_ERROR_BIT
@ CAN_ERROR_BIT
A single bit error.
Definition: err.h:44
CANFD_MAX_LEN
#define CANFD_MAX_LEN
The maximum number of bytes in the payload of a CAN FD format frame.
Definition: msg.h:76
string.h
can_msg
A CAN or CAN FD format frame.
Definition: msg.h:87
IO_SVC_INIT
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
Definition: ctx.h:57
io_dev_vtbl
Definition: dev.h:41
io_can_chan_write::task
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the write operation.
Definition: can.h:121
can_msg::len
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
Definition: msg.h:100
util.h
diag.h
MIN
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
io_can_chan_vtbl
Definition: can.h:149
io_ixxat_fini
void io_ixxat_fini(void)
Frees the "vcinpl.dll" or "vcinpl2.dll" library and terminates the availability of the IXXAT function...
io_can_chan_write::errc
int errc
The error number, obtained as if by get_errc(), if an error occurred or the operation was canceled.
Definition: can.h:126
io_ixxat_chan_create
io_can_chan_t * io_ixxat_chan_create(io_ctx_t *ctx, ev_exec_t *exec, int rxtimeo, int txtimeo)
Creates a new IXXAT CAN channel.
CAN_STATE_PASSIVE
@ CAN_STATE_PASSIVE
The error passive state (TX/RX error count < 256).
Definition: err.h:32
sllist_push_front
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
Definition: sllist.h:205
io_ctx_insert
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
Definition: ctx.c:121
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
CAN_ERROR_ACK
@ CAN_ERROR_ACK
An acknowledgment error.
Definition: err.h:52
can_err
A CAN error frame.
Definition: err.h:28
io_ixxat_chan_is_open
int io_ixxat_chan_is_open(const io_can_chan_t *chan)
Returns 1 is the CAN channel is open and 0 if not.
io_ixxat_chan_get_handle
HANDLE io_ixxat_chan_get_handle(const io_can_chan_t *chan)
Returns the native handle of the CAN channel, or NULL if the channel is closed.
io_can_chan_read
A CAN channel read operation.
Definition: can.h:74
sllist_append
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
Definition: sllist.h:233
io.h
CAN_MSG_INIT
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition: msg.h:113
CAN_ERROR_FORM
@ CAN_ERROR_FORM
A form error.
Definition: err.h:50
io_can_chan_read::msg
struct can_msg * msg
The address at which to store the CAN frame.
Definition: can.h:80
IO_CAN_BUS_FLAG_FDF
@ IO_CAN_BUS_FLAG_FDF
FD Format (formerly Extended Data Length) support is enabled.
Definition: can.h:42
can_error
can_error
The error flags of a CAN bus, which are not mutually exclusive.
Definition: err.h:42
io_can_chan_write
A CAN channel write operation.
Definition: can.h:110
io_ixxat_chan_destroy
void io_ixxat_chan_destroy(io_can_chan_t *chan)
Destroys an IXXAT CAN channel.
io_can_chan_t
const struct io_can_chan_vtbl *const io_can_chan_t
An abstract CAN channel.
Definition: can.h:59
io_ixxat_chan_release
HANDLE io_ixxat_chan_release(io_can_chan_t *chan)
Dissociates and returns the native handle from a CAN channel.
CAN_MAX_LEN
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:72
io_can_chan_write::msg
const struct can_msg * msg
A pointer to the CAN frame to be written.
Definition: can.h:116
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
sllist_empty
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
Definition: sllist.h:190
DIAG_WARNING
@ DIAG_WARNING
A warning.
Definition: diag.h:47
ev_task_queue_abort
size_t ev_task_queue_abort(struct sllist *queue)
Aborts the tasks in queue by invoking ev_exec_on_task_fini() for each of them.
Definition: task.c:55
io_ixxat_ctrl_create_from_luid
io_can_ctrl_t * io_ixxat_ctrl_create_from_luid(const LUID *lpLuid, UINT32 dwCanNo, int flags, int nominal, int data)
Creates a new IXXAT CAN controller from a locally unique identifier (LUID).
io_ixxat_ctrl_create_from_index
io_can_ctrl_t * io_ixxat_ctrl_create_from_index(UINT32 dwIndex, UINT32 dwCanNo, int flags, int nominal, int data)
Creates a new IXXAT CAN controller from a device index.
can_err::error
int error
The error flags of the CAN bus (any combination of CAN_ERROR_BIT, CAN_ERROR_STUFF,...
Definition: err.h:39
can_state
can_state
The states of a CAN node, depending on the TX/RX error count.
Definition: err.h:28
io_svc
An I/O service.
Definition: ctx.h:49
sllist_init
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition: sllist.h:184
sllist_pop_front
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
Definition: sllist.h:221
ev_exec_abort
size_t ev_exec_abort(ev_exec_t *exec, struct ev_task *task)
Aborts the specified task submitted to *exec, if it has not yet begun executing, or all pending tasks...
Definition: exec.h:138
can_err::state
int state
The state of the CAN node (one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE or CAN_STATE_BUSOFF).
Definition: err.h:33
io_ctx_remove
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
Definition: ctx.c:136
io_can_chan_read::tp
struct timespec * tp
The address at which to store the system time at which the CAN frame or CAN error frame was received.
Definition: can.h:93
diag
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
CAN_ERROR_STUFF
@ CAN_ERROR_STUFF
A bit stuffing error.
Definition: err.h:46
sllist
A singly-linked list.
Definition: sllist.h:51
CAN_ERROR_CRC
@ CAN_ERROR_CRC
A CRC sequence error.
Definition: err.h:48
CAN_FLAG_RTR
@ CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition: msg.h:48
IO_CAN_BUS_FLAG_BRS
@ IO_CAN_BUS_FLAG_BRS
Bit Rate Switch support is enabled.
Definition: can.h:44
io_ixxat_ctrl_destroy
void io_ixxat_ctrl_destroy(io_can_ctrl_t *ctrl)
Destroys an IXXAT CAN controller.
io_can_chan_read::err
struct can_err * err
The address at which to store the CAN error frame.
Definition: can.h:86
io_can_chan_write_from_task
struct io_can_chan_write * io_can_chan_write_from_task(struct ev_task *task)
Obtains a pointer to a CAN channel write operation from a pointer to its completion task.
Definition: can.c:97
structof
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
ev_task
An executable task.
Definition: task.h:41
htole32
uint_least32_t htole32(uint_least32_t x)
Converts a 32-bit unsigned integer from host to little-endian byte order.
Definition: endian.h:383
io_dev_t
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
Definition: dev.h:35
CAN_FLAG_FDF
@ CAN_FLAG_FDF
The FD Format (FDF) flag, formerly known as Extended Data Length (EDL).
Definition: msg.h:54
EV_TASK_INIT
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition: task.h:53
ixxat.h
ev_exec_on_task_init
void ev_exec_on_task_init(ev_exec_t *exec)
Indicates to the specified executor that a task will be submitted for execution in the future.
Definition: exec.h:108
io_ctx
Definition: ctx.c:35
ev_exec_post
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
Definition: exec.h:126
io_can_chan_read::task
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
Definition: can.h:98
stdlib.h
io_can_ctrl_set_bitrate
int io_can_ctrl_set_bitrate(io_can_ctrl_t *ctrl, int nominal, int data)
Configures the bitrate(s) of a CAN controller.
Definition: can.h:433
io_ixxat_init
int io_ixxat_init(void)
Loads the "vcinpl.dll" or "vcinpl2.dll" library and makes the IXXAT functions available for use.
sllist_push_back
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
Definition: sllist.h:213
CAN_FLAG_IDE
@ CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition: msg.h:43
io_ixxat_chan_open
int io_ixxat_chan_open(io_can_chan_t *chan, const io_can_ctrl_t *ctrl, UINT16 wRxFifoSize, UINT16 wTxFifoSize)
Opens a CAN channel.
LELY_IO_TX_TIMEOUT
#define LELY_IO_TX_TIMEOUT
The default timeout (in milliseconds) for I/O write operations.
Definition: io2.h:36
ev_task::exec
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition: task.h:43
io_ixxat_chan_assign
int io_ixxat_chan_assign(io_can_chan_t *chan, HANDLE hCanChn, UINT32 dwTscClkFreq, UINT32 dwTscDivisor)
Assigns an existing handle to a CAN channel, and activates the channel if necessary.
can_msg::id
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:89
io_can_ctrl_t
const struct io_can_ctrl_vtbl *const io_can_ctrl_t
An abstract CAN controller.
Definition: can.h:56
endian.h
io_ixxat_chan_close
int io_ixxat_chan_close(io_can_chan_t *chan)
Closes a CAN channel.