Skip to content

Commit bb83fcb

Browse files
Check firmware target on WiFi based TX/RX and BFPassthrough RX (ExpressLRS#545)
* Check firmware target on ESP32 based TXs * Add update code to ESP8266/85 RXs to check target firmware Changes ESP32 TX code to match RX code * Move target_name to config.cpp Moves so it can be used in PR#539 (xmodem upload via betaflight) * Enable target_name check on buttonless passthrough - Extend the reboot command on RX to print current target_name before rebooting into flash mode - Extend the BFInitPassthrough script to accept the PIOENV as target and compare against RX * Pass target down to BFInitPassthrough from UARTupload - this allows the target_name to be checked for STM32 RX targets * Changes as per discord - Also allow upload on mac to SPF3 * Fix detection of unknown target Co-authored-by: AlessandroAU <[email protected]>
1 parent e3610c9 commit bb83fcb

10 files changed

Lines changed: 136 additions & 21 deletions

File tree

src/python/BFinitPassthrough.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class PassthroughEnabled(Exception):
1313
class PassthroughFailed(Exception):
1414
pass
1515

16+
class WrongTargetSelected(Exception):
17+
pass
1618

1719
def dbg_print(line=''):
1820
sys.stdout.write(line + '\n')
@@ -115,14 +117,24 @@ def reset_to_bootloader(args):
115117
s = serial.Serial(port=args.port, baudrate=args.baud,
116118
bytesize=8, parity='N', stopbits=1,
117119
timeout=1, xonxoff=0, rtscts=0)
120+
rl = SerialHelper.SerialHelper(s, 3.)
121+
rl.clear()
118122
if args.half_duplex:
119123
BootloaderInitSeq = bootloader.get_init_seq('GHST', args.type)
120124
dbg_print(" * Using half duplex (GHST)")
121125
else:
122126
BootloaderInitSeq = bootloader.get_init_seq('CRSF', args.type)
123127
dbg_print(" * Using full duplex (CFSF)")
124-
s.write(BootloaderInitSeq)
128+
rl.write(BootloaderInitSeq)
125129
s.flush()
130+
rx_target = rl.read_line().strip()
131+
flash_target = re.sub("_VIA_.*", "", args.target.upper())
132+
if rx_target == "":
133+
dbg_print("Cannot detect RX target, blindly flashing!")
134+
elif rx_target != flash_target:
135+
raise WrongTargetSelected("Wrong target selected your RX is '%s', trying to flash '%s'" % (rx_target, flash_target))
136+
elif flash_target != "":
137+
dbg_print("Verified RX target '%s'" % (flash_target))
126138
time.sleep(.5)
127139
s.close()
128140

@@ -134,6 +146,8 @@ def reset_to_bootloader(args):
134146
help="Baud rate for passthrough communication")
135147
parser.add_argument("-p", "--port", type=str,
136148
help="Override serial port autodetection and use PORT")
149+
parser.add_argument("-r", "--target", type=str,
150+
help="The target firmware that is going to be uploaded")
137151
parser.add_argument("-nr", "--no-reset", action="store_false",
138152
dest="reset_to_bl", help="Do not send reset_to_bootloader command sequence")
139153
parser.add_argument("-hd", "--half-duplex", action="store_true",
@@ -151,4 +165,8 @@ def reset_to_bootloader(args):
151165
dbg_print(str(err))
152166

153167
if args.reset_to_bl:
154-
reset_to_bootloader(args)
168+
try:
169+
reset_to_bootloader(args)
170+
except WrongTargetSelected as err:
171+
dbg_print(str(err))
172+
exit(-1)

src/python/UARTupload.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def dbg_print(line=''):
2020
return
2121

2222

23-
def uart_upload(port, filename, baudrate, ghst=False, key=None):
23+
def uart_upload(port, filename, baudrate, ghst=False, key=None, target=""):
2424
half_duplex = False
2525

2626
dbg_print("=================== FIRMWARE UPLOAD ===================\n")
@@ -139,6 +139,13 @@ def uart_upload(port, filename, baudrate, ghst=False, key=None):
139139
gotBootloader = True
140140
break
141141

142+
elif "_RX_" in line:
143+
flash_target = re.sub("_VIA_.*", "", target.upper())
144+
if line != flash_target:
145+
raise Exception("Wrong target selected your RX is '%s', trying to flash '%s'" % (line, flash_target))
146+
elif flash_target != "":
147+
dbg_print("Verified RX target '%s'" % flash_target)
148+
142149
dbg_print(" Got into bootloader after: %u attempts\n" % currAttempt)
143150

144151
# sanity check! Make sure the bootloader is started
@@ -223,7 +230,7 @@ def on_upload(source, target, env):
223230
envkey = flag.split("=")[1]
224231

225232
try:
226-
uart_upload(upload_port, firmware_path, upload_speed, ghst, key=envkey)
233+
uart_upload(upload_port, firmware_path, upload_speed, ghst, key=envkey, target=env['PIOENV'])
227234
except Exception as e:
228235
dbg_print("{0}\n".format(e))
229236
return -1

src/python/build_flags.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def get_git_sha():
105105
process_flags("user_defines.txt")
106106
process_flags("super_defines.txt") # allow secret super_defines to override user_defines
107107
build_flags.append("-DLATEST_COMMIT=" + get_git_sha())
108+
build_flags.append("-DTARGET_NAME=" + re.sub("_VIA_.*", "", env['PIOENV'].upper()))
108109
condense_flags()
109110

110111
env['BUILD_FLAGS'] = build_flags

src/python/serials_find.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def serial_ports():
4040
ports.extend(glob.glob('/dev/ttyUSB*'))
4141
elif platform.startswith('darwin'):
4242
ports = glob.glob('/dev/tty.usbmodem*')
43+
ports.extend(glob.glob('/dev/tty.SLAB*'))
4344
else:
4445
raise Exception('Unsupported platform')
4546

src/src/ESP32_WebUpdate.cpp

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ extern CRSF crsf;
2626
#include <Update.h>
2727

2828
#include "ESP32_WebUpdate.h"
29+
#include "config.h"
30+
31+
uint8_t target_seen = 0;
32+
uint8_t target_pos = 0;
2933

3034
const char *ssid = "ExpressLRS TX Module"; // The name of the Wi-Fi network that will be created
3135
const char *password = "expresslrs"; // The password required to connect to it, leave blank for an open network
@@ -158,31 +162,54 @@ void BeginWebUpdate()
158162

159163
server.on(
160164
"/update", HTTP_POST, []() {
165+
server.client().setNoDelay(true);
161166
server.sendHeader("Connection", "close");
162-
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
167+
server.send(200, "text/plain", target_seen ? ((Update.hasError()) ? "FAIL" : "OK") : "WRONG FIRMWARE");
163168
delay(100);
164169
server.client().stop();
165-
ESP.restart(); }, []() {
170+
ESP.restart(); },
171+
[]() {
166172
HTTPUpload& upload = server.upload();
167173
if (upload.status == UPLOAD_FILE_START) {
168174
Serial.setDebugOutput(true);
169175
Serial.printf("Update: %s\n", upload.filename.c_str());
170176
if (!Update.begin()) { //start with max available size
171177
Update.printError(Serial);
172178
}
179+
target_seen = 0;
180+
target_pos = 0;
173181
} else if (upload.status == UPLOAD_FILE_WRITE) {
174182
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
175183
Update.printError(Serial);
176184
}
185+
if (!target_seen) {
186+
for (int i=0 ; i<upload.currentSize ;i++) {
187+
if (upload.buf[i] == target_name[target_pos]) {
188+
++target_pos;
189+
if (target_pos >= target_name_size) {
190+
target_seen = 1;
191+
}
192+
}
193+
else {
194+
target_pos = 0; // Startover
195+
}
196+
}
197+
}
177198
} else if (upload.status == UPLOAD_FILE_END) {
178-
if (Update.end(true)) { //true to set the size to the current progress
179-
Serial.printf("Upload Success: %ubytes\nPlease wait for LED to resume blinking before disconnecting power\n", upload.totalSize);
199+
if (target_seen) {
200+
if (Update.end(true)) { //true to set the size to the current progress
201+
Serial.printf("Upload Success: %ubytes\nPlease wait for LED to resume blinking before disconnecting power\n", upload.totalSize);
202+
} else {
203+
Update.printError(Serial);
204+
}
180205
} else {
181-
Update.printError(Serial);
206+
Update.abort();
207+
Serial.printf("Wrong firmware uploaded, not %s, update aborted\n", &target_name[4]);
182208
}
183209
Serial.setDebugOutput(false);
184-
} else {
185-
Serial.printf("Update Failed Unexpectedly (likely broken connection): status=%d\n", upload.status);
210+
} else if(upload.status == UPLOAD_FILE_ABORTED){
211+
Update.abort();
212+
Serial.println("Update was aborted");
186213
} });
187214

188215
dnsServer.start(DNS_PORT, "*", apIP);
@@ -205,4 +232,4 @@ void HandleWebUpdate()
205232
yield();
206233
}
207234

