|
13 | 13 | from can import CanError, BusABC |
14 | 14 | from can import Message |
15 | 15 | from can.interfaces.ixxat import constants, structures |
16 | | - |
| 16 | +from can.broadcastmanager import (LimitedDurationCyclicSendTaskABC, |
| 17 | + RestartableCyclicTaskABC) |
17 | 18 | from can.ctypesutil import CLibrary, HANDLE, PHANDLE |
18 | 19 |
|
19 | 20 | from .constants import VCI_MAX_ERRSTRLEN |
@@ -176,6 +177,22 @@ def __check_status(result, function, arguments): |
176 | 177 | _canlib.map_symbol("canControlAddFilterIds", ctypes.c_long, (HANDLE, ctypes.c_int, ctypes.c_uint32, ctypes.c_uint32), __check_status) |
177 | 178 | #EXTERN_C HRESULT canControlRemFilterIds (HANDLE hControl, BOOL fExtendend, UINT32 dwCode, UINT32 dwMask ); |
178 | 179 | _canlib.map_symbol("canControlRemFilterIds", ctypes.c_long, (HANDLE, ctypes.c_int, ctypes.c_uint32, ctypes.c_uint32), __check_status) |
| 180 | + #EXTERN_C HRESULT canSchedulerOpen (HANDLE hDevice, UINT32 dwCanNo, PHANDLE phScheduler ); |
| 181 | + _canlib.map_symbol("canSchedulerOpen", ctypes.c_long, (HANDLE, ctypes.c_uint32, PHANDLE), __check_status) |
| 182 | + #EXTERN_C HRESULT canSchedulerClose (HANDLE hScheduler ); |
| 183 | + _canlib.map_symbol("canSchedulerClose", ctypes.c_long, (HANDLE, ), __check_status) |
| 184 | + #EXTERN_C HRESULT canSchedulerGetCaps (HANDLE hScheduler, PCANCAPABILITIES pCaps ); |
| 185 | + _canlib.map_symbol("canSchedulerGetCaps", ctypes.c_long, (HANDLE, structures.PCANCAPABILITIES), __check_status) |
| 186 | + #EXTERN_C HRESULT canSchedulerActivate ( HANDLE hScheduler, BOOL fEnable ); |
| 187 | + _canlib.map_symbol("canSchedulerActivate", ctypes.c_long, (HANDLE, ctypes.c_int), __check_status) |
| 188 | + #EXTERN_C HRESULT canSchedulerAddMessage (HANDLE hScheduler, PCANCYCLICTXMSG pMessage, PUINT32 pdwIndex ); |
| 189 | + _canlib.map_symbol("canSchedulerAddMessage", ctypes.c_long, (HANDLE, structures.PCANCYCLICTXMSG, ctypes.POINTER(ctypes.c_uint32)), __check_status) |
| 190 | + #EXTERN_C HRESULT canSchedulerRemMessage (HANDLE hScheduler, UINT32 dwIndex ); |
| 191 | + _canlib.map_symbol("canSchedulerRemMessage", ctypes.c_long, (HANDLE, ctypes.c_uint32), __check_status) |
| 192 | + #EXTERN_C HRESULT canSchedulerStartMessage (HANDLE hScheduler, UINT32 dwIndex, UINT16 dwCount ); |
| 193 | + _canlib.map_symbol("canSchedulerStartMessage", ctypes.c_long, (HANDLE, ctypes.c_uint32, ctypes.c_uint16), __check_status) |
| 194 | + #EXTERN_C HRESULT canSchedulerStopMessage (HANDLE hScheduler, UINT32 dwIndex ); |
| 195 | + _canlib.map_symbol("canSchedulerStopMessage", ctypes.c_long, (HANDLE, ctypes.c_uint32), __check_status) |
179 | 196 | _canlib.vciInitialize() |
180 | 197 | except AttributeError: |
181 | 198 | # In case _canlib == None meaning we're not on win32/no lib found |
@@ -337,6 +354,11 @@ def __init__(self, channel, can_filters=None, **config): |
337 | 354 | # Start the CAN controller. Messages will be forwarded to the channel |
338 | 355 | _canlib.canControlStart(self._control_handle, constants.TRUE) |
339 | 356 |
|
| 357 | + # For cyclic transmit list. Set when .send_periodic() is first called |
| 358 | + self._scheduler = None |
| 359 | + self._scheduler_resolution = None |
| 360 | + self.channel = channel |
| 361 | + |
340 | 362 | # Usually you get back 3 messages like "CAN initialized" ecc... |
341 | 363 | # Filter them out with low timeout |
342 | 364 | while True: |
@@ -460,8 +482,67 @@ def send(self, msg, timeout=None): |
460 | 482 | else: |
461 | 483 | _canlib.canChannelPostMessage(self._channel_handle, message) |
462 | 484 |
|
| 485 | + def send_periodic(self, msg, period, duration=None): |
| 486 | + """Send a message using built-in cyclic transmit list functionality.""" |
| 487 | + if self._scheduler is None: |
| 488 | + self._scheduler = HANDLE() |
| 489 | + _canlib.canSchedulerOpen(self._device_handle, self.channel, |
| 490 | + self._scheduler) |
| 491 | + caps = structures.CANCAPABILITIES() |
| 492 | + _canlib.canSchedulerGetCaps(self._scheduler, caps) |
| 493 | + self._scheduler_resolution = float(caps.dwClockFreq) / caps.dwCmsDivisor |
| 494 | + _canlib.canSchedulerActivate(self._scheduler, constants.TRUE) |
| 495 | + return CyclicSendTask(self._scheduler, msg, period, duration, |
| 496 | + self._scheduler_resolution) |
| 497 | + |
463 | 498 | def shutdown(self): |
| 499 | + if self._scheduler is not None: |
| 500 | + _canlib.canSchedulerClose(self._scheduler) |
464 | 501 | _canlib.canChannelClose(self._channel_handle) |
465 | 502 | _canlib.canControlStart(self._control_handle, constants.FALSE) |
466 | 503 | _canlib.canControlClose(self._control_handle) |
467 | 504 | _canlib.vciDeviceClose(self._device_handle) |
| 505 | + |
| 506 | + |
| 507 | +class CyclicSendTask(LimitedDurationCyclicSendTaskABC, |
| 508 | + RestartableCyclicTaskABC): |
| 509 | + """A message in the cyclic transmit list.""" |
| 510 | + |
| 511 | + def __init__(self, scheduler, msg, period, duration, resolution): |
| 512 | + super(CyclicSendTask, self).__init__(msg, period, duration) |
| 513 | + self._scheduler = scheduler |
| 514 | + self._index = None |
| 515 | + self._count = int(duration / period) if duration else 0 |
| 516 | + |
| 517 | + self._msg = structures.CANCYCLICTXMSG() |
| 518 | + self._msg.wCycleTime = int(round(period * resolution)) |
| 519 | + self._msg.dwMsgId = msg.arbitration_id |
| 520 | + self._msg.uMsgInfo.Bits.type = constants.CAN_MSGTYPE_DATA |
| 521 | + self._msg.uMsgInfo.Bits.ext = 1 if msg.id_type else 0 |
| 522 | + self._msg.uMsgInfo.Bits.rtr = 1 if msg.is_remote_frame else 0 |
| 523 | + self._msg.uMsgInfo.Bits.dlc = msg.dlc |
| 524 | + for i, b in enumerate(msg.data): |
| 525 | + self._msg.abData[i] = b |
| 526 | + self.start() |
| 527 | + |
| 528 | + def start(self): |
| 529 | + """Start transmitting message (add to list if needed).""" |
| 530 | + if self._index is None: |
| 531 | + self._index = ctypes.c_uint32() |
| 532 | + _canlib.canSchedulerAddMessage(self._scheduler, |
| 533 | + self._msg, |
| 534 | + self._index) |
| 535 | + _canlib.canSchedulerStartMessage(self._scheduler, |
| 536 | + self._index, |
| 537 | + self._count) |
| 538 | + |
| 539 | + def pause(self): |
| 540 | + """Pause transmitting message (keep it in the list).""" |
| 541 | + _canlib.canSchedulerStopMessage(self._scheduler, self._index) |
| 542 | + |
| 543 | + def stop(self): |
| 544 | + """Stop transmitting message (remove from list).""" |
| 545 | + # Remove it completely instead of just stopping it to avoid filling up |
| 546 | + # the list with permanently stopped messages |
| 547 | + _canlib.canSchedulerRemMessage(self._scheduler, self._index) |
| 548 | + self._index = None |
0 commit comments