Skip to content

Commit

Permalink
Merge pull request #365 from Lauszus/pcan_mac
Browse files Browse the repository at this point in the history
Added support for PCAN on Mac; added docs; fixed some bugs in pcan interface
  • Loading branch information
felixdivo committed Aug 9, 2018
2 parents 95c5c1a + 6118964 commit 7b3bb42
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 57 deletions.
6 changes: 5 additions & 1 deletion can/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,11 @@ def __new__(cls, channel=None, *args, **config):
channel = config['channel']
del config['channel']

return cls(channel, *args, **config)
if channel is None:
# Use the default channel for the backend
return cls(*args, **config)
else:
return cls(channel, *args, **config)


def detect_available_configs(interfaces=None):
Expand Down
84 changes: 43 additions & 41 deletions can/interfaces/pcan/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
PCAN_LANBUS15 = TPCANHandle(0x80F) # PCAN-LAN interface, channel 15
PCAN_LANBUS16 = TPCANHandle(0x810) # PCAN-LAN interface, channel 16

# Represent the PCAN error and status codes
# Represent the PCAN error and status codes
PCAN_ERROR_OK = TPCANStatus(0x00000) # No error
PCAN_ERROR_XMTFULL = TPCANStatus(0x00001) # Transmit buffer in CAN controller is full
PCAN_ERROR_OVERRUN = TPCANStatus(0x00002) # CAN controller was read too late
Expand Down Expand Up @@ -239,7 +239,7 @@

# Baud rate codes = BTR0/BTR1 register values for the CAN controller.
# You can define your own Baud rate with the BTROBTR1 register.
# Take a look at www.peak-system.com for our free software "BAUDTOOL"
# Take a look at www.peak-system.com for our free software "BAUDTOOL"
# to calculate the BTROBTR1 register for every bit rate and sample point.