208-
#endif
235+
#endif

src/src/ESP8266_WebUpdate.cpp

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#ifdef PLATFORM_ESP8266
22
#include "ESP8266_WebUpdate.h"
3+
#include "config.h"
34

45
#if defined(Regulatory_Domain_AU_915) || defined(Regulatory_Domain_EU_868) || defined(Regulatory_Domain_IN_866) || defined(Regulatory_Domain_FCC_915) || defined(Regulatory_Domain_AU_433) || defined(Regulatory_Domain_EU_433)
56
#include "SX127xDriver.h"
@@ -11,6 +12,9 @@ extern SX127xDriver Radio;
1112
extern SX1280Driver Radio;
1213
#endif
1314

15+
uint8_t target_seen = 0;
16+
uint8_t target_pos = 0;
17+
1418
#define STASSID "ExpressLRS RX"
1519
#define STAPSK "expresslrs"
1620
const char *myHostname = "elrs_rx";
@@ -27,8 +31,6 @@ DNSServer dnsServer;
2731
//MDNSResponder mdns;
2832
ESP8266WebServer server(80);
2933

30-
ESP8266HTTPUpdateServer httpUpdater;
31-
3234
/** Is this an IP? */
3335
boolean isIp(String str)
3436
{
@@ -152,12 +154,60 @@ void BeginWebUpdate(void)
152154
server.on("/fwlink", WebUpdateHandleRoot);
153155
server.onNotFound(WebUpdateHandleNotFound);
154156

155-
// if (mdns.begin(myHostname, apIP))
156-
// {
157-
// mdns.addService("http", "tcp", 80);
158-
// mdns.update();
159-
// }
160-
httpUpdater.setup(&server);
157+
// handler for the /update form POST (once file upload finishes)
158+
server.on("/update", HTTP_POST, [&](){
159+
server.client().setNoDelay(true);
160+
server.sendHeader("Connection", "close");
161+
server.send(200, "text/plain", target_seen ? ((Update.hasError()) ? "FAIL" : "OK") : "WRONG FIRMWARE");
162+
delay(100);
163+
server.client().stop();
164+
ESP.restart(); },
165+
[]() {
166+
HTTPUpload& upload = server.upload();
167+
if(upload.status == UPLOAD_FILE_START){
168+
Serial.setDebugOutput(true);
169+
WiFiUDP::stopAll();
170+
Serial.printf("Update: %s\n", upload.filename.c_str());
171+
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
172+
if (!Update.begin(maxSketchSpace, U_FLASH)){//start with max available size
173+
Update.printError(Serial);
174+
}
175+
target_seen = 0;
176+
target_pos = 0;
177+
} else if(upload.status == UPLOAD_FILE_WRITE){
178+
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
179+
Update.printError(Serial);
180+
}
181+
if (!target_seen) {
182+
for (size_t i=0 ; i<upload.currentSize ;i++) {
183+
if (upload.buf[i] == target_name[target_pos]) {
184+
++target_pos;
185+
if (target_pos >= target_name_size) {
186+
target_seen = 1;
187+
}
188+
}
189+
else {
190+
target_pos = 0; // Startover
191+
}
192+
}
193+
}
194+
} else if(upload.status == UPLOAD_FILE_END){
195+
if (target_seen) {
196+
if(Update.end(true)){ //true to set the size to the current progress
197+
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
198+
} else {
199+
Update.printError(Serial);
200+
}
201+
} else {
202+
Serial.printf("Wrong firmware uploaded, not %s, update aborted\n", &target_name[4]);
203+
}
204+
Serial.setDebugOutput(false);
205+
} else if(upload.status == UPLOAD_FILE_ABORTED){
206+
Serial.println("Update was aborted");
207+
}
208+
delay(0);
209+
});
210+
161211
server.begin();
162212
Serial.printf("HTTPUpdateServer ready! Open http://%s in your browser\n", myHostname);
163213
}

