2015-06-24 11:32:12 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
"""
|
2015-06-28 12:23:55 +01:00
|
|
|
The WiPy firmware update script. Transmits the specified firmware file
|
|
|
|
over FTP, and then resets the WiPy and optionally verifies that software
|
|
|
|
was correctly updated.
|
2015-06-24 11:32:12 +01:00
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
|
|
|
./update-wipy.py --file "path_to_mcuimg.bin" --verify
|
|
|
|
|
|
|
|
Or:
|
|
|
|
|
|
|
|
python update-wipy.py --file "path_to_mcuimg.bin"
|
|
|
|
"""
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import argparse
|
|
|
|
import time
|
2015-09-26 23:16:20 +01:00
|
|
|
import socket
|
2015-06-24 11:32:12 +01:00
|
|
|
from ftplib import FTP
|
|
|
|
from telnetlib import Telnet
|
|
|
|
|
|
|
|
|
|
|
|
def print_exception(e):
|
2015-06-24 14:23:03 +01:00
|
|
|
print ('Exception: {}, on line {}'.format(e, sys.exc_info()[-1].tb_lineno))
|
2015-06-24 11:32:12 +01:00
|
|
|
|
|
|
|
|
2015-07-05 21:31:50 +01:00
|
|
|
def ftp_directory_exists(ftpobj, directory_name):
|
|
|
|
filelist = []
|
|
|
|
ftpobj.retrlines('LIST',filelist.append)
|
|
|
|
for f in filelist:
|
|
|
|
if f.split()[-1] == directory_name:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2015-06-24 11:32:12 +01:00
|
|
|
def transfer_file(args):
|
2015-07-05 21:31:50 +01:00
|
|
|
with FTP(args.ip, timeout=20) as ftp:
|
2015-06-24 11:32:12 +01:00
|
|
|
print ('FTP connection established')
|
|
|
|
|
|
|
|
if '230' in ftp.login(args.user, args.password):
|
|
|
|
print ('Login successful')
|
|
|
|
|
2015-07-05 21:31:50 +01:00
|
|
|
if '250' in ftp.cwd('/flash'):
|
|
|
|
if not ftp_directory_exists(ftp, 'sys'):
|
|
|
|
print ('/flash/sys directory does not exist')
|
|
|
|
if not '550' in ftp.mkd('sys'):
|
|
|
|
print ('/flash/sys directory created')
|
2015-06-24 11:32:12 +01:00
|
|
|
else:
|
2015-07-05 21:31:50 +01:00
|
|
|
print ('Error: cannot create /flash/sys directory')
|
|
|
|
return False
|
|
|
|
if '250' in ftp.cwd('sys'):
|
|
|
|
print ("Entered '/flash/sys' directory")
|
|
|
|
with open(args.file, "rb") as fwfile:
|
|
|
|
print ('Firmware image found, initiating transfer...')
|
|
|
|
if '226' in ftp.storbinary("STOR " + 'mcuimg.bin', fwfile, 512):
|
|
|
|
print ('File transfer complete')
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
print ('Error: file transfer failed')
|
|
|
|
else:
|
|
|
|
print ('Error: cannot enter /flash/sys directory')
|
2015-06-24 11:32:12 +01:00
|
|
|
else:
|
2015-07-05 21:31:50 +01:00
|
|
|
print ('Error: cannot enter /flash directory')
|
2015-06-24 11:32:12 +01:00
|
|
|
else:
|
|
|
|
print ('Error: ftp login failed')
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def reset_board(args):
|
|
|
|
success = False
|
|
|
|
|
|
|
|
try:
|
|
|
|
tn = Telnet(args.ip, timeout=5)
|
|
|
|
print("Connected via Telnet, trying to login now")
|
|
|
|
|
|
|
|
if b'Login as:' in tn.read_until(b"Login as:", timeout=5):
|
|
|
|
tn.write(bytes(args.user, 'ascii') + b"\r\n")
|
|
|
|
|
|
|
|
if b'Password:' in tn.read_until(b"Password:", timeout=5):
|
|
|
|
# needed because of internal implementation details of the WiPy's telnet server
|
2015-06-28 12:23:55 +01:00
|
|
|
time.sleep(0.2)
|
2015-06-24 11:32:12 +01:00
|
|
|
tn.write(bytes(args.password, 'ascii') + b"\r\n")
|
|
|
|
|
2015-06-24 14:23:03 +01:00
|
|
|
if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
|
2015-06-24 11:32:12 +01:00
|
|
|
print("Telnet login succeeded")
|
2015-06-24 14:23:03 +01:00
|
|
|
tn.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
|
2015-06-24 11:32:12 +01:00
|
|
|
time.sleep(1)
|
2015-06-24 14:23:03 +01:00
|
|
|
tn.write(b'\r\x02') # ctrl-B: enter friendly REPL
|
|
|
|
if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
|
2015-09-27 12:45:48 +01:00
|
|
|
tn.write(b"import machine\r\n")
|
|
|
|
tn.write(b"machine.reset()\r\n")
|
|
|
|
time.sleep(2)
|
2015-06-24 14:23:03 +01:00
|
|
|
print("Reset performed")
|
|
|
|
success = True
|
|
|
|
else:
|
|
|
|
print("Error: cannot enter friendly REPL")
|
2015-06-24 11:32:12 +01:00
|
|
|
else:
|
|
|
|
print("Error: telnet login failed")
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print_exception(e)
|
|
|
|
finally:
|
|
|
|
try:
|
|
|
|
tn.close()
|
|
|
|
except Exception as e:
|
|
|
|
pass
|
|
|
|
return success
|
|
|
|
|
|
|
|
|
|
|
|
def verify_update(args):
|
|
|
|
success = False
|
|
|
|
firmware_tag = ''
|
|
|
|
|
|
|
|
def find_tag (tag):
|
|
|
|
if tag in firmware_tag:
|
|
|
|
print("Verification passed")
|
2015-07-05 21:31:50 +01:00
|
|
|
return True
|
2015-06-24 11:32:12 +01:00
|
|
|
else:
|
|
|
|
print("Error: verification failed, the git tag doesn't match")
|
2015-07-05 21:31:50 +01:00
|
|
|
return False
|
2015-06-24 11:32:12 +01:00
|
|
|
|
2015-09-26 23:16:20 +01:00
|
|
|
retries = 0
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
# Specify a longer time out value here because the board has just been
|
|
|
|
# reset and the wireless connection might not be fully established yet
|
|
|
|
tn = Telnet(args.ip, timeout=10)
|
|
|
|
print("Connected via telnet again, lets check the git tag")
|
|
|
|
break
|
|
|
|
except socket.timeout:
|
|
|
|
if retries < 5:
|
|
|
|
print("Timeout while connecting via telnet, retrying...")
|
|
|
|
retries += 1
|
|
|
|
else:
|
|
|
|
print('Error: Telnet connection timed out!')
|
|
|
|
return False
|
2015-06-24 11:32:12 +01:00
|
|
|
|
2015-09-26 23:16:20 +01:00
|
|
|
try:
|
2015-06-24 11:32:12 +01:00
|
|
|
firmware_tag = tn.read_until (b'with CC3200')
|
|
|
|
tag_file_path = args.file.rstrip('mcuimg.bin') + 'genhdr/mpversion.h'
|
|
|
|
|
|
|
|
if args.tag is not None:
|
2015-07-05 21:31:50 +01:00
|
|
|
success = find_tag(bytes(args.tag, 'ascii'))
|
2015-06-24 11:32:12 +01:00
|
|
|
else:
|
|
|
|
with open(tag_file_path) as tag_file:
|
|
|
|
for line in tag_file:
|
|
|
|
bline = bytes(line, 'ascii')
|
|
|
|
if b'MICROPY_GIT_HASH' in bline:
|
|
|
|
bline = bline.lstrip(b'#define MICROPY_GIT_HASH ').replace(b'"', b'').replace(b'\r', b'').replace(b'\n', b'')
|
2015-07-05 21:31:50 +01:00
|
|
|
success = find_tag(bline)
|
2015-06-24 11:32:12 +01:00
|
|
|
break
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print_exception(e)
|
|
|
|
finally:
|
|
|
|
try:
|
|
|
|
tn.close()
|
|
|
|
except Exception as e:
|
|
|
|
pass
|
|
|
|
return success
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
cmd_parser = argparse.ArgumentParser(description='Update the WiPy firmware with the specified image file')
|
|
|
|
cmd_parser.add_argument('-f', '--file', default=None, help='the path of the firmware file')
|
|
|
|
cmd_parser.add_argument('-u', '--user', default='micro', help='the username')
|
|
|
|
cmd_parser.add_argument('-p', '--password', default='python', help='the login password')
|
|
|
|
cmd_parser.add_argument('--ip', default='192.168.1.1', help='the ip address of the WiPy')
|
2015-06-28 12:23:55 +01:00
|
|
|
cmd_parser.add_argument('--verify', action='store_true', help='verify that the update succeeded')
|
2015-06-24 11:32:12 +01:00
|
|
|
cmd_parser.add_argument('-t', '--tag', default=None, help='git tag of the firmware image')
|
|
|
|
args = cmd_parser.parse_args()
|
|
|
|
|
|
|
|
result = 1
|
|
|
|
|
|
|
|
try:
|
|
|
|
if args.file is None:
|
|
|
|
raise ValueError('the image file path must be specified')
|
|
|
|
if transfer_file(args):
|
|
|
|
if reset_board(args):
|
|
|
|
if args.verify:
|
|
|
|
print ('Waiting for the WiFi connection to come up again...')
|
2015-09-26 23:16:20 +01:00
|
|
|
# this time is to allow the system's wireless network card to
|
|
|
|
# connect to the WiPy again.
|
|
|
|
time.sleep(5)
|
2015-06-24 11:32:12 +01:00
|
|
|
if verify_update(args):
|
|
|
|
result = 0
|
|
|
|
else:
|
|
|
|
result = 0
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print_exception(e)
|
|
|
|
finally:
|
|
|
|
sys.exit(result)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|