PCAN_BAUD_1M = TPCANBaudrate(0x0014) # 1 MBit/s
Expand All @@ -260,7 +260,7 @@
# Represents the configuration for a CAN bit rate
# Note:
# * Each parameter and its value must be separated with a '='.
# * Each pair of parameter/value must be separated using ','.
# * Each pair of parameter/value must be separated using ','.
#
# Example:
# f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
Expand Down Expand Up @@ -292,7 +292,7 @@ class TPCANMsg (Structure):
"""
Represents a PCAN message
"""
_fields_ = [ ("ID", c_uint), # 11/29-bit message identifier
_fields_ = [ ("ID", c_ulong), # 11/29-bit message identifier - was changed from u_uint to c_ulong, so it is compatible with the PCAN-USB Driver for macOS
("MSGTYPE", TPCANMessageType), # Type of the message
("LEN", c_ubyte), # Data Length Code of the message (0..8)
("DATA", c_ubyte * 8) ] # Data of the message (DATA[0]..DATA[7])
Expand All @@ -303,7 +303,7 @@ class TPCANTimestamp (Structure):
Represents a timestamp of a received PCAN message
Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
"""
_fields_ = [ ("millis", c_uint), # Base-value: milliseconds: 0.. 2^32-1
_fields_ = [ ("millis", c_ulong), # Base-value: milliseconds: 0.. 2^32-1 - was changed from u_uint to c_ulong, so it is compatible with the PCAN-USB Driver for macOS
("millis_overflow", c_ushort), # Roll-arounds of millis
("micros", c_ushort) ] # Microseconds: 0..999

Expand All @@ -312,7 +312,7 @@ class TPCANMsgFD (Structure):
"""
Represents a PCAN message
"""
_fields_ = [ ("ID", c_uint), # 11/29-bit message identifier
_fields_ = [ ("ID", c_ulong), # 11/29-bit message identifier - was changed from u_uint to c_ulong, so it is compatible with the PCAN-USB Driver for macOS
("MSGTYPE", TPCANMessageType), # Type of the message
("DLC", c_ubyte), # Data Length Code of the message (0..15)
("DATA", c_ubyte * 64) ] # Data of the message (DATA[0]..DATA[63])
Expand All @@ -329,6 +329,8 @@ def __init__(self):
# Loads the PCANBasic.dll
if platform.system() == 'Windows':
self.__m_dllBasic = windll.LoadLibrary("PCANBasic")
elif platform.system() == 'Darwin':
self.__m_dllBasic = cdll.LoadLibrary('libPCBUSB.dylib')
else:
self.__m_dllBasic = cdll.LoadLibrary("libpcanbasic.so")
if self.__m_dllBasic == None:
Expand All @@ -351,7 +353,7 @@ def Initialize(
HwType : NON PLUG&PLAY: The type of hardware and operation mode
IOPort : NON PLUG&PLAY: The I/O address for the parallel port
Interrupt: NON PLUG&PLAY: Interrupt number of the parallel port
Returns:
A TPCANStatus error code
"""
Expand All @@ -368,7 +370,7 @@ def InitializeFD(
BitrateFD):

"""
Initializes a FD capable PCAN Channel
Initializes a FD capable PCAN Channel
Parameters:
Channel : The handle of a FD capable PCAN Channel
Expand Down Expand Up @@ -401,13 +403,13 @@ def Uninitialize(

"""
Uninitializes one or all PCAN Channels initialized by CAN_Initialize
Remarks:
Giving the TPCANHandle value "PCAN_NONEBUS", uninitialize all initialized channels
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A TPCANStatus error code
"""
Expand All @@ -424,13 +426,13 @@ def Reset(

"""
Resets the receive and transmit queues of the PCAN Channel
Remarks:
A reset of the CAN controller is not performed
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A TPCANStatus error code
"""
Expand All @@ -447,10 +449,10 @@ def GetStatus(

"""
Gets the current status of a PCAN Channel
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A TPCANStatus error code
"""
Expand All @@ -469,16 +471,16 @@ def Read(
Reads a CAN message from the receive queue of a PCAN Channel
Remarks:
The return value of this method is a 3-touple, where
The return value of this method is a 3-touple, where
the first value is the result (TPCANStatus) of the method.
The order of the values are:
[0]: A TPCANStatus error code
[1]: A TPCANMsg structure with the CAN message read
[2]: A TPCANTimestamp structure with the time when a message was read
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Returns:
A touple with three values
"""
Expand All @@ -499,16 +501,16 @@ def ReadFD(
Reads a CAN message from the receive queue of a FD capable PCAN Channel
Remarks:
The return value of this method is a 3-touple, where
The return value of this method is a 3-touple, where
the first value is the result (TPCANStatus) of the method.
The order of the values are:
[0]: A TPCANStatus error code
[1]: A TPCANMsgFD structure with the CAN message read
[2]: A TPCANTimestampFD that is the time when a message was read
Parameters:
Channel : The handle of a FD capable PCAN Channel
Returns:
A touple with three values
"""
Expand All @@ -527,12 +529,12 @@ def Write(
MessageBuffer):

"""
Transmits a CAN message
Transmits a CAN message
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
MessageBuffer: A TPCANMsg representing the CAN message to be sent
Returns:
A TPCANStatus error code
"""
Expand All @@ -549,12 +551,12 @@ def WriteFD(
MessageBuffer):

"""
Transmits a CAN message over a FD capable PCAN Channel
Transmits a CAN message over a FD capable PCAN Channel
Parameters:
Channel : The handle of a FD capable PCAN Channel
MessageBuffer: A TPCANMsgFD buffer with the message to be sent
Returns:
A TPCANStatus error code
"""
Expand All @@ -578,14 +580,14 @@ def FilterMessages(
Remarks:
The message filter will be expanded with every call to this function.
If it is desired to reset the filter, please use the 'SetValue' function.
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
FromID : A c_uint value with the lowest CAN ID to be received
ToID : A c_uint value with the highest CAN ID to be received
Mode : A TPCANMode representing the message type (Standard, 11-bit
Mode : A TPCANMode representing the message type (Standard, 11-bit
identifier, or Extended, 29-bit identifier)
Returns:
A TPCANStatus error code
"""
Expand All @@ -608,15 +610,15 @@ def GetValue(
Parameters can be present or not according with the kind
of Hardware (PCAN Channel) being used. If a parameter is not available,
a PCAN_ERROR_ILLPARAMTYPE error will be returned.
The return value of this method is a 2-touple, where
The return value of this method is a 2-touple, where
the first value is the result (TPCANStatus) of the method and
the second one, the asked value
the second one, the asked value
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Parameter : The TPCANParameter parameter to get
Returns:
A touple with 2 values
"""
Expand Down Expand Up @@ -646,13 +648,13 @@ def SetValue(
Parameters can be present or not according with the kind
of Hardware (PCAN Channel) being used. If a parameter is not available,
a PCAN_ERROR_ILLPARAMTYPE error will be returned.
Parameters:
Channel : A TPCANHandle representing a PCAN Channel
Parameter : The TPCANParameter parameter to set
Buffer : Buffer with the value to be set
BufferLength : Size in bytes of the buffer
Returns:
A TPCANStatus error code
"""
Expand Down Expand Up @@ -681,16 +683,16 @@ def GetErrorText(
The current languages available for translation are:
Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A),
Italian (0x10) and French (0x0C)
Italian (0x10) and French (0x0C)
The return value of this method is a 2-touple, where
the first value is the result (TPCANStatus) of the method and
the second one, the error text
Parameters:
Error : A TPCANStatus error code
Language : Indicates a 'Primary language ID' (Default is Neutral(0))
Returns:
A touple with 2 values
"""
Expand Down
14 changes: 5 additions & 9 deletions can/interfaces/pcan/pcan.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@

class PcanBus(BusABC):

def __init__(self, channel, state=BusState.ACTIVE, *args, **kwargs):
def __init__(self, channel='PCAN_USBBUS1', state=BusState.ACTIVE, bitrate=500000, *args, **kwargs):
"""A PCAN USB interface to CAN.
On top of the usual :class:`~can.Bus` methods provided,
Expand All @@ -77,6 +77,7 @@ def __init__(self, channel, state=BusState.ACTIVE, *args, **kwargs):
:param str channel:
The can interface name. An example would be 'PCAN_USBBUS1'
Default is 'PCAN_USBBUS1'
:param can.bus.BusState state:
BusState of the channel.
Expand All @@ -87,12 +88,7 @@ def __init__(self, channel, state=BusState.ACTIVE, *args, **kwargs):
Default is 500 kbit/s.
"""
if not channel:
raise ArgumentError("Must specify a PCAN channel")
else:
self.channel_info = channel

bitrate = kwargs.get('bitrate', 500000)
self.channel_info = channel
pcan_bitrate = pcan_bitrate_objs.get(bitrate, PCAN_BAUD_500K)

hwtype = PCAN_TYPE_ISA
Expand All @@ -119,7 +115,7 @@ def __init__(self, channel, state=BusState.ACTIVE, *args, **kwargs):
if result != PCAN_ERROR_OK:
raise PcanError(self._get_formatted_error(result))

super(PcanBus, self).__init__(channel=channel, *args, **kwargs)
super(PcanBus, self).__init__(channel=channel, state=state, bitrate=bitrate, *args, **kwargs)

def _get_formatted_error(self, error):
"""
Expand Down Expand Up @@ -219,7 +215,7 @@ def _recv_internal(self, timeout):
bIsExt = (theMsg.MSGTYPE & PCAN_MESSAGE_EXTENDED.value) == PCAN_MESSAGE_EXTENDED.value

dlc = theMsg.LEN
timestamp = boottimeEpoch + ((itsTimeStamp.micros + (1000 * itsTimeStamp.millis)) / (1000.0 * 1000.0))
timestamp = boottimeEpoch + ((itsTimeStamp.micros + 1000 * itsTimeStamp.millis + 0x100000000 * 1000 * itsTimeStamp.millis_overflow) / (1000.0 * 1000.0))

rx_msg = Message(timestamp=timestamp,
arbitration_id=theMsg.ID,
Expand Down
35 changes: 30 additions & 5 deletions doc/interfaces/pcan.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,52 @@
PCAN Basic API
==============

.. warning::
Interface to `Peak-System <https://www.peak-system.com/?&L=1/>`__'s PCAN-Basic API.

This ``PCAN`` documentation is a work in progress. Feedback and revisions are most welcome!
Windows driver: https://www.peak-system.com/Downloads.76.0.html?&L=1

Linux driver: https://www.peak-system.com/fileadmin/media/linux/index.htm#download and https://www.peak-system.com/Downloads.76.0.html?&L=1 (PCAN-Basic API (Linux))

Interface to `Peak-System <http://www.peak-system.com/>`__'s PCAN-Basic API.
Mac driver: http://www.mac-can.com

Configuration
-------------

An example `can.ini` file for windows 7:
Here is an example configuration file for using `PCAN-USB <https://www.peak-system.com/PCAN-USB.199.0.html?&L=1>`_:

::

[default]
interface = pcan
channel = PCAN_USBBUS1
state = can.bus.BusState.PASSIVE
bitrate = 500000

``channel``: (default PCAN_USBBUS1) CAN interface name

``state``: (default can.bus.BusState.ACTIVE) BusState of the channel

``bitrate``: (default 500000) Channel bitrate

Valid ``channel`` values:

::

PCAN_ISABUSx
PCAN_DNGBUSx
PCAN_PCIBUSx
PCAN_USBBUSx
PCAN_PCCBUSx
PCAN_LANBUSx

Where ``x`` should be replaced with the desired channel number starting at 1.

Linux installation
------------------

Kernels >= 3.4 supports the PCAN adapters natively via :doc:`/interfaces/socketcan`, refer to: :ref:`socketcan-pcan`.

Bus
---

.. autoclass:: can.interfaces.pcan.PcanBus

Loading

0 comments on commit 7b3bb42

Please sign in to comment.