From c513356b0361a37dfb5c4f5cbdc85329f5f795cb Mon Sep 17 00:00:00 2001 From: LJ Date: Sat, 4 Dec 2021 21:46:32 +0100 Subject: [PATCH 01/27] Init uCAN cfuc interface --- can/interfaces/__init__.py | 1 + can/interfaces/cfuc/__init__.py | 5 + can/interfaces/cfuc/can_calc_bittiming.py | 169 ++++++++++ can/interfaces/cfuc/cfuc.py | 374 ++++++++++++++++++++++ doc/interfaces.rst | 1 + doc/interfaces/cfuc.rst | 26 ++ setup.py | 1 + test/test_cfuc.py | 51 +++ 8 files changed, 628 insertions(+) create mode 100644 can/interfaces/cfuc/__init__.py create mode 100644 can/interfaces/cfuc/can_calc_bittiming.py create mode 100644 can/interfaces/cfuc/cfuc.py create mode 100644 doc/interfaces/cfuc.rst create mode 100644 test/test_cfuc.py diff --git a/can/interfaces/__init__.py b/can/interfaces/__init__.py index 884665934..aa547e088 100644 --- a/can/interfaces/__init__.py +++ b/can/interfaces/__init__.py @@ -25,6 +25,7 @@ "gs_usb": ("can.interfaces.gs_usb", "GsUsbBus"), "nixnet": ("can.interfaces.nixnet", "NiXNETcanBus"), "neousys": ("can.interfaces.neousys", "NeousysBus"), + "cfuc": ("can.interfaces.cfuc","cfucBus"), } try: diff --git a/can/interfaces/cfuc/__init__.py b/can/interfaces/cfuc/__init__.py new file mode 100644 index 000000000..35b1ccf8f --- /dev/null +++ b/can/interfaces/cfuc/__init__.py @@ -0,0 +1,5 @@ +# coding: utf-8 + +""" +""" +from can.interfaces.cfuc.cfuc import cfucBus diff --git a/can/interfaces/cfuc/can_calc_bittiming.py b/can/interfaces/cfuc/can_calc_bittiming.py new file mode 100644 index 000000000..de084d808 --- /dev/null +++ b/can/interfaces/cfuc/can_calc_bittiming.py @@ -0,0 +1,169 @@ +# from _typeshed import HasFileno +import math + +INT_MAX = 2147483647 +UINT_MAX = INT_MAX * 2 + 1 + +CAN_CALC_MAX_ERROR = 50 # in one-tenth of a percent */ +CAN_CALC_SYNC_SEG = 1 + +class btc(object): + tseg1_min = 1 # Time segement 1 = prop_seg + phase_seg1 */ + tseg1_max = 16 + tseg2_min = 1 # Time segement 2 = phase_seg2 */ + tseg2_max = 8 + sjw_max = 4 # Synchronisation jump width */ + brp_min = 1 # Bit-rate prescaler */ + brp_max = 64 + brp_inc = 1 + +class bt(object): + bitrate = 0 # Bit-rate in bits/second */ + sample_point = 0 # Sample point in one-tenth of a percent */ + tq = 0 # Time quanta (TQ) in nanoseconds */ + prop_seg = 0 # Propagation segment in TQs */ + phase_seg1 = 0 # Phase buffer segment 1 in TQs */ + phase_seg2 = 0 # Phase buffer segment 2 in TQs */ + sjw = 0 # Synchronisation jump width in TQs */ + brp = 0 # Bit-rate prescaler */ + +def clamp(val, lo, hi): + if (val < lo): val = lo + if (val > hi): val = hi + return val + + + +def can_update_spt(btc, spt_nominal, tseg, tseg1_ptr, tseg2_ptr, spt_error_ptr): + spt_error = 0 + best_spt_error = UINT_MAX + spt = 0 + best_spt = 0 + tseg1 = 0 + tseg2 = 0 + i = 0 + + while (i <= 1): + + tseg2 = tseg + CAN_CALC_SYNC_SEG - math.floor((spt_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000) - i + tseg2 = clamp(tseg2, btc.tseg2_min, btc.tseg2_max) + tseg1 = tseg - tseg2 + if (tseg1 > btc.tseg1_max): + tseg1 = btc.tseg1_max + tseg2 = tseg - tseg1 + spt = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG) + spt_error = abs(spt_nominal - spt) + + if ((spt <= spt_nominal) & (spt_error < best_spt_error)) : + best_spt_ptr = spt + best_spt_error = spt_error + tseg1_ptr = tseg1 + tseg2_ptr = tseg2 + i = i + 1 + + spt_error_ptr = best_spt_error + + return tseg1_ptr,tseg2_ptr,spt_error_ptr, best_spt_ptr + + + +def CAN_CALC_BITTIMING(bt, btc): + clock_freq = 144000000 + spt_nominal = 0 + best_tseg = 0 #' current best value for tseg */ + best_brp = 0 # current best value for brp */ + brp = 0 + tsegall = 0 + tseg = 0 + tseg1 = 0 + tseg2 = 0 + rate_error = 0 # difference between current and nominal value */ + best_rate_error = UINT_MAX + spt_error = 0 # difference between current and nominal value */ + best_spt_error = UINT_MAX + + if (bt.bitrate > 800000): + spt_nominal = 750 + else: + if (bt.bitrate > 500000): + spt_nominal = 800 + else: + spt_nominal = 875 + + # tseg even = round down, odd = round up + tsegall = 0 + tseg = (btc.tseg1_max + btc.tseg2_max) * 2 + 2 + while tseg >= (btc.tseg1_min + btc.tseg2_min) * 2: + tseg = tseg - 1 + tsegall = math.floor(CAN_CALC_SYNC_SEG + tseg / 2) + + # Compute all possible tseg choices (tseg=tseg1+tseg2) + brp = math.floor(clock_freq / (tsegall * bt.bitrate) + tseg % 2) + + # choose brp step which is possible in system */ + brp = math.floor((brp / btc.brp_inc) * btc.brp_inc) + if (brp < btc.brp_min) | (brp > btc.brp_max): + continue + + rate = math.floor(clock_freq / (brp * tsegall)) + rate_error = abs(bt.bitrate - rate) + + # tseg brp biterror + if (rate_error > best_rate_error): + continue + # reset sample point error if we have a better bitrate */ + if (rate_error < best_rate_error): + best_spt_error = UINT_MAX + + tseg1,tseg2,spt_error, spt = can_update_spt(btc, spt_nominal, math.floor(tseg / 2), tseg1, tseg2, spt_error) + if (spt_error > best_spt_error): + continue + + best_spt_error = spt_error + best_rate_error = rate_error + best_tseg = tseg / 2 + best_brp = brp + + if ((rate_error == 0) & (spt_error == 0)): + break + + if (best_rate_error != 0) : + # Error in one-tenth of a percent */ + rate_error = (best_rate_error * 1000) / bt.bitrate + if (rate_error > CAN_CALC_MAX_ERROR): + return -33 + + bt.sample_point = can_update_spt(btc, spt_nominal, best_tseg,tseg1, tseg2, 0)[3] + v64 = best_brp * 1000 * 1000 * 1000 + #do_div(v64, clock_freq) + v64 = v64 / clock_freq + # eof do_div + + bt.tq = math.floor(v64) + bt.prop_seg = math.floor(tseg1 / 2) + bt.phase_seg1 = tseg1 - bt.prop_seg + bt.phase_seg2 = tseg2 + + if ((bt.sjw == 0) | (btc.sjw_max == 0)): + bt.sjw = 1 + else: + # bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ + if (bt.sjw > btc.sjw_max): + bt.sjw = btc.sjw_max + # bt->sjw must not be higher than tseg2 */ + if (tseg2 < bt.sjw): + bt.sjw = tseg2 + + bt.brp = best_brp + + # real bit-rate */ + bt.bitrate = math.floor(clock_freq / (bt.brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2))) + + return bt + + + + + + + diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py new file mode 100644 index 000000000..fecb656f2 --- /dev/null +++ b/can/interfaces/cfuc/cfuc.py @@ -0,0 +1,374 @@ +# coding: utf-8 + +""" +Serial based interface. For example use over serial ports like +"/dev/ttyS1" or "/dev/ttyUSB0" on Linux machines or "COM1" on Windows. +The interface is a simple implementation for uCAN CAN/USB CFUC converter. +""" +from __future__ import absolute_import, division +from typing import Optional + +import logging +import struct +from . import can_calc_bittiming + +from can import BusABC, Message + +logger = logging.getLogger("can.serial") + +try: + import serial +except ImportError: + logger.warning( + "You won't be able to use the serial can backend without " + "the serial module installed!" + ) + serial = None + +ADLC = { + 0: 0x00000000, + 1: 0x00010000, + 2: 0x00020000, + 3: 0x00030000, + 4: 0x00040000, + 5: 0x00050000, + 6: 0x00060000, + 7: 0x00070000, + 8: 0x00080000, + 9: 0x00090000, + 10: 0x000A0000, + 11: 0x000B0000, + 12: 0x000C0000, + 13: 0x000D0000, + 14: 0x000E0000, + 15: 0x000F0000, +} + + +class cfucBus(BusABC): + """ + Enable can communication over a ucan CFUC device. + + """ + + can_frame_count = 0 + + def append_int32(self, dest, source): + for i in range(0, 4): + dest.append(source[i]) + return dest + + def consturct_init_frame( + self, + IsFD=False, + IsBRS=False, + IsAutoRetransmission=False, + NominalPrescalerValue=1, + NominalSyncJumpWidthValue=1, + NominalTimeSeg1Value=13, + NominalTimeSeg2Value=2, + DataPrescalerValue=1, + DataSyncJumpWidthValue=1, + DataTimeSeg1Value=1, + DataTimeSeg2Value=1, + ): + + byte_msg = bytearray() + + UCAN_FD_INIT = struct.pack(" 0) & (self.can_frame_count < 10): + self.can_frame_count = self.can_frame_count - 1 + s = bytearray(self.ser.read(4)) + arb_id = (struct.unpack("=0.2.1"], "nixnet": ["nixnet>=0.3.1"], "pcan": ["uptime~=3.0.1"], + "cfuc": ["pyserial~=3.0"], } setup( diff --git a/test/test_cfuc.py b/test/test_cfuc.py new file mode 100644 index 000000000..ba5efbc06 --- /dev/null +++ b/test/test_cfuc.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# coding: utf-8 + +""" +This module is for CFUC testing the serial interface, UCANDevices +""" + + +import unittest +import can +# import can.interfaces.cfucBus + +class SerialDummy(object): + """ + Dummy to mock the serial communication + """ + msg = None + + def __init__(self): + self.msg = bytearray() + + def read(self, size=1): + return_value = bytearray() + for i in range(size): + return_value.append(self.msg.pop(0)) + return bytes(return_value) + + def write(self, msg): + self.msg = bytearray(msg) + + def reset(self): + self.msg = None + +class CFUCTestCase(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + self.bus.shutdown() + + + def test_rx_tx_min_max_data(self): + """ + Tests the transfer of init frame + """ + self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + self.serial = self.bus.ser + msg = self.serial.read(self.serial.in_waiting) + # msg = self.bus.recv(0) + self.assertIsNotNone(msg) \ No newline at end of file From 73f6a8f5cc8fe070e5bed664f8c12d1dd3a77631 Mon Sep 17 00:00:00 2001 From: LJ Date: Fri, 10 Dec 2021 15:26:30 +0100 Subject: [PATCH 02/27] add cfuc_tests --- can/interfaces/cfuc/cfuc_examples.py | 38 ++++++++++++ .../cfuc/test_can_calc_bittiming.py | 33 ++++++++++ test/test_cfuc.py | 62 ++++++++++++++++++- 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 can/interfaces/cfuc/cfuc_examples.py create mode 100644 can/interfaces/cfuc/test_can_calc_bittiming.py diff --git a/can/interfaces/cfuc/cfuc_examples.py b/can/interfaces/cfuc/cfuc_examples.py new file mode 100644 index 000000000..8b46f9295 --- /dev/null +++ b/can/interfaces/cfuc/cfuc_examples.py @@ -0,0 +1,38 @@ +from time import sleep +import cfuc +from can import Message +import threading + +c = cfuc.cfucBus("COM50", 100 * 1000) + +m = Message( + 0, + 0x11223344, + True, + False, + False, + None, + 5, + bytearray(b"\x01\x02\x03\x04\x05"), + False, + False, + False, + None, + False, +) +c.send(m, None) + + +def rx_function(caninterface): + retry = 0 + while retry < 60: + caninterface._recv_internal(0) + retry = retry + 1 + + +x = threading.Thread(target=rx_function, args=(c,)) +x.start() + +x.join() + +c.shutdown() diff --git a/can/interfaces/cfuc/test_can_calc_bittiming.py b/can/interfaces/cfuc/test_can_calc_bittiming.py new file mode 100644 index 000000000..2cc7dde27 --- /dev/null +++ b/can/interfaces/cfuc/test_can_calc_bittiming.py @@ -0,0 +1,33 @@ +import can_calc_bittiming + + +def test_baud100k(): + + bt = can_calc_bittiming.bt() + bt.bitrate = 100*1000 + btc = can_calc_bittiming.btc() + bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt,btc) + assert bt.brp == 60 + assert bt.bitrate == 100000 + +def test_baud250k(): + + bt = can_calc_bittiming.bt() + bt.bitrate = 250*1000 + btc = can_calc_bittiming.btc() + bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt,btc) + assert bt.brp == 36 + assert bt.bitrate == 250000 + +def test_baud1000k(): + + bt = can_calc_bittiming.bt() + bt.bitrate = 1000*1000 + btc = can_calc_bittiming.btc() + bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt,btc) + assert bt.brp == 9 + assert bt.tq == 62 + assert bt.prop_seg == 5 + assert bt.phase_seg1 == 6 + assert bt.phase_seg2 == 4 + assert bt.bitrate == 1000*1000 \ No newline at end of file diff --git a/test/test_cfuc.py b/test/test_cfuc.py index ba5efbc06..6d019dd58 100644 --- a/test/test_cfuc.py +++ b/test/test_cfuc.py @@ -6,8 +6,10 @@ """ +from logging import log import unittest import can +from can.message import Message # import can.interfaces.cfucBus class SerialDummy(object): @@ -40,7 +42,7 @@ def tearDown(self): self.bus.shutdown() - def test_rx_tx_min_max_data(self): + def test_init(self): """ Tests the transfer of init frame """ @@ -48,4 +50,60 @@ def test_rx_tx_min_max_data(self): self.serial = self.bus.ser msg = self.serial.read(self.serial.in_waiting) # msg = self.bus.recv(0) - self.assertIsNotNone(msg) \ No newline at end of file + self.assertIsNotNone(msg) + + def test_tx_frame_extended(self): + """ + Tests the transfer of extented CAN frame + """ + self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + self.serial = self.bus.ser + self.serial.read(self.serial.in_waiting) + + msg = can.Message( + arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55] + ) + self.bus.send(msg) + + data = self.serial.read(self.serial.in_waiting) + self.assertEqual(data[11],64) # standart / extended field + # self.assertIsNotNone(data) + + + def test_tx_frame_standart(self): + """ + Tests the transfer of extented CAN frame + """ + self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + self.serial = self.bus.ser + self.serial.read(self.serial.in_waiting) + + msg = can.Message( + arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55] + ) + self.bus.send(msg) + + data = self.serial.read(self.serial.in_waiting) + + self.assertEqual(data[11],0) # standart extended + # self.assertEqual(data[18],2) + + def test_tx_fd_frame(self): + """ + Tests the transfer of extented CAN frame + """ + self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + self.serial = self.bus.ser + self.serial.read(self.serial.in_waiting) + + msg = can.Message( + arbitration_id=0x12ABCDEF, is_extended_id=True, is_fd = True, data=[0xAA, 0x55] + ) + self.bus.send(msg) + + data = self.serial.read(self.serial.in_waiting) + self.assertIsNotNone(data) + #len #ErrorState #BitRateSwitch #FDFormat +# b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00 \x00\x00\x00\x00\ x00\x02\x00\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00 \x00 \x00\x00\x00\x00\ x00\x00\x02\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00 \x00\x00\x00\x00\ x00\x02\x00\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \ No newline at end of file From 90d2769870b3893f815df5e83803f9f5765110d8 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sun, 26 Dec 2021 12:51:17 +0100 Subject: [PATCH 03/27] proper tests --- test/test_cfuc.py | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/test/test_cfuc.py b/test/test_cfuc.py index 6d019dd58..a34125a60 100644 --- a/test/test_cfuc.py +++ b/test/test_cfuc.py @@ -47,62 +47,57 @@ def test_init(self): Tests the transfer of init frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - self.serial = self.bus.ser - msg = self.serial.read(self.serial.in_waiting) - # msg = self.bus.recv(0) + msg = self.bus.recv(None) self.assertIsNotNone(msg) + def test_tx_frame_extended(self): """ Tests the transfer of extented CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - self.serial = self.bus.ser - self.serial.read(self.serial.in_waiting) + msg = self.bus.recv(None) msg = can.Message( arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55] ) self.bus.send(msg) - data = self.serial.read(self.serial.in_waiting) - self.assertEqual(data[11],64) # standart / extended field - # self.assertIsNotNone(data) + msg = self.bus.recv(None) + self.assertTrue(msg.is_extended_id) # standart / extended field def test_tx_frame_standart(self): """ - Tests the transfer of extented CAN frame + Tests the transfer of standart CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - self.serial = self.bus.ser - self.serial.read(self.serial.in_waiting) + msg = self.bus.recv(None) msg = can.Message( arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55] ) self.bus.send(msg) - data = self.serial.read(self.serial.in_waiting) - - self.assertEqual(data[11],0) # standart extended - # self.assertEqual(data[18],2) + msg = self.bus.recv(None) + self.assertFalse(msg.is_extended_id) # standart / extended field + def test_tx_fd_frame(self): """ - Tests the transfer of extented CAN frame + Tests the transfer of Flexible Data-Rate CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - self.serial = self.bus.ser - self.serial.read(self.serial.in_waiting) + msg = self.bus.recv(None) msg = can.Message( arbitration_id=0x12ABCDEF, is_extended_id=True, is_fd = True, data=[0xAA, 0x55] ) self.bus.send(msg) - data = self.serial.read(self.serial.in_waiting) - self.assertIsNotNone(data) + msg = self.bus.recv(None) + self.assertTrue(msg.is_extended_id) + self.assertTrue(msg.is_fd) #len #ErrorState #BitRateSwitch #FDFormat # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00 \x00\x00\x00\x00\ x00\x02\x00\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00 \x00 \x00\x00\x00\x00\ x00\x00\x02\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' From 77cca5a73aac33c726b78c229900c070add2a5da Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sun, 26 Dec 2021 13:18:00 +0100 Subject: [PATCH 04/27] communication through serial - ok incoming data parsing - not ok --- can/interfaces/cfuc/cfuc.py | 17 ++++++++++++++++- test/test_cfuc.py | 30 +++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index fecb656f2..630079931 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -14,6 +14,13 @@ from can import BusABC, Message +from can import ( + CanInterfaceNotImplementedError, + CanInitializationError, + CanOperationError, + CanTimeoutError, +) + logger = logging.getLogger("can.serial") try: @@ -236,15 +243,19 @@ def __init__( self.ser.write(frame) + super().__init__(channel, *args, **kwargs) # super(cfucBus, self).__init__(channel=channel, *args, **kwargs) + def shutdown(self): """ Close the serial interface. """ + super().shutdown() self.ser.close() - def send(self, msg, timeout=None): + + def send(self, msg: Message, timeout=None): """ Send a message over the serial device. @@ -264,6 +275,7 @@ def send(self, msg, timeout=None): a_id = struct.pack(" Date: Sun, 26 Dec 2021 15:24:05 +0100 Subject: [PATCH 05/27] new recv --- can/interfaces/cfuc/cfuc.py | 142 ++++++++++++++++++++++++------------ test/test_cfuc.py | 28 +++---- 2 files changed, 111 insertions(+), 59 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 630079931..d74a3caab 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -11,7 +11,7 @@ import logging import struct from . import can_calc_bittiming - +import enum from can import BusABC, Message from can import ( @@ -50,6 +50,19 @@ 14: 0x000E0000, 15: 0x000F0000, } +# class UCAN_FRAME_TYPE(enum.Enum): +# UCAN_FD_INIT = 0 +# Mon = 1 + +class UCAN_FRAME_TYPE(enum.Enum): + UCAN_FD_INIT = 0 # init CAN with all parameters, open in mode specified in init data. Frame direction USB->CAN*/ + UCAN_FD_DEINIT = 1 # deinit CAN, close CAN connection. Frame direction USB->CAN*/ + UCAN_FD_TX = 2 # send new frame on CAN network. Frame direction USB->CAN */ + UCAN_FD_SAVE_CONFIG = 3 # saves CAN config to NVM USB->CAN*/ + UCAN_FD_GO_TO_BOOTLOADER = 4 # go to USB bootloader USB->CAN*/ + UCAN_FD_GET_CAN_STATUS = 5 # request status USB->CAN*/ + UCAN_FD_RX = 6 # new CAN frame received on network. Frame direction CAN->USB*/ + UCAN_FD_ACK = 7 # gets CAN status from CONVERTER. Also ACK resposne for all frames form USB. Frame direction CAN->USB */ class cfucBus(BusABC): @@ -58,8 +71,6 @@ class cfucBus(BusABC): """ - can_frame_count = 0 - def append_int32(self, dest, source): for i in range(0, 4): dest.append(source[i]) @@ -200,8 +211,6 @@ def __init__( channel, baudrate=115200, timeout=0.1, rtscts=False ) - self.can_frame_count = 0 - self.ser.reset_input_buffer() self.ser.reset_output_buffer() @@ -325,6 +334,47 @@ def send(self, msg: Message, timeout=None): self.ser.write(byte_msg) + def _read(self, length): + rx_buffer = bytearray(self.ser.read(4)) + rx_length = len(rx_buffer) + + if length == rx_length: + result = (struct.unpack(" Message: + # read ucan_can_rx_def structure + + # read FDCAN_RxHeaderTypeDef structure + can_rx_header_Identifier = self._read(4) + can_rx_header_IdType = self._read(4) + can_rx_header_RxFrameType = self._read(4) + can_rx_header_DataLength = self._read(4) + can_rx_header_ErrorStateIndicator = self._read(4) + can_rx_header_BitRateSwitch = self._read(4) + can_rx_header_FDFormat = self._read(4) + can_rx_header_RxTimestamp = self._read(4) + can_rx_header_FilterIndex = self._read(4) + can_rx_header_IsFilterMatchingFrame = self._read(4) + + #read Data CAN buffer + can_data = bytearray(self.ser.read(64)) + + #read Flasg and Errors + packed_flags_and_error_counters = self._read(4) + + dlc = list(ADLC.values()).index(can_rx_header_DataLength) + + msg = Message( + timestamp = can_rx_header_RxTimestamp / 1000, + arbitration_id = can_rx_header_Identifier, + dlc = dlc, + data = can_data, + ) + return msg + def _recv_internal(self, timeout): """ @@ -346,44 +396,44 @@ def _recv_internal(self, timeout): :rtype: can.Message, bool """ - if self.can_frame_count == 0: - # ser.read can return an empty string - # or raise a SerialException - try: - rx_byte = self.ser.read(4) - rx_byte = (struct.unpack(" 0) & (self.can_frame_count < 10): - self.can_frame_count = self.can_frame_count - 1 - s = bytearray(self.ser.read(4)) - arb_id = (struct.unpack(" Date: Sun, 26 Dec 2021 15:25:10 +0100 Subject: [PATCH 06/27] cleanup --- can/interfaces/cfuc/cfuc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index d74a3caab..cb936ae41 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -50,9 +50,6 @@ 14: 0x000E0000, 15: 0x000F0000, } -# class UCAN_FRAME_TYPE(enum.Enum): -# UCAN_FD_INIT = 0 -# Mon = 1 class UCAN_FRAME_TYPE(enum.Enum): UCAN_FD_INIT = 0 # init CAN with all parameters, open in mode specified in init data. Frame direction USB->CAN*/ From b574fa920ca8057e5c3dda5cca65dc382ab249df Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sun, 26 Dec 2021 15:27:44 +0100 Subject: [PATCH 07/27] hot fix --- can/interfaces/cfuc/cfuc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index cb936ae41..39f0d9bf6 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -332,7 +332,7 @@ def send(self, msg: Message, timeout=None): self.ser.write(byte_msg) def _read(self, length): - rx_buffer = bytearray(self.ser.read(4)) + rx_buffer = bytearray(self.ser.read(length)) rx_length = len(rx_buffer) if length == rx_length: From 00042d8498a5f2843311033440087c21237266c3 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sun, 26 Dec 2021 15:52:59 +0100 Subject: [PATCH 08/27] read fix --- can/interfaces/cfuc/cfuc.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 39f0d9bf6..db252f5c2 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -276,7 +276,7 @@ def send(self, msg: Message, timeout=None): """ - UCAN_FD_TX = struct.pack(" Date: Sun, 26 Dec 2021 16:02:22 +0100 Subject: [PATCH 09/27] init frame --- can/interfaces/cfuc/cfuc.py | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index db252f5c2..0ac053a90 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -88,10 +88,10 @@ def consturct_init_frame( DataTimeSeg2Value=1, ): - byte_msg = bytearray() - UCAN_FD_INIT = struct.pack(" Date: Sun, 26 Dec 2021 16:17:01 +0100 Subject: [PATCH 10/27] update tests --- test/test_cfuc.py | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/test/test_cfuc.py b/test/test_cfuc.py index a2b0d5990..7876a9953 100644 --- a/test/test_cfuc.py +++ b/test/test_cfuc.py @@ -47,7 +47,9 @@ def test_init(self): Tests the transfer of init frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - msg_init = self.bus.recv(None) + + self.serial = self.bus.ser + msg_init = self.serial.read(self.serial.in_waiting) self.assertIsNotNone(msg_init) @@ -56,6 +58,8 @@ def test_serial(self): Tests the correctness of reading and sending through serial """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + + # skip init frame self.serial = self.bus.ser msg_init = self.serial.read(self.serial.in_waiting) @@ -75,7 +79,10 @@ def test_tx_frame_extended(self): Tests the transfer of extented CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - msg_init = self.bus.recv(None) + + # skip init frame + self.serial = self.bus.ser + msg_init = self.serial.read(self.serial.in_waiting) msg_send = can.Message( arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55] @@ -83,8 +90,11 @@ def test_tx_frame_extended(self): self.bus.send(msg_send) msg_recv = self.bus.recv(None) - self.assertTrue(msg_recv.is_extended_id) # standart / extended field - self.assertEqual(msg_recv, msg_send) + self.assertEqual(msg_recv.arbitration_id, msg_send.arbitration_id) + self.assertEqual(msg_recv.is_extended_id, msg_send.is_extended_id) + self.assertEqual(msg_recv.is_fd, msg_send.is_fd) + self.assertEqual(msg_recv.data[0:2], msg_send.data[0:2]) + def test_tx_frame_standart(self): @@ -92,7 +102,10 @@ def test_tx_frame_standart(self): Tests the transfer of standart CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - msg_init = self.bus.recv(None) + + # skip init frame + self.serial = self.bus.ser + msg_init = self.serial.read(self.serial.in_waiting) msg_send = can.Message( arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55] @@ -100,8 +113,10 @@ def test_tx_frame_standart(self): self.bus.send(msg_send) msg_recv = self.bus.recv(None) - self.assertFalse(msg_recv.is_extended_id) # standart / extended field - self.assertEqual(msg_recv, msg_send) + self.assertEqual(msg_recv.arbitration_id, msg_send.arbitration_id) + self.assertEqual(msg_recv.is_extended_id, msg_send.is_extended_id) # error + self.assertEqual(msg_recv.is_fd, msg_send.is_fd) + self.assertEqual(msg_recv.data[0:2], msg_send.data[0:2]) def test_tx_fd_frame(self): @@ -109,7 +124,10 @@ def test_tx_fd_frame(self): Tests the transfer of Flexible Data-Rate CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - msg_init = self.bus.recv(None) + + # skip init frame + self.serial = self.bus.ser + msg_init = self.serial.read(self.serial.in_waiting) msg_send = can.Message( arbitration_id=0x12ABCDEF, is_extended_id=True, is_fd = True, data=[0xAA, 0x55] @@ -117,9 +135,10 @@ def test_tx_fd_frame(self): self.bus.send(msg_send) msg_recv = self.bus.recv(None) - self.assertTrue(msg_recv.is_extended_id) - self.assertTrue(msg_recv.is_fd) - self.assertEqual(msg_recv, msg_send) + self.assertEqual(msg_recv.arbitration_id, msg_send.arbitration_id) + self.assertEqual(msg_recv.is_extended_id, msg_send.is_extended_id) + self.assertEqual(msg_recv.is_fd, msg_send.is_fd) # error + self.assertEqual(msg_recv.data[0:2], msg_send.data[0:2]) #len #ErrorState #BitRateSwitch #FDFormat # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00 \x00\x00\x00\x00\ x00\x02\x00\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00 \x00 \x00\x00\x00\x00\ x00\x00\x02\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' From 97a581147400722e8d5f85447d154917b0aaf569 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Thu, 6 Jan 2022 16:17:37 +0100 Subject: [PATCH 11/27] fixed bug --- can/interfaces/cfuc/cfuc.py | 107 ++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 60 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 0ac053a90..c65369841 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -78,18 +78,17 @@ def consturct_init_frame( IsFD=False, IsBRS=False, IsAutoRetransmission=False, - NominalPrescalerValue=1, - NominalSyncJumpWidthValue=1, - NominalTimeSeg1Value=13, - NominalTimeSeg2Value=2, - DataPrescalerValue=1, - DataSyncJumpWidthValue=1, - DataTimeSeg1Value=1, - DataTimeSeg2Value=1, + NominalPrescaler: int = 1, + NominalSyncJumpWidthValue: int = 1, + NominalTimeSeg1Value: int = 13, + NominalTimeSeg2Value: int = 2, + DataPrescalerValue: int = 1, + DataSyncJumpWidthValue: int = 1, + DataTimeSeg1Value: int = 1, + DataTimeSeg2Value: int = 1, ): - - UCAN_FD_INIT = struct.pack(" Date: Thu, 6 Jan 2022 16:49:26 +0100 Subject: [PATCH 12/27] fixed fd and extended flags --- can/interfaces/cfuc/cfuc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index c65369841..db6df62e4 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -400,6 +400,8 @@ def _recv_internal(self, timeout): arbitration_id = can_tx_header_Identifier, dlc = dlc, data = can_data, + is_fd = True if can_tx_header_FDFormat else False, + is_extended_id = True if can_tx_header_IdType else False, ) return msg, False From 70d1415f0f45e4fe631d0499749e2973ec8083ec Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Thu, 6 Jan 2022 16:59:27 +0100 Subject: [PATCH 13/27] fixed messages flags --- can/interfaces/cfuc/cfuc.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index db6df62e4..2c0bcb67a 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -352,6 +352,10 @@ def _read_rx_frame(self) -> Message: arbitration_id = can_rx_header_Identifier, dlc = dlc, data = can_data, + is_fd = True if can_rx_header_FDFormat else False, + is_extended_id = True if can_rx_header_IdType else False, + bitrate_switch= True if can_rx_header_BitRateSwitch else False, + is_remote_frame= True if can_rx_header_RxFrameType else False, ) return msg @@ -402,6 +406,8 @@ def _recv_internal(self, timeout): data = can_data, is_fd = True if can_tx_header_FDFormat else False, is_extended_id = True if can_tx_header_IdType else False, + bitrate_switch= True if can_tx_header_BitRateSwitch else False, + is_remote_frame= True if can_tx_header_TxFrameType else False, ) return msg, False From 6c0139a4610e94bd8c548bd3a2f10c7114882441 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sat, 15 Jan 2022 19:18:26 +0100 Subject: [PATCH 14/27] fix --- can/interfaces/cfuc/cfuc.py | 51 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 2c0bcb67a..0b0463838 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -68,12 +68,7 @@ class cfucBus(BusABC): """ - def append_int32(self, dest, source): - for i in range(0, 4): - dest.append(source[i]) - return dest - - def consturct_init_frame( + def _consturct_init_frame( self, IsFD=False, IsBRS=False, @@ -87,8 +82,12 @@ def consturct_init_frame( DataTimeSeg1Value: int = 1, DataTimeSeg2Value: int = 1, ): + """ + Generate an initialization frame for CFUC device. - UCAN_FD_INIT = bytearray(b'\x00\x00\x00\x00') + """ + + FrameType = struct.pack(" Message: # read ucan_can_rx_def structure @@ -382,7 +380,6 @@ def _recv_internal(self, timeout): """ frame_type = self._read(4) - if frame_type == UCAN_FRAME_TYPE.UCAN_FD_TX.value: # read FDCAN_TxHeaderTypeDef structure @@ -411,7 +408,6 @@ def _recv_internal(self, timeout): ) return msg, False - if frame_type == UCAN_FRAME_TYPE.UCAN_FD_RX.value: can_frame_count = self._read(4) results = list() @@ -421,5 +417,4 @@ def _recv_internal(self, timeout): return tuple(results), False - return None, False \ No newline at end of file From 656339ef6f5c63b8db5ec88f582544d7ff78abdd Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sun, 16 Jan 2022 12:52:45 +0100 Subject: [PATCH 15/27] cleanup --- test/test_cfuc.py | 57 +++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/test/test_cfuc.py b/test/test_cfuc.py index 7876a9953..69f325ce3 100644 --- a/test/test_cfuc.py +++ b/test/test_cfuc.py @@ -61,11 +61,8 @@ def test_serial(self): # skip init frame self.serial = self.bus.ser - msg_init = self.serial.read(self.serial.in_waiting) - msg_to_send = can.Message( - arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55] - ) + msg_to_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55]) self.bus.send(msg_to_send) msg_template = b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' @@ -79,21 +76,15 @@ def test_tx_frame_extended(self): Tests the transfer of extented CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - - # skip init frame - self.serial = self.bus.ser - msg_init = self.serial.read(self.serial.in_waiting) - msg_send = can.Message( - arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55] - ) + msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55]) self.bus.send(msg_send) msg_recv = self.bus.recv(None) - self.assertEqual(msg_recv.arbitration_id, msg_send.arbitration_id) - self.assertEqual(msg_recv.is_extended_id, msg_send.is_extended_id) - self.assertEqual(msg_recv.is_fd, msg_send.is_fd) - self.assertEqual(msg_recv.data[0:2], msg_send.data[0:2]) + self.assertEqual(msg_recv[0].arbitration_id, msg_send.arbitration_id) + self.assertEqual(msg_recv[0].is_extended_id, msg_send.is_extended_id) + self.assertEqual(msg_recv[0].is_fd, msg_send.is_fd) + self.assertEqual(msg_recv[0].data[0:2], msg_send.data[0:2]) @@ -103,20 +94,14 @@ def test_tx_frame_standart(self): """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - # skip init frame - self.serial = self.bus.ser - msg_init = self.serial.read(self.serial.in_waiting) - - msg_send = can.Message( - arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55] - ) + msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55]) self.bus.send(msg_send) msg_recv = self.bus.recv(None) - self.assertEqual(msg_recv.arbitration_id, msg_send.arbitration_id) - self.assertEqual(msg_recv.is_extended_id, msg_send.is_extended_id) # error - self.assertEqual(msg_recv.is_fd, msg_send.is_fd) - self.assertEqual(msg_recv.data[0:2], msg_send.data[0:2]) + self.assertEqual(msg_recv[0].arbitration_id, msg_send.arbitration_id) + self.assertEqual(msg_recv[0].is_extended_id, msg_send.is_extended_id) # error + self.assertEqual(msg_recv[0].is_fd, msg_send.is_fd) + self.assertEqual(msg_recv[0].data[0:2], msg_send.data[0:2]) def test_tx_fd_frame(self): @@ -124,22 +109,12 @@ def test_tx_fd_frame(self): Tests the transfer of Flexible Data-Rate CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - - # skip init frame - self.serial = self.bus.ser - msg_init = self.serial.read(self.serial.in_waiting) - msg_send = can.Message( - arbitration_id=0x12ABCDEF, is_extended_id=True, is_fd = True, data=[0xAA, 0x55] - ) + msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=True, is_fd = True, data=[0xAA, 0x55]) self.bus.send(msg_send) msg_recv = self.bus.recv(None) - self.assertEqual(msg_recv.arbitration_id, msg_send.arbitration_id) - self.assertEqual(msg_recv.is_extended_id, msg_send.is_extended_id) - self.assertEqual(msg_recv.is_fd, msg_send.is_fd) # error - self.assertEqual(msg_recv.data[0:2], msg_send.data[0:2]) - #len #ErrorState #BitRateSwitch #FDFormat -# b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00 \x00\x00\x00\x00\ x00\x02\x00\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00 \x00 \x00\x00\x00\x00\ x00\x00\x02\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - # b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00 \x00\x00\x00\x00\ x00\x02\x00\x00\ x00\x00\x00\x00 \x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\x00\x00\ x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \ No newline at end of file + self.assertEqual(msg_recv[0].arbitration_id, msg_send.arbitration_id) + self.assertEqual(msg_recv[0].is_extended_id, msg_send.is_extended_id) + self.assertEqual(msg_recv[0].is_fd, msg_send.is_fd) # error + self.assertEqual(msg_recv[0].data[0:2], msg_send.data[0:2]) \ No newline at end of file From b33734981237491f88f9160f8ea2934dafbad4bb Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sun, 16 Jan 2022 13:03:23 +0100 Subject: [PATCH 16/27] works --- can/interfaces/cfuc/cfuc.py | 73 +++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 0b0463838..55ba6f68b 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -72,9 +72,9 @@ def _consturct_init_frame( self, IsFD=False, IsBRS=False, - IsAutoRetransmission=False, - NominalPrescaler: int = 1, - NominalSyncJumpWidthValue: int = 1, + IsAutoRetransmission=True, + NominalPrescaler: int = 90, + NominalSyncJumpWidthValue: int = 128, NominalTimeSeg1Value: int = 13, NominalTimeSeg2Value: int = 2, DataPrescalerValue: int = 1, @@ -235,7 +235,6 @@ def __init__( self.ser.write(init_frame) super().__init__(channel, *args, **kwargs) - # super(cfucBus, self).__init__(channel=channel, *args, **kwargs) def shutdown(self): @@ -323,8 +322,6 @@ def _read(self, length): def _read_rx_frame(self) -> Message: - # read ucan_can_rx_def structure - # read FDCAN_RxHeaderTypeDef structure can_rx_header_Identifier = self._read(4) can_rx_header_IdType = self._read(4) @@ -358,6 +355,34 @@ def _read_rx_frame(self) -> Message: return msg + def _read_tx_frame(self) -> Message: + # read FDCAN_TxHeaderTypeDef structure + can_tx_header_Identifier = self._read(4) + can_tx_header_IdType = self._read(4) + can_tx_header_TxFrameType = self._read(4) + can_tx_header_DataLength = self._read(4) + can_tx_header_ErrorStateIndicator = self._read(4) + can_tx_header_BitRateSwitch = self._read(4) + can_tx_header_FDFormat = self._read(4) + can_tx_header_TxEventFifoControl = self._read(4) + can_tx_header_MessageMarker = self._read(4) + + can_data = bytearray(self.ser.read(64)) + + dlc = list(ADLC.values()).index(can_tx_header_DataLength) + + msg = Message( + arbitration_id = can_tx_header_Identifier, + dlc = dlc, + data = can_data, + is_fd = True if can_tx_header_FDFormat else False, + is_extended_id = True if can_tx_header_IdType else False, + bitrate_switch= True if can_tx_header_BitRateSwitch else False, + is_remote_frame= True if can_tx_header_TxFrameType else False, + ) + return msg, False + + def _recv_internal(self, timeout): """ Read a message from the serial device. @@ -378,39 +403,15 @@ def _recv_internal(self, timeout): :rtype: can.Message, bool """ - frame_type = self._read(4) + frame_type = self._read(4) # read frame type if frame_type == UCAN_FRAME_TYPE.UCAN_FD_TX.value: - - # read FDCAN_TxHeaderTypeDef structure - can_tx_header_Identifier = self._read(4) - can_tx_header_IdType = self._read(4) - can_tx_header_TxFrameType = self._read(4) - can_tx_header_DataLength = self._read(4) - can_tx_header_ErrorStateIndicator = self._read(4) - can_tx_header_BitRateSwitch = self._read(4) - can_tx_header_FDFormat = self._read(4) - can_tx_header_TxEventFifoControl = self._read(4) - can_tx_header_MessageMarker = self._read(4) - - can_data = bytearray(self.ser.read(64)) - - dlc = list(ADLC.values()).index(can_tx_header_DataLength) - - msg = Message( - arbitration_id = can_tx_header_Identifier, - dlc = dlc, - data = can_data, - is_fd = True if can_tx_header_FDFormat else False, - is_extended_id = True if can_tx_header_IdType else False, - bitrate_switch= True if can_tx_header_BitRateSwitch else False, - is_remote_frame= True if can_tx_header_TxFrameType else False, - ) - return msg, False - - if frame_type == UCAN_FRAME_TYPE.UCAN_FD_RX.value: - can_frame_count = self._read(4) + results = self._read_tx_frame() + return results, False + + elif frame_type == UCAN_FRAME_TYPE.UCAN_FD_RX.value: # if its UCAN_FD_RX results = list() + can_frame_count = self._read(4) # read frame count for i in range(can_frame_count): results.append(self._read_rx_frame()) From d731b362eb96bdfb43aa29a906e3847f1682e4a6 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Thu, 27 Jan 2022 18:12:51 +0100 Subject: [PATCH 17/27] update --- can/interfaces/cfuc/cfuc.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 55ba6f68b..23b3097b3 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -349,8 +349,9 @@ def _read_rx_frame(self) -> Message: data = can_data, is_fd = True if can_rx_header_FDFormat else False, is_extended_id = True if can_rx_header_IdType else False, - bitrate_switch= True if can_rx_header_BitRateSwitch else False, - is_remote_frame= True if can_rx_header_RxFrameType else False, + bitrate_switch = True if can_rx_header_BitRateSwitch else False, + is_remote_frame = True if can_rx_header_RxFrameType else False, + error_state_indicator = True if can_rx_header_ErrorStateIndicator else False, ) return msg @@ -379,6 +380,7 @@ def _read_tx_frame(self) -> Message: is_extended_id = True if can_tx_header_IdType else False, bitrate_switch= True if can_tx_header_BitRateSwitch else False, is_remote_frame= True if can_tx_header_TxFrameType else False, + error_state_indicator = True if can_tx_header_ErrorStateIndicator else False, ) return msg, False @@ -409,7 +411,7 @@ def _recv_internal(self, timeout): results = self._read_tx_frame() return results, False - elif frame_type == UCAN_FRAME_TYPE.UCAN_FD_RX.value: # if its UCAN_FD_RX + elif frame_type == UCAN_FRAME_TYPE.UCAN_FD_RX.value: results = list() can_frame_count = self._read(4) # read frame count @@ -417,5 +419,11 @@ def _recv_internal(self, timeout): results.append(self._read_rx_frame()) return tuple(results), False + + elif frame_type == -1: + return None, False + + # else: + # print("ERROR", frame_type) return None, False \ No newline at end of file From 1a4ef28ad69de98f6a864e5887f05ea5e12afd7d Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Tue, 8 Feb 2022 19:27:42 +0100 Subject: [PATCH 18/27] add bootloader function --- can/interfaces/cfuc/cfuc.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 23b3097b3..095f4421f 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -68,6 +68,15 @@ class cfucBus(BusABC): """ + def _construct_bootloader_frame(self): + FrameType = struct.pack(" Date: Mon, 21 Feb 2022 22:17:42 +0100 Subject: [PATCH 19/27] hotfix --- can/interfaces/cfuc/cfuc.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 095f4421f..216e30ff5 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -119,15 +119,15 @@ def _consturct_init_frame( byte_msg += AutoRetransmission #AutoRetransmission byte_msg += bytearray(b'\x00') #TransmitPause byte_msg += bytearray(b'\x00') #ProtocolException - byte_msg += bytearray(b'\x00') #bug - empty byte, fillup byte + byte_msg += bytearray(b'\x00') #empty/fillup byte byte_msg += struct.pack(" Date: Sat, 5 Mar 2022 11:04:11 +0100 Subject: [PATCH 20/27] fix --- can/interfaces/cfuc/cfuc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 216e30ff5..98ed6e281 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -51,6 +51,7 @@ 15: 0x000F0000, } +UCAN_RX_FRAME_DEF_CAN_COUNT_MAX = 10 class UCAN_FRAME_TYPE(enum.Enum): UCAN_FD_INIT = 0 # init CAN with all parameters, open in mode specified in init data. Frame direction USB->CAN*/ UCAN_FD_DEINIT = 1 # deinit CAN, close CAN connection. Frame direction USB->CAN*/ @@ -431,7 +432,10 @@ def _recv_internal(self, timeout): for i in range(can_frame_count): results.append(self._read_rx_frame()) - + + for i in range(UCAN_RX_FRAME_DEF_CAN_COUNT_MAX - can_frame_count): + self._read_rx_frame() # drop empty frames + return tuple(results), False else: From 31535b49ed3d13f0a30a2a8ea33aa22795e44137 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Wed, 23 Mar 2022 22:17:53 +0100 Subject: [PATCH 21/27] fix --- test/test_cfuc.py | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/test/test_cfuc.py b/test/test_cfuc.py index 69f325ce3..4d0f82ce1 100644 --- a/test/test_cfuc.py +++ b/test/test_cfuc.py @@ -53,34 +53,33 @@ def test_init(self): self.assertIsNotNone(msg_init) - def test_serial(self): + def test_tx_frame_extended(self): """ - Tests the correctness of reading and sending through serial + Tests the transfer of extented CAN frame """ - self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + self.bus = can.Bus( + bustype="cfuc", + channel="loop://", + CANBaudRate=100000, + IsFD=True, + FDDataBaudRate=500000, + ) + - # skip init frame self.serial = self.bus.ser + msg_init = self.serial.read(self.serial.in_waiting) - msg_to_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55]) - self.bus.send(msg_to_send) - - msg_template = b'\x02\x00\x00\x00\xef\xcd\xab\x12\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaaU\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' - - msg_recv = self.serial.read(self.serial.in_waiting) - self.assertEqual(msg_recv, msg_template) - + msg_send = can.Message( + arbitration_id=0xAAABBCC, + data=[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 1,1], + is_extended_id=True, + is_fd=True, + bitrate_switch=True + ) - def test_tx_frame_extended(self): - """ - Tests the transfer of extented CAN frame - """ - self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - - msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=True, data=[0xAA, 0x55]) self.bus.send(msg_send) - msg_recv = self.bus.recv(None) + msg_recv = self.bus.recv() self.assertEqual(msg_recv[0].arbitration_id, msg_send.arbitration_id) self.assertEqual(msg_recv[0].is_extended_id, msg_send.is_extended_id) self.assertEqual(msg_recv[0].is_fd, msg_send.is_fd) @@ -93,6 +92,9 @@ def test_tx_frame_standart(self): Tests the transfer of standart CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + + self.serial = self.bus.ser + msg_init = self.serial.read(self.serial.in_waiting) msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55]) self.bus.send(msg_send) @@ -109,6 +111,9 @@ def test_tx_fd_frame(self): Tests the transfer of Flexible Data-Rate CAN frame """ self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + + self.serial = self.bus.ser + msg_init = self.serial.read(self.serial.in_waiting) msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=True, is_fd = True, data=[0xAA, 0x55]) self.bus.send(msg_send) From 7130352f2051cf322dcf3f499ad535a711169ad8 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Thu, 24 Mar 2022 22:24:58 +0100 Subject: [PATCH 22/27] update baudrate warrnings --- can/interfaces/cfuc/cfuc.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 98ed6e281..d4204706a 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -206,6 +206,12 @@ def __init__( self.ser.reset_input_buffer() self.ser.reset_output_buffer() + if CANBaudRate < 100000: + raise ValueError("Baudrate must be equal to or greater than 100kbit/s") + + if CANBaudRate > 37000000: + raise ValueError("Baudrate must be equal to or less than 37000kbit/s") + if CANBaudRate != 0: bt = can_calc_bittiming.bt() bt.bitrate = CANBaudRate From 074a9871c029ddda6409825b341052bc9ab8be56 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Sat, 23 Apr 2022 10:22:59 +0200 Subject: [PATCH 23/27] fix dlc --- can/interfaces/cfuc/cfuc.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index d4204706a..9e0e38de8 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -266,6 +266,19 @@ def shutdown(self): self.ser.close() + def _get_DLC(self, dlc): + if dlc < 0: raise ValueError("DLC are intended to be greater than zero") + if dlc > 64: raise ValueError("DLC above 15 are not supported") + if dlc > 48: return int(ADLC[15]) + if dlc > 32: return int(ADLC[14]) + if dlc > 24: return int(ADLC[13]) + if dlc > 20: return int(ADLC[12]) + if dlc > 16: return int(ADLC[11]) + if dlc > 12: return int(ADLC[10]) + if dlc > 8: return int(ADLC[9]) + return int(ADLC[dlc]) + + def send(self, msg: Message, timeout=None): """ Send a message over the serial device. @@ -290,7 +303,7 @@ def send(self, msg: Message, timeout=None): a_ex = bytearray(b'\x00\x00\x00\x40') if (msg.is_extended_id) else bytearray(b'\x00\x00\x00\x00') a_rmt = bytearray(b'\x00\x00\x00\x20') if (msg.is_remote_frame) else bytearray(b'\x00\x00\x00\x00') - a_dlc = struct.pack(" Date: Sat, 9 Jul 2022 14:44:10 +0200 Subject: [PATCH 24/27] fix bootloader fun --- can/interfaces/cfuc/cfuc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 9e0e38de8..9779df1bd 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -77,6 +77,7 @@ def _construct_bootloader_frame(self): def go_to_bootloader(self): frame = self._construct_bootloader_frame() self.ser.write(frame) + self.shutdown() def _consturct_init_frame( self, From 4af7548a7ef45fb06886675ec486f9f6b35ad820 Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Tue, 2 Aug 2022 23:12:31 +0200 Subject: [PATCH 25/27] dlc fix --- can/interfaces/cfuc/cfuc.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 9779df1bd..60c3f1321 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -51,6 +51,25 @@ 15: 0x000F0000, } +DLC_TO_BYTES = { + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 12, + 10: 16, + 11: 20, + 12: 24, + 13: 32, + 14: 48, + 15: 64 +} + UCAN_RX_FRAME_DEF_CAN_COUNT_MAX = 10 class UCAN_FRAME_TYPE(enum.Enum): UCAN_FD_INIT = 0 # init CAN with all parameters, open in mode specified in init data. Frame direction USB->CAN*/ @@ -375,7 +394,8 @@ def _read_rx_frame(self) -> Message: #read Flasg and Errors packed_flags_and_error_counters = self._read(4) - dlc = list(ADLC.values()).index(can_rx_header_DataLength) + tmp = hex(can_rx_header_DataLength) + dlc = DLC_TO_BYTES[int(tmp[2], base=16)] msg = Message( timestamp = can_rx_header_RxTimestamp / 1000, @@ -405,7 +425,8 @@ def _read_tx_frame(self) -> Message: can_data = bytearray(self.ser.read(64)) - dlc = list(ADLC.values()).index(can_tx_header_DataLength) + tmp = hex(can_tx_header_DataLength) + dlc = DLC_TO_BYTES[int(tmp[2], base=16)] msg = Message( arbitration_id = can_tx_header_Identifier, From a41527967be52bb166dd5456a8595a81e6e8c0dd Mon Sep 17 00:00:00 2001 From: Marcin Bober Date: Thu, 4 Aug 2022 10:47:38 +0200 Subject: [PATCH 26/27] add contributor --- CONTRIBUTORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index ae7792e42..ac9c8ab8e 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -32,6 +32,7 @@ Lear Corporation Nick Black Francisco Javier Burgos Macia Felix Nieuwenhuizen +Marcin Bober @marcel-kanter @bessman @koberbe From 344fc3ee96162d8a6e0559073dbcecf2de73f10c Mon Sep 17 00:00:00 2001 From: mbober1 Date: Sat, 31 Dec 2022 11:17:00 +0000 Subject: [PATCH 27/27] Format code with black --- can/interfaces/__init__.py | 2 +- can/interfaces/cfuc/can_calc_bittiming.py | 119 +++++------ can/interfaces/cfuc/cfuc.py | 195 +++++++++--------- .../cfuc/test_can_calc_bittiming.py | 16 +- test/test_cfuc.py | 78 ++++--- 5 files changed, 224 insertions(+), 186 deletions(-) diff --git a/can/interfaces/__init__.py b/can/interfaces/__init__.py index 2711b94b2..6f579c0f6 100644 --- a/can/interfaces/__init__.py +++ b/can/interfaces/__init__.py @@ -28,7 +28,7 @@ "gs_usb": ("can.interfaces.gs_usb", "GsUsbBus"), "nixnet": ("can.interfaces.nixnet", "NiXNETcanBus"), "neousys": ("can.interfaces.neousys", "NeousysBus"), - "cfuc": ("can.interfaces.cfuc","cfucBus"), + "cfuc": ("can.interfaces.cfuc", "cfucBus"), "etas": ("can.interfaces.etas", "EtasBus"), "socketcand": ("can.interfaces.socketcand", "SocketCanDaemonBus"), } diff --git a/can/interfaces/cfuc/can_calc_bittiming.py b/can/interfaces/cfuc/can_calc_bittiming.py index de084d808..132f1651f 100644 --- a/can/interfaces/cfuc/can_calc_bittiming.py +++ b/can/interfaces/cfuc/can_calc_bittiming.py @@ -4,36 +4,40 @@ INT_MAX = 2147483647 UINT_MAX = INT_MAX * 2 + 1 -CAN_CALC_MAX_ERROR = 50 # in one-tenth of a percent */ -CAN_CALC_SYNC_SEG = 1 +CAN_CALC_MAX_ERROR = 50 # in one-tenth of a percent */ +CAN_CALC_SYNC_SEG = 1 + class btc(object): - tseg1_min = 1 # Time segement 1 = prop_seg + phase_seg1 */ + tseg1_min = 1 # Time segement 1 = prop_seg + phase_seg1 */ tseg1_max = 16 - tseg2_min = 1 # Time segement 2 = phase_seg2 */ + tseg2_min = 1 # Time segement 2 = phase_seg2 */ tseg2_max = 8 - sjw_max = 4 # Synchronisation jump width */ - brp_min = 1 # Bit-rate prescaler */ + sjw_max = 4 # Synchronisation jump width */ + brp_min = 1 # Bit-rate prescaler */ brp_max = 64 brp_inc = 1 + class bt(object): - bitrate = 0 # Bit-rate in bits/second */ - sample_point = 0 # Sample point in one-tenth of a percent */ - tq = 0 # Time quanta (TQ) in nanoseconds */ - prop_seg = 0 # Propagation segment in TQs */ - phase_seg1 = 0 # Phase buffer segment 1 in TQs */ - phase_seg2 = 0 # Phase buffer segment 2 in TQs */ - sjw = 0 # Synchronisation jump width in TQs */ - brp = 0 # Bit-rate prescaler */ + bitrate = 0 # Bit-rate in bits/second */ + sample_point = 0 # Sample point in one-tenth of a percent */ + tq = 0 # Time quanta (TQ) in nanoseconds */ + prop_seg = 0 # Propagation segment in TQs */ + phase_seg1 = 0 # Phase buffer segment 1 in TQs */ + phase_seg2 = 0 # Phase buffer segment 2 in TQs */ + sjw = 0 # Synchronisation jump width in TQs */ + brp = 0 # Bit-rate prescaler */ + def clamp(val, lo, hi): - if (val < lo): val = lo - if (val > hi): val = hi + if val < lo: + val = lo + if val > hi: + val = hi return val - def can_update_spt(btc, spt_nominal, tseg, tseg1_ptr, tseg2_ptr, spt_error_ptr): spt_error = 0 best_spt_error = UINT_MAX @@ -43,18 +47,23 @@ def can_update_spt(btc, spt_nominal, tseg, tseg1_ptr, tseg2_ptr, spt_error_ptr): tseg2 = 0 i = 0 - while (i <= 1): - - tseg2 = tseg + CAN_CALC_SYNC_SEG - math.floor((spt_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000) - i + while i <= 1: + + tseg2 = ( + tseg + + CAN_CALC_SYNC_SEG + - math.floor((spt_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000) + - i + ) tseg2 = clamp(tseg2, btc.tseg2_min, btc.tseg2_max) tseg1 = tseg - tseg2 - if (tseg1 > btc.tseg1_max): + if tseg1 > btc.tseg1_max: tseg1 = btc.tseg1_max tseg2 = tseg - tseg1 - spt = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG) + spt = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG) spt_error = abs(spt_nominal - spt) - if ((spt <= spt_nominal) & (spt_error < best_spt_error)) : + if (spt <= spt_nominal) & (spt_error < best_spt_error): best_spt_ptr = spt best_spt_error = spt_error tseg1_ptr = tseg1 @@ -63,41 +72,40 @@ def can_update_spt(btc, spt_nominal, tseg, tseg1_ptr, tseg2_ptr, spt_error_ptr): spt_error_ptr = best_spt_error - return tseg1_ptr,tseg2_ptr,spt_error_ptr, best_spt_ptr - + return tseg1_ptr, tseg2_ptr, spt_error_ptr, best_spt_ptr def CAN_CALC_BITTIMING(bt, btc): clock_freq = 144000000 spt_nominal = 0 - best_tseg = 0 #' current best value for tseg */ - best_brp = 0 # current best value for brp */ - brp = 0 - tsegall = 0 - tseg = 0 + best_tseg = 0 #' current best value for tseg */ + best_brp = 0 # current best value for brp */ + brp = 0 + tsegall = 0 + tseg = 0 tseg1 = 0 tseg2 = 0 - rate_error = 0 # difference between current and nominal value */ + rate_error = 0 # difference between current and nominal value */ best_rate_error = UINT_MAX - spt_error = 0 # difference between current and nominal value */ + spt_error = 0 # difference between current and nominal value */ best_spt_error = UINT_MAX - if (bt.bitrate > 800000): + if bt.bitrate > 800000: spt_nominal = 750 - else: - if (bt.bitrate > 500000): + else: + if bt.bitrate > 500000: spt_nominal = 800 else: spt_nominal = 875 - # tseg even = round down, odd = round up + # tseg even = round down, odd = round up tsegall = 0 tseg = (btc.tseg1_max + btc.tseg2_max) * 2 + 2 while tseg >= (btc.tseg1_min + btc.tseg2_min) * 2: tseg = tseg - 1 tsegall = math.floor(CAN_CALC_SYNC_SEG + tseg / 2) - # Compute all possible tseg choices (tseg=tseg1+tseg2) + # Compute all possible tseg choices (tseg=tseg1+tseg2) brp = math.floor(clock_freq / (tsegall * bt.bitrate) + tseg % 2) # choose brp step which is possible in system */ @@ -108,15 +116,17 @@ def CAN_CALC_BITTIMING(bt, btc): rate = math.floor(clock_freq / (brp * tsegall)) rate_error = abs(bt.bitrate - rate) - # tseg brp biterror - if (rate_error > best_rate_error): + # tseg brp biterror + if rate_error > best_rate_error: continue - # reset sample point error if we have a better bitrate */ - if (rate_error < best_rate_error): + # reset sample point error if we have a better bitrate */ + if rate_error < best_rate_error: best_spt_error = UINT_MAX - tseg1,tseg2,spt_error, spt = can_update_spt(btc, spt_nominal, math.floor(tseg / 2), tseg1, tseg2, spt_error) - if (spt_error > best_spt_error): + tseg1, tseg2, spt_error, spt = can_update_spt( + btc, spt_nominal, math.floor(tseg / 2), tseg1, tseg2, spt_error + ) + if spt_error > best_spt_error: continue best_spt_error = spt_error @@ -124,18 +134,18 @@ def CAN_CALC_BITTIMING(bt, btc): best_tseg = tseg / 2 best_brp = brp - if ((rate_error == 0) & (spt_error == 0)): + if (rate_error == 0) & (spt_error == 0): break - if (best_rate_error != 0) : + if best_rate_error != 0: # Error in one-tenth of a percent */ rate_error = (best_rate_error * 1000) / bt.bitrate - if (rate_error > CAN_CALC_MAX_ERROR): + if rate_error > CAN_CALC_MAX_ERROR: return -33 - bt.sample_point = can_update_spt(btc, spt_nominal, best_tseg,tseg1, tseg2, 0)[3] + bt.sample_point = can_update_spt(btc, spt_nominal, best_tseg, tseg1, tseg2, 0)[3] v64 = best_brp * 1000 * 1000 * 1000 - #do_div(v64, clock_freq) + # do_div(v64, clock_freq) v64 = v64 / clock_freq # eof do_div @@ -144,14 +154,14 @@ def CAN_CALC_BITTIMING(bt, btc): bt.phase_seg1 = tseg1 - bt.prop_seg bt.phase_seg2 = tseg2 - if ((bt.sjw == 0) | (btc.sjw_max == 0)): + if (bt.sjw == 0) | (btc.sjw_max == 0): bt.sjw = 1 else: # bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ - if (bt.sjw > btc.sjw_max): + if bt.sjw > btc.sjw_max: bt.sjw = btc.sjw_max # bt->sjw must not be higher than tseg2 */ - if (tseg2 < bt.sjw): + if tseg2 < bt.sjw: bt.sjw = tseg2 bt.brp = best_brp @@ -160,10 +170,3 @@ def CAN_CALC_BITTIMING(bt, btc): bt.bitrate = math.floor(clock_freq / (bt.brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2))) return bt - - - - - - - diff --git a/can/interfaces/cfuc/cfuc.py b/can/interfaces/cfuc/cfuc.py index 60c3f1321..f1fab8b69 100644 --- a/can/interfaces/cfuc/cfuc.py +++ b/can/interfaces/cfuc/cfuc.py @@ -67,19 +67,21 @@ 12: 24, 13: 32, 14: 48, - 15: 64 + 15: 64, } UCAN_RX_FRAME_DEF_CAN_COUNT_MAX = 10 + + class UCAN_FRAME_TYPE(enum.Enum): - UCAN_FD_INIT = 0 # init CAN with all parameters, open in mode specified in init data. Frame direction USB->CAN*/ - UCAN_FD_DEINIT = 1 # deinit CAN, close CAN connection. Frame direction USB->CAN*/ - UCAN_FD_TX = 2 # send new frame on CAN network. Frame direction USB->CAN */ - UCAN_FD_SAVE_CONFIG = 3 # saves CAN config to NVM USB->CAN*/ - UCAN_FD_GO_TO_BOOTLOADER = 4 # go to USB bootloader USB->CAN*/ - UCAN_FD_GET_CAN_STATUS = 5 # request status USB->CAN*/ - UCAN_FD_RX = 6 # new CAN frame received on network. Frame direction CAN->USB*/ - UCAN_FD_ACK = 7 # gets CAN status from CONVERTER. Also ACK resposne for all frames form USB. Frame direction CAN->USB */ + UCAN_FD_INIT = 0 # init CAN with all parameters, open in mode specified in init data. Frame direction USB->CAN*/ + UCAN_FD_DEINIT = 1 # deinit CAN, close CAN connection. Frame direction USB->CAN*/ + UCAN_FD_TX = 2 # send new frame on CAN network. Frame direction USB->CAN */ + UCAN_FD_SAVE_CONFIG = 3 # saves CAN config to NVM USB->CAN*/ + UCAN_FD_GO_TO_BOOTLOADER = 4 # go to USB bootloader USB->CAN*/ + UCAN_FD_GET_CAN_STATUS = 5 # request status USB->CAN*/ + UCAN_FD_RX = 6 # new CAN frame received on network. Frame direction CAN->USB*/ + UCAN_FD_ACK = 7 # gets CAN status from CONVERTER. Also ACK resposne for all frames form USB. Frame direction CAN->USB */ class cfucBus(BusABC): @@ -90,7 +92,7 @@ class cfucBus(BusABC): def _construct_bootloader_frame(self): FrameType = struct.pack(" 64: raise ValueError("DLC above 15 are not supported") - if dlc > 48: return int(ADLC[15]) - if dlc > 32: return int(ADLC[14]) - if dlc > 24: return int(ADLC[13]) - if dlc > 20: return int(ADLC[12]) - if dlc > 16: return int(ADLC[11]) - if dlc > 12: return int(ADLC[10]) - if dlc > 8: return int(ADLC[9]) + if dlc < 0: + raise ValueError("DLC are intended to be greater than zero") + if dlc > 64: + raise ValueError("DLC above 15 are not supported") + if dlc > 48: + return int(ADLC[15]) + if dlc > 32: + return int(ADLC[14]) + if dlc > 24: + return int(ADLC[13]) + if dlc > 20: + return int(ADLC[12]) + if dlc > 16: + return int(ADLC[11]) + if dlc > 12: + return int(ADLC[10]) + if dlc > 8: + return int(ADLC[9]) return int(ADLC[dlc]) - def send(self, msg: Message, timeout=None): """ Send a message over the serial device. @@ -320,8 +327,16 @@ def send(self, msg: Message, timeout=None): except struct.error: raise ValueError("Arbitration Id is out of range") - a_ex = bytearray(b'\x00\x00\x00\x40') if (msg.is_extended_id) else bytearray(b'\x00\x00\x00\x00') - a_rmt = bytearray(b'\x00\x00\x00\x20') if (msg.is_remote_frame) else bytearray(b'\x00\x00\x00\x00') + a_ex = ( + bytearray(b"\x00\x00\x00\x40") + if (msg.is_extended_id) + else bytearray(b"\x00\x00\x00\x00") + ) + a_rmt = ( + bytearray(b"\x00\x00\x00\x20") + if (msg.is_remote_frame) + else bytearray(b"\x00\x00\x00\x00") + ) a_dlc = struct.pack(" Message: # read FDCAN_RxHeaderTypeDef structure can_rx_header_Identifier = self._read(4) @@ -388,29 +401,28 @@ def _read_rx_frame(self) -> Message: can_rx_header_FilterIndex = self._read(4) can_rx_header_IsFilterMatchingFrame = self._read(4) - #read Data CAN buffer + # read Data CAN buffer can_data = bytearray(self.ser.read(64)) - #read Flasg and Errors - packed_flags_and_error_counters = self._read(4) - + # read Flasg and Errors + packed_flags_and_error_counters = self._read(4) + tmp = hex(can_rx_header_DataLength) dlc = DLC_TO_BYTES[int(tmp[2], base=16)] msg = Message( - timestamp = can_rx_header_RxTimestamp / 1000, - arbitration_id = can_rx_header_Identifier, - dlc = dlc, - data = can_data, - is_fd = True if can_rx_header_FDFormat else False, - is_extended_id = True if can_rx_header_IdType else False, - bitrate_switch = True if can_rx_header_BitRateSwitch else False, - is_remote_frame = True if can_rx_header_RxFrameType else False, - error_state_indicator = True if can_rx_header_ErrorStateIndicator else False, + timestamp=can_rx_header_RxTimestamp / 1000, + arbitration_id=can_rx_header_Identifier, + dlc=dlc, + data=can_data, + is_fd=True if can_rx_header_FDFormat else False, + is_extended_id=True if can_rx_header_IdType else False, + bitrate_switch=True if can_rx_header_BitRateSwitch else False, + is_remote_frame=True if can_rx_header_RxFrameType else False, + error_state_indicator=True if can_rx_header_ErrorStateIndicator else False, ) return msg - def _read_tx_frame(self) -> Message: # read FDCAN_TxHeaderTypeDef structure can_tx_header_Identifier = self._read(4) @@ -429,18 +441,17 @@ def _read_tx_frame(self) -> Message: dlc = DLC_TO_BYTES[int(tmp[2], base=16)] msg = Message( - arbitration_id = can_tx_header_Identifier, - dlc = dlc, - data = can_data, - is_fd = True if can_tx_header_FDFormat else False, - is_extended_id = True if can_tx_header_IdType else False, - bitrate_switch= True if can_tx_header_BitRateSwitch else False, - is_remote_frame= True if can_tx_header_TxFrameType else False, - error_state_indicator = True if can_tx_header_ErrorStateIndicator else False, + arbitration_id=can_tx_header_Identifier, + dlc=dlc, + data=can_data, + is_fd=True if can_tx_header_FDFormat else False, + is_extended_id=True if can_tx_header_IdType else False, + bitrate_switch=True if can_tx_header_BitRateSwitch else False, + is_remote_frame=True if can_tx_header_TxFrameType else False, + error_state_indicator=True if can_tx_header_ErrorStateIndicator else False, ) return msg, False - def _recv_internal(self, timeout): """ Read a message from the serial device. @@ -461,23 +472,23 @@ def _recv_internal(self, timeout): :rtype: can.Message, bool """ - frame_type = self._read(4) # read frame type + frame_type = self._read(4) # read frame type if frame_type == UCAN_FRAME_TYPE.UCAN_FD_TX.value: results = self._read_tx_frame() return results, False - + elif frame_type == UCAN_FRAME_TYPE.UCAN_FD_RX.value: results = list() - can_frame_count = self._read(4) # read frame count + can_frame_count = self._read(4) # read frame count for i in range(can_frame_count): results.append(self._read_rx_frame()) - + for i in range(UCAN_RX_FRAME_DEF_CAN_COUNT_MAX - can_frame_count): - self._read_rx_frame() # drop empty frames - + self._read_rx_frame() # drop empty frames + return tuple(results), False - + else: - return None, False \ No newline at end of file + return None, False diff --git a/can/interfaces/cfuc/test_can_calc_bittiming.py b/can/interfaces/cfuc/test_can_calc_bittiming.py index 2cc7dde27..e9129879b 100644 --- a/can/interfaces/cfuc/test_can_calc_bittiming.py +++ b/can/interfaces/cfuc/test_can_calc_bittiming.py @@ -4,30 +4,32 @@ def test_baud100k(): bt = can_calc_bittiming.bt() - bt.bitrate = 100*1000 + bt.bitrate = 100 * 1000 btc = can_calc_bittiming.btc() - bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt,btc) + bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt, btc) assert bt.brp == 60 assert bt.bitrate == 100000 + def test_baud250k(): bt = can_calc_bittiming.bt() - bt.bitrate = 250*1000 + bt.bitrate = 250 * 1000 btc = can_calc_bittiming.btc() - bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt,btc) + bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt, btc) assert bt.brp == 36 assert bt.bitrate == 250000 + def test_baud1000k(): bt = can_calc_bittiming.bt() - bt.bitrate = 1000*1000 + bt.bitrate = 1000 * 1000 btc = can_calc_bittiming.btc() - bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt,btc) + bt = can_calc_bittiming.CAN_CALC_BITTIMING(bt, btc) assert bt.brp == 9 assert bt.tq == 62 assert bt.prop_seg == 5 assert bt.phase_seg1 == 6 assert bt.phase_seg2 == 4 - assert bt.bitrate == 1000*1000 \ No newline at end of file + assert bt.bitrate == 1000 * 1000 diff --git a/test/test_cfuc.py b/test/test_cfuc.py index 4d0f82ce1..cda2df542 100644 --- a/test/test_cfuc.py +++ b/test/test_cfuc.py @@ -10,12 +10,15 @@ import unittest import can from can.message import Message -# import can.interfaces.cfucBus + +# import can.interfaces.cfucBus + class SerialDummy(object): """ Dummy to mock the serial communication """ + msg = None def __init__(self): @@ -33,48 +36,51 @@ def write(self, msg): def reset(self): self.msg = None -class CFUCTestCase(unittest.TestCase): +class CFUCTestCase(unittest.TestCase): def setUp(self): pass def tearDown(self): self.bus.shutdown() - def test_init(self): """ Tests the transfer of init frame """ - self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - + self.bus = can.Bus( + bustype="cfuc", + channel="loop://", + CANBaudRate=250000, + IsFD=True, + FDDataBaudRate=500000, + ) + self.serial = self.bus.ser msg_init = self.serial.read(self.serial.in_waiting) self.assertIsNotNone(msg_init) - def test_tx_frame_extended(self): """ Tests the transfer of extented CAN frame """ self.bus = can.Bus( - bustype="cfuc", - channel="loop://", - CANBaudRate=100000, - IsFD=True, - FDDataBaudRate=500000, + bustype="cfuc", + channel="loop://", + CANBaudRate=100000, + IsFD=True, + FDDataBaudRate=500000, ) - self.serial = self.bus.ser msg_init = self.serial.read(self.serial.in_waiting) msg_send = can.Message( - arbitration_id=0xAAABBCC, - data=[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 1,1], - is_extended_id=True, - is_fd=True, - bitrate_switch=True + arbitration_id=0xAAABBCC, + data=[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 1, 1], + is_extended_id=True, + is_fd=True, + bitrate_switch=True, ) self.bus.send(msg_send) @@ -85,41 +91,57 @@ def test_tx_frame_extended(self): self.assertEqual(msg_recv[0].is_fd, msg_send.is_fd) self.assertEqual(msg_recv[0].data[0:2], msg_send.data[0:2]) - - def test_tx_frame_standart(self): """ Tests the transfer of standart CAN frame """ - self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) + self.bus = can.Bus( + bustype="cfuc", + channel="loop://", + CANBaudRate=250000, + IsFD=True, + FDDataBaudRate=500000, + ) self.serial = self.bus.ser msg_init = self.serial.read(self.serial.in_waiting) - - msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55]) + + msg_send = can.Message( + arbitration_id=0x12ABCDEF, is_extended_id=False, data=[0xAA, 0x55] + ) self.bus.send(msg_send) msg_recv = self.bus.recv(None) self.assertEqual(msg_recv[0].arbitration_id, msg_send.arbitration_id) - self.assertEqual(msg_recv[0].is_extended_id, msg_send.is_extended_id) # error + self.assertEqual(msg_recv[0].is_extended_id, msg_send.is_extended_id) # error self.assertEqual(msg_recv[0].is_fd, msg_send.is_fd) self.assertEqual(msg_recv[0].data[0:2], msg_send.data[0:2]) - def test_tx_fd_frame(self): """ Tests the transfer of Flexible Data-Rate CAN frame """ - self.bus = can.Bus(bustype="cfuc", channel="loop://", CANBaudRate=250000, IsFD=True, FDDataBaudRate=500000) - + self.bus = can.Bus( + bustype="cfuc", + channel="loop://", + CANBaudRate=250000, + IsFD=True, + FDDataBaudRate=500000, + ) + self.serial = self.bus.ser msg_init = self.serial.read(self.serial.in_waiting) - msg_send = can.Message(arbitration_id=0x12ABCDEF, is_extended_id=True, is_fd = True, data=[0xAA, 0x55]) + msg_send = can.Message( + arbitration_id=0x12ABCDEF, + is_extended_id=True, + is_fd=True, + data=[0xAA, 0x55], + ) self.bus.send(msg_send) msg_recv = self.bus.recv(None) self.assertEqual(msg_recv[0].arbitration_id, msg_send.arbitration_id) self.assertEqual(msg_recv[0].is_extended_id, msg_send.is_extended_id) self.assertEqual(msg_recv[0].is_fd, msg_send.is_fd) # error - self.assertEqual(msg_recv[0].data[0:2], msg_send.data[0:2]) \ No newline at end of file + self.assertEqual(msg_recv[0].data[0:2], msg_send.data[0:2])