class sqnsupgrade: global sysname def __init__(self): self.__sysname = sysname self.__pins = None self.__connected = False self.__sdpath = None self.__resp_921600 = False self.__serial = None self.__kill_ppp_ok = False if 'GPy' in self.__sysname: self.__pins = ('P5', 'P98', 'P7', 'P99') else: self.__pins = ('P20', 'P18', 'P19', 'P17') def special_print(self, msg, flush=None, end='\n'): if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: print(msg, end=end) else: print(msg, flush=flush, end=end) def read_rsp(self, size=None, timeout=-1): if timeout < 0: timeout = 20000 elif timeout is None: timeout = 0 if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: while not self.__serial.any() and timeout > 0: time.sleep_ms(1) timeout -= 1 else: while self.__serial.in_waiting <= 0 and timeout > 0: time.sleep(0.001) timeout -= 1 if size is not None: rsp = self.__serial.read(size) else: rsp = self.__serial.read() if rsp is not None: return rsp else: return b'' def print_pretty_response(self, rsp, flush=False): lines = rsp.decode('ascii').split('\r\n') for line in lines: if 'OK' not in line and line != '': self.special_print(line, flush=flush) def return_pretty_response(self, rsp): ret_str = '' lines = rsp.decode('ascii').split('\r\n') for line in lines: if 'OK' not in line: ret_str += line return ret_str def return_upgrade_response(self, rsp): pretty = self.return_pretty_response(rsp) if "+SMUPGRADE:" in pretty: try: return pretty.split(':')[1].strip() except: pass return None def return_code(self, rsp, debug=False): ret_str = b'' lines = rsp.decode('ascii').split('\r\n') for line in lines: if 'OK' not in line and len(line) > 0: try: if debug: print('Converting response: {} to int...'.format(line)) return int(line) except: pass raise OSError('Could not decode modem state') def wait_for_modem(self, send=True, expected=b'OK', echo_char=None): rsp = b'' start = time.time() while True: if send: self.__serial.write(b"AT\r\n") r = self.read_rsp(size=(len(expected) + 4), timeout=50) if r: rsp += r if expected in rsp: if echo_char is not None: print() break else: if echo_char is not None: self.special_print(echo_char, end='', flush=True) time.sleep(0.5) if time.time() - start >= 300: raise OSError('Timeout waiting for modem to respond!') def __check_file(self, file_path, debug=False): if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: if file_path[ 0] == '/' and not 'flash' in file_path and not file_path.split( '/')[1] in os.listdir('/'): if self.__sdpath is None: self.__sdpath = file_path.split('/')[1] try: sd = SD() time.sleep(0.5) os.mount(sd, '/{}'.format(self.__sdpath)) except Exception as ex: print('Unable to mount SD card!') return False else: print('SD card already mounted on {}!'.format( self.__sdpath)) return False try: size = os.stat(file_path)[6] if debug: print('File {} has size {}'.format(file_path, size)) return True except Exception as ex: print('Exception when checking file {}... wrong file name?'.format( file_path)) print('{}'.format(ex)) return False return False def check_files(self, ffile, mfile=None, debug=False): if mfile is not None: if self.__check_file(mfile, debug): return self.__check_file(ffile, debug) else: return False else: return self.__check_file(ffile, debug) def __check_resp(self, resp, kill_ppp=False): if resp is not None: self.__resp_921600 = b'OK' in resp or b'ERROR' in resp self.__kill_ppp_ok = self.__kill_ppp_ok or (kill_ppp and b'OK' in resp) def __hangup_modem(self, delay, debug): self.__serial.read() if not self.__kill_ppp_ok: self.__serial.write(b"+++") time.sleep_ms(1150) resp = self.__serial.read() if debug: print('Response (+++ #1): {}'.format(resp)) self.__check_resp(resp, True) self.__serial.write(b"AT\r\n") time.sleep_ms(250) resp = self.__serial.read() if debug: print('Response (AT #1) {}'.format(resp)) self.__check_resp(resp) if resp is not None: if b'OK' not in resp and not self.__kill_ppp_ok: self.__serial.write(b"AT\r\n") time.sleep_ms(250) resp = self.__serial.read() if debug: print('Response (AT #2) {}'.format(resp)) self.__check_resp(resp) if resp is not None and b'OK' in resp: return True self.__serial.write(b"+++") time.sleep_ms(1150) resp = self.__serial.read() if debug: print('Response (+++ #2): {}'.format(resp)) self.__check_resp(resp, True) if resp is not None and b'OK' in resp: self.__serial.write(b"AT\r\n") time.sleep_ms(250) resp = self.__serial.read() if debug: print('Response (AT #2) {}'.format(resp)) self.__check_resp(resp) if resp is not None and b'OK' in resp: return True return False def detect_modem_state(self, retry=3, initial_delay=1000, debug=False): count = 0 self.__serial = UART(1, baudrate=921600, pins=self.__pins, timeout_chars=1) self.__serial.read() while count < retry: count += 1 delay = initial_delay * count if debug: print("The current delay is {}".format(delay)) self.__serial = UART(1, baudrate=921600, pins=self.__pins, timeout_chars=10) #if True: if self.__hangup_modem(initial_delay, debug): self.__serial.write(b"AT+SMOD?\r\n") time.sleep_ms(delay) resp = self.__serial.read() if debug: print('Response (AT+SMOD?) {}'.format(resp)) try: return self.return_code(resp, debug) except: pass else: self.__serial = UART(1, baudrate=921600, pins=self.__pins, timeout_chars=1) self.__serial.read() self.__serial.write(b"AT\r\n") time.sleep_ms(delay) resp = self.__serial.read() self.__check_resp(resp) if debug: print('Response (AT #3) {}'.format(resp)) if resp is not None and b'OK' in resp: self.__serial.write(b"AT+SMOD?\r\n") time.sleep_ms(delay) resp = self.__serial.read() try: if debug: print('Response (AT+SMOD?) {}'.format(resp)) return self.return_code(resp, debug) except: pass self.__serial.write(b"AT\r\n") time.sleep_ms(delay) resp = self.__serial.read() self.__check_resp(resp) if debug: print('Response (AT #4) {}'.format(resp)) if resp is not None and b'OK' in resp: self.__serial.write(b"AT+SMOD?\r\n") time.sleep_ms(delay) resp = self.__serial.read() try: return self.return_code(resp, debug) if debug: print('Response (AT+SMOD?) {}'.format(resp)) except: pass else: if not self.__resp_921600: self.__serial = UART(1, baudrate=115200, pins=self.__pins, timeout_chars=10) self.__serial.write(b"AT\r\n") time.sleep_ms(delay) resp = self.__serial.read() if debug: print('Response (AT #1 @ 115200) {}'.format(resp)) if resp is not None and b'OK' in resp: self.__serial.write(b"AT+SMOD?\r\n") time.sleep_ms(delay) resp = self.__serial.read() try: if debug: print( 'Response (AT+SMOD?) {}'.format(resp)) return self.return_code(resp, debug) except: pass self.__serial.write(b"AT\r\n") time.sleep_ms(delay) resp = self.__serial.read() if debug: print('Response (AT #2 @ 115200) {}'.format(resp)) if resp is not None and b'OK' in resp: self.__serial.write(b"AT+SMOD?\r\n") time.sleep_ms(delay) resp = self.__serial.read() try: if debug: print( 'Response (AT+SMOD?) {}'.format(resp)) return self.return_code(resp, debug) except: pass return None def __get_power_warning(self): return "<<<=== DO NOT DISCONNECT POWER ===>>>" def __get_wait_msg(self, load_fff=True): if not self.__wait_msg: self.__wait_msg = True if load_fff: return "Waiting for modem to finish the update...\nThis might take several minutes!\n" + self.__get_power_warning( ) else: return "Waiting for modem to finish the update...\n" + self.__get_power_warning( ) return None def __run(self, file_path=None, baudrate=921600, port=None, resume=False, load_ffh=False, mirror=False, switch_ffh=False, bootrom=False, rgbled=0x050505, debug=False, pkgdebug=False, atneg=True, max_try=10, direct=True, atneg_only=False, version_only=False, expected_smod=None, verbose=False, load_fff=False): self.__wait_msg = False mirror = True if atneg_only else mirror recover = True if atneg_only else load_ffh resume = True if mirror or recover or atneg_only or version_only else resume verbose = True if debug else verbose load_fff = False if bootrom and switch_ffh else load_fff if debug: print( 'mirror? {} recover? {} resume? {} direct? {} atneg_only? {} bootrom? {} load_fff? {}' .format(mirror, recover, resume, direct, atneg_only, bootrom, load_fff)) abort = True external = False self.__serial = None if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: self.__serial = UART(1, baudrate=115200 if recover else baudrate, pins=self.__pins, timeout_chars=100) self.__serial.read() else: if port is None: raise ValueError('serial port not specified') if debug: print('Setting port {}'.format(port)) external = True br = 115200 if recover and not direct else baudrate if debug: print('Setting baudrate to {}'.format(br)) self.__serial = serial.Serial(port, br, bytesize=serial.EIGHTBITS, timeout=1 if version_only else 0.1) self.__serial.reset_input_buffer() self.__serial.reset_output_buffer() if version_only: self.__serial.read() self.__serial.write(b'AT\r\n') self.__serial.write(b'AT\r\n') self.__serial.read() if verbose: self.__serial.write(b"AT!=\"showver\"\r\n") else: self.__serial.write(b"ATI1\r\n") time.sleep(.5) shver = self.read_rsp(2000) if shver is not None: self.print_pretty_response(shver) return True if debug: print('Initial prepartion complete...') if not mirror: if bootrom: if debug: print('Loading built-in recovery bootrom...') try: # try compressed bootrom first from sqnsbrz import bootrom except: # fallback to uncompressed from sqnsbr import bootrom blob = bootrom() blobsize = blob.get_size() else: if debug: print('Loading {}'.format(file_path)) blobsize = os.stat(file_path)[6] if blobsize < 128: print('Firmware file is too small!') reconnect_uart() sys.exit(1) if blobsize > 4194304: if load_fff: print( "Firmware file is too big to load via FFF method. Using ON_THE_FLY" ) load_fff = False blob = open(file_path, "rb") if not load_ffh: if not self.wakeup_modem(baudrate, port, 10, 1, debug): return False if not resume: # disable echo self.__serial.write(b"ATE0\r\n") response = self.read_rsp(size=6) self.__serial.read(100) if debug: print('Entering upgrade mode...') self.__serial.write(b"AT+SMOD?\r\n") response = self.return_pretty_response(self.read_rsp(size=7)) self.__serial.read(100) if debug: print("AT+SMOD? returned {}".format(response)) self.__serial.write(b"AT+SQNSUPGRADENTF=\"started\"\r\n") self.wait_for_modem() if not load_fff: self.__serial.write(b"AT+SMSWBOOT=3,1\r\n") resp = self.read_rsp(100) if debug: print('AT+SMSWBOOT=3,1 returned: {}'.format(resp)) if b'ERROR' in resp: time.sleep(5) self.__serial.write(b"AT+SMSWBOOT=3,0\r\n") resp = self.read_rsp(100) if debug: print('AT+SMSWBOOT=3,0 returned: {}'.format(resp)) if b'OK' in resp: self.__serial.write(b"AT^RESET\r\n") resp = self.read_rsp(100) if debug: print('AT^RESET returned: {}'.format(resp)) else: print('Received ERROR from AT+SMSWBOOT=3,1! Aborting!') reconnect_uart() sys.exit(1) time.sleep(3) resp = self.__serial.read() if debug: print("Response after reset: {}".format(resp)) self.wait_for_modem() self.__serial.write(b"AT\r\n") else: self.__serial.read(100) if debug: print('Entering recovery mode') self.__serial.write(b"AT+SMOD?\r\n") response = self.return_pretty_response(self.read_rsp(size=7)) self.__serial.read(100) if debug: print("AT+SMOD? returned {}".format(response)) time.sleep(1) self.__serial.read() if (not recover) and (not direct): if mirror: time.sleep(.5) self.__serial.read(100) print( 'Going into MIRROR mode... please close this terminal to resume the upgrade via UART' ) self.uart_mirror(rgbled) elif bootrom: if verbose: print('Starting STP') else: if verbose: if load_fff: print('Starting STP [FFF]') else: print('Starting STP ON_THE_FLY') self.__serial.read(100) if verbose: print("Sending AT+CFUN=4") resonse = self.__serial.write(b'AT+CFUN=4\r\n') if verbose: print("AT+CFUN=4 returned {}".format(response)) self.__serial.read(100) if load_fff: if debug: print("Sending AT+SMSTPU") self.__serial.write(b'AT+SMSTPU\r\n') else: if debug: print("Sending AT+SMSTPU=\"ON_THE_FLY\"") self.__serial.write(b'AT+SMSTPU=\"ON_THE_FLY\"\r\n') response = self.read_rsp(size=4) if response != b'OK\r\n' and response != b'\r\nOK' and response != b'\nOK': raise OSError("Invalid answer '%s' from the device" % response) blob.close() self.__serial.read() elif recover and (not direct): if atneg: result = self.at_negotiation(baudrate, port, max_try, mirror, atneg_only, debug) if result: if atneg_only: return True if mirror: time.sleep(.5) self.__serial.read(100) print( 'Going into MIRROR mode... please close this terminal to resume the upgrade via UART' ) self.uart_mirror(rgbled) else: self.__serial.write(b"AT+STP\n") response = self.read_rsp(size=6) if not b'OK' in response: print('Failed to start STP mode!') reconnect_uart() sys.exit(1) else: print('AT auto-negotiation failed! Exiting.') return False else: if debug: print('Starting STP mode...') self.__serial.write(b"AT+STP\n") response = self.read_rsp(size=6) if not b'OK' in response: print('Failed to start STP mode!') reconnect_uart() sys.exit(1) try: if debug: if verbose: print('Starting STP code upload') if stp.start(blob, blobsize, self.__serial, baudrate, AT=False, debug=debug, pkgdebug=pkgdebug): blob.close() self.__serial.read() if switch_ffh: if verbose: print( 'Bootrom updated successfully, switching to recovery mode' ) abort = False elif load_ffh: if not self.wakeup_modem(baudrate, port, 100, 1, debug, 'Waiting for updater to load...'): return False if verbose: print( 'Upgrader loaded successfully, modem is in update mode' ) return True else: if verbose: print('Code download done, returning to user mode') abort = recover else: blob.close() print('Code download failed, aborting!') return False except: blob.close() print('Code download failed, aborting!') abort = True time.sleep(1.5) if not abort: self.__serial.read() if switch_ffh: self.__serial.write(b"AT+SMSWBOOT=0,1\r\n") resp = self.read_rsp(100) if debug: print("AT+SMSWBOOT=0,1 returned {}".format(resp)) if b"ERROR" in resp: time.sleep(5) self.__serial.write(b"AT+SMSWBOOT=0,0\r\n") resp = self.read_rsp(100) if debug: print('AT+SMSWBOOT=0,0 returned: {}'.format(resp)) if b'OK' in resp: self.__serial.write(b"AT^RESET\r\n") resp = self.read_rsp(100) if debug: print('AT^RESET returned: {}'.format(resp)) return True else: print('Received ERROR from AT+SMSWBOOT=0,0! Aborting!') return False return True else: if load_fff: self.__serial.write(b"AT+SMUPGRADE\r\n") if not self.wakeup_modem( baudrate, port, 100, 1, debug, self.__get_wait_msg(load_fff=load_fff)): print( "Timeout while waiting for modem to finish updating!") reconnect_uart() sys.exit(1) start = time.time() while True: self.__serial.read() self.__serial.write(b"AT+SMUPGRADE?\r\n") resp = self.read_rsp(1024) if debug: print("AT+SMUPGRADE? returned {} [timeout: {}]".format( resp, time.time() - start)) if resp == b'\x00' or resp == b'': time.sleep(2) if b'No report' in resp or b'on-going' in resp: time.sleep(1) if b'success' in resp or b'fail' in resp: break if time.time() - start >= 300: raise OSError('Timeout waiting for modem to respond!') self.__serial.write(b"AT+SMSWBOOT?\r\n") resp = self.read_rsp(100) if debug: print("AT+SMSWBOOT? returned {}".format(resp)) start = time.time() while (b"RECOVERY" not in resp) and (b"FFH" not in resp) and (b"FFF" not in resp): if debug: print("Timeout: {}".format(time.time() - start)) if time.time() - start >= 300: reconnect_uart() raise OSError('Timeout waiting for modem to respond!') time.sleep(2) if not self.wakeup_modem( baudrate, port, 100, 1, debug, self.__get_wait_msg(load_fff=load_fff)): reconnect_uart() raise OSError( 'Timeout while waiting for modem to finish updating!' ) self.__serial.read() self.__serial.write(b"AT+SMSWBOOT?\r\n") resp = self.read_rsp(100) if debug: print("AT+SMSWBOOT? returned {}".format(resp)) self.__serial.read() self.__serial.write(b"AT+SMUPGRADE?\r\n") resp = self.read_rsp(1024) if debug: print("AT+SMUPGRADE? returned {}".format(resp)) sqnup_result = self.return_upgrade_response(resp) if debug: print('This is my result: {}'.format(sqnup_result)) if 'success' in sqnup_result: if not load_fff: self.special_print('Resetting.', end='', flush=True) self.__serial.write(b"AT+SMSWBOOT=1,1\r\n") if debug: print("AT+SMSWBOOT=1,1 returned {}".format(resp)) if b"ERROR" in resp: time.sleep(5) self.__serial.write(b"AT+SMSWBOOT=1,0\r\n") resp = self.read_rsp(100) if debug: print('AT+SMSWBOOT=1,0 returned: {}'.format( resp)) if b'OK' in resp: self.__serial.write(b"AT^RESET\r\n") resp = self.read_rsp(100) if debug: print('AT^RESET returned: {}'.format(resp)) return True else: print( 'Received ERROR from AT+SMSWBOOT=1,0! Aborting!' ) return False self.wait_for_modem(send=False, echo_char='.', expected=b'+SYSSTART') elif sqnup_result is not None: print( 'Upgrade failed with result {}!'.format(sqnup_result)) print('Please check your firmware file(s)') else: print("Invalid response after upgrade... aborting.") reconnect_uart() sys.exit(1) self.__serial.write(b"AT\r\n") self.__serial.write(b"AT\r\n") time.sleep(0.5) if 'success' in sqnup_result: self.__serial.write(b"AT+SQNSUPGRADENTF=\"success\"\r\n") self.__serial.read() return True elif sqnup_result is None: print( 'Modem upgrade was unsucessfull. Please check your firmware file(s)' ) return False def __check_br(self, br_only=False, verbose=False, debug=False): old_br = None old_sw = None if debug: print("Checking bootrom & application") self.__serial.write(b"AT!=\"showver\"\r\n") time.sleep(.5) shver = self.read_rsp(2000) if shver is not None: for line in shver.decode('ascii').split('\n'): if debug: print('Checking line {}'.format(line)) if "Bootloader0" in line: old_br = "[33080]" in line if debug: print("old_br: {}".format(old_br)) if "Software" in line: old_sw = "[33080]" in line if debug: print("old_sw: {}".format(old_sw)) if old_br is None or old_sw is None: if debug: print("Returning: None") return None if old_br and (br_only or not old_sw): if debug: print("Returning: True") return True if debug: print("Returning: False") return False def wakeup_modem(self, baudrate, port, max_try, delay, debug, msg='Attempting AT wakeup...'): if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=1) MAX_TRY = max_try count = 0 if msg is not None: print(msg) self.__serial.read() self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) while (not b'OK' in response) and (count < MAX_TRY): count = count + 1 if debug: print('count={}'.format(count)) time.sleep(delay) self.__serial.read() self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) if 'FiPy' in sysname or 'GPy' in sysname: self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=100) return count < MAX_TRY def at_negotiation(self, baudrate, port, max_try, mirror, atneg_only, debug): MAX_TRY = max_try count = 0 print('Attempting AT auto-negotiation...') self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) while (not b'OK' in response) and (count < MAX_TRY): count = count + 1 if debug: print('count={}'.format(count)) time.sleep(1) self.__serial.read() self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) if b'OK' in response: self.__serial.read() cmd = "AT+IPR=%d\n" % baudrate if debug: print('Setting baudrate to {}'.format(baudrate)) self.__serial.write(cmd.encode()) response = self.read_rsp(size=6) if debug: print('{}'.format(response)) if b'OK' in response: if atneg_only: return True if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=100) else: self.__serial = None self.__serial = serial.Serial(port, baudrate, bytesize=serial.EIGHTBITS, timeout=0.1) self.__serial.reset_input_buffer() self.__serial.reset_output_buffer() self.__serial.flush() self.__serial.read() if debug: print('Checking SMOD') self.__serial.write(b"AT+SMOD?\r\n") response = self.read_rsp(size=1) if b'0' in response: if debug: print("AT+SMOD? returned {}".format(response)) self.__serial.read() return True else: print('ERROR in AT+SMOD returned {}'.format(response)) return False else: print('ERROR in AT+IPR={} returned {}'.format( baudrate, response)) return False else: print( 'ERROR sending AT command... no response? {}'.format(response)) return False time.sleep(1) return True def uart_mirror(self, color): import pycom pycom.heartbeat(False) time.sleep(.5) pycom.rgbled(color) LTE.modem_upgrade_mode() def success_message(self, port=None, verbose=False, debug=False): print("Your modem has been successfully updated.") print("Here is the current firmware version:\n") self.show_version(port=port, verbose=verbose, debug=debug) def upgrade(self, ffile, mfile=None, baudrate=921600, retry=False, resume=False, debug=False, pkgdebug=False, verbose=False, load_fff=True): success = True if not retry and mfile is not None: if resume or self.__check_br( br_only=True, verbose=verbose, debug=debug): success = False success = self.__run(bootrom=True, resume=resume, switch_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug, verbose=verbose) time.sleep(1) else: print('{} is not required. Resumining normal upgrade.'.format( mfile)) mfile = None success = True if debug: print('Success1? {}'.format(success)) if success: if mfile is not None: success = False success = self.__run(file_path=mfile, load_ffh=True, direct=False, baudrate=baudrate, debug=debug, pkgdebug=pkgdebug, verbose=verbose) time.sleep(1) else: success = True else: print('Unable to upgrade bootrom.') if debug: print('Success2? {}'.format(success)) if success: if self.__run(file_path=ffile, resume=True if mfile is not None else resume, baudrate=baudrate, direct=False, debug=debug, pkgdebug=pkgdebug, verbose=verbose, load_fff=False if mfile else load_fff): if self.__check_br(verbose=verbose, debug=debug): self.__run(bootrom=True, debug=debug, direct=False, pkgdebug=pkgdebug, verbose=verbose, load_fff=True) self.success_message(verbose=verbose, debug=debug) else: print('Unable to load updater from {}'.format(mfile)) def upgrade_uart(self, ffh_mode=False, mfile=None, retry=False, resume=False, color=0x050505, debug=False, pkgdebug=False, verbose=False, load_fff=True): success = False try: success = hasattr(LTE, 'modem_upgrade_mode') except: success = False if not success: print('Firmware does not support LTE.modem_upgrade_mode()!') reconnect_uart() sys.exit(1) print('Preparing modem for upgrade...') if not retry and ffh_mode: success = False success = self.__run(bootrom=True, resume=resume, switch_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug, verbose=verbose) time.sleep(1) if success: if mfile is not None: success = False success = self.__run(file_path=mfile, load_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug, verbose=verbose) if debug: print('Success2? {}'.format(success)) if success: self.__run(mirror=True, load_ffh=False, direct=False, rgbled=color, debug=debug, verbose=verbose) else: print('Unable to load updater from {}'.format(mfile)) else: self.__run(mirror=True, load_ffh=ffh_mode, direct=False, rgbled=color, debug=debug, verbose=verbose) else: print('Unable to upgrade bootrom.') def show_version(self, port=None, debug=False, verbose=False): self.__run(port=port, debug=debug, version_only=True, verbose=verbose) def upgrade_ext(self, port, ffile, mfile, resume=False, debug=False, pkgdebug=False, verbose=False, load_fff=True): success = True if mfile is not None: success = False success = self.__run(file_path=mfile, load_ffh=True, port=port, debug=debug, pkgdebug=pkgdebug, verbose=verbose) if success: if self.__run(file_path=ffile, resume=True if mfile is not None else resume, direct=False, port=port, debug=debug, pkgdebug=pkgdebug, verbose=verbose, load_fff=load_fff): self.success_message(port=port, verbose=verbose, debug=debug) else: print('Unable to load updater from {}'.format(mfile))
class sqnsupgrade: global sysname def __init__(self): self.__sysname = sysname self.__pins = None self.__connected = False self.__sdpath = None def special_print(self, msg, flush=None, end='\n'): if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: print(msg, end=end) else: print(msg, flush=flush, end=end) def read_rsp(self, size=None, timeout=-1): if timeout < 0: timeout = 20000 elif timeout is None: timeout = 0 if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: while not self.__serial.any() and timeout > 0: time.sleep_ms(1) timeout -= 1 else: while self.__serial.in_waiting <= 0 and timeout > 0: time.sleep(0.001) timeout -= 1 if size is not None: rsp = self.__serial.read(size) else: rsp = self.__serial.read() if rsp is not None: return rsp else: return b'' def print_pretty_response(self, rsp, flush=False): lines = rsp.decode('ascii').split('\r\n') for line in lines: if 'OK' not in line: self.special_print(line, flush=flush) def return_pretty_response(self, rsp): ret_str = '' lines = rsp.decode('ascii').split('\r\n') for line in lines: if 'OK' not in line: ret_str += line return ret_str def return_code(self, rsp): ret_str = b'' lines = rsp.decode('ascii').split('\r\n') for line in lines: if 'OK' not in line: ret_str += line try: return int(ret_str) except: return -1 def wait_for_modem(self, send=True, expected=b'OK'): rsp = b'' while True: if send: self.__serial.write(b"AT\r\n") r = self.read_rsp(size=(len(expected) + 4), timeout=50) if r: rsp += r if expected in rsp: print() break else: self.special_print('.', end='', flush=True) time.sleep(0.5) def __check_file(self, file_path, debug=False): if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: if file_path[ 0] == '/' and not 'flash' in file_path and not file_path.split( '/')[1] in os.listdir('/'): if self.__sdpath is None: self.__sdpath = file_path.split('/')[1] sd = SD() time.sleep(0.5) os.mount(sd, '/{}'.format(self.__sdpath)) else: print('SD card already mounted on {}!'.format( self.__sdpath)) return False try: size = os.stat(file_path)[6] if debug: print('File {} has size {}'.format(file_path, size)) return True except Exception as ex: print('Exception when checking file... wrong file name?') print('{}'.format(ex)) return False return False def check_files(self, ffile, mfile=None, debug=False): if mfile is not None: if self.__check_file(mfile, debug): return self.__check_file(ffile, debug) else: return False else: return self.__check_file(ffile, debug) def detect_modem_state(self, retry=10, initial_delay=5): if 'FiPy' or 'GPy' in self.__sysname: if 'GPy' in self.__sysname: pins = ('P5', 'P98', 'P7', 'P99') else: pins = ('P20', 'P18', 'P19', 'P17') count = 0 while count < retry: count += 1 delay = initial_delay * count s = UART(1, baudrate=921600, pins=pins, timeout_chars=10) s.read() s.write(b"AT\r\n") time.sleep_ms(delay) resp = s.read() s.write(b"AT\r\n") time.sleep_ms(delay) resp = s.read() if resp is not None and b'OK' in resp: s.write(b"AT+SMOD?\r\n") time.sleep_ms(delay) resp = s.read() try: return self.return_code(resp) except: continue else: s = UART(1, baudrate=115200, pins=pins, timeout_chars=10) s.write(b"AT\r\n") time.sleep_ms(delay) resp = s.read() s.write(b"AT\r\n") time.sleep_ms(delay) resp = s.read() if resp is not None and b'OK' in resp: s.write(b"AT+SMOD?\r\n") time.sleep_ms(delay) resp = s.read() try: return self.return_code(resp) except: continue def __run(self, file_path=None, baudrate=921600, port=None, resume=False, load_ffh=False, mirror=False, switch_ffh=False, bootrom=False, rgbled=0x050505, debug=False, pkgdebug=False, atneg=True, max_try=10, direct=True, atneg_only=False, version_only=False): mirror = True if atneg_only else mirror recover = True if atneg_only else load_ffh resume = True if mirror or recover or atneg_only or version_only else resume if debug: print( 'mirror? {} recover? {} resume? {} direct? {} atneg_only? {} bootrom? {} ' .format(mirror, recover, resume, direct, atneg_only, bootrom)) abort = True external = False self.__serial = None if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: if 'GPy' in self.__sysname: self.__pins = ('P5', 'P98', 'P7', 'P99') else: self.__pins = ('P20', 'P18', 'P19', 'P17') self.__serial = UART(1, baudrate=115200 if recover else baudrate, pins=self.__pins, timeout_chars=100) self.__serial.read() else: if port is None: raise ValueError('serial port not specified') if debug: print('Setting port {}'.format(port)) external = True br = 115200 if recover and not direct else baudrate if debug: print('Setting baudrate to {}'.format(br)) self.__serial = serial.Serial(port, br, bytesize=serial.EIGHTBITS, timeout=1 if version_only else 0.1) self.__serial.reset_input_buffer() self.__serial.reset_output_buffer() if debug: print('Initial prepartion complete...') if version_only: self.__serial.read() self.__serial.write(b"AT!=\"showver\"\r\n") time.sleep(.5) shver = self.read_rsp(2000) if shver is not None: self.print_pretty_response(shver) return True if not mirror: if bootrom: if debug: print('Loading built-in recovery bootrom') from sqnsbr import bootrom blob = bootrom() blobsize = blob.get_size() else: if debug: print('Loading {}'.format(file_path)) blobsize = os.stat(file_path)[6] blob = open(file_path, "rb") if not load_ffh: if not self.wakeup_modem(baudrate, port, 10, 1, debug): return False if not resume: # disable echo self.__serial.write(b"ATE0\r\n") response = self.read_rsp(size=6) self.__serial.read(100) if debug: print('Entering recovery mode') self.__serial.write(b"AT+SMOD?\r\n") response = self.return_pretty_response(self.read_rsp(size=7)) self.__serial.read(100) if debug: print("AT+SMOD? returned {}".format(response)) if not bootrom: self.__serial.write(b"AT+SMSWBOOT=3,1\r\n") time.sleep(2) self.wait_for_modem() self.__serial.write(b"AT\r\n") self.__serial.write(b"AT\r\n") else: self.__serial.read(100) if debug: print('Entering recovery mode') self.__serial.write(b"AT+SMOD?\r\n") response = self.return_pretty_response(self.read_rsp(size=7)) self.__serial.read(100) if debug: print("AT+SMOD? returned {}".format(response)) time.sleep(1) self.__serial.read() if (not recover) and (not direct): if mirror: time.sleep(.5) self.__serial.read(100) print( 'Going into MIRROR mode... please close this terminal to resume the upgrade via UART' ) self.uart_mirror(rgbled) elif bootrom: print('Starting STP (DO NOT DISCONNECT POWER!!!)') else: print('Starting STP ON_THE_FLY') self.__serial.read(100) self.__serial.write(b'AT+SMSTPU=\"ON_THE_FLY\"\r\n') response = self.read_rsp(size=4) if response != b'OK\r\n' and response != b'\r\nOK' and response != b'\nOK': raise OSError("Invalid answer '%s' from the device" % response) blob.close() self.__serial.read() elif recover and (not direct): if atneg: result = self.at_negotiation(baudrate, port, max_try, mirror, atneg_only, debug) if result: if atneg_only: return True if mirror: time.sleep(.5) self.__serial.read(100) print( 'Going into MIRROR mode... please close this terminal to resume the upgrade via UART' ) self.uart_mirror(rgbled) else: self.__serial.write(b"AT+STP\n") response = self.read_rsp(size=6) if not b'OK' in response: print('Failed to start STP mode!') sys.exit(1) else: print('AT auto-negotiation failed! Exiting.') return False else: if debug: print('Starting STP mode...') self.__serial.write(b"AT+STP\n") response = self.read_rsp(size=6) if not b'OK' in response: print('Failed to start STP mode!') sys.exit(1) try: if debug: print('Starting STP code upload') if stp.start(blob, blobsize, self.__serial, baudrate, AT=False, debug=debug, pkgdebug=pkgdebug): blob.close() if switch_ffh: print( 'Bootrom updated successfully, switching to upgrade mode' ) abort = False elif load_ffh: if not self.wakeup_modem(baudrate, port, 100, 1, debug): return False print( 'Upgrader loaded successfully, modem is in upgrade mode' ) return True else: print('Code download done, returning to user mode') abort = recover else: blob.close() print('Code download failed, aborting!') return False except: blob.close() print('Code download failed, aborting!') abort = True time.sleep(1.5) if not abort: self.__serial.read() if switch_ffh: self.__serial.write(b"AT+SMSWBOOT=0,1\r\n") return True else: self.special_print('Resetting (DO NOT DISCONNECT POWER!!!).', end='', flush=True) self.__serial.write(b"AT+SMSWBOOT=1,1\r\n") self.wait_for_modem(send=False, expected=b'+SYSSTART') self.__serial.write(b"AT\r\n") self.__serial.write(b"AT\r\n") time.sleep(0.5) self.__serial.read() print('Upgrade completed!') print("Here's the current firmware version:") time.sleep(0.5) self.__serial.read() self.__serial.write(b"AT!=\"showver\"\r\n") time.sleep(.5) shver = self.read_rsp(2000) if shver is not None: self.print_pretty_response(shver) return True return False def wakeup_modem(self, baudrate, port, max_try, delay, debug): if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=1) MAX_TRY = max_try count = 0 print('Attempting AT wakeup...') self.__serial.read() self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) while (not b'OK' in response) and (count < MAX_TRY): count = count + 1 if debug: print('count={}'.format(count)) time.sleep(delay) self.__serial.read() self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) if 'FiPy' in sysname or 'GPy' in sysname: self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=100) return count < MAX_TRY def at_negotiation(self, baudrate, port, max_try, mirror, atneg_only, debug): MAX_TRY = max_try count = 0 print('Attempting AT auto-negotiation...') self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) while (not b'OK' in response) and (count < MAX_TRY): count = count + 1 if debug: print('count={}'.format(count)) time.sleep(1) self.__serial.read() self.__serial.write(b"AT\r\n") response = self.read_rsp(size=6) if debug: print('{}'.format(response)) if b'OK' in response: self.__serial.read() cmd = "AT+IPR=%d\n" % baudrate if debug: print('Setting baudrate to {}'.format(baudrate)) self.__serial.write(cmd.encode()) response = self.read_rsp(size=6) if debug: print('{}'.format(response)) if b'OK' in response: if atneg_only: return True if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=100) else: self.__serial = None self.__serial = serial.Serial(port, baudrate, bytesize=serial.EIGHTBITS, timeout=0.1) self.__serial.reset_input_buffer() self.__serial.reset_output_buffer() self.__serial.flush() self.__serial.read() if debug: print('Checking SMOD') self.__serial.write(b"AT+SMOD?\r\n") response = self.read_rsp(size=1) if b'0' in response: if debug: print("AT+SMOD? returned {}".format(response)) self.__serial.read() return True else: print('ERROR in AT+SMOD returned {}'.format(response)) return False else: print('ERROR in AT+IPR={} returned {}'.format( baudrate, response)) return False else: print( 'ERROR sending AT command... no response? {}'.format(response)) return False time.sleep(1) return True def uart_mirror(self, color): import pycom pycom.heartbeat(False) time.sleep(.5) pycom.rgbled(color) from network import LTE LTE.modem_upgrade_mode() def upgrade_sd(self, ffile, mfile=None, baudrate=921600, retry=False, resume=False, debug=False, pkgdebug=False): print('<<< Welcome to the SQN3330 firmware updater >>>') success = True if not retry and mfile is not None: success = False success = self.__run(bootrom=True, resume=resume, switch_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug) time.sleep(1) if debug: print('Success1? {}'.format(success)) if success: if mfile is not None: success = False success = self.__run(file_path=mfile, load_ffh=True, direct=False, baudrate=baudrate, debug=debug, pkgdebug=pkgdebug) time.sleep(1) else: success = True else: print('Unable to upgrade bootrom.') if debug: print('Success2? {}'.format(success)) if success: self.__run(file_path=ffile, resume=True if mfile is not None else resume, baudrate=baudrate, direct=False, debug=debug, pkgdebug=pkgdebug) else: print('Unable to load updater from {}'.format(mfile)) def upgrade_uart(self, ffh_mode=False, mfile=None, retry=False, resume=False, color=0x050505, debug=False, pkgdebug=False): success = True print('Preparing modem for upgrade...') if not retry and ffh_mode: success = False success = self.__run(bootrom=True, resume=resume, switch_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug) time.sleep(1) if success: if mfile is not None: success = False success = self.__run(file_path=mfile, load_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug) if debug: print('Success2? {}'.format(success)) if success: self.__run(mirror=True, load_ffh=False, direct=False, rgbled=color, debug=debug) else: print('Unable to load updater from {}'.format(mfile)) else: self.__run(mirror=True, load_ffh=ffh_mode, direct=False, rgbled=color, debug=debug) else: print('Unable to upgrade bootrom.') def show_version(self, port=None, debug=False): self.__run(port=port, debug=debug, version_only=True) def upgrade_ext(self, port, ffile, mfile, resume=False, debug=False, pkgdebug=False): success = True print('<<< Welcome to the SQN3330 firmware updater >>>') if mfile is not None: success = False success = self.__run(file_path=mfile, load_ffh=True, port=port, debug=debug, pkgdebug=pkgdebug) if success: self.__run(file_path=ffile, resume=True if mfile is not None else resume, direct=False, port=port, debug=debug, pkgdebug=pkgdebug) else: print('Unable to load updater from {}'.format(mfile))
def run(file_path, baudrate, port=None, resume=False): global sysname abort = True s = None print('<<< Welcome to the SQN3330 firmware updater >>>') if 'FiPy' in sysname or 'GPy' in sysname: if '/sd' in file_path and not 'sd' in os.listdir('/'): sd = SD() time.sleep(0.5) os.mount(sd, '/sd') time.sleep(0.5) if 'GPy' in sysname: pins = ('P5', 'P98', 'P7', 'P99') else: pins = ('P20', 'P18', 'P19', 'P17') s = UART(1, baudrate=baudrate, pins=pins, timeout_chars=100) s.read() else: if port is None: raise ValueError('serial port not specified') s = serial.Serial(port, baudrate=921600, bytesize=serial.EIGHTBITS, timeout=0.1) s.reset_input_buffer() s.reset_output_buffer() blobsize = os.stat(file_path)[6] blob = open(file_path, "rb") if not resume: # disable echo s.write(b"ATE0\r\n") response = read_rsp(s, size=6) s.read(100) print('Entering recovery mode') s.write(b"AT+SMSWBOOT=3,0\r\n") response = read_rsp(s, size=6) if b'OK' in response: print('Resetting.', end='', flush=True) s.write(b'AT^RESET\r\n') wait_for_modem(s, send=False, expected=b'+SHUTDOWN') time.sleep(2) wait_for_modem(s) s.write(b"AT\r\n") s.write(b"AT\r\n") else: raise OSError('AT+SMSWBOOT=3,0 failed!') time.sleep(1) s.read() print('Starting STP (DO NOT DISCONNECT POWER!!!)') s.read(100) s.write(b'AT+SMSTPU=\"ON_THE_FLY\"\r\n') response = read_rsp(s, size=4) if response != b'OK\r\n' and response != b'\r\nOK' and response != b'\nOK': raise OSError("Invalid answer '%s' from the device" % response) blob.close() s.read() try: stp.start(blob, blobsize, s, baudrate, AT=False) print('Code download done, returning to user mode') abort = False except: blob.close() print('Code download failed, aborting!') abort = True time.sleep(1.5) s.read() s.write(b"AT+SMSWBOOT=1,0\r\n") response = read_rsp(s, size=6) print('Resetting (DO NOT DISCONNECT POWER!!!).', end='', flush=True) time.sleep(1.5) s.write(b"AT^RESET\r\n") wait_for_modem(s, send=False, expected=b'+SHUTDOWN') time.sleep(2) wait_for_modem(s, send=False, expected=b'+SYSSTART') if not abort: time.sleep(0.5) print('Deploying the upgrade (DO NOT DISCONNECT POWER!!!)...') s.write(b"AT+SMUPGRADE\r\n") response = read_rsp(s, size=6, timeout=120000) print('Resetting (DO NOT DISCONNECT POWER!!!).', end='', flush=True) time.sleep(1.5) s.write(b"AT^RESET\r\n") wait_for_modem(s, send=False, expected=b'+SHUTDOWN') time.sleep(2) wait_for_modem(s, send=False, expected=b'+SYSSTART') s.write(b"AT\r\n") s.write(b"AT\r\n") time.sleep(0.5) s.read() print('Upgrade completed!') print("Here's the current firmware version:") time.sleep(0.5) s.read() s.write(b"ATI1\r\n") response = read_rsp(s, size=100) print_pretty_response(response)