src/src/config.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#include "common.h"
33
#include "POWERMGNT.h"
44

5+
#define QUOTE(arg) #arg
6+
#define STR(macro) QUOTE(macro)
7+
const unsigned char target_name[] = "\xBE\xEF\xCA\xFE" STR(TARGET_NAME);
8+
const uint8_t target_name_size = sizeof(target_name);
9+
510
void
611
TxConfig::Load()
712
{

src/src/config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#include "targets.h"
44
#include "elrs_eeprom.h"
55

6+
extern const unsigned char target_name[];
7+
extern const uint8_t target_name_size;
8+
69
#define TX_CONFIG_VERSION 1
710
#define RX_CONFIG_VERSION 1
811
#define UID_LEN 6

src/src/rx_main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,8 @@ struct bootloader {
13491349

13501350
void reset_into_bootloader(void)
13511351
{
1352+
CRSF_TX_SERIAL.println((const char *)&target_name[4]);
1353+
CRSF_TX_SERIAL.flush();
13521354
#if defined(PLATFORM_STM32)
13531355
delay(100);
13541356
Serial.println("Jumping to Bootloader...");
@@ -1367,6 +1369,7 @@ void reset_into_bootloader(void)
13671369

13681370
HAL_NVIC_SystemReset();
13691371
#elif defined(PLATFORM_ESP8266)
1372+
delay(100);
13701373
ESP.rebootIntoUartDownloadMode();
13711374
#endif
13721375
}

src/targets/common.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ upload_speed = 460800
4646
monitor_speed = 420000
4747
upload_resetmethod = nodemcu
4848
bf_upload_command =
49-
python "$PROJECT_DIR/python/BFinitPassthrough.py" -b $UPLOAD_SPEED ${UPLOAD_PORT and "-p "+UPLOAD_PORT}
49+
python "$PROJECT_DIR/python/BFinitPassthrough.py" -b $UPLOAD_SPEED ${UPLOAD_PORT and "-p "+UPLOAD_PORT} -r $PIOENV
5050
python "$PROJECT_DIR/python/esptool-3.0/esptool.py" -b $UPLOAD_SPEED ${UPLOAD_PORT and "-p "+UPLOAD_PORT} -c esp8266 --before no_reset --after soft_reset write_flash 0x0000 "$SOURCE"
5151

5252
# ------------------------- COMMON STM32 DEFINITIONS -----------------

0 commit comments

Comments
 (0)