26 #if _WIN32 && LELY_HAVE_IXXAT
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
43 #undef CAN_ERROR_OTHER
47 #undef CAN_ERROR_STUFF
54 #include <processthreadsapi.h>
58 #pragma GCC diagnostic push
59 #pragma GCC diagnostic ignored "-Wpedantic"
60 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
71 #pragma GCC diagnostic pop
74 #ifndef LELY_IO_IXXAT_RX_FIFO_SIZE
79 #define LELY_IO_IXXAT_RX_FIFO_SIZE 1024
82 #ifndef LELY_IO_IXXAT_TX_FIFO_SIZE
87 #define LELY_IO_IXXAT_TX_FIFO_SIZE 128
90 static size_t io_ixxat_init_refcnt = 0;
92 static HMODULE hLibModule;
94 #define LELY_IO_DEFINE_IXXAT(name) static PF_##name p_##name;
96 #undef LELY_IO_DEFINE_IXXAT
98 static int io_ixxat_read(HANDLE hCanChn,
struct can_msg *msg,
99 struct can_err *err, PUINT32 pdwTime, PUINT32 pdwTimeOvr,
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);
111 static int io_ixxat_ctrl_get_bitrate(
113 static int io_ixxat_ctrl_set_bitrate(
115 static int io_ixxat_ctrl_get_state(
const io_can_ctrl_t *ctrl);
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
128 struct io_ixxat_ctrl {
138 static inline struct io_ixxat_ctrl *io_ixxat_ctrl_from_ctrl(
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);
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
156 static int io_ixxat_chan_get_flags(
const io_can_chan_t *chan);
158 struct can_err *err,
struct timespec *tp,
int timeout);
159 static void io_ixxat_chan_submit_read(
161 static int io_ixxat_chan_write(
163 static void io_ixxat_chan_submit_write(
168 &io_ixxat_chan_get_dev,
169 &io_ixxat_chan_get_flags,
171 &io_ixxat_chan_submit_read,
172 &io_ixxat_chan_write,
173 &io_ixxat_chan_submit_write
177 static void io_ixxat_chan_svc_shutdown(
struct io_svc *svc);
180 static const struct io_svc_vtbl io_ixxat_chan_svc_vtbl = {
182 &io_ixxat_chan_svc_shutdown
186 struct io_ixxat_chan {
197 CRITICAL_SECTION CriticalSection;
204 unsigned shutdown : 1;
205 unsigned read_posted : 1;
206 unsigned write_posted : 1;
208 struct sllist write_queue;
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);
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(
219 static inline struct io_ixxat_chan *io_ixxat_chan_from_svc(
220 const struct io_svc *svc);
222 static int io_ixxat_chan_read_impl(
struct io_ixxat_chan *ixxat,
225 static int io_ixxat_chan_write_impl(
struct io_ixxat_chan *ixxat,
226 const struct can_msg *msg,
int timeout);
228 static void io_ixxat_chan_pop(
struct io_ixxat_chan *ixxat,
232 static size_t io_ixxat_chan_do_abort_tasks(
struct io_ixxat_chan *ixxat);
234 static HANDLE io_ixxat_chan_set_handle(
struct io_ixxat_chan *ixxat,
235 HANDLE hCanChn,
int flags, UINT32 dwTscClkFreq,
236 UINT32 dwTscDivisor);
241 if (io_ixxat_init_refcnt++)
247 hLibModule = LoadLibraryA(
"vcinpl.dll");
249 hLibModule = LoadLibraryA(
"vcinpl2.dll");
252 dwErrCode = GetLastError();
253 goto error_LoadLibrary;
256 #if defined(__MINGW32__) && __GNUC__ >= 8
257 #pragma GCC diagnostic push
258 #pragma GCC diagnostic ignored "-Wcast-function-type"
260 #define LELY_IO_DEFINE_IXXAT(name) \
261 if (!(p_##name = (PF_##name)GetProcAddress(hLibModule, #name))) { \
262 dwErrCode = GetLastError(); \
263 goto error_GetProcAddress; \
266 #undef LELY_IO_DEFINE_IXXAT
267 #if defined(__MINGW32__) && __GNUC__ >= 8
268 #pragma GCC diagnostic pop
273 error_GetProcAddress:
274 #define LELY_IO_DEFINE_IXXAT(name) p_##name = NULL;
276 #undef LELY_IO_DEFINE_IXXAT
277 FreeLibrary(hLibModule);
280 SetLastError(dwErrCode);
281 io_ixxat_init_refcnt--;
288 assert(io_ixxat_init_refcnt);
290 if (--io_ixxat_init_refcnt)
293 #define LELY_IO_DEFINE_IXXAT(name) p_##name = NULL;
295 #undef LELY_IO_DEFINE_IXXAT
297 FreeLibrary(hLibModule);
302 io_ixxat_ctrl_alloc(
void)
304 struct io_ixxat_ctrl *ixxat = malloc(
sizeof(*ixxat));
309 return &ixxat->ctrl_vptr;
313 io_ixxat_ctrl_free(
void *ptr)
316 free(io_ixxat_ctrl_from_ctrl(ptr));
320 io_ixxat_ctrl_init(
io_can_ctrl_t *ctrl,
const LUID *lpLuid, UINT32 dwCanNo,
321 int flags,
int nominal,
int data)
323 struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
327 HRESULT hResult = VCI_OK;
329 ixxat->ctrl_vptr = &io_ixxat_ctrl_vtbl;
331 VCIID VciObjectId = { .AsLuid = *lpLuid };
332 ixxat->hDevice = NULL;
333 if ((hResult = p_vciDeviceOpen(&VciObjectId, &ixxat->hDevice))
335 if (hResult == VCI_E_INVALIDARG)
336 dwErrCode = ERROR_DEV_NOT_EXIST;
338 dwErrCode = io_ixxat_error(hResult);
339 goto error_vciDeviceOpen;
342 ixxat->dwCanNo = dwCanNo;
343 ixxat->hCanCtl = NULL;
345 if ((hResult = p_canControlOpen(ixxat->hDevice, ixxat->dwCanNo,
346 &ixxat->hCanCtl)) != VCI_OK) {
348 if (hResult == VCI_E_INVALID_INDEX)
349 dwErrCode = ERROR_DEV_NOT_EXIST;
351 dwErrCode = io_ixxat_error(hResult);
352 goto error_canControlOpen;
356 CANCAPABILITIES sCanCaps;
358 CANCAPABILITIES2 sCanCaps;
360 if ((hResult = p_canControlGetCaps(ixxat->hCanCtl, &sCanCaps))
362 dwErrCode = io_ixxat_error(hResult);
363 goto error_canControlGetCaps;
365 if (!(sCanCaps.dwFeatures & CAN_FEATURE_STDANDEXT)) {
366 dwErrCode = io_ixxat_error(hResult);
367 goto error_canControlGetCaps;
370 ixxat->flags = flags;
371 if (ixxat->flags & ~IO_CAN_BUS_FLAG_MASK) {
372 dwErrCode = ERROR_INVALID_PARAMETER;
376 && !(sCanCaps.dwFeatures & CAN_FEATURE_ERRFRAME)) {
377 dwErrCode = ERROR_INVALID_PARAMETER;
382 && !(sCanCaps.dwFeatures & CAN_FEATURE_EXTDATA)) {
383 dwErrCode = ERROR_INVALID_PARAMETER;
387 && !(sCanCaps.dwFeatures & CAN_FEATURE_FASTDATA)) {
388 dwErrCode = ERROR_INVALID_PARAMETER;
394 ixxat->dwTscClkFreq = sCanCaps.dwClockFreq;
396 ixxat->dwTscClkFreq = sCanCaps.dwTscClkFreq;
398 ixxat->dwTscDivisor = sCanCaps.dwTscDivisor;
401 dwErrCode = GetLastError();
402 goto error_set_bitrate;
409 error_canControlGetCaps:
410 p_canControlClose(ixxat->hCanCtl);
411 error_canControlOpen:
412 p_vciDeviceClose(ixxat->hDevice);
414 SetLastError(dwErrCode);
421 struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
423 p_canControlClose(ixxat->hCanCtl);
424 p_vciDeviceClose(ixxat->hDevice);
429 int nominal,
int data)
431 HRESULT hResult = VCI_OK;
434 if ((hResult = p_vciEnumDeviceOpen(&hEnum)) != VCI_OK) {
435 SetLastError(io_ixxat_error(hResult));
439 VCIDEVICEINFO sInfo = { .VciObjectId = { .AsLuid = { 0, 0 } } };
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);
446 SetLastError(io_ixxat_error(hResult));
449 }
while (dwIndex-- > 0);
451 p_vciEnumDeviceClose(hEnum);
454 dwCanNo, flags, nominal, data);
459 int nominal,
int data)
465 dwErrCode = GetLastError();
470 ctrl, lpLuid, dwCanNo, flags, nominal, data);
472 dwErrCode = GetLastError();
480 io_ixxat_ctrl_free((
void *)ctrl);
482 SetLastError(dwErrCode);
490 io_ixxat_ctrl_fini(ctrl);
491 io_ixxat_ctrl_free((
void *)ctrl);
498 const struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
500 return ixxat->hCanCtl;
504 io_ixxat_chan_alloc(
void)
506 struct io_ixxat_chan *ixxat = malloc(
sizeof(*ixxat));
511 return &ixxat->chan_vptr;
515 io_ixxat_chan_free(
void *ptr)
518 free(io_ixxat_chan_from_chan(ptr));
523 int rxtimeo,
int txtimeo)
525 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
533 ixxat->dev_vptr = &io_ixxat_chan_dev_vtbl;
534 ixxat->chan_vptr = &io_ixxat_chan_vtbl;
541 ixxat->rxtimeo = rxtimeo;
542 ixxat->txtimeo = txtimeo;
545 ixxat->
exec, &io_ixxat_chan_read_task_func);
547 ixxat->
exec, &io_ixxat_chan_write_task_func);
550 InitializeCriticalSection(&ixxat->CriticalSection);
553 ixxat->hCanChn = NULL;
556 ixxat->dwTscClkFreq = 0;
557 ixxat->dwTscDivisor = 0;
558 ixxat->dwTimeOvr = 0;
561 ixxat->read_posted = 0;
562 ixxat->write_posted = 0;
567 ixxat->current_read = NULL;
568 ixxat->current_write = NULL;
578 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
582 io_ixxat_chan_svc_shutdown(&ixxat->svc);
586 p_canChannelActivate(ixxat->hCanChn, FALSE);
590 EnterCriticalSection(&ixxat->CriticalSection);
593 while (ixxat->read_posted || ixxat->write_posted) {
594 if (io_ixxat_chan_do_abort_tasks(ixxat))
596 LeaveCriticalSection(&ixxat->CriticalSection);
600 "io_ixxat_chan_fini() invoked with pending operations");
603 EnterCriticalSection(&ixxat->CriticalSection);
605 LeaveCriticalSection(&ixxat->CriticalSection);
610 p_canChannelClose(ixxat->hCanChn);
613 DeleteCriticalSection(&ixxat->CriticalSection);
624 dwErrCode = GetLastError();
629 io_ixxat_chan_init(chan, ctx, exec, rxtimeo, txtimeo);
631 dwErrCode = GetLastError();
639 io_ixxat_chan_free((
void *)chan);
641 SetLastError(dwErrCode);
649 io_ixxat_chan_fini(chan);
650 io_ixxat_chan_free((
void *)chan);
657 const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
660 EnterCriticalSection((LPCRITICAL_SECTION)&ixxat->CriticalSection);
662 HANDLE hCanChn = ixxat->hCanChn;
664 LeaveCriticalSection((LPCRITICAL_SECTION)&ixxat->CriticalSection);
671 UINT16 wRxFifoSize, UINT16 wTxFifoSize)
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);
677 wRxFifoSize = LELY_IO_IXXAT_RX_FIFO_SIZE;
679 wTxFifoSize = LELY_IO_IXXAT_TX_FIFO_SIZE;
684 HANDLE hCanChn = NULL;
686 if ((hResult = p_canChannelOpen(ixxat_ctrl->hDevice,
687 ixxat_ctrl->dwCanNo, FALSE, &hCanChn)) != VCI_OK) {
689 dwErrCode = io_ixxat_error(hResult);
690 goto error_canChannelOpen;
695 if ((hResult = p_canChannelInitialize(hCanChn, wRxFifoSize, 1,
696 wTxFifoSize, 1)) != VCI_OK) {
698 if ((hResult = p_canChannelInitialize(hCanChn, wRxFifoSize, 1,
699 wTxFifoSize, 1, 0, CAN_FILTER_PASS)) != VCI_OK) {
702 dwErrCode = io_ixxat_error(hResult);
703 goto error_canChannelInitialize;
706 if ((hResult = p_canChannelActivate(hCanChn, TRUE)) != VCI_OK) {
707 dwErrCode = io_ixxat_error(hResult);
708 goto error_canChannelActivate;
711 hCanChn = io_ixxat_chan_set_handle(ixxat_chan, hCanChn,
712 ixxat_ctrl->flags, ixxat_ctrl->dwTscClkFreq,
713 ixxat_ctrl->dwTscDivisor);
715 p_canChannelClose(hCanChn);
719 error_canChannelActivate:
720 error_canChannelInitialize:
721 p_canChannelClose(hCanChn);
722 error_canChannelOpen:
723 SetLastError(dwErrCode);
731 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
736 SetLastError(ERROR_INVALID_HANDLE);
741 CANCHANSTATUS sStatus;
743 CANCHANSTATUS2 sStatus;
745 if ((hResult = p_canChannelGetStatus(hCanChn, &sStatus)) != VCI_OK) {
746 SetLastError(io_ixxat_error(hResult));
751 if (sStatus.sLineStatus.bOpMode & CAN_OPMODE_ERRFRAME)
754 if (sStatus.sLineStatus.bExMode & CAN_EXMODE_EXTDATA)
756 if (sStatus.sLineStatus.bExMode & CAN_EXMODE_FASTDATA)
760 if (!sStatus.fActivated
761 && (hResult = p_canChannelActivate(hCanChn, TRUE))
763 SetLastError(io_ixxat_error(hResult));
767 hCanChn = io_ixxat_chan_set_handle(
768 ixxat, hCanChn, flags, dwTscClkFreq, dwTscDivisor);
770 p_canChannelClose(hCanChn);
778 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
780 return io_ixxat_chan_set_handle(ixxat, NULL, 0, 0, 0);
794 HRESULT hResult = p_canChannelClose(hCanChn);
795 if (hResult != VCI_OK) {
796 SetLastError(io_ixxat_error(hResult));
804 io_ixxat_read(HANDLE hCanChn,
struct can_msg *msg,
struct can_err *err,
805 PUINT32 pdwTime, PUINT32 pdwTimeOvr,
int timeout)
811 SetLastError(ERROR_INVALID_HANDLE);
816 CANMSG CanMsg = { .dwMsgId = 0 };
818 CANMSG2 CanMsg = { .dwMsgId = 0 };
821 DWORD dwTimeout = timeout < 0 ? INFINITE : (DWORD)timeout;
823 HRESULT hResult = p_canChannelReadMessage(
824 hCanChn, dwTimeout, &CanMsg);
825 if (hResult != VCI_OK) {
826 SetLastError(io_ixxat_error(hResult));
829 type = CanMsg.uMsgInfo.Bits.type;
830 if (type == CAN_MSGTYPE_DATA || type == CAN_MSGTYPE_ERROR
831 || type == CAN_MSGTYPE_STATUS) {
834 if (type == CAN_MSGTYPE_TIMEOVR && pdwTimeOvr)
837 *pdwTimeOvr += CanMsg.dwMsgId;
838 if (dwTimeout != INFINITE) {
839 SetLastError(ERROR_TIMEOUT);
846 if (type == CAN_MSGTYPE_ERROR) {
850 switch (CanMsg.abData[0]) {
856 default: error |= LELY_IO_CAN_ERROR_OTHER;
break;
859 enum can_state state = io_ixxat_state(CanMsg.abData[1]);
865 }
else if (type == CAN_MSGTYPE_STATUS) {
869 err->
state = io_ixxat_state(CanMsg.abData[0]);
871 assert(type == CAN_MSGTYPE_DATA);
874 if (CanMsg.uMsgInfo.Bits.ext) {
880 if (CanMsg.uMsgInfo.Bits.rtr)
883 if (CanMsg.uMsgInfo.Bits.edl)
885 if (CanMsg.uMsgInfo.Bits.fdr)
887 if (CanMsg.uMsgInfo.Bits.esi)
891 if (CanMsg.uMsgInfo.Bits.edl) {
892 if (CanMsg.uMsgInfo.Bits.dlc <= 8) {
893 msg->
len = CanMsg.uMsgInfo.Bits.dlc;
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;
907 msg->
len = CanMsg.uMsgInfo.Bits.dlc;
908 memcpy(msg->
data, CanMsg.abData, msg->
len);
912 *pdwTime = CanMsg.dwTime;
918 io_ixxat_write(HANDLE hCanChn,
const struct can_msg *msg,
int timeout)
923 SetLastError(ERROR_INVALID_HANDLE);
928 CANMSG CanMsg = { .dwMsgId = 0 };
930 CANMSG2 CanMsg = { .dwMsgId = 0 };
934 CanMsg.uMsgInfo.Bits.ext = 1;
938 CanMsg.uMsgInfo.Bits.type = CAN_MSGTYPE_DATA;
940 CanMsg.uMsgInfo.Bits.rtr = 1;
943 CanMsg.uMsgInfo.Bits.edl = 1;
945 CanMsg.uMsgInfo.Bits.fdr = 1;
947 CanMsg.uMsgInfo.Bits.esi = 1;
954 CanMsg.uMsgInfo.Bits.dlc =
len;
956 CanMsg.uMsgInfo.Bits.dlc = 0x9;
958 CanMsg.uMsgInfo.Bits.dlc = 0xa;
960 CanMsg.uMsgInfo.Bits.dlc = 0xb;
962 CanMsg.uMsgInfo.Bits.dlc = 0xc;
964 CanMsg.uMsgInfo.Bits.dlc = 0xd;
966 CanMsg.uMsgInfo.Bits.dlc = 0xe;
968 CanMsg.uMsgInfo.Bits.dlc = 0xf;
972 memcpy(CanMsg.abData, msg->
data,
len);
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));
985 io_ixxat_error(HRESULT hResult)
987 if (GETSEVERITY(hResult) != SEV_ERROR)
990 switch (GETSCODE(hResult)) {
992 return ERROR_UNEXP_NET_ERR;
994 return ERROR_CALL_NOT_IMPLEMENTED;
996 return ERROR_NOT_ENOUGH_MEMORY;
998 return ERROR_BAD_ARGUMENTS;
1000 #ifndef ERROR_NOINTERFACE
1001 #define ERROR_NOINTERFACE 632
1003 return ERROR_NOINTERFACE;
1005 return ERROR_INVALID_ADDRESS;
1007 return ERROR_INVALID_HANDLE;
1009 return ERROR_OPERATION_ABORTED;
1011 return ERROR_GEN_FAILURE;
1013 return ERROR_ACCESS_DENIED;
1015 return ERROR_TIMEOUT;
1019 return ERROR_IO_PENDING;
1021 return ERROR_NO_DATA;
1023 return ERROR_NO_MORE_ITEMS;
1025 #ifndef PEERDIST_ERROR_NOT_INITIALIZED
1026 #define PEERDIST_ERROR_NOT_INITIALIZED 4054
1028 return PEERDIST_ERROR_NOT_INITIALIZED;
1030 #ifndef PEERDIST_ERROR_ALREADY_INITIALIZED
1031 #define PEERDIST_ERROR_ALREADY_INITIALIZED 4055
1033 return PEERDIST_ERROR_ALREADY_INITIALIZED;
1038 return ERROR_BUFFER_OVERFLOW;
1040 #ifndef PEERDIST_ERROR_INVALIDATED
1041 #define PEERDIST_ERROR_INVALIDATED 4057
1043 return PEERDIST_ERROR_INVALIDATED;
1045 return ERROR_ALREADY_EXISTS;
1047 return ERROR_INVALID_INDEX;
1049 return ERROR_HANDLE_EOF;
1051 return ERROR_GRACEFUL_DISCONNECT;
1053 #ifndef PEERDIST_ERROR_VERSION_UNSUPPORTED
1054 #define PEERDIST_ERROR_VERSION_UNSUPPORTED 4062
1056 return PEERDIST_ERROR_VERSION_UNSUPPORTED;
1060 #ifndef PEERDIST_ERROR_NOT_LICENSED
1061 #define PEERDIST_ERROR_NOT_LICENSED 4064
1063 return PEERDIST_ERROR_NOT_LICENSED;
1065 return ERROR_LICENSE_QUOTA_EXCEEDED;
1067 return ERROR_INVALID_PARAMETER;
1069 return ERROR_DEVICE_IN_USE;
1071 return ERROR_DEV_NOT_EXIST;
1073 return ERROR_NOT_CONNECTED;
1075 return ERROR_NOT_READY;
1077 return ERROR_BAD_DEV_TYPE;
1079 return ERROR_NOT_SUPPORTED;
1081 return ERROR_ALREADY_ASSIGNED;
1083 return ERROR_NOT_FOUND;
1085 return ERROR_INVALID_LEVEL;
1087 return PEERDIST_ERROR_VERSION_UNSUPPORTED;
1089 return ERROR_LUIDS_EXHAUSTED;
1090 default:
return ERROR_UNEXP_NET_ERR;
1095 io_ixxat_state(UINT32 dwStatus)
1097 if (dwStatus & CAN_STATUS_BUSOFF)
1099 if (dwStatus & CAN_STATUS_ERRLIM)
1104 static struct timespec
1105 io_ixxat_time(UINT64 qwTime, UINT32 dwTscClkFreq, UINT32 dwTscDivisor)
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;
1120 struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1122 HRESULT hResult = p_canControlStart(ixxat->hCanCtl, FALSE);
1123 if (hResult != VCI_OK) {
1124 SetLastError(io_ixxat_error(hResult));
1133 const struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1136 CANLINESTATUS sStatus;
1138 CANLINESTATUS2 sStatus;
1140 HRESULT hResult = p_canControlGetStatus(ixxat->hCanCtl, &sStatus);
1141 if (hResult != VCI_OK) {
1142 SetLastError(io_ixxat_error(hResult));
1145 return !!(sStatus.dwStatus & CAN_STATUS_ININIT);
1151 struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1153 HRESULT hResult = p_canControlStart(ixxat->hCanCtl, TRUE);
1154 if (hResult != VCI_OK) {
1155 SetLastError(io_ixxat_error(hResult));
1162 io_ixxat_ctrl_get_bitrate(
const io_can_ctrl_t *ctrl,
int *pnominal,
int *pdata)
1164 struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1167 CANLINESTATUS sStatus;
1169 CANLINESTATUS2 sStatus;
1171 HRESULT hResult = p_canControlGetStatus(ixxat->hCanCtl, &sStatus);
1172 if (hResult != VCI_OK) {
1173 SetLastError(io_ixxat_error(hResult));
1179 UINT8 bBtr0 = sStatus.bBtReg0;
1180 UINT8 bBtr1 = sStatus.bBtReg1;
1181 if (bBtr0 == CAN_BT0_5KB && bBtr1 == CAN_BT1_5KB) {
1183 }
else if (bBtr0 == CAN_BT0_10KB && bBtr1 == CAN_BT1_10KB) {
1185 }
else if (bBtr0 == CAN_BT0_20KB && bBtr1 == CAN_BT1_20KB) {
1187 }
else if (bBtr0 == CAN_BT0_50KB && bBtr1 == CAN_BT1_50KB) {
1189 }
else if (bBtr0 == CAN_BT0_100KB && bBtr1 == CAN_BT1_100KB) {
1191 }
else if (bBtr0 == CAN_BT0_125KB && bBtr1 == CAN_BT1_125KB) {
1193 }
else if (bBtr0 == CAN_BT0_250KB && bBtr1 == CAN_BT1_250KB) {
1195 }
else if (bBtr0 == CAN_BT0_500KB && bBtr1 == CAN_BT1_500KB) {
1197 }
else if (bBtr0 == CAN_BT0_800KB && bBtr1 == CAN_BT1_800KB) {
1199 }
else if (bBtr0 == CAN_BT0_1000KB && bBtr1 == CAN_BT1_1000KB) {
1200 *pnominal = 1000000;
1209 *pnominal = sStatus.sBtpSdr.dwBPS;
1211 *pdata = (sStatus.bExMode & CAN_FEATURE_FASTDATA)
1212 ? sStatus.sBtpFdr.dwBPS
1220 io_ixxat_ctrl_set_bitrate(
io_can_ctrl_t *ctrl,
int nominal,
int data)
1222 struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1227 UINT8 bOpMode = CAN_OPMODE_STANDARD | CAN_OPMODE_EXTENDED;
1229 bOpMode |= CAN_OPMODE_ERRFRAME;
1235 bBtr0 = CAN_BT0_5KB;
1236 bBtr1 = CAN_BT1_5KB;
1239 bBtr0 = CAN_BT0_10KB;
1240 bBtr1 = CAN_BT1_10KB;
1243 bBtr0 = CAN_BT0_20KB;
1244 bBtr1 = CAN_BT1_20KB;
1247 bBtr0 = CAN_BT0_50KB;
1248 bBtr1 = CAN_BT1_50KB;
1251 bBtr0 = CAN_BT0_100KB;
1252 bBtr1 = CAN_BT1_100KB;
1255 bBtr0 = CAN_BT0_125KB;
1256 bBtr1 = CAN_BT1_125KB;
1259 bBtr0 = CAN_BT0_250KB;
1260 bBtr1 = CAN_BT1_250KB;
1263 bBtr0 = CAN_BT0_500KB;
1264 bBtr1 = CAN_BT1_500KB;
1267 bBtr0 = CAN_BT0_800KB;
1268 bBtr1 = CAN_BT1_800KB;
1271 bBtr0 = CAN_BT0_1000KB;
1272 bBtr1 = CAN_BT1_1000KB;
1274 default: SetLastError(ERROR_INVALID_PARAMETER);
return -1;
1276 HRESULT hResult = p_canControlInitialize(
1277 ixxat->hCanCtl, bOpMode, bBtr0, bBtr1);
1279 UINT8 bExMode = CAN_EXMODE_DISABLED;
1281 bExMode |= CAN_EXMODE_EXTDATA;
1283 bExMode |= CAN_EXMODE_FASTDATA;
1284 CANBTP sBtpSDR, sBtpFDR;
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;
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;
1313 HRESULT hResult = p_canControlInitialize(ixxat->hCanCtl, bOpMode,
1314 bExMode, CAN_FILTER_PASS, CAN_FILTER_PASS, 0, 0,
1318 if (hResult != VCI_OK) {
1319 SetLastError(io_ixxat_error(hResult));
1329 const struct io_ixxat_ctrl *ixxat = io_ixxat_ctrl_from_ctrl(ctrl);
1332 CANLINESTATUS sStatus;
1334 CANLINESTATUS2 sStatus;
1336 HRESULT hResult = p_canControlGetStatus(ixxat->hCanCtl, &sStatus);
1337 if (hResult != VCI_OK) {
1338 SetLastError(io_ixxat_error(hResult));
1342 return io_ixxat_state(sStatus.dwStatus);
1345 static inline struct io_ixxat_ctrl *
1350 return structof(ctrl,
struct io_ixxat_ctrl, ctrl_vptr);
1354 io_ixxat_chan_dev_get_ctx(
const io_dev_t *dev)
1356 const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1362 io_ixxat_chan_dev_get_exec(
const io_dev_t *dev)
1364 const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1372 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1374 struct sllist read_queue, write_queue;
1378 io_ixxat_chan_pop(ixxat, &read_queue, &write_queue, task);
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;
1390 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_dev(dev);
1395 io_ixxat_chan_pop(ixxat, &queue, &queue, task);
1403 const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1405 return &ixxat->dev_vptr;
1411 const struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1413 #if !LELY_NO_THREADS
1414 EnterCriticalSection((CRITICAL_SECTION *)&ixxat->CriticalSection);
1416 int flags = ixxat->flags;
1417 #if !LELY_NO_THREADS
1418 LeaveCriticalSection((CRITICAL_SECTION *)&ixxat->CriticalSection);
1425 struct can_err *err,
struct timespec *tp,
int timeout)
1427 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1429 return io_ixxat_chan_read_impl(ixxat, msg, err, tp, timeout);
1435 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1440 task->
exec = ixxat->exec;
1444 #if !LELY_NO_THREADS
1445 EnterCriticalSection(&ixxat->CriticalSection);
1447 if (ixxat->shutdown) {
1448 #if !LELY_NO_THREADS
1449 LeaveCriticalSection(&ixxat->CriticalSection);
1451 io_can_chan_read_post(read, -1, ERROR_OPERATION_ABORTED);
1453 int post_read = !ixxat->read_posted
1457 ixxat->read_posted = 1;
1458 #if !LELY_NO_THREADS
1459 LeaveCriticalSection(&ixxat->CriticalSection);
1461 assert(ixxat->read_task.exec);
1463 ev_exec_post(ixxat->read_task.exec, &ixxat->read_task);
1470 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1472 return io_ixxat_chan_write_impl(ixxat, msg, timeout);
1478 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_chan(chan);
1492 task->
exec = ixxat->exec;
1496 #if !LELY_NO_THREADS
1497 EnterCriticalSection(&ixxat->CriticalSection);
1499 if (ixxat->shutdown) {
1500 #if !LELY_NO_THREADS
1501 LeaveCriticalSection(&ixxat->CriticalSection);
1503 io_can_chan_write_post(write, ERROR_OPERATION_ABORTED);
1505 }
else if ((flags & ixxat->flags) != flags) {
1506 #if !LELY_NO_THREADS
1507 LeaveCriticalSection(&ixxat->CriticalSection);
1509 io_can_chan_write_post(write, ERROR_INVALID_PARAMETER);
1512 int post_write = !ixxat->write_posted
1516 ixxat->write_posted = 1;
1517 #if !LELY_NO_THREADS
1518 LeaveCriticalSection(&ixxat->CriticalSection);
1520 assert(ixxat->write_task.exec);
1523 &ixxat->write_task);
1528 io_ixxat_chan_svc_shutdown(
struct io_svc *svc)
1530 struct io_ixxat_chan *ixxat = io_ixxat_chan_from_svc(svc);
1533 #if !LELY_NO_THREADS
1534 EnterCriticalSection(&ixxat->CriticalSection);
1536 int shutdown = !ixxat->shutdown;
1537 ixxat->shutdown = 1;
1541 io_ixxat_chan_do_abort_tasks(ixxat);
1542 #if !LELY_NO_THREADS
1543 LeaveCriticalSection(&ixxat->CriticalSection);
1548 io_ixxat_chan_dev_cancel(dev, NULL);
1552 io_ixxat_chan_read_task_func(
struct ev_task *task)
1555 struct io_ixxat_chan *ixxat =
1556 structof(task,
struct io_ixxat_chan, read_task);
1558 DWORD dwErrCode = GetLastError();
1560 HANDLE hCanChn = NULL;
1563 #if !LELY_NO_THREADS
1564 EnterCriticalSection(&ixxat->CriticalSection);
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;
1573 #if !LELY_NO_THREADS
1574 LeaveCriticalSection(&ixxat->CriticalSection);
1580 UINT32 dwTimeOvr = 0;
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);
1590 errc = GetLastError();
1591 if (errc == ERROR_TIMEOUT)
1596 #if !LELY_NO_THREADS
1597 EnterCriticalSection(&ixxat->CriticalSection);
1599 if (hCanChn == ixxat->hCanChn)
1600 ixxat->dwTimeOvr += dwTimeOvr;
1603 if (result == -1 && errc == ERROR_RETRY
1604 && read == ixxat->current_read) {
1609 ixxat->current_read = NULL;
1610 int post_read = ixxat->read_posted =
1612 #if !LELY_NO_THREADS
1613 LeaveCriticalSection(&ixxat->CriticalSection);
1616 if (result == -1 && errc == ERROR_RETRY)
1617 errc = ERROR_OPERATION_ABORTED;
1618 io_can_chan_read_post(read, result, errc);
1622 ev_exec_post(ixxat->read_task.exec, &ixxat->read_task);
1624 SetLastError(dwErrCode);
1628 io_ixxat_chan_write_task_func(
struct ev_task *
task)
1631 struct io_ixxat_chan *ixxat =
1632 structof(task,
struct io_ixxat_chan, write_task);
1634 DWORD dwErrCode = GetLastError();
1636 HANDLE hCanChn = NULL;
1639 #if !LELY_NO_THREADS
1640 EnterCriticalSection(&ixxat->CriticalSection);
1642 if (!ixxat->shutdown)
1643 hCanChn = ixxat->hCanChn;
1645 write = ixxat->current_write =
1647 #if !LELY_NO_THREADS
1648 LeaveCriticalSection(&ixxat->CriticalSection);
1654 result = io_ixxat_write(hCanChn, write->
msg, ixxat->txtimeo);
1656 errc = GetLastError();
1657 if (
errc == ERROR_TIMEOUT)
1662 #if !LELY_NO_THREADS
1663 EnterCriticalSection(&ixxat->CriticalSection);
1667 if (result == -1 &&
errc == ERROR_RETRY
1668 && write == ixxat->current_write) {
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);
1681 if (result == -1 &&
errc == ERROR_RETRY)
1682 errc = ERROR_OPERATION_ABORTED;
1683 io_can_chan_write_post(write,
errc);
1687 ev_exec_post(ixxat->write_task.exec, &ixxat->write_task);
1689 SetLastError(dwErrCode);
1692 static inline struct io_ixxat_chan *
1693 io_ixxat_chan_from_dev(
const io_dev_t *dev)
1697 return structof(dev,
struct io_ixxat_chan, dev_vptr);
1700 static inline struct io_ixxat_chan *
1705 return structof(chan,
struct io_ixxat_chan, chan_vptr);
1708 static inline struct io_ixxat_chan *
1709 io_ixxat_chan_from_svc(
const struct io_svc *svc)
1713 return structof(svc,
struct io_ixxat_chan, svc);
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)
1722 #if !LELY_NO_THREADS
1723 EnterCriticalSection(&ixxat->CriticalSection);
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);
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);
1742 #if !LELY_NO_THREADS
1743 EnterCriticalSection(&ixxat->CriticalSection);
1745 if (hCanChn == ixxat->hCanChn)
1746 ixxat->dwTimeOvr += dwTimeOvr;
1747 #if !LELY_NO_THREADS
1748 LeaveCriticalSection(&ixxat->CriticalSection);
1755 io_ixxat_chan_write_impl(
struct io_ixxat_chan *ixxat,
const struct can_msg *msg,
1769 #if !LELY_NO_THREADS
1770 EnterCriticalSection(&ixxat->CriticalSection);
1773 if ((flags & ixxat->flags) != flags) {
1774 #if !LELY_NO_THREADS
1775 LeaveCriticalSection(&ixxat->CriticalSection);
1777 SetLastError(ERROR_INVALID_PARAMETER);
1781 HANDLE hCanChn = ixxat->hCanChn;
1782 #if !LELY_NO_THREADS
1783 LeaveCriticalSection(&ixxat->CriticalSection);
1786 return io_ixxat_write(hCanChn, msg, timeout);
1790 io_ixxat_chan_pop(
struct io_ixxat_chan *ixxat,
struct sllist *read_queue,
1795 assert(write_queue);
1797 #if !LELY_NO_THREADS
1798 EnterCriticalSection(&ixxat->CriticalSection);
1803 }
else if (
sllist_remove(&ixxat->read_queue, &task->_node)) {
1805 }
else if (
sllist_remove(&ixxat->write_queue, &task->_node)) {
1808 #if !LELY_NO_THREADS
1809 LeaveCriticalSection(&ixxat->CriticalSection);
1814 io_ixxat_chan_do_abort_tasks(
struct io_ixxat_chan *ixxat)
1822 if (ixxat->read_posted &&
ev_exec_abort(ixxat->read_task.exec,
1823 &ixxat->read_task)) {
1825 ixxat->read_posted = 0;
1831 if (ixxat->write_posted &&
ev_exec_abort(ixxat->write_task.exec,
1832 &ixxat->write_task)) {
1834 ixxat->write_posted = 0;
1842 io_ixxat_chan_set_handle(
struct io_ixxat_chan *ixxat, HANDLE hCanChn,
int flags,
1843 UINT32 dwTscClkFreq, UINT32 dwTscDivisor)
1846 assert(!(flags & ~IO_CAN_BUS_FLAG_MASK));
1848 struct sllist read_queue, write_queue;
1852 #if !LELY_NO_THREADS
1853 EnterCriticalSection(&ixxat->CriticalSection);
1856 HANDLE tmp = ixxat->hCanChn;
1857 ixxat->hCanChn = hCanChn;
1860 ixxat->flags = flags;
1861 ixxat->dwTscClkFreq = dwTscClkFreq;
1862 ixxat->dwTscDivisor = dwTscDivisor;
1863 ixxat->dwTimeOvr = 0;
1868 ixxat->current_read = NULL;
1869 ixxat->current_write = NULL;
1871 #if !LELY_NO_THREADS
1872 LeaveCriticalSection(&ixxat->CriticalSection);
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);
can_error
The error flags of a CAN bus, which are not mutually exclusive.
@ CAN_ERROR_FORM
A form error.
@ CAN_ERROR_BIT
A single bit error.
@ CAN_ERROR_STUFF
A bit stuffing error.
@ CAN_ERROR_ACK
An acknowledgment error.
@ CAN_ERROR_CRC
A CRC sequence error.
can_state
The states of a CAN node, depending on the TX/RX error count.
@ CAN_STATE_BUSOFF
The bus off state (TX/RX error count >= 256).
@ CAN_STATE_PASSIVE
The error passive state (TX/RX error count < 256).
@ CAN_STATE_ACTIVE
The error active state (TX/RX error count < 128).
@ CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
@ CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
@ CAN_FLAG_FDF
The FD Format (FDF) flag, formerly known as Extended Data Length (EDL).
@ CAN_FLAG_BRS
The Bit Rate Switch (BRS) flag (only available in CAN FD format frames).
@ CAN_FLAG_ESI
The Error State Indicator (ESI) flag (only available in CAN FD format frames).
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
#define CANFD_MAX_LEN
The maximum number of bytes in the payload of a CAN FD format frame.
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
#define CAN_MSG_INIT
The static initializer for can_msg.
This header file is part of the I/O library; it contains the I/O context and service declarations.
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
This header file is part of the utilities library; it contains the diagnostic declarations.
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
This header file is part of the utilities library; it contains the byte order (endianness) function d...
uint_least32_t htole32(uint_least32_t x)
Converts a 32-bit unsigned integer from host to little-endian byte order.
uint_least32_t letoh32(uint_least32_t x)
Converts a 32-bit unsigned integer from little-endian to host byte order.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
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...
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
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.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
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.
const struct io_can_chan_vtbl *const io_can_chan_t
An abstract CAN channel.
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.
const struct io_can_ctrl_vtbl *const io_can_ctrl_t
An abstract CAN controller.
int io_can_ctrl_set_bitrate(io_can_ctrl_t *ctrl, int nominal, int data)
Configures the bitrate(s) of a CAN controller.
@ IO_CAN_BUS_FLAG_BRS
Bit Rate Switch support is enabled.
@ IO_CAN_BUS_FLAG_FDF
FD Format (formerly Extended Data Length) support is enabled.
@ IO_CAN_BUS_FLAG_ERR
Reception of error frames is enabled.
#define LELY_IO_RX_TIMEOUT
The default timeout (in milliseconds) for I/O read operations.
#define LELY_IO_TX_TIMEOUT
The default timeout (in milliseconds) for I/O write operations.
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
#define MIN(a, b)
Returns the minimum of a and b.
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
This header file is part of the I/O library; it contains the IXXAT CAN bus declarations for Windows.
HANDLE io_ixxat_ctrl_get_handle(const io_can_ctrl_t *ctrl)
Returns the native handle of the CAN controller.
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.
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).
void io_ixxat_fini(void)
Frees the "vcinpl.dll" or "vcinpl2.dll" library and terminates the availability of the IXXAT function...
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.
int io_ixxat_chan_open(io_can_chan_t *chan, const io_can_ctrl_t *ctrl, UINT16 wRxFifoSize, UINT16 wTxFifoSize)
Opens a CAN channel.
int io_ixxat_chan_close(io_can_chan_t *chan)
Closes a CAN channel.
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.
void io_ixxat_ctrl_destroy(io_can_ctrl_t *ctrl)
Destroys an IXXAT CAN controller.
int io_ixxat_init(void)
Loads the "vcinpl.dll" or "vcinpl2.dll" library and makes the IXXAT functions available for use.
void io_ixxat_chan_destroy(io_can_chan_t *chan)
Destroys an IXXAT CAN channel.
int io_ixxat_chan_is_open(const io_can_chan_t *chan)
Returns 1 is the CAN channel is open and 0 if not.
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.
HANDLE io_ixxat_chan_release(io_can_chan_t *chan)
Dissociates and returns the native handle from a CAN channel.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
This is the internal header file of the Windows-specific I/O declarations.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
int state
The state of the CAN node (one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE or CAN_STATE_BUSOFF).
int error
The error flags of the CAN bus (any combination of CAN_ERROR_BIT, CAN_ERROR_STUFF,...
A CAN or CAN FD format frame.
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
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...
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
A CAN channel read operation.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
struct timespec * tp
The address at which to store the system time at which the CAN frame or CAN error frame was received.
struct can_msg * msg
The address at which to store the CAN frame.
struct can_err * err
The address at which to store the CAN error frame.
A CAN channel write operation.
const struct can_msg * msg
A pointer to the CAN frame to be written.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the write operation.
int errc
The error number, obtained as if by get_errc(), if an error occurred or the operation was canceled.
The virtual table of an I/O service.
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.
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.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.