Skip to content

Commit 582619d

Browse files
R4ynorAlessandroAU
andauthored
Added bootloader to r9mx (ExpressLRS#137)
* Initial support for r9mx receiver * r9mx working Added r9mx enviroment, fixed build with ststm32 7.2.0 platform. PIO upload not working * Updated target with bootloader * Cleanup PR Co-authored-by: Alessandro <[email protected]>
1 parent f53fbc7 commit 582619d

3 files changed

Lines changed: 291 additions & 83 deletions

File tree

src/bootloader/r9mx_bootloader.bin

9.83 KB
Binary file not shown.

src/python/UARTupload.py

Lines changed: 89 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,20 @@
1818

1919
sys.stdout.flush()
2020

21-
def StatusCallback(total_packets, success_count, error_count):
22-
#sys.stdout.write(".")
23-
sys.stdout.flush()
24-
25-
if(total_packets % 10 == 0):
26-
27-
if(error_count > 0):
28-
sys.stdout.write(str(round((total_packets/filechunks)*100)) + "% err: " + str(error_count) + "\n")
29-
else:
30-
sys.stdout.write(str(round((total_packets/filechunks)*100)) + "%\n")
31-
32-
sys.stdout.flush()
21+
try:
22+
filename = sys.argv[1]
23+
except:
24+
dbg_print("Filename not provided, going to use default firmware.bin")
25+
filename = "firmware.bin"
3326

34-
def getc(size, timeout=3):
35-
return s.read(size)
27+
if not os.path.exists(filename):
28+
msg = "[FAILED] bin file '%s' does not exist\n" % filename
29+
dbg_print(msg)
30+
raise EnvironmentError(msg)
3631

37-
def putc(data, timeout=3):
38-
s.write(data)
32+
def dbg_print(line):
33+
sys.stdout.write(line)
34+
sys.stdout.flush()
3935

4036
def serial_ports():
4137
""" Lists serial port names
@@ -70,101 +66,111 @@ def serial_ports():
7066
#sys.stdout.write(str(serial_ports())[1:-1])
7167
#sys.stdout.write("\n")
7268

73-
sys.stdout.write("Going to use "+ result[0] + "\n")
69+
if not result:
70+
msg = "\n[FAILED] Cannot find suitable serial port\n\n"
71+
dbg_print(msg)
72+
raise EnvironmentError(msg)
7473

75-
s = serial.Serial(port=result[0], baudrate=420000, bytesize=8, parity='N', stopbits=1, timeout=5, xonxoff=0, rtscts=0)
76-
77-
alreadyInBootloader = False
78-
s.flush()
79-
time.sleep(1)
74+
dbg_print("Going to use "+ result[0]+"\n")
8075

76+
s = serial.Serial(port=result[0], baudrate=420000, bytesize=8, parity='N', stopbits=1, timeout=.5, xonxoff=0, rtscts=0)
8177

78+
s.timeout = 1.
8279
try:
83-
reading = s.read(3).decode('utf-8')
80+
already_in_bl = s.read(3).decode('utf-8')
8481
except UnicodeDecodeError:
85-
reading = ""
86-
87-
if('C' in reading):
88-
alreadyInBootloader = True
82+
already_in_bl = ""
8983

90-
MaxBootloaderAttempts = 20
91-
currAttempt = 0
92-
gotBootloader = False
84+
if 'CC' not in already_in_bl:
85+
s.timeout = .5
86+
s.write_timeout = .5
9387

94-
if(alreadyInBootloader == False):
88+
currAttempt = 0
89+
gotBootloader = False
9590

96-
sys.stdout.write("\nAttempting to reboot into bootloader...\n")
91+
dbg_print("\nAttempting to reboot into bootloader...\n")
9792

9893
while gotBootloader == False:
9994

100-
s.flush()
101-
s.write(BootloaderInitSeq1)
102-
time.sleep(1)
103-
s.write(BootloaderInitSeq2)
104-
105-
lines = []
106-
inChars = ""
95+
currAttempt += 1
96+
dbg_print("[%2u] retry...\n" % currAttempt)
97+
time.sleep(.5)
98+
if 10 < currAttempt:
99+
msg = "Failed to get to BL in reasonable time\n"
100+
dbg_print(msg)
101+
raise EnvironmentError(msg)
107102

108-
while s.in_waiting:
103+
# request reboot
104+
s.write(BootloaderInitSeq1)
105+
s.flush()
106+
start = time.time()
107+
while ((time.time() - start) < 2):
109108
try:
110-
inChars += s.read().decode('utf-8')
109+
line = s.readline().decode('utf-8')
110+
if not line and s.in_waiting:
111+
line = s.read(1000).decode('utf-8')
111112
except UnicodeDecodeError:
112-
pass
113-
114-
for line in inChars.split('\n'):
115-
if "UART Bootloader for ExpressLRS" in line:
116-
sys.stdout.write("Got into bootloader after: ")
117-
sys.stdout.write(str(currAttempt+1))
118-
sys.stdout.write(" attempts\n")
119-
sys.stdout.flush()
113+
continue
114+
#dbg_print("line : '%s'\n" % (line.strip(), ))
115+
if "'2bl', 'bbb'" in line:
116+
# notify bootloader to start uploading
117+
s.write(BootloaderInitSeq2)
118+
s.flush()
119+
dbg_print("Got into bootloader after: %u attempts\n" % (currAttempt))
120120
gotBootloader = True
121121
break
122122

123-
if('C' in line):
124-
gotBootloader = True
125-
break
123+
# change timeout to 30sec
124+
s.timeout = 30.
125+
s.write_timeout = 5.
126126

127-
if(currAttempt == 20):
128-
sys.stdout.write("Failed to get to BL in reasonable time\n")
129-
raise SystemExit
127+
# sanity check! Make sure the bootloader is started
128+
start = time.time()
129+
while True:
130+
char = s.read().decode('utf-8')
131+
if char == 'C':
130132
break
131-
132-
currAttempt = currAttempt + 1
133-
134-
s.write(BootloaderInitSeq2)
135-
133+
if ((time.time() - start) > 10):
134+
msg = "[FAILED] Unable to communicate with bootloader...\n"
135+
dbg_print(msg)
136+
raise EnvironmentError(msg)
136137
else:
137-
sys.stdout.write("\nWe were already in bootloader\n")
138-
sys.stdout.flush()
139-
140-
141-
time.sleep(0.2)
142-
s.close()
143-
s.open()
144-
138+
dbg_print("\nWe were already in bootloader\n")
145139

146-
try:
147-
filename = sys.argv[1]
148-
except:
149-
print("Filename not provided, going to use default firmware.bin")
150-
filename = "firmware.bin"
140+
# change timeout to 5sec
141+
s.timeout = 5.
142+
s.write_timeout = 5.
151143

144+
# open binary
152145
stream = open(filename, 'rb')
153146
filesize = os.stat(filename).st_size
154147
filechunks = filesize/128
155148

156-
sys.stdout.write("uploading ")
157-
sys.stdout.write(str(filesize)+" bytes...\n")
158-
sys.stdout.flush()
149+
dbg_print("uploading %d bytes...\n" % (filesize,))
159150

160-
modem = XMODEM(getc, putc)
161-
status = modem.send(stream, retry=10, callback=StatusCallback)
151+
def StatusCallback(total_packets, success_count, error_count):
152+
sys.stdout.flush()
153+
if (total_packets % 10 == 0):
154+
if (error_count > 0):
155+
dbg_print(str(round((total_packets/filechunks)*100)) + "% err: " + str(error_count) + "\n")
156+
else:
157+
dbg_print(str(round((total_packets/filechunks)*100)) + "%\n")
162158

163-
if(status):
164-
print("100%\nSuccess!!!!")
165-
else:
166-
print("FAILED")
167-
raise EnvironmentError('Failed to Upload')
159+
def getc(size, timeout=3):
160+
return s.read(size) or None
161+
162+
def putc(data, timeout=3):
163+
return s.write(data)
164+
165+
modem = XMODEM(getc, putc, mode='xmodem')
166+
#modem.log.setLevel(logging.DEBUG)
167+
status = modem.send(stream, retry=10, callback=StatusCallback)
168168

169169
s.close()
170170
stream.close()
171+
172+
if (status):
173+
dbg_print("Success!!!!\n\n")
174+
else:
175+
dbg_print("[FAILED] Upload failed!\n\n")
176+
raise EnvironmentError('Failed to Upload')

0 commit comments

Comments
 (0)