1- from typing import TYPE_CHECKING , List , Optional
1+ from typing import TYPE_CHECKING , Callable , List , Optional
22from enum import IntEnum
33import logging
44import struct
@@ -18,24 +18,49 @@ class LSSState(IntEnum):
1818
1919
2020class LSSSlave :
21+ CiA_bit_timing_table = {
22+ 0 : 1000000 ,
23+ 1 : 800000 ,
24+ 2 : 500000 ,
25+ 3 : 250000 ,
26+ 4 : 125000 ,
27+ 6 : 50000 ,
28+ 7 : 20000 ,
29+ 8 : 10000 ,
30+ }
31+
2132 def __init__ (self , node : "Node" ):
2233 self ._node = node
2334
2435 self ._state = LSSState .WAITING
2536
2637 self ._received_selective_address : List [Optional [int ]] = [None ] * 4
2738 self ._remote_responder_address : List [Optional [int ]] = [None ] * 6
28- self ._fastscan_state = 0
39+ self ._fastscan_state : int = 0
2940
30- self ._pending_baudrate = None
31- self ._change_baudrate_cb = None
41+ self ._pending_baudrate : int | None = None
42+ self ._change_baudrate_cb : Callable [[int , float ], None ] | None = None
43+
44+ self ._store_configuration_cb : Callable [[int , int ], None ] | None = None
3245
3346 node .network .add_subscription (cob_id = 0x7E5 , callback = self .handle_msg )
3447 node .nmt .state_callbacks .add (self .on_nmt_state_update )
3548
36- def set_baudrate_change_callback (self , cb ):
49+ def set_baudrate_change_callback (self , cb : Callable [[int , float ], None ]):
50+ """Defines a callback function to change bitrate. The delay is obtained from
51+ the `activate_bit_timing` command.
52+ This callback is called after the delay specified in the command and should
53+ change the bitrate of the network after waiting for the delay again.
54+ :param cb: callback function with signature (baudrate, delay)
55+ """
3756 self ._change_baudrate_cb = cb
3857
58+ def set_store_configuration_callback (self , cb : Callable [[int , int ], None ]):
59+ """Defines a callback function to store new bitrate and node id persistently.
60+ :param cb: callback function with signature (baudrate, node_id)
61+ """
62+ self ._store_configuration_cb = cb
63+
3964 def on_nmt_state_update (self , state : StateEnum ):
4065 if state == StateEnum .INITIALISATION :
4166 self ._state = LSSState .WAITING
@@ -124,18 +149,17 @@ def cmd_configure_node_id(self, msg: bytes):
124149 )
125150
126151 def cmd_configure_bit_timing (self , msg : bytes ):
127- valid_table_entries = (0 , 1 , 2 , 3 , 4 , 6 , 7 , 8 )
128152 selector , index = msg [1 :3 ]
129153
130154 if (
131155 selector != 0
132- or index not in valid_table_entries
156+ or index not in self . CiA_bit_timing_table
133157 or self ._change_baudrate_cb is None
134158 ):
135159 self ._node .network .send (0x7E4 , b"\x13 \x01 " + bytes (6 ))
136160 return
137161
138- self ._pending_baudrate = index
162+ self ._pending_baudrate = self . CiA_bit_timing_table [ index ]
139163 self ._node .network .send (0x7E4 , b"\x13 \x00 " + bytes (6 ))
140164
141165 def cmd_activate_bit_timing (self , msg : bytes ):
@@ -146,13 +170,19 @@ def cmd_activate_bit_timing(self, msg: bytes):
146170
147171 def _change_baudrate (self , delay : float ):
148172 if self ._change_baudrate_cb :
149- self ._change_baudrate_cb (self ._pending_baudrate )
173+ self ._change_baudrate_cb (self ._pending_baudrate , delay )
150174 self ._pending_baudrate = None
151- get_scheduler ().add (delay , self ._node .nmt .reset )
152175
153176 def cmd_store_configuration (self , _msg : bytes ):
154- # store configuration is not supported
155- self ._node .network .send (0x7E4 , b"\x17 \x01 " + bytes (6 ))
177+ if self ._store_configuration_cb is not None :
178+ self ._store_configuration_cb (self ._pending_baudrate , self ._node .nmt .pending_node_id )
179+ result = 0 # 0x00 = successfully completed
180+ else :
181+ result = 1 # 0x01 = not supported
182+
183+ self ._node .network .send (
184+ 0x7E4 , b"\x17 " + result .to_bytes (1 , "little" ) + bytes (6 )
185+ )
156186
157187 def cmd_identify_remote_responders (self , msg : bytes ):
158188 index = msg [0 ] - 0x46
0 commit comments