Skip to content

Commit 7c4b82c

Browse files
committed
Updated bue_main and base_station_main to reflect ota changes
1 parent f25a3c2 commit 7c4b82c

File tree

7 files changed

+59
-58
lines changed

7 files changed

+59
-58
lines changed

base_station_main.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,18 @@ def message_listener(self):
173173
new_messages = self.ota.get_new_messages()
174174

175175
for message in new_messages:
176-
try: # Receive messages should look like "+RCV={origin},{len(message)},{message}"
176+
try: # Receive messages should look like "{bue_id},{message}"
177177
try:
178178
message = message[5:]
179179
parts = message.split(",")
180180
bue_id = int(parts[0])
181+
message_body = parts[1]
181182

182183
except Exception as e:
183184
logger.error(f"message_listener: Failed to parse message '{message}': {e}")
184185
continue # Skip to the next message
185186

186-
if parts[2].startswith("REQ:"):
187+
if message_body.startswith("REQ:"):
187188
logger.debug("Sending a CON")
188189
self.ota.send_ota_message(bue_id, f"CON:{self.ota.id}")
189190
self.bue_timeout_tracker[bue_id] = TIMEOUT
@@ -193,21 +194,21 @@ def message_listener(self):
193194
else:
194195
logger.error(f"Got a connection request from {bue_id} but it is already listed as connected")
195196

196-
if parts[2].startswith("ACK:"):
197+
if message_body.startswith("ACK:"):
197198
logger.bind(bue_id=bue_id).info(f"Received ACK from {bue_id}")
198199

199-
if parts[2].startswith("PING:"): # Looks like <origin id>,<length>,PING,<lat>,<long>,-55,8
200-
if len(parts) >= 5:
201-
lat = parts[3]
202-
long = parts[4]
200+
if message_body.startswith("PING:"): # Looks like <origin id>,<length>,PING,<lat>,<long>,-55,8
201+
if len(parts) >= 4:
202+
lat = parts[2]
203+
long = parts[3]
203204
self.ping_bue(bue_id, lat, long)
204205

205-
if parts[2].startswith("UPD:"): # 40,55,UPD:LAT,LONG,STDOUT: [helloworld.py STDOUT] TyGoodTest,-42,8
206+
if message_body.startswith("UPD:"): # 40,55,UPD:LAT,LONG,STDOUT: [helloworld.py STDOUT] TyGoodTest,-42,8
206207
if not bue_id in self.testing_bues:
207208
self.testing_bues.append(bue_id)
208-
lat = parts[3]
209-
long = parts[4]
210-
stdout = parts[5]
209+
lat = parts[2]
210+
long = parts[3]
211+
stdout = parts[4]
211212
# logger.info(f"Received UPD from {bue_id}. Currently at Latitude: {lat}, Longitude: {long}. Message: {stdout}")
212213
logger.bind(bue_id=bue_id).info(f"Received UPD from {bue_id}. Message: {stdout}")
213214
if lat != "" and long != "":
@@ -220,19 +221,19 @@ def message_listener(self):
220221
if stdout != "":
221222
self.stdout_history.append(stdout)
222223

223-
if parts[2].startswith("FAIL:"):
224+
if message_body.startswith("FAIL:"):
224225
logger.bind(bue_id=bue_id).error(f"Received FAIL from {bue_id}")
225226
self.testing_bues.remove(bue_id)
226227

227-
if parts[2].startswith("DONE:"):
228+
if message_body.startswith("DONE:"):
228229
logger.bind(bue_id=bue_id).info(f"Received DONE from {bue_id}")
229230
self.testing_bues.remove(bue_id)
230231

231-
if parts[2].startswith("PREPR:"):
232+
if message_body.startswith("PREPR:"):
232233
logger.bind(bue_id=bue_id).info(f"Received PREPR from {bue_id}")
233234
self.testing_bues.append(bue_id)
234235

235-
if parts[2].startswith("CANCD:"):
236+
if message_body.startswith("CANCD:"):
236237
logger.bind(bue_id=bue_id).info(f"Received CANCD from {bue_id}")
237238
self.testing_bues.remove(bue_id)
238239

bue_main.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -134,24 +134,23 @@ def ota_connect_req(self):
134134

135135
for message in new_messages:
136136
try:
137-
# A connecting message would take the form of "+RCV=<base station id>,<Length>,CON:<base station id>"
137+
# A connecting message would take the form of "<base station id>,CON:<base station id>"
138138
# We want to extract the base station id from this message
139139
if "CON:" in message:
140-
message = message[5:] # Remove the "+RCV=" part
141-
parts = message.split(",")
140+
base_id, message_body = message.split(",")
142141
# This checks to see if the received message matches a base station connecting
143142
# format. If it does we are now going to be in the connected state
144-
if parts[2].startswith("CON:"):
145-
if parts[0] == parts[2][4:]:
143+
if message_body.startswith("CON:"):
144+
if base_id == message_body[4:]:
146145
self.ota_connected = True
147-
self.ota_base_station_id = int(parts[0])
146+
self.ota_base_station_id = int(base_id)
148147
logger.info(f"ota_connect_req: OTA device connected to base station {self.ota_base_station_id}")
149148
self.ota_timeout = TIMEOUT
150149
self.ota.send_ota_message(self.ota_base_station_id, "ACK")
151150
return
152151
else:
153152
logger.warning(
154-
f"ota_connect_req: received malformed message: base station id {parts[0]} does not match {parts[2][4:]}"
153+
f"ota_connect_req: received malformed message: base station id {base_id} does not match {message_body[4:]}"
155154
)
156155

157156
except ValueError:
@@ -191,30 +190,29 @@ def ota_idle_ping(self):
191190
got_pingr = False
192191

193192
for message in new_messages:
194-
message = message[5:] # Remove the "+RCV=" part
195-
parts = message.split(",", 3)
193+
sender, message_body = message.split(",", 1)
196194

197195
# 1. A CON (connect0 message from the base station; we can (probably) ignore this for now;
198196
# ideally, the base station would have seen our ACK message, but it can also see our PING
199-
if parts[2].startswith("ACK"):
197+
if message_body.startswith("ACK"):
200198
logger.info(f"Got an ACK from {self.ota_base_station_id}")
201199

202200
# If we received a PINGR message, we know we are still connected to the base station.
203201
# We will not time out our connection
204-
if parts[2].startswith("PINGR"):
202+
if message_body.startswith("PINGR"):
205203
logger.info(f"Got a PINGR from {self.ota_base_station_id}")
206204
self.ota_timeout = TIMEOUT
207205
got_pingr = True
208206

209207
# Message should look like 1,34,TEST,<file>,<configuration>,<role>,<starttime>
210-
if parts[2].startswith("TEST"):
211-
input = parts[2]
208+
if message_body.startswith("TEST"):
209+
input = message_body
212210
self.test_handler(input)
213-
if parts[2].startswith("RELOAD"):
211+
if message_body.startswith("RELOAD"):
214212
logger.info(f"Received a RELOAD message")
215213
self.reload_service()
216214

217-
if parts[2].startswith("RESTART"):
215+
if message_body.startswith("RESTART"):
218216
logger.info(f"Received a RESTART message")
219217
self.restart_system()
220218

ota.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,25 @@ def read_from_port(self):
5757
message_with_crc = self.ser.readline().decode("utf-8", errors="ignore").strip()
5858
parts = message_with_crc.split(",")
5959

60+
if message_with_crc == "" or message_with_crc == "OK":
61+
continue
62+
63+
print(message_with_crc)
64+
6065
if len(parts) != 5:
6166
continue
6267
# TODO: Maybe log if we are not putting a message into the recv_msgs?
6368

6469
# Extract components: +RCV=sender,length,message_with_crc,rssi,snr
70+
origin = parts[0][5:]
6571
message_with_crc_part = parts[2]
6672

6773
valid_crc, original_message = self.verify_crc(message_with_crc_part)
6874

69-
print(original_message)
70-
7175
if not valid_crc: # Bad checksum
7276
continue
7377

74-
self.recv_msgs.put(f"+RCV={original_message}")
78+
self.recv_msgs.put(f"{origin},{original_message}")
7579
except Exception as e:
7680
print(f"OTA encountered some error: {e}")
7781

@@ -101,7 +105,7 @@ def verify_crc(self, message_with_crc):
101105

102106
# Reconstruct the full message format that was used for CRC calculation
103107
# This should match the format used in send_ota_message: "{len(message)},{message}"
104-
full_message_for_crc = f"{len(original_message)},{original_message}"
108+
full_message_for_crc = f"{original_message}"
105109
calculated_crc = self.calculate_crc(full_message_for_crc)
106110

107111
is_valid = received_crc.lower() == calculated_crc.lower()
@@ -117,15 +121,14 @@ def send_ota_message(self, dest: int, message: str, include_crc: bool = True):
117121
include_crc (bool): Whether to include CRC checksum (default: True)
118122
"""
119123
try:
120-
full_message = f"{len(message)},{message}"
121124

122125
if include_crc:
123-
crc = self.calculate_crc(full_message)
124-
message_with_crc = f"{full_message}{crc}"
126+
crc = self.calculate_crc(message)
127+
message_with_crc = f"{message}{crc}"
125128
else:
126-
message_with_crc = full_message
129+
message_with_crc = message
127130

128-
full_message = f"AT+SEND={dest},{message_with_crc}\r\n"
131+
full_message = f"AT+SEND={dest},{len(message)},{message_with_crc}\r\n"
129132
self.ser.write(full_message.encode("utf-8"))
130133
except Exception as e:
131134
print(f"Failed to send OTA message: {e}")

setup/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pyserial==3.5
66
pynmeagps==1.0.50
77
rich==14.1.0
88
keyboard==0.13.5
9+
crc8==0.2.1

setup/requirements_bue.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
pynmeagps
2-
loguru
1+
pynmeagps==1.0.50
2+
loguru==0.7.3
3+
crc8==0.2.1

tests/conftest.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ def create_rcv_message(sender_id: int, message: str, rssi: int = -80, snr: int =
4949
"""Create a +RCV message as received from the LoRa module"""
5050
if include_crc:
5151
# Create the message format used for CRC: "{len(message)},{message}"
52-
msg_for_crc = f"{len(message)},{message}"
53-
crc = MessageHelper.calculate_crc8(msg_for_crc)
52+
crc = MessageHelper.calculate_crc8(message)
5453
message_with_crc = f"{message}{crc}"
55-
return f"+RCV={sender_id},{len(message_with_crc)},{message_with_crc},{rssi},{snr}"
54+
return f"+RCV={sender_id},{len(message)},{message_with_crc},{rssi},{snr}"
5655
else:
5756
return f"+RCV={sender_id},{len(message)},{message},{rssi},{snr}"
5857

@@ -61,10 +60,9 @@ def create_at_command(dest_id: int, message: str, include_crc: bool = True) -> s
6160
"""Create an AT+SEND command as sent to the LoRa module"""
6261
if include_crc:
6362
# Create the message format used for CRC: "{len(message)},{message}"
64-
msg_for_crc = f"{len(message)},{message}"
65-
crc = MessageHelper.calculate_crc8(msg_for_crc)
66-
message_with_crc = f"{msg_for_crc}{crc}"
67-
return f"AT+SEND={dest_id},{message_with_crc}\r\n"
63+
crc = MessageHelper.calculate_crc8(message)
64+
message_with_crc = f"{message}{crc}"
65+
return f"AT+SEND={dest_id},{len(message)},{message_with_crc}\r\n"
6866
else:
6967
msg_for_send = f"{len(message)},{message}"
7068
return f"AT+SEND={dest_id},{msg_for_send}\r\n"

tests/test_ota.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def test_receive_ota_message(self, ota_device):
4949
# Get new messages - should have CRC stripped and be prefixed with "RCV="
5050
messages = device.get_new_messages()
5151
assert len(messages) == 1
52-
assert messages[0] == "+RCV=PINGR"
52+
assert messages[0] == "1,PINGR"
5353

5454
def test_message_filtering(self, ota_device):
5555
"""Test that messages with bad CRC are filtered out"""
@@ -71,18 +71,18 @@ def test_message_filtering(self, ota_device):
7171
# Should only get the valid message
7272
messages = device.get_new_messages()
7373
assert len(messages) == 1
74-
assert messages[0] == "+RCV=ACK"
74+
assert messages[0] == "1,ACK"
7575

7676
def test_crc8_validation(self, ota_device):
7777
"""Test CRC8 checksum validation specifically"""
7878
device, mock_serial = ota_device
7979

8080
# Test with a known message and CRC
8181
message = "TEST"
82-
crc = MessageHelper.calculate_crc8(f"{len(message)},{message}")
82+
crc = MessageHelper.calculate_crc8(f"{message}")
8383

8484
# Create a valid message with correct CRC
85-
valid_rcv = f"+RCV=1,{len(message + crc)},{message}{crc},-50,1"
85+
valid_rcv = f"+RCV=1,{len(message)},{message}{crc},-50,1"
8686
mock_serial.add_incoming_message(valid_rcv)
8787

8888
# Create an invalid message with wrong CRC
@@ -95,7 +95,7 @@ def test_crc8_validation(self, ota_device):
9595
# Should only get the valid message
9696
messages = device.get_new_messages()
9797
assert len(messages) == 1
98-
assert messages[0] == f"+RCV={message}"
98+
assert messages[0] == f"1,{message}"
9999

100100

101101
class TestConnectionProtocol:
@@ -309,17 +309,16 @@ def test_create_rcv_message(self):
309309
"""Test creating RCV messages"""
310310
message = MessageHelper.create_rcv_message(5, MessageTypes.PING, -80, 10, include_crc=True)
311311
# With CRC, the length and content will be different
312-
expected_crc = MessageHelper.calculate_crc8(f"{len(MessageTypes.PING)},{MessageTypes.PING}")
313-
expected = f"+RCV=5,{len(MessageTypes.PING + expected_crc)},{MessageTypes.PING}{expected_crc},-80,10"
312+
expected_crc = MessageHelper.calculate_crc8(f"{MessageTypes.PING}")
313+
expected = f"+RCV=5,{len(MessageTypes.PING)},{MessageTypes.PING}{expected_crc},-80,10"
314314
assert message == expected
315315

316316
def test_create_at_command(self):
317317
"""Test creating AT commands"""
318318
command = MessageHelper.create_at_command(10, MessageTypes.PING, include_crc=True)
319319
# With CRC, the command will include the checksum
320-
msg_for_crc = f"{len(MessageTypes.PING)},{MessageTypes.PING}"
321-
expected_crc = MessageHelper.calculate_crc8(msg_for_crc)
322-
expected = f"AT+SEND=10,{msg_for_crc}{expected_crc}\r\n"
320+
expected_crc = MessageHelper.calculate_crc8(MessageTypes.PING)
321+
expected = f"AT+SEND=10,4,PING{expected_crc}\r\n"
323322
assert command == expected
324323

325324
def test_parse_message_type(self):

0 commit comments

Comments
 (0)