Skip to content

Commit 4263f85

Browse files
committed
DS402: Clean up docstrings.
Follow PEP-257 regarding overall formatting. Fix typos. Fix incorrect usage of Sphinx directives (:return: does not take an inline type as :param: does). Standardize on :raises: directive. Fix wrapping to eliminate Sphinx warnings. Add missing parameter and return documentation for is_homed(). Move all property documentation to the getter functions, where Python expects it and where it is not ignored by Sphinx. Fix incorrectly documented return types. Improve some descriptions that were unclear (to me).
1 parent 475d22c commit 4263f85

File tree

1 file changed

+66
-54
lines changed

1 file changed

+66
-54
lines changed

canopen/profiles/p402.py

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,11 @@ class State402(object):
8787

8888
@staticmethod
8989
def next_state_for_enabling(_from):
90-
"""Returns the next state needed for reach the state Operation Enabled
91-
:param string target: Target state
92-
:return string: Next target to chagne
90+
"""Return the next state needed for reach the state Operation Enabled.
91+
92+
:param string target: Target state.
93+
:return: Next target to change.
94+
:rtype: str
9395
"""
9496
for cond, next_state in State402.NEXTSTATE2ENABLE.items():
9597
if _from in cond:
@@ -209,10 +211,10 @@ def __init__(self, node_id, object_dictionary):
209211
self.rpdo_pointers = dict() # { index: RPDO_pointer }
210212

211213
def setup_402_state_machine(self):
212-
"""Configure the state machine by searching for a TPDO that has the
213-
StatusWord mapped.
214-
:raise ValueError: If the the node can't find a Statusword configured
215-
in the any of the TPDOs
214+
"""Configure the state machine by searching for a TPDO that has the StatusWord mapped.
215+
216+
:raises ValueError:
217+
If the the node can't find a Statusword configured in the any of the TPDOs.
216218
"""
217219
self.nmt.state = 'PRE-OPERATIONAL' # Why is this necessary?
218220
self.setup_pdos()
@@ -258,8 +260,7 @@ def _check_statusword_configured(self):
258260
self.id))
259261

260262
def reset_from_fault(self):
261-
"""Reset node from fault and set it to Operation Enable state
262-
"""
263+
"""Reset node from fault and set it to Operation Enable state."""
263264
if self.state == 'FAULT':
264265
# Resets the Fault Reset bit (rising edge 0 -> 1)
265266
self.controlword = State402.CW_DISABLE_VOLTAGE
@@ -275,7 +276,12 @@ def is_faulted(self):
275276
return self.statusword & bitmask == bits
276277

277278
def is_homed(self, restore_op_mode=False):
278-
"""Switch to homing mode and determine its status."""
279+
"""Switch to homing mode and determine its status.
280+
281+
:param bool restore_op_mode: Switch back to the previous operation mode when done.
282+
:return: If the status indicates successful homing.
283+
:rtype: bool
284+
"""
279285
previous_op_mode = self.op_mode
280286
if previous_op_mode != 'HOMING':
281287
logger.info('Switch to HOMING from %s', previous_op_mode)
@@ -290,11 +296,13 @@ def is_homed(self, restore_op_mode=False):
290296
return homingstatus in ('TARGET REACHED', 'ATTAINED')
291297

