From 7cbdcf5af85778faa85900cb0b6c0cbeb3b58515 Mon Sep 17 00:00:00 2001 From: Christian Sandberg Date: Mon, 19 Sep 2016 17:11:24 +0200 Subject: [PATCH] Add SYNC support. --- canopen/emcy.py | 2 ++ canopen/network.py | 2 ++ canopen/pdo.py | 19 ++++++++++++++----- canopen/sync.py | 40 ++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 5 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 canopen/sync.py diff --git a/canopen/emcy.py b/canopen/emcy.py index 8feca41d..feb85be2 100644 --- a/canopen/emcy.py +++ b/canopen/emcy.py @@ -32,6 +32,8 @@ def __init__(self): self.log = [] def on_emcy(self, can_id, data, timestamp): + if can_id == 0x80: + return code, register, data = EMCY_STRUCT.unpack(data) if code & 0xFF == 0: entry = ErrorReset(code, register, data, timestamp) diff --git a/canopen/network.py b/canopen/network.py index ecf255de..bf0ba050 100644 --- a/canopen/network.py +++ b/canopen/network.py @@ -5,6 +5,7 @@ import can from .node import Node +from .sync import SyncProducer logger = logging.getLogger(__name__) @@ -18,6 +19,7 @@ def __init__(self): self.notifier = None self.nodes = [] self.send_lock = threading.Lock() + self.sync = SyncProducer(self) # NMT to all nodes #self.nmt = NmtNode(0) diff --git a/canopen/pdo.py b/canopen/pdo.py index 9485f136..c34dcbfe 100644 --- a/canopen/pdo.py +++ b/canopen/pdo.py @@ -24,8 +24,10 @@ def __init__(self, parent): def on_message(self, can_id, data, timestamp): for pdo_map in self.tx.values(): if pdo_map.cob_id == can_id: - pdo_map.data = data - pdo_map.timestamp = timestamp + with pdo_map.receive_condition: + pdo_map.data = data + pdo_map.timestamp = timestamp + pdo_map.receive_condition.notify_all() def get_by_name(self, name): for pdo_maps in (self.rx, self.tx): @@ -53,11 +55,10 @@ def export(self, filename): continue frame = canmatrix.Frame("PDO_0x%X" % pdo_map.cob_id, Id=pdo_map.cob_id, - dlc=len(pdo_map.data), extended=0) for var in pdo_map.map: is_signed = var.od.data_type in objectdictionary.SIGNED_TYPES - if_float = var.od.data_type == objectdictionary.REAL32 + is_float = var.od.data_type == objectdictionary.REAL32 min_value = var.od.min max_value = var.od.max if min_value is not None: @@ -68,7 +69,7 @@ def export(self, filename): startBit=var.offset, signalSize=len(var.od), is_signed=is_signed, - is_float=if_float, + is_float=is_float, factor=var.od.factor, min=min_value, max=max_value, @@ -76,6 +77,7 @@ def export(self, filename): for value, desc in var.od.value_descriptions.items(): signal.addValues(value, desc) frame.addSignal(signal) + frame.calcDLC() db._fl.addFrame(frame) exportdbc.exportDbc(db, filename) @@ -118,6 +120,7 @@ def __init__(self, pdo_node, com_index, map_index): self.timestamp = None self.period = None self.transmit_thread = None + self.receive_condition = threading.Condition() self.stop_event = threading.Event() def __getitem__(self, key): @@ -251,6 +254,12 @@ def stop(self): self.transmit_thread.join(2) self.transmit_thread = None + def wait_for_reception(self, timeout=10): + with self.receive_condition: + self.timestamp = None + self.receive_condition.wait(timeout) + return self.timestamp + def _periodic_transmit(self): while not self.stop_event.is_set(): start = time.time() diff --git a/canopen/sync.py b/canopen/sync.py new file mode 100644 index 00000000..bc1f5bb1 --- /dev/null +++ b/canopen/sync.py @@ -0,0 +1,40 @@ +import time +import threading + + +class SyncProducer(object): + + def __init__(self, network): + self.network = network + self.period = None + self.transmit_thread = None + self.stop_event = threading.Event() + + def transmit(self): + self.network.send_message(0x80, []) + + def start(self, period=None): + """Start periodic transmission of SYNC message in a background thread.""" + if period is not None: + self.period = period + + if not self.period: + raise ValueError("A valid transmission period has not been given") + + if not self.transmit_thread or not self.transmit_thread.is_alive(): + self.stop_event.clear() + self.transmit_thread = threading.Thread(target=self._periodic_transmit) + self.transmit_thread.daemon = True + self.transmit_thread.start() + + def stop(self): + self.stop_event.set() + if self.transmit_thread: + self.transmit_thread.join(2) + self.transmit_thread = None + + def _periodic_transmit(self): + while not self.stop_event.is_set(): + start = time.time() + self.transmit() + time.sleep(self.period - (time.time() - start)) diff --git a/setup.py b/setup.py index bdba0f52..16064b68 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -__version__ = "0.3.0.dev3" +__version__ = "0.3.0.dev4" setup( name="canopen",