@@ -21,15 +21,16 @@ def crc8_dvb_s2(crc, a):
2121 crc = crc << 1
2222 return crc & 0xFF
2323
24+ def format_bytes (data ):
25+ return " " .join (f"{ b :02X} " for b in data )
26+
2427def send_msp (s , body ):
2528 crc = 0
2629 for x in body :
2730 crc = crc8_dvb_s2 (crc , x )
28- msp = [ord ('$' ),ord ('X' ),ord ('<' )]
29- msp = msp + body
30- msp .append (crc )
31+ msp = bytes ([ord ('$' ), ord ('X' ), ord ('<' )] + body + [crc ])
3132 s .write (msp )
32- print (' Sending ' + str (msp ))
33+ print (" Sending " + format_bytes (msp ))
3334
3435def send_clear (s ):
3536 msp = [0 ,0xb6 ,0x00 ,1 ,0 ,0x02 ]
@@ -46,10 +47,86 @@ def send_msg(s, row, col, str):
4647 msp .append (ord (x ))
4748 send_msp (s , msp )
4849
50+ class MspReader :
51+ def __init__ (self ):
52+ self .buffer = bytearray ()
53+ self .text_buffer = bytearray ()
54+
55+ def _flush_text (self , chunk ):
56+ events = []
57+ if not chunk :
58+ return events
59+ self .text_buffer .extend (chunk )
60+ while True :
61+ newline_pos = - 1
62+ for marker in (b"\n " , b"\r " ):
63+ pos = self .text_buffer .find (marker )
64+ if pos != - 1 and (newline_pos == - 1 or pos < newline_pos ):
65+ newline_pos = pos
66+ if newline_pos == - 1 :
67+ break
68+ line = bytes (self .text_buffer [:newline_pos ]).decode ("utf-8" , errors = "replace" ).strip ()
69+ del self .text_buffer [:newline_pos + 1 ]
70+ if line :
71+ events .append (("text" , line ))
72+ return events
73+
74+ def feed (self , data ):
75+ self .buffer .extend (data )
76+ events = []
77+ while True :
78+ start = self .buffer .find (b"$X" )
79+ if start < 0 :
80+ events .extend (self ._flush_text (self .buffer ))
81+ self .buffer .clear ()
82+ break
83+ if start > 0 :
84+ events .extend (self ._flush_text (self .buffer [:start ]))
85+ del self .buffer [:start ]
86+ if len (self .buffer ) < 9 :
87+ break
88+ direction = self .buffer [2 ]
89+ if direction not in (ord ("<" ), ord (">" ), ord ("!" )):
90+ events .extend (self ._flush_text (self .buffer [:1 ]))
91+ del self .buffer [0 ]
92+ continue
93+ payload_size = self .buffer [6 ] | (self .buffer [7 ] << 8 )
94+ frame_size = 9 + payload_size
95+ if len (self .buffer ) < frame_size :
96+ break
97+ frame = bytes (self .buffer [:frame_size ])
98+ del self .buffer [:frame_size ]
99+ body = frame [3 :- 1 ]
100+ expected_crc = frame [- 1 ]
101+ crc = 0
102+ for value in body :
103+ crc = crc8_dvb_s2 (crc , value )
104+ events .append (("packet" , frame , crc == expected_crc ))
105+ return events
106+
107+ def describe_packet (frame , crc_valid ):
108+ direction = chr (frame [2 ])
109+ function = frame [5 ] << 8 | frame [4 ]
110+ payload_size = frame [6 ] | (frame [7 ] << 8 )
111+ payload = frame [8 :8 + payload_size ]
112+ status = "OK" if crc_valid else "BAD CRC"
113+ prefix = f"Received { direction } 0x{ function :04X} [{ status } ]"
114+ if payload :
115+ return f"{ prefix } : { format_bytes (payload )} "
116+ return prefix
117+
49118def thread_function (s : serial .Serial ):
119+ reader = MspReader ()
50120 while True :
51- b = s .readall ()
52- if len (b ): print (b )
121+ data = s .read (s .in_waiting or 1 )
122+ if not data :
123+ continue
124+ for event in reader .feed (data ):
125+ if event [0 ] == "text" :
126+ print (f"Serial log: { event [1 ]} " )
127+ else :
128+ _ , frame , crc_valid = event
129+ print (describe_packet (frame , crc_valid ))
53130
54131def short_help ():
55132 print ("Command should be one of:" )
@@ -60,7 +137,7 @@ def short_help():
60137
61138def help ():
62139 print ()
63- print ("Depending on the OSD font only UPPERCASE letters ay display as actual letters," )
140+ print ("Depending on the OSD font only UPPERCASE letters may display as actual letters," )
64141 print ("this is because the other character positions are used to display other symbols on the OSD." )
65142 short_help ()
66143 print ()
@@ -82,7 +159,7 @@ def help():
82159 args .port = serials_find .get_serial_port ()
83160
84161 s = serial .Serial (port = args .port , baudrate = args .baud , bytesize = 8 , parity = 'N' , stopbits = 1 , timeout = 1 , xonxoff = 0 , rtscts = 0 )
85- threading .Thread (target = thread_function , args = (s ,)).start ()
162+ threading .Thread (target = thread_function , args = (s ,), daemon = True ).start ()
86163
87164 help ()
88165 for line in sys .stdin :
0 commit comments