292298
def homing(self, timeout=TIMEOUT_HOMING_DEFAULT, set_new_home=True):
293-
"""Function to execute the configured Homing Method on the node
294-
:param int timeout: Timeout value (default: 30)
295-
:param bool set_new_home: Defines if the node should set the home offset
296-
object (0x607C) to the current position after the homing procedure (default: true)
297-
:return: If the homing was complete with success
299+
"""Execute the configured Homing method on the node.
300+
301+
:param int timeout: Timeout value (default: 30).
302+
:param bool set_new_home:
303+
Defines if the node should set the home offset object (0x607C) to the current
304+
position after the homing procedure (default: true).
305+
:return: If the homing was complete with success.
298306
:rtype: bool
299307
"""
300308
previus_op_mode = self.op_mode
@@ -333,18 +341,11 @@ def homing(self, timeout=TIMEOUT_HOMING_DEFAULT, set_new_home=True):
333341

334342
@property
335343
def op_mode(self):
336-
"""
337-
:return: Return the operation mode stored in the object 0x6061 through SDO
338-
:rtype: int
339-
"""
340-
return OperationMode.CODE2NAME[self.sdo[0x6061].raw]
344+
"""The node's Operation Mode stored in the object 0x6061.
341345
342-
@op_mode.setter
343-
def op_mode(self, mode):
344-
"""Function to define the operation mode of the node
345-
:param string mode: Mode to define.
346+
Uses SDO to access the current value. The modes are passed as one of the
347+
following strings:
346348
347-
The modes can be:
348349
- 'NO MODE'
349350
- 'PROFILED POSITION'
350351
- 'VELOCITY'
@@ -357,7 +358,14 @@ def op_mode(self, mode):
357358
- 'CYCLIC SYNCHRONOUS TORQUE'
358359
- 'OPEN LOOP SCALAR MODE'
359360
- 'OPEN LOOP VECTOR MODE'
361+
362+
:raises TypeError: When setting a mode not advertised as supported by the node.
363+
:raises RuntimeError: If the switch is not confirmed within the configured timeout.
360364
"""
365+
return OperationMode.CODE2NAME[self.sdo[0x6061].raw]
366+
367+
@op_mode.setter
368+
def op_mode(self, mode):
361369
try:
362370
if not self.is_op_mode_supported(mode):
363371
raise TypeError(
@@ -394,9 +402,13 @@ def _clear_target_values(self):
394402
self.sdo[target_index].raw = 0
395403

396404
def is_op_mode_supported(self, mode):
397-
"""Function to check if the operation mode is supported by the node
398-
:param int mode: Operation mode
399-
:return: If the operation mode is supported
405+
"""Check if the operation mode is supported by the node.
406+
407+
The object listing the supported modes is retrieved once using SDO, then cached
408+
for later checks.
409+
410+
:param str mode: Same format as the :attr:`op_mode` property.
411+
:return: If the operation mode is supported.
400412
:rtype: bool
401413
"""
402414
if not hasattr(self, '_op_mode_support'):
@@ -408,18 +420,20 @@ def is_op_mode_supported(self, mode):
408420
return self._op_mode_support & bits == bits
409421

410422
def on_TPDOs_update_callback(self, mapobject):
411-
"""This function receives a map object.
412-
this map object is then used for changing the
413-
:param mapobject: :class: `canopen.objectdictionary.Variable`
423+
"""Cache updated values from a TPDO received from this node.
424+
425+
:param mapobject: The received PDO message.
426+
:type mapobject: canopen.pdo.Map
414427
"""
415428
for obj in mapobject:
416429
self.tpdo_values[obj.index] = obj.raw
417430

418431
@property
419432
def statusword(self):
420-
"""Returns the last read value of the Statusword (0x6041) from the device.
421-
If the the object 0x6041 is not configured in any TPDO it will fallback to the SDO mechanism
422-
and try to tget the value.
433+
"""Return the last read value of the Statusword (0x6041) from the device.
434+
435+
If the the object 0x6041 is not configured in any TPDO it will fall back to the
436+
SDO mechanism and try to get the value.
423437
"""
424438
try:
425439
return self.tpdo_values[0x6041]
@@ -429,13 +443,15 @@ def statusword(self):
429443

430444
@property
431445
def controlword(self):
446+
"""Send a state change command using PDO or SDO.
447+
448+
:param int value: Controlword value to set.
449+
:raises RuntimeError: Read access to the controlword is not intended.
450+
"""
432451
raise RuntimeError('The Controlword is write-only.')
433452

434453
@controlword.setter
435454
def controlword(self, value):
436-
"""Send the state using PDO or SDO objects.
437-
:param int value: State value to send in the message
438-
"""
439455
if 0x6040 in self.rpdo_pointers:
440456
self.rpdo_pointers[0x6040].raw = value
441457
self.rpdo_pointers[0x6040].pdo_parent.transmit()
@@ -444,16 +460,24 @@ def controlword(self, value):
444460

445461
@property
446462
def state(self):
447-
"""Attribute to get or set node's state as a string for the DS402 State Machine.
448-
States of the node can be one of:
449-
- 'NOT READY TO SWITCH ON'
463+
"""Manipulate current state of the DS402 State Machine on the node.
464+
465+
Uses the last received Statusword value for read access, and manipulates the
466+
:attr:`controlword` for changing states. The states are passed as one of the
467+
following strings:
468+
469+
- 'NOT READY TO SWITCH ON' (cannot be switched to deliberately)
450470
- 'SWITCH ON DISABLED'
451471
- 'READY TO SWITCH ON'
452472
- 'SWITCHED ON'
453473
- 'OPERATION ENABLED'
454-
- 'FAULT'
455-
- 'FAULT REACTION ACTIVE'
474+
- 'FAULT' (cannot be switched to deliberately)
475+
- 'FAULT REACTION ACTIVE' (cannot be switched to deliberately)
456476
- 'QUICK STOP ACTIVE'
477+
- 'DISABLE VOLTAGE' (only as a command when writing)
478+
479+
:raises RuntimeError: If the switch is not confirmed within the configured timeout.
480+
:raises ValueError: Trying to execute a illegal transition in the state machine.
457481
"""
458482
for state, mask_val_pair in State402.SW_MASK.items():
459483
bitmask, bits = mask_val_pair
@@ -463,18 +487,6 @@ def state(self):
463487

464488
@state.setter
465489
def state(self, target_state):
466-
""" Defines the state for the DS402 state machine
467-
States to switch to can be one of:
468-
- 'SWITCH ON DISABLED'
469-
- 'DISABLE VOLTAGE'
470-
- 'READY TO SWITCH ON'
471-
- 'SWITCHED ON'
472-
- 'OPERATION ENABLED'
473-
- 'QUICK STOP ACTIVE'
474-
:param string target_state: Target state
475-
:raise RuntimeError: Occurs when the time defined to change the state is reached
476-
:raise ValueError: Occurs when trying to execute a ilegal transition in the sate machine
477-
"""
478490
timeout = time.monotonic() + self.TIMEOUT_SWITCH_STATE_FINAL
479491
while self.state != target_state:
480492
next_state = self._next_state(target_state)

0 commit comments

Comments
 (0)