# coding: utf-8 from ctypes import Structure, POINTER, sizeof from ctypes import ( c_ubyte as BYTE, c_ushort as WORD, c_ulong as DWORD, c_long as BOOL, c_void_p as LPVOID, ) import os # Workaround for Unix based platforms to be able to load structures for testing, etc... if os.name == "nt": from ctypes import WINFUNCTYPE as FUNCTYPE else: from ctypes import CFUNCTYPE as FUNCTYPE from .constants import MsgFrameFormat class CanMsg(Structure): """ Structure of a CAN message. .. seealso:: :meth:`UcanServer.read_can_msg` :meth:`UcanServer.write_can_msg` :meth:`UcanServer.define_cyclic_can_msg` :meth:`UcanServer.read_cyclic_can_msg` """ _pack_ = 1 _fields_ = [ ("m_dwID", DWORD), # CAN Identifier ("m_bFF", BYTE), # CAN Frame Format (see enum :class:`MsgFrameFormat`) ("m_bDLC", BYTE), # CAN Data Length Code ("m_bData", BYTE * 8), # CAN Data (array of 8 bytes) ( "m_dwTime", DWORD, ), # Receive time stamp in ms (for transmit messages no meaning) ] def __init__(self, id=0, frame_format=MsgFrameFormat.MSG_FF_STD, data=None): data = [] if data is None else data super().__init__(id, frame_format, len(data), (BYTE * 8)(*data), 0) def __eq__(self, other): if not isinstance(other, CanMsg): return False return ( self.id == other.id and self.frame_format == other.frame_format and self.data == other.data ) @property def id(self): return self.m_dwID @id.setter def id(self, id): self.m_dwID = id @property def frame_format(self): return self.m_bFF @frame_format.setter def frame_format(self, frame_format): self.m_bFF = frame_format @property def data(self): return self.m_bData[: self.m_bDLC] @data.setter def data(self, data): self.m_bDLC = len(data) self.m_bData((BYTE * 8)(*data)) @property def time(self): return self.m_dwTime class Status(Structure): """ Structure with the error status of CAN and USB. Use this structure with the method :meth:`UcanServer.get_status` .. seealso:: :meth:`UcanServer.get_status` :meth:`UcanServer.get_can_status_message` """ _pack_ = 1 _fields_ = [ ("m_wCanStatus", WORD), # CAN error status (see enum :class:`CanStatus`) ("m_wUsbStatus", WORD), # USB error status (see enum :class:`UsbStatus`) ] def __eq__(self, other): if not isinstance(other, Status): return False return ( self.can_status == other.can_status and self.usb_status == other.usb_status ) @property def can_status(self): return self.m_wCanStatus @property def usb_status(self): return self.m_wUsbStatus class InitCanParam(Structure): """ Structure including initialisation parameters used internally in :meth:`UcanServer.init_can`. .. note:: This structure is only used internally. """ _pack_ = 1 _fields_ = [ ("m_dwSize", DWORD), # size of this structure (only used internally) ( "m_bMode", BYTE, ), # selects the mode of CAN controller (see enum :class:`Mode`) # Baudrate Registers for GW-001 or GW-002 ("m_bBTR0", BYTE), # Bus Timing Register 0 (see enum :class:`Baudrate`) ("m_bBTR1", BYTE), # Bus Timing Register 1 (see enum :class:`Baudrate`) ("m_bOCR", BYTE), # Output Control Register (see enum :class:`OutputControl`) ( "m_dwAMR", DWORD, ), # Acceptance Mask Register (see method :meth:`UcanServer.set_acceptance`) ( "m_dwACR", DWORD, ), # Acceptance Code Register (see method :meth:`UcanServer.set_acceptance`) ("m_dwBaudrate", DWORD), # Baudrate Register for all systec USB-CANmoduls # (see enum :class:`BaudrateEx`) ( "m_wNrOfRxBufferEntries", WORD, ), # number of receive buffer entries (default is 4096) ( "m_wNrOfTxBufferEntries", WORD, ), # number of transmit buffer entries (default is 4096) ] def __init__( self, mode, BTR, OCR, AMR, ACR, baudrate, rx_buffer_entries, tx_buffer_entries ): super().__init__( sizeof(InitCanParam), mode, BTR >> 8, BTR, OCR, AMR, ACR, baudrate, rx_buffer_entries, tx_buffer_entries, ) def __eq__(self, other): if not isinstance(other, InitCanParam): return False return ( self.mode == other.mode and self.BTR == other.BTR and self.OCR == other.OCR and self.baudrate == other.baudrate and self.rx_buffer_entries == other.rx_buffer_entries and self.tx_buffer_entries == other.tx_buffer_entries ) @property def mode(self): return self.m_bMode @mode.setter def mode(self, mode): self.m_bMode = mode @property def BTR(self): return self.m_bBTR0 << 8 | self.m_bBTR1 @BTR.setter def BTR(self, BTR): self.m_bBTR0, self.m_bBTR1 = BTR >> 8, BTR @property def OCR(self): return self.m_bOCR @OCR.setter def OCR(self, OCR): self.m_bOCR = OCR @property def baudrate(self): return self.m_dwBaudrate @baudrate.setter def baudrate(self, baudrate): self.m_dwBaudrate = baudrate @property def rx_buffer_entries(self): return self.m_wNrOfRxBufferEntries @rx_buffer_entries.setter def rx_buffer_entries(self, rx_buffer_entries): self.m_wNrOfRxBufferEntries = rx_buffer_entries @property def tx_buffer_entries(self): return self.m_wNrOfTxBufferEntries @tx_buffer_entries.setter def tx_buffer_entries(self, tx_buffer_entries): self.m_wNrOfTxBufferEntries = tx_buffer_entries class Handle(BYTE): pass class HardwareInfoEx(Structure): """ Structure including hardware information about the USB-CANmodul. This structure is used with the method :meth:`UcanServer.get_hardware_info`. .. seealso:: :meth:`UcanServer.get_hardware_info` """ _pack_ = 1 _fields_ = [ ("m_dwSize", DWORD), # size of this structure (only used internally) ("m_UcanHandle", Handle), # USB-CAN-Handle assigned by the DLL ("m_bDeviceNr", BYTE), # device number of the USB-CANmodul ("m_dwSerialNr", DWORD), # serial number from USB-CANmodul ("m_dwFwVersionEx", DWORD), # version of firmware ("m_dwProductCode", DWORD), # product code (see enum :class:`ProductCode`) # unique ID (available since V5.01) !!! m_dwSize must be >= HWINFO_SIZE_V2 ("m_dwUniqueId0", DWORD), ("m_dwUniqueId1", DWORD), ("m_dwUniqueId2", DWORD), ("m_dwUniqueId3", DWORD), ("m_dwFlags", DWORD), # additional flags ] def __init__(self): super(HardwareInfoEx, self).__init__(sizeof(HardwareInfoEx)) def __eq__(self, other): if not isinstance(other, HardwareInfoEx): return False return ( self.device_number == other.device_number and self.serial == other.serial and self.fw_version == other.fw_version and self.product_code == other.product_code and self.unique_id == other.unique_id and self.flags == other.flags ) @property def device_number(self): return self.m_bDeviceNr @property def serial(self): return self.m_dwSerialNr @property def fw_version(self): return self.m_dwFwVersionEx @property def product_code(self): return self.m_dwProductCode @property def unique_id(self): return ( self.m_dwUniqueId0, self.m_dwUniqueId1, self.m_dwUniqueId2, self.m_dwUniqueId3, ) @property def flags(self): return self.m_dwFlags # void PUBLIC UcanCallbackFktEx (Handle UcanHandle_p, DWORD dwEvent_p, # BYTE bChannel_p, void* pArg_p); CallbackFktEx = FUNCTYPE(None, Handle, DWORD, BYTE, LPVOID) class HardwareInitInfo(Structure): """ Structure including information about the enumeration of USB-CANmoduls. .. seealso:: :meth:`UcanServer.enumerate_hardware` .. note:: This structure is only used internally. """ _pack_ = 1 _fields_ = [ ("m_dwSize", DWORD), # size of this structure ( "m_fDoInitialize", BOOL, ), # specifies if the found module should be initialized by the DLL ("m_pUcanHandle", Handle), # pointer to variable receiving the USB-CAN-Handle ("m_fpCallbackFktEx", CallbackFktEx), # pointer to callback function ( "m_pCallbackArg", LPVOID, ), # pointer to user defined parameter for callback function ("m_fTryNext", BOOL), # specifies if a further module should be found ] class ChannelInfo(Structure): """ Structure including CAN channel information. This structure is used with the method :meth:`UcanServer.get_hardware_info`. .. seealso:: :meth:`UcanServer.get_hardware_info` """ _pack_ = 1 _fields_ = [ ("m_dwSize", DWORD), # size of this structure ("m_bMode", BYTE), # operation mode of CAN controller (see enum :class:`Mode`) ("m_bBTR0", BYTE), # Bus Timing Register 0 (see enum :class:`Baudrate`) ("m_bBTR1", BYTE), # Bus Timing Register 1 (see enum :class:`Baudrate`) ("m_bOCR", BYTE), # Output Control Register (see enum :class:`OutputControl`) ( "m_dwAMR", DWORD, ), # Acceptance Mask Register (see method :meth:`UcanServer.set_acceptance`) ( "m_dwACR", DWORD, ), # Acceptance Code Register (see method :meth:`UcanServer.set_acceptance`) ("m_dwBaudrate", DWORD), # Baudrate Register for all systec USB-CANmoduls # (see enum :class:`BaudrateEx`) ( "m_fCanIsInit", BOOL, ), # True if the CAN interface is initialized, otherwise false ( "m_wCanStatus", WORD, ), # CAN status (same as received by method :meth:`UcanServer.get_status`) ] def __init__(self): super().__init__(sizeof(ChannelInfo)) def __eq__(self, other): if not isinstance(other, ChannelInfo): return False return ( self.mode == other.mode and self.BTR == other.BTR and self.OCR == other.OCR and self.AMR == other.AMR and self.ACR == other.ACR and self.baudrate == other.baudrate and self.can_is_init == other.can_is_init and self.can_status == other.can_status ) @property def mode(self): return self.m_bMode @property def BTR(self): return self.m_bBTR0 << 8 | self.m_bBTR1 @property def OCR(self): return self.m_bOCR @property def AMR(self): return self.m_dwAMR @property def ACR(self): return self.m_dwACR @property def baudrate(self): return self.m_dwBaudrate @property def can_is_init(self): return self.m_fCanIsInit @property def can_status(self): return self.m_wCanStatus class MsgCountInfo(Structure): """ Structure including the number of sent and received CAN messages. This structure is used with the method :meth:`UcanServer.get_msg_count_info`. .. seealso:: :meth:`UcanServer.get_msg_count_info` .. note:: This structure is only used internally. """ _fields_ = [ ("m_wSentMsgCount", WORD), # number of sent CAN messages ("m_wRecvdMsgCount", WORD), # number of received CAN messages ] @property def sent_msg_count(self): return self.m_wSentMsgCount @property def recv_msg_count(self): return self.m_wRecvdMsgCount # void (PUBLIC *ConnectControlFktEx) (DWORD dwEvent_p, DWORD dwParam_p, void* pArg_p); ConnectControlFktEx = FUNCTYPE(None, DWORD, DWORD, LPVOID) # typedef void (PUBLIC *EnumCallback) (DWORD dwIndex_p, BOOL fIsUsed_p, # HardwareInfoEx* pHwInfoEx_p, HardwareInitInfo* pInitInfo_p, void* pArg_p); EnumCallback = FUNCTYPE( None, DWORD, BOOL, POINTER(HardwareInfoEx), POINTER(HardwareInitInfo), LPVOID )