Skip to content

Commit 4f0ba10

Browse files
committed
add BitTiming configuration to PCAN
1 parent 81f44e1 commit 4f0ba10

File tree

1 file changed

+79
-22
lines changed

1 file changed

+79
-22
lines changed

can/interfaces/pcan/pcan.py

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
from datetime import datetime
88
import platform
99

10-
from typing import Optional
10+
from typing import Optional, Union
1111

1212
from packaging import version
1313

14+
from ... import BitTiming, BitTimingFd
1415
from ...message import Message
1516
from ...bus import BusABC, BusState
1617
from ...util import len2dlc, dlc2len
@@ -57,6 +58,7 @@
5758
FEATURE_FD_CAPABLE,
5859
PCAN_DICT_STATUS,
5960
PCAN_BUSOFF_AUTORESET,
61+
TPCANBaudrate,
6062
)
6163

6264

@@ -103,10 +105,11 @@
103105
class PcanBus(BusABC):
104106
def __init__(
105107
self,
106-
channel="PCAN_USBBUS1",
107-
device_id=None,
108-
state=BusState.ACTIVE,
109-
bitrate=500000,
108+
channel: str = "PCAN_USBBUS1",
109+
device_id: Optional[int] = None,
110+
state: BusState = BusState.ACTIVE,
111+
timing: Optional[Union[BitTiming, BitTimingFd]] = None,
112+
bitrate: int = 500000,
110113
*args,
111114
**kwargs,
112115
):
@@ -133,6 +136,18 @@ def __init__(
133136
BusState of the channel.
134137
Default is ACTIVE
135138
139+
:param timing:
140+
An instance of :class:`~can.BitTiming` or :class:`~can.BitTimingFd`
141+
to specify the bit timing parameters for the PCAN interface. If this parameter
142+
is provided, it takes precedence over all other timing-related parameters.
143+
If this parameter is not provided, the bit timing parameters can be specified
144+
using the `bitrate` parameter for standard CAN or the `fd`, `f_clock`,
145+
`f_clock_mhz`, `nom_brp`, `nom_tseg1`, `nom_tseg2`, `nom_sjw`, `data_brp`,
146+
`data_tseg1`, `data_tseg2`, and `data_sjw` parameters for CAN FD.
147+
Note that the `f_clock` value of the `timing` instance must be 8_000_000
148+
for standard CAN or any of the following values for CAN FD: 20_000_000,
149+
24_000_000, 30_000_000, 40_000_000, 60_000_000, 80_000_000.
150+
136151
:param int bitrate:
137152
Bitrate of channel in bit/s.
138153
Default is 500 kbit/s.
@@ -222,8 +237,9 @@ def __init__(
222237
raise ValueError(err_msg)
223238

224239
self.channel_info = str(channel)
225-
self.fd = kwargs.get("fd", False)
226-
pcan_bitrate = PCAN_BITRATES.get(bitrate, PCAN_BAUD_500K)
240+
self.fd = isinstance(timing, BitTimingFd) or (
241+
timing is None and kwargs.get("fd", False)
242+
)
227243

228244
hwtype = PCAN_TYPE_ISA
229245
ioport = 0x02A0
@@ -241,28 +257,69 @@ def __init__(
241257
else:
242258
raise ValueError("BusState must be Active or Passive")
243259

244-
if self.fd:
245-
f_clock_val = kwargs.get("f_clock", None)
246-
if f_clock_val is None:
247-
f_clock = "{}={}".format("f_clock_mhz", kwargs.get("f_clock_mhz", None))
248-
else:
249-
f_clock = "{}={}".format("f_clock", kwargs.get("f_clock", None))
250-
251-
fd_parameters_values = [f_clock] + [
252-
f"{key}={kwargs.get(key, None)}"
253-
for key in PCAN_FD_PARAMETER_LIST
254-
if kwargs.get(key, None) is not None
260+
if isinstance(timing, BitTimingFd):
261+
valid_fd_clocks = [
262+
20000000,
263+
24000000,
264+
30000000,
265+
40000000,
266+
60000000,
267+
80000000,
255268
]
256-
257-
self.fd_bitrate = " ,".join(fd_parameters_values).encode("ascii")
258-
269+
if timing.f_clock not in valid_fd_clocks:
270+
raise CanInitializationError(
271+
f"The PcanBus requires one of the following CAN clocks for CAN FD: "
272+
f"{','.join([str(f) for f in valid_fd_clocks])} (timing={timing!r})"
273+
)
274+
self.fd_bitrate = (
275+
f"f_clock={timing.f_clock},"
276+
f"nom_brp={timing.nom_brp},"
277+
f"nom_tseg1={timing.nom_tseg1},"
278+
f"nom_tseg2={timing.nom_tseg2},"
279+
f"nom_sjw={timing.nom_sjw},"
280+
f"data_brp={timing.data_brp},"
281+
f"data_tseg1={timing.data_tseg1},"
282+
f"data_tseg2={timing.data_tseg2},"
283+
f"data_sjw={timing.data_sjw}"
284+
).encode("ascii")
259285
result = self.m_objPCANBasic.InitializeFD(
260286
self.m_PcanHandle, self.fd_bitrate
261287
)
262-
else:
288+
elif isinstance(timing, BitTiming):
289+
if timing.f_clock != 8_000_000:
290+
raise CanInitializationError(
291+
f"The PcanBus requires a 8MHz CAN clock for CAN2.0 (timing={timing!r})"
292+
)
293+
pcan_bitrate = TPCANBaudrate(timing.btr0 << 8 | timing.btr1)
263294
result = self.m_objPCANBasic.Initialize(
264295
self.m_PcanHandle, pcan_bitrate, hwtype, ioport, interrupt
265296
)
297+
else:
298+
if self.fd:
299+
f_clock_val = kwargs.get("f_clock", None)
300+
if f_clock_val is None:
301+
f_clock = "{}={}".format(
302+
"f_clock_mhz", kwargs.get("f_clock_mhz", None)
303+
)
304+
else:
305+
f_clock = "{}={}".format("f_clock", kwargs.get("f_clock", None))
306+
307+
fd_parameters_values = [f_clock] + [
308+
f"{key}={kwargs.get(key, None)}"
309+
for key in PCAN_FD_PARAMETER_LIST
310+
if kwargs.get(key, None) is not None
311+
]
312+
313+
self.fd_bitrate = " ,".join(fd_parameters_values).encode("ascii")
314+
315+
result = self.m_objPCANBasic.InitializeFD(
316+
self.m_PcanHandle, self.fd_bitrate
317+
)
318+
else:
319+
pcan_bitrate = PCAN_BITRATES.get(bitrate, PCAN_BAUD_500K)
320+
result = self.m_objPCANBasic.Initialize(
321+
self.m_PcanHandle, pcan_bitrate, hwtype, ioport, interrupt
322+
)
266323

267324
if result != PCAN_ERROR_OK:
268325
raise PcanCanInitializationError(self._get_formatted_error(result))

0 commit comments

Comments
 (0)