1
1
2
- from enum import Enum
3
2
from logging import getLogger
4
3
from typing import Union
5
4
6
5
from openlcb .physicallayer import PhysicalLayer
6
+ from openlcb .portinterface import PortInterface
7
7
8
8
logger = getLogger (__name__ )
9
9
10
10
11
11
class RealtimePhysicalLayer (PhysicalLayer ):
12
-
12
+ """A realtime physical layer is only for use when there is an
13
+ absence of a link layer (or link layer doesn't enqueue frames) *and*
14
+ the application is not multi-threaded or uses a lock and avoids
15
+ race conditions.
16
+ Otherwise, overlapping port calls (*undefined behavior* at OS level)
17
+ may occur!
18
+ TODO: Add a lock variable and do reads here so all port usage can
19
+ utilize the lock and prevent overlapping use of the port.
20
+ """
13
21
class State :
14
22
Initial = 0
15
23
Disconnected = 1
@@ -18,34 +26,74 @@ class State:
18
26
DisconnectedState = State .Disconnected
19
27
20
28
def __init__ (self , socket ):
29
+ PhysicalLayer .__init__ (self )
21
30
# sock to distinguish from socket module or socket.socket class!
22
31
self .sock = socket
23
32
24
- def sendDataAfter (self , data : Union [bytearray , bytes ]):
33
+ def sendDataAfter (self , data : Union [bytearray , bytes ], verbose = True ):
34
+ """Send data (immediately, since realtime subclass).
35
+
36
+ Args:
37
+ data (Union[bytearray, bytes, CanFrame]): data to send.
38
+ verbose (bool, optional): verbose is only for Realtime
39
+ subclass (since data is sent immediately), otherwise set
40
+ verbose on sendAll. Defaults to False.
41
+ """
25
42
# if isinstance(data, list):
26
43
# raise TypeError(
27
44
# "Got {}({}) but expected str"
28
45
# .format(type(data).__name__, data)
29
46
# )
30
47
assert isinstance (data , (bytes , bytearray ))
31
- print (" SR: {}" .format (data ))
48
+ if verbose :
49
+ print (" SR: {}" .format (data ))
32
50
self .sock .send (data )
33
51
34
- def sendFrameAfter (self , frame ):
52
+ def sendFrameAfter (self , frame , verbose = False ):
53
+ """Send frame (immediately, since realtime subclass).
54
+
55
+ Args:
56
+ data (Union[bytearray, bytes, CanFrame]): data to send.
57
+ verbose (bool, optional): verbose is only for Realtime
58
+ subclass (since data is sent immediately), otherwise set
59
+ verbose on sendAll. Defaults to False.
60
+ """
61
+ if hasattr (self , 'encodeFrameAsData' ):
62
+ data = self .encodeFrameAsData (frame )
63
+ else :
64
+ assert isinstance (frame , (bytes , bytearray , str )), \
65
+ "Use a FrameEncoder implementation if not using bytes/str"
66
+ if isinstance (frame , str ):
67
+ data = frame .encode ("utf-8" )
68
+ else :
69
+ data = frame
35
70
# if isinstance(data, list):
36
71
# raise TypeError(
37
72
# "Got {}({}) but expected str"
38
73
# .format(type(data).__name__, data)
39
74
# )
40
- print (" SR: {}" .format (frame .encode ()))
75
+ if verbose :
76
+ print (" SR: {}" .format (frame ))
41
77
# send and fireFrameReceived would usually occur after
42
78
# frame from _send_frames.popleft is sent,
43
79
# but we do all this here in the Realtime subclass:
44
- self .sock .send (frame .encode ())
45
- # TODO: finish onFrameSent
46
- if frame .afterSendState :
80
+ self .sock .send (data )
81
+ if hasattr (frame , 'afterSendState' ) and frame .afterSendState :
82
+ # Use hasattr since only applicable to subclasses that use
83
+ # CanFrame.
47
84
self .fireFrameReceived (frame ) # also calls self.onFrameSent(frame)
48
85
86
+ def sendAll (self , device : PortInterface , mode = "binary" ,
87
+ verbose = False ) -> int :
88
+ """sendAll is only a stub in the case of realtime subclasses.
89
+ Instead of popping frames it performs a check to ensure the
90
+ queue is not used (since queue should only be used for typical
91
+ subclasses which are queued).
92
+ """
93
+ if len (self ._send_frames ) > 0 :
94
+ raise AssertionError ("Realtime subclasses should not use a queue!" )
95
+ logger .debug ("sendAll ran (realtime subclass, so nothing to do)" )
96
+
49
97
def registerFrameReceivedListener (self , listener ):
50
98
"""Register a new frame received listener
51
99
(optional since LinkLayer subclass constructor sets
0 commit comments