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);
1881 #endif // _WIN32 && LELY_HAVE_IXXAT