From 9e72e9ad4807f7822057d773111bbe648cfa2d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Thu, 12 Aug 2021 10:51:03 +0200 Subject: [PATCH 1/5] p402: Do not switch any states during setup_402_state_machine(). Reading the PDO configuration is possible in OPERATIONAL or PRE-OPERATIONAL states, so switching that is unnecessary. The application should be responsible to handle such transitions, and the library function should be usable without disturbing the application logic. Changing the DS402 state machine to SWITCH ON DISABLED is also not necessary. The drive may be in whatever state from a previous usage, and then the change to SWITCH ON DISABLED may even trigger an exception because there is no way to reach it directly. So this transition should also be the application's responsibility. --- canopen/profiles/p402.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/canopen/profiles/p402.py b/canopen/profiles/p402.py index f5233ea4..f64e1889 100644 --- a/canopen/profiles/p402.py +++ b/canopen/profiles/p402.py @@ -216,12 +216,9 @@ def setup_402_state_machine(self): :raises ValueError: If the the node can't find a Statusword configured in any of the TPDOs. """ - self.nmt.state = 'PRE-OPERATIONAL' # Why is this necessary? self.setup_pdos() self._check_controlword_configured() self._check_statusword_configured() - self.nmt.state = 'OPERATIONAL' - self.state = 'SWITCH ON DISABLED' # Why change state? def setup_pdos(self): self.pdo.read() # TPDO and RPDO configurations From 2245add15b094e77bc6e4525e5f864b7d30faea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Thu, 12 Aug 2021 11:02:09 +0200 Subject: [PATCH 2/5] p402: Check NMT state before reading PDO configuration. SDOs are allowed in all but the STOPPED state. That would lead to a timeout and an SdoCommunicationError exception. Checking the NMT state here raises an exception without a timeout involved. --- canopen/profiles/p402.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/canopen/profiles/p402.py b/canopen/profiles/p402.py index f64e1889..c62892f4 100644 --- a/canopen/profiles/p402.py +++ b/canopen/profiles/p402.py @@ -221,6 +221,12 @@ def setup_402_state_machine(self): self._check_statusword_configured() def setup_pdos(self): + """Find the relevant PDO configuration to handle the state machine. + + :raises AssertionError: + When the node's NMT state disallows SDOs for reading the PDO configuration. + """ + assert self.nmt.state in 'PRE-OPERATIONAL', 'OPERATIONAL' self.pdo.read() # TPDO and RPDO configurations self._init_tpdo_values() self._init_rpdo_pointers() From 19ad2449420f26f600112efe3227f014c29cda28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Thu, 12 Aug 2021 11:11:10 +0200 Subject: [PATCH 3/5] p402: Make reading the PDO configuration optional during setup. If the application already configured the PDOs and called .save() on the pdo.Maps object, there is no sense in reading everything back again in the setup_pdos() method. Provide an optional argument to disable that behavior. A call to subscribe to the PDOs from the network is added because that side-effect of pdo.read() is necessary for the TPDO callback to work. --- canopen/profiles/p402.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/canopen/profiles/p402.py b/canopen/profiles/p402.py index c62892f4..c97cf8d4 100644 --- a/canopen/profiles/p402.py +++ b/canopen/profiles/p402.py @@ -220,14 +220,20 @@ def setup_402_state_machine(self): self._check_controlword_configured() self._check_statusword_configured() - def setup_pdos(self): + def setup_pdos(self, upload=True): """Find the relevant PDO configuration to handle the state machine. + :param bool upload: + Retrieve up-to-date configuration via SDO. If False, the node's mappings must + already be configured in the object, matching the drive's settings. :raises AssertionError: When the node's NMT state disallows SDOs for reading the PDO configuration. """ - assert self.nmt.state in 'PRE-OPERATIONAL', 'OPERATIONAL' - self.pdo.read() # TPDO and RPDO configurations + if upload: + assert self.nmt.state in 'PRE-OPERATIONAL', 'OPERATIONAL' + self.pdo.read() # TPDO and RPDO configurations + else: + self.pdo.subscribe() # Get notified on reception, usually a side-effect of read() self._init_tpdo_values() self._init_rpdo_pointers() From 93a7312794e3408270dcb9a17c53a57505afff71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Thu, 12 Aug 2021 11:14:29 +0200 Subject: [PATCH 4/5] p402: Allow skipping PDO upload from setup_402_state_machine(). Add an optional argument which is simply passed down to setup_pdos() to choose whether reading the PDO configuration is necessary. --- canopen/profiles/p402.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/canopen/profiles/p402.py b/canopen/profiles/p402.py index c97cf8d4..8f1eb6ee 100644 --- a/canopen/profiles/p402.py +++ b/canopen/profiles/p402.py @@ -210,13 +210,14 @@ def __init__(self, node_id, object_dictionary): self.tpdo_values = dict() # { index: TPDO_value } self.rpdo_pointers = dict() # { index: RPDO_pointer } - def setup_402_state_machine(self): + def setup_402_state_machine(self, read_pdos=True): """Configure the state machine by searching for a TPDO that has the StatusWord mapped. + :param bool read_pdos: Upload current PDO configuration from node. :raises ValueError: If the the node can't find a Statusword configured in any of the TPDOs. """ - self.setup_pdos() + self.setup_pdos(read_pdos) self._check_controlword_configured() self._check_statusword_configured() From edc4b1c08d7d052982b9a74ef858dd1ef91484c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Thu, 12 Aug 2021 11:37:42 +0200 Subject: [PATCH 5/5] Fix DS402 documentation to match the implementation. Besides the changes regarding setup_402_state_machine(), there were numerous errors where the documentation talks about nonexistent or differently named attributes. Also fix the description regaring what the method actually does. It won't configure the TPDO1 to contain the Statusword, but only check the PDO configuration for Statusword and Controlword presence. --- doc/profiles.rst | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/doc/profiles.rst b/doc/profiles.rst index 1047c7f9..1ef5ab58 100644 --- a/doc/profiles.rst +++ b/doc/profiles.rst @@ -34,10 +34,13 @@ The current status can be read from the device by reading the register 0x6041, which is called the "Statusword". Changes in state can only be done in the 'OPERATIONAL' state of the NmtMaster -TPDO1 needs to be set up correctly. For this, run the the -`BaseNode402.setup_402_state_machine()` method. Note that this setup -routine will change only TPDO1 and automatically go to the 'OPERATIONAL' state -of the NmtMaster:: +PDOs with the Controlword and Statusword mapped need to be set up correctly, +which is the default configuration of most DS402-compatible drives. To make +them accessible to the state machine implementation, run the the +`BaseNode402.setup_402_state_machine()` method. Note that this setup routine +will read the current PDO configuration by default, causing some SDO traffic. +That works only in the 'OPERATIONAL' or 'PRE-OPERATIONAL' states of the +:class:`NmtMaster`:: # run the setup routine for TPDO1 and it's callback some_node.setup_402_state_machine() @@ -50,21 +53,20 @@ Write Controlword and read Statusword:: # Read the state of the Statusword some_node.sdo[0x6041].raw -During operation the state can change to states which cannot be commanded -by the Controlword, for example a 'FAULT' state. -Therefore the :class:`PowerStateMachine` class (in similarity to the :class:`NmtMaster` -class) automatically monitors state changes of the Statusword which is sent -by TPDO1. The available callback on thet TPDO1 will then extract the -information and mirror the state change in the :attr:`BaseNode402.powerstate_402` -attribute. +During operation the state can change to states which cannot be commanded by the +Controlword, for example a 'FAULT' state. Therefore the :class:`BaseNode402` +class (in similarity to :class:`NmtMaster`) automatically monitors state changes +of the Statusword which is sent by TPDO. The available callback on that TPDO +will then extract the information and mirror the state change in the +:attr:`BaseNode402.state` attribute. Similar to the :class:`NmtMaster` class, the states of the :class:`BaseNode402` -class :attr:`._state` attribute can be read and set (command) by a string:: +class :attr:`.state` attribute can be read and set (command) by a string:: # command a state (an SDO message will be called) - some_node.powerstate_402.state = 'SWITCHED ON' + some_node.state = 'SWITCHED ON' # read the current state - some_node.powerstate_402.state = 'SWITCHED ON' + some_node.state = 'SWITCHED ON' Available states: