Skip to content

Commit 5fde381

Browse files
committed
Add passthrough mode for LoRa radio firmware update
1 parent 9da7dd3 commit 5fde381

File tree

6 files changed

+264
-130
lines changed

6 files changed

+264
-130
lines changed

Firmware/RTK_Everywhere/ESPNOW.ino

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,47 @@
1313
few seconds so a single dropped frame is not critical.
1414
*/
1515

16+
// Called from main loop
17+
// Control incoming/outgoing RTCM data from internal ESP NOW radio
18+
// Use the ESP32 to directly transmit/receive RTCM over 2.4GHz (no WiFi needed)
19+
void updateEspnow()
20+
{
21+
#ifdef COMPILE_ESPNOW
22+
if (settings.enableEspNow == true)
23+
{
24+
if (espnowState == ESPNOW_PAIRED)
25+
{
26+
// If it's been longer than a few ms since we last added a byte to the buffer
27+
// then we've reached the end of the RTCM stream. Send partial buffer.
28+
if (espnowOutgoingSpot > 0 && (millis() - espnowLastAdd) > 50)
29+
{
30+
if (settings.espnowBroadcast == false)
31+
esp_now_send(0, (uint8_t *)&espnowOutgoing, espnowOutgoingSpot); // Send partial packet to all peers
32+
else
33+
{
34+
uint8_t broadcastMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
35+
esp_now_send(broadcastMac, (uint8_t *)&espnowOutgoing,
36+
espnowOutgoingSpot); // Send packet via broadcast
37+
}
38+
39+
if (!inMainMenu)
40+
{
41+
if (settings.debugEspNow == true)
42+
systemPrintf("ESPNOW transmitted %d RTCM bytes\r\n", espnowBytesSent + espnowOutgoingSpot);
43+
}
44+
espnowBytesSent = 0;
45+
espnowOutgoingSpot = 0; // Reset
46+
}
47+
48+
// If we don't receive an ESP NOW packet after some time, set RSSI to very negative
49+
// This removes the ESPNOW icon from the display when the link goes down
50+
if (millis() - lastEspnowRssiUpdate > 5000 && espnowRSSI > -255)
51+
espnowRSSI = -255;
52+
}
53+
}
54+
#endif // COMPILE_ESPNOW
55+
}
56+
1657
// Create a struct for ESP NOW pairing
1758
typedef struct PairMessage
1859
{

Firmware/RTK_Everywhere/LoRa.ino

Lines changed: 202 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,59 +3,29 @@ LoRa.ino
33
44
This module implements the interface to the LoRa radio in the Torch.
55
6-
------------------------------------------------------------------------------*/
6+
Bootloading the STM32 requires a connection to the USB serial. Because it is
7+
not directly connected, we reconfigure the ESP32 to be a passthrough.
78
8-
// See menuRadio() to get LoRa Settings
9+
ESP32 UART0 RX -> ESP32 UART1 TX -> STM32 UART0 RX
10+
STM32 UART0 TX -> ESP32 UART1 RX -> ESP32 UART0 RX
911
10-
void muxSelectLora()
11-
{
12-
digitalWrite(pin_muxA, HIGH); // Connect ESP UART1 to LoRa
13-
}
14-
void muxSelectUm980()
15-
{
16-
digitalWrite(pin_muxA, LOW); // Connect ESP UART1 to UM980
17-
}
12+
Because the STM32CubeProgrammer and other terminal software cause the DTR
13+
line to toggle, this causes the ESP32 to reset. Therefore, to enter passthrough
14+
mode we write a file to LittleFS then reboot. If the file is seen, we enter
15+
passthrough mode indefinitely until the user presses the external button.
16+
Then we delete the file and reboot to return to normal operation.
1817
19-
void muxSelectCh340()
20-
{
21-
pinMode(pin_muxB, OUTPUT); // Make really sure we can control this pin
22-
digitalWrite(pin_muxB, LOW); // Connect ESP UART0 to CH340 Serial
23-
}
24-
void muxSelectLoRaConfigure()
25-
{
26-
pinMode(pin_muxB, OUTPUT); // Make really sure we can control this pin
27-
digitalWrite(pin_muxA, LOW); // Connect ESP UART1 to UM980
28-
digitalWrite(pin_muxB, HIGH); // Connect ESP UART0 to U11
29-
}
30-
31-
void loraEnterBootloader()
32-
{
33-
digitalWrite(pin_loraRadio_boot, HIGH); // Enter bootload mode
34-
loraReset();
35-
}
36-
37-
void loraExitBootloader()
38-
{
39-
digitalWrite(pin_loraRadio_boot, LOW); // Exit bootload mode
40-
loraReset();
41-
}
42-
43-
void loraReset()
44-
{
45-
digitalWrite(pin_loraRadio_reset, LOW); // Reset STM32/radio
46-
delay(15);
47-
digitalWrite(pin_loraRadio_reset, HIGH); // Run STM32/radio
48-
delay(15);
49-
}
18+
------------------------------------------------------------------------------*/
5019

51-
void loraPowerOn()
52-
{
53-
digitalWrite(pin_loraRadio_power, HIGH); // Power STM32/radio
54-
}
20+
// See menuRadio() to get LoRa Settings
5521

56-
void loraPowerOff()
22+
// Called from main loop
23+
// Control incoming/outgoing RTCM data from STM32 based LoRa radio (if supported by platform)
24+
void updateLora()
5725
{
58-
digitalWrite(pin_loraRadio_power, LOW); // Power off STM32/radio
26+
if (settings.enableLora == true)
27+
{
28+
}
5929
}
6030

6131
void beginLora()
@@ -124,6 +94,57 @@ void loraSetup(bool transmit)
12494
systemPrintf("Response: %s\r\n", response);
12595
}
12696

97+
void muxSelectLora()
98+
{
99+
digitalWrite(pin_muxA, HIGH); // Connect ESP UART1 to LoRa
100+
}
101+
void muxSelectUm980()
102+
{
103+
digitalWrite(pin_muxA, LOW); // Connect ESP UART1 to UM980
104+
}
105+
106+
void muxSelectCh340()
107+
{
108+
pinMode(pin_muxB, OUTPUT); // Make really sure we can control this pin
109+
digitalWrite(pin_muxB, LOW); // Connect ESP UART0 to CH340 Serial
110+
}
111+
void muxSelectLoRaConfigure()
112+
{
113+
pinMode(pin_muxB, OUTPUT); // Make really sure we can control this pin
114+
digitalWrite(pin_muxA, LOW); // Connect ESP UART1 to UM980
115+
digitalWrite(pin_muxB, HIGH); // Connect ESP UART0 to U11
116+
}
117+
118+
void loraEnterBootloader()
119+
{
120+
digitalWrite(pin_loraRadio_boot, HIGH); // Enter bootload mode
121+
loraReset();
122+
}
123+
124+
void loraExitBootloader()
125+
{
126+
digitalWrite(pin_loraRadio_boot, LOW); // Exit bootload mode
127+
loraReset();
128+
}
129+
130+
void loraReset()
131+
{
132+
digitalWrite(pin_loraRadio_reset, LOW); // Reset STM32/radio
133+
delay(15);
134+
digitalWrite(pin_loraRadio_reset, HIGH); // Run STM32/radio
135+
delay(15);
136+
}
137+
138+
void loraPowerOn()
139+
{
140+
digitalWrite(pin_loraRadio_power, HIGH); // Power STM32/radio
141+
}
142+
143+
void loraPowerOff()
144+
{
145+
digitalWrite(pin_loraRadio_power, LOW); // Power off STM32/radio
146+
}
147+
127148
void loraSetupTransmit()
128149
{
129150
loraSetup(true);
@@ -133,3 +154,137 @@ void loraSetupReceive()
133154
{
134155
loraSetup(false);
135156
}
157+
158+
// Check if updateLoraFirmware.txt exists
159+
bool checkUpdateLoraFirmware()
160+
{
161+
if (online.fs == false)
162+
return false;
163+
164+
if (LittleFS.exists("/updateLoraFirmware.txt"))
165+
{
166+
if (settings.debugLora)
167+
systemPrintln("LittleFS updateLoraFirmware.txt exists");
168+
169+
// We do not remove the file here. See removeupdateLoraFirmware().
170+
171+
return true;
172+
}
173+
174+
return false;
175+
}
176+
177+
void removeUpdateLoraFirmware()
178+
{
179+
if (online.fs == false)
180+
return;
181+
182+
if (LittleFS.exists("/updateLoraFirmware.txt"))
183+
{
184+
if (settings.debugLora)
185+
systemPrintln("Removing updateLoraFirmware.txt ");
186+
187+
LittleFS.remove("/updateLoraFirmware.txt");
188+
}
189+
}
190+
191+
// Force UART connection to LoRa radio for firmware update on the next boot by creating updateLoraFirmware.txt in
192+
// LittleFS
193+
bool forceLoRaPassthrough()
194+
{
195+
if (online.fs == false)
196+
return false;
197+
198+
if (LittleFS.exists("/updateLoraFirmware.txt"))
199+
{
200+
if (settings.debugLora)
201+
systemPrintln("LittleFS updateLoraFirmware.txt already exists");
202+
return true;
203+
}
204+
205+
File updateLoraFirmware = LittleFS.open("/updateLoraFirmware.txt", FILE_WRITE);
206+
updateLoraFirmware.close();
207+
208+
if (LittleFS.exists("/updateLoraFirmware.txt"))
209+
return true;
210+
211+
if (settings.debugLora)
212+
systemPrintln("Unable to create updateLoraFirmware.txt on LittleFS");
213+
return false;
214+
}
215+
216+
void beginLoraFirmwareUpdate()
217+
{
218+
// Change Serial speed of UART0
219+
Serial.end(); // We must end before we begin otherwise the UART settings are corrupted
220+
Serial.begin(57600); // Keep this at slower rate
221+
222+
if (serialGNSS == nullptr)
223+
serialGNSS = new HardwareSerial(2); // Use UART2 on the ESP32 for communication with the GNSS module
224+
225+
serialGNSS->begin(115200, SERIAL_8N1, pin_GnssUart_RX, pin_GnssUart_TX); // Keep this at 115200
226+
227+
// If the radio is off, turn it on
228+
if (digitalRead(pin_loraRadio_power) == LOW)
229+
{
230+
systemPrintln("Turning on radio");
231+
loraPowerOn();
232+
delay(500); // Allow power to stablize
233+
}
234+
235+
// Make sure ESP-UART1 is connected to LoRA STM32 UART0
236+
muxSelectLora();
237+
238+
loraEnterBootloader(); // Push boot pin high and reset STM32
239+
240+
delay(500);
241+
242+
while (Serial.available())
243+
Serial.read();
244+
245+
systemPrintln();
246+
systemPrintln("Entering STM32 direct connect for firmware update. Disconnect this terminal connection. Use "
247+
"'STM32CubeProgrammer' to update the "
248+
"firmware. Baudrate: 57600bps. Parity: None. RTS/DTR: High. Press the power button to return "
249+
"to normal operation.");
250+
251+
delay(50); // Allow print to complete
252+
253+
// Push any incoming ESP32 UART0 to UART1 and vice versa
254+
// Infinite loop until button is pressed
255+
while (1)
256+
{
257+
while (Serial.available())
258+
serialGNSS->write(Serial.read());
259+
260+
while (serialGNSS->available())
261+
Serial.write(serialGNSS->read());
262+
263+
if (digitalRead(pin_powerButton) == HIGH)
264+
{
265+
while (digitalRead(pin_powerButton) == HIGH)
266+
delay(100);
267+
268+
// Remove file and reset to exit LoRa update pass-through mode
269+
removeUpdateLoraFirmware();
270+
271+
// Beep if we are not locally compiled or a release candidate
272+
if (ENABLE_DEVELOPER == false)
273+
{
274+
beepOn();
275+
delay(300);
276+
beepOff();
277+
delay(100);
278+
beepOn();
279+
delay(300);
280+
beepOff();
281+
}
282+
283+
systemPrintln("Exiting LoRa Firmware update mode");
284+
285+
delay(50); // Allow prints to complete
286+
287+
ESP.restart();
288+
}
289+
}
290+
}

0 commit comments

Comments
 (0)