44 from collections import MutableMapping
55import logging
66import threading
7- import struct
7+ from typing import Callable , Dict , Iterable , List , Optional , Union
88
99try :
1010 import can
2222from .nmt import NmtMaster
2323from .lss import LssMaster
2424from .objectdictionary .eds import import_from_node
25+ from .objectdictionary import ObjectDictionary
2526
2627logger = logging .getLogger (__name__ )
2728
29+ Callback = Callable [[int , bytearray , float ], None ]
30+
2831
2932class Network (MutableMapping ):
3033 """Representation of one CAN bus containing one or more nodes."""
@@ -43,8 +46,8 @@ def __init__(self, bus=None):
4346 #: Includes at least MessageListener.
4447 self .listeners = [MessageListener (self )]
4548 self .notifier = None
46- self .nodes = {}
47- self .subscribers = {}
49+ self .nodes : Dict [ int , Union [ RemoteNode , LocalNode ]] = {}
50+ self .subscribers : Dict [ int , List [ Callback ]] = {}
4851 self .send_lock = threading .Lock ()
4952 self .sync = SyncProducer (self )
5053 self .time = TimeProducer (self )
@@ -55,10 +58,10 @@ def __init__(self, bus=None):
5558 self .lss .network = self
5659 self .subscribe (self .lss .LSS_RX_COBID , self .lss .on_message_received )
5760
58- def subscribe (self , can_id , callback ) :
61+ def subscribe (self , can_id : int , callback : Callback ) -> None :
5962 """Listen for messages with a specific CAN ID.
6063
61- :param int can_id:
64+ :param can_id:
6265 The CAN ID to listen for.
6366 :param callback:
6467 Function to call when message is received.
@@ -67,7 +70,7 @@ def subscribe(self, can_id, callback):
6770 if callback not in self .subscribers [can_id ]:
6871 self .subscribers [can_id ].append (callback )
6972
70- def unsubscribe (self , can_id , callback = None ):
73+ def unsubscribe (self , can_id , callback = None ) -> None :
7174 """Stop listening for message.
7275
7376 :param int can_id:
@@ -81,7 +84,7 @@ def unsubscribe(self, can_id, callback=None):
8184 else :
8285 self .subscribers [can_id ].remove (callback )
8386
84- def connect (self , * args , ** kwargs ):
87+ def connect (self , * args , ** kwargs ) -> "Network" :
8588 """Connect to CAN bus using python-can.
8689
8790 Arguments are passed directly to :class:`can.BusABC`. Typically these
@@ -111,7 +114,7 @@ def connect(self, *args, **kwargs):
111114 self .notifier = can .Notifier (self .bus , self .listeners , 1 )
112115 return self
113116
114- def disconnect (self ):
117+ def disconnect (self ) -> None :
115118 """Disconnect from the CAN bus.
116119
117120 Must be overridden in a subclass if a custom interface is used.
@@ -132,7 +135,12 @@ def __enter__(self):
132135 def __exit__ (self , type , value , traceback ):
133136 self .disconnect ()
134137
135- def add_node (self , node , object_dictionary = None , upload_eds = False ):
138+ def add_node (
139+ self ,
140+ node : Union [int , RemoteNode , LocalNode ],
141+ object_dictionary : Union [str , ObjectDictionary , None ] = None ,
142+ upload_eds : bool = False ,
143+ ) -> RemoteNode :
136144 """Add a remote node to the network.
137145
138146 :param node:
@@ -142,12 +150,11 @@ def add_node(self, node, object_dictionary=None, upload_eds=False):
142150 Can be either a string for specifying the path to an
143151 Object Dictionary file or a
144152 :class:`canopen.ObjectDictionary` object.
145- :param bool upload_eds:
153+ :param upload_eds:
146154 Set ``True`` if EDS file should be uploaded from 0x1021.
147155
148156 :return:
149157 The Node object that was added.
150- :rtype: canopen.RemoteNode
151158 """
152159 if isinstance (node , int ):
153160 if upload_eds :
@@ -157,7 +164,11 @@ def add_node(self, node, object_dictionary=None, upload_eds=False):
157164 self [node .id ] = node
158165 return node
159166
160- def create_node (self , node , object_dictionary = None ):
167+ def create_node (
168+ self ,
169+ node : int ,
170+ object_dictionary : Union [str , ObjectDictionary , None ] = None ,
171+ ) -> LocalNode :
161172 """Create a local node in the network.
162173
163174 :param node:
@@ -169,14 +180,13 @@ def create_node(self, node, object_dictionary=None):
169180
170181 :return:
171182 The Node object that was added.
172- :rtype: canopen.LocalNode
173183 """
174184 if isinstance (node , int ):
175185 node = LocalNode (node , object_dictionary )
176186 self [node .id ] = node
177187 return node
178188
179- def send_message (self , can_id , data , remote = False ):
189+ def send_message (self , can_id : int , data : bytes , remote : bool = False ) -> None :
180190 """Send a raw CAN message to the network.
181191
182192 This method may be overridden in a subclass if you need to integrate
@@ -203,35 +213,36 @@ def send_message(self, can_id, data, remote=False):
203213 self .bus .send (msg )
204214 self .check ()
205215
206- def send_periodic (self , can_id , data , period , remote = False ):
216+ def send_periodic (
217+ self , can_id : int , data : bytes , period : float , remote : bool = False
218+ ) -> "PeriodicMessageTask" :
207219 """Start sending a message periodically.
208220
209- :param int can_id:
221+ :param can_id:
210222 CAN-ID of the message
211223 :param data:
212224 Data to be transmitted (anything that can be converted to bytes)
213- :param float period:
225+ :param period:
214226 Seconds between each message
215- :param bool remote:
227+ :param remote:
216228 indicates if the message frame is a remote request to the slave node
217229
218230 :return:
219231 An task object with a ``.stop()`` method to stop the transmission
220- :rtype: canopen.network.PeriodicMessageTask
221232 """
222233 return PeriodicMessageTask (can_id , data , period , self .bus , remote )
223234
224- def notify (self , can_id , data , timestamp ) :
235+ def notify (self , can_id : int , data : bytearray , timestamp : float ) -> None :
225236 """Feed incoming message to this library.
226237
227238 If a custom interface is used, this function must be called for each
228239 message read from the CAN bus.
229240
230- :param int can_id:
241+ :param can_id:
231242 CAN-ID of the message
232- :param bytearray data:
243+ :param data:
233244 Data part of the message (0 - 8 bytes)
234- :param float timestamp:
245+ :param timestamp:
235246 Timestamp of the message, preferably as a Unix timestamp
236247 """
237248 if can_id in self .subscribers :
@@ -240,7 +251,7 @@ def notify(self, can_id, data, timestamp):
240251 callback (can_id , data , timestamp )
241252 self .scanner .on_message_received (can_id )
242253
243- def check (self ):
254+ def check (self ) -> None :
244255 """Check that no fatal error has occurred in the receiving thread.
245256
246257 If an exception caused the thread to terminate, that exception will be
@@ -252,22 +263,22 @@ def check(self):
252263 logger .error ("An error has caused receiving of messages to stop" )
253264 raise exc
254265
255- def __getitem__ (self , node_id ) :
266+ def __getitem__ (self , node_id : int ) -> Union [ RemoteNode , LocalNode ] :
256267 return self .nodes [node_id ]
257268
258- def __setitem__ (self , node_id , node ):
269+ def __setitem__ (self , node_id : int , node : Union [ RemoteNode , LocalNode ] ):
259270 assert node_id == node .id
260271 self .nodes [node_id ] = node
261272 node .associate_network (self )
262273
263- def __delitem__ (self , node_id ):
274+ def __delitem__ (self , node_id : int ):
264275 self .nodes [node_id ].remove_network ()
265276 del self .nodes [node_id ]
266277
267- def __iter__ (self ):
278+ def __iter__ (self ) -> Iterable [ int ] :
268279 return iter (self .nodes )
269280
270- def __len__ (self ):
281+ def __len__ (self ) -> int :
271282 return len (self .nodes )
272283
273284
@@ -277,13 +288,20 @@ class PeriodicMessageTask(object):
277288 CyclicSendTask
278289 """
279290
280- def __init__ (self , can_id , data , period , bus , remote = False ):
281- """
282- :param int can_id:
291+ def __init__ (
292+ self ,
293+ can_id : int ,
294+ data : bytes ,
295+ period : float ,
296+ bus ,
297+ remote : bool = False ,
298+ ):
299+ """
300+ :param can_id:
283301 CAN-ID of the message
284302 :param data:
285303 Data to be transmitted (anything that can be converted to bytes)
286- :param float period:
304+ :param period:
287305 Seconds between each message
288306 :param can.BusABC bus:
289307 python-can bus to use for transmission
@@ -303,7 +321,7 @@ def stop(self):
303321 """Stop transmission"""
304322 self ._task .stop ()
305323
306- def update (self , data ) :
324+ def update (self , data : bytes ) -> None :
307325 """Update data of message
308326
309327 :param data:
@@ -323,11 +341,11 @@ def update(self, data):
323341class MessageListener (Listener ):
324342 """Listens for messages on CAN bus and feeds them to a Network instance.
325343
326- :param canopen.Network network:
344+ :param network:
327345 The network to notify on new messages.
328346 """
329347
330- def __init__ (self , network ):
348+ def __init__ (self , network : Network ):
331349 self .network = network
332350
333351 def on_message_received (self , msg ):
@@ -359,12 +377,12 @@ class NodeScanner(object):
359377
360378 SERVICES = (0x700 , 0x580 , 0x180 , 0x280 , 0x380 , 0x480 , 0x80 )
361379
362- def __init__ (self , network = None ):
380+ def __init__ (self , network : Optional [ Network ] = None ):
363381 self .network = network
364382 #: A :class:`list` of nodes discovered
365- self .nodes = []
383+ self .nodes : List [ int ] = []
366384
367- def on_message_received (self , can_id ):
385+ def on_message_received (self , can_id : int ):
368386 service = can_id & 0x780
369387 node_id = can_id & 0x7F
370388 if node_id not in self .nodes and node_id != 0 and service in self .SERVICES :
@@ -374,11 +392,10 @@ def reset(self):
374392 """Clear list of found nodes."""
375393 self .nodes = []
376394
377- def search (self , limit = 127 ):
395+ def search (self , limit : int = 127 ) -> None :
378396 """Search for nodes by sending SDO requests to all node IDs."""
379397 if self .network is None :
380398 raise RuntimeError ("A Network is required to do active scanning" )
381399 sdo_req = b"\x40 \x00 \x10 \x00 \x00 \x00 \x00 \x00 "
382400 for node_id in range (1 , limit + 1 ):
383401 self .network .send_message (0x600 + node_id , sdo_req )
384-
0 commit comments