From fc11ffdad43ddb4ae4e04edf9465bd5d637eb3f0 Mon Sep 17 00:00:00 2001 From: silbo Date: Sun, 23 Aug 2020 20:27:22 +0200 Subject: [PATCH] Add FW update functionality * refactor code --- Makefile | 16 +++++++++++++--- boot.py | 34 +++++++++++++++++++++++++++++++--- hal.py | 48 ++++++++++++++++++++++++------------------------ main.py | 15 +++++++-------- 4 files changed, 75 insertions(+), 38 deletions(-) diff --git a/Makefile b/Makefile index c76f925..8a6c8ad 100755 --- a/Makefile +++ b/Makefile @@ -1,8 +1,18 @@ #!/bin/bash -#SERIAL_PORT=/dev/ttyUSB0 -SERIAL_PORT=/dev/tty.usbserial-1420 -#SERIAL_PORT=/dev/tty.SLAB_USBtoUART +SERIAL_PORT=/dev/ttyUSB0 + +ifeq (,$(wildcard $(SERIAL_PORT))) + SERIAL_PORT=/dev/tty.usbserial-1410 +endif + +ifeq (,$(wildcard $(SERIAL_PORT))) + SERIAL_PORT=/dev/tty.usbserial-1420 +endif + +ifeq (,$(wildcard $(SERIAL_PORT))) + SERIAL_PORT=/dev/tty.SLAB_USBtoUART +endif all: flash delay config update reset diff --git a/boot.py b/boot.py index b06a0c4..8c7964a 100755 --- a/boot.py +++ b/boot.py @@ -1,5 +1,33 @@ +import os +import machine from utime import sleep_ms -# Give time to cancel boot script -print("Press Ctrl-C to stop boot script...") -sleep_ms(500) +# Give time to cancel this boot script +print("Press Ctrl-C to stop new boot script...") +sleep_ms(1000) + +root_files = os.listdir() +update_files = ['boot.py.new', 'main.py.new', 'hal.py.new'] +files_to_update = [] + +# Check for FW updates and verify new FW files +for file in update_files: + if file in root_files: + print("boot.py: trying to update " + file) + # Try to load the user code + try: + with open(file, 'r') as code: + compile(code.read(), "snippet", 'exec') + files_to_update.append(file) + except: + print("boot.py: " + file + " compilation failed") + files_to_update.clear() + break + +# If valid updates replace with new FW +for file in files_to_update: + os.rename(file, file.replace('.new', '')) + +# If updates, reboot to load new FW +if len(files_to_update) != 0: + machine.reset() diff --git a/hal.py b/hal.py index bc293e3..b93839e 100755 --- a/hal.py +++ b/hal.py @@ -34,7 +34,7 @@ class Sumorobot(object): # LED sensor feedback self.sensor_feedback = True # Bottom status LED - self.status_led = Pin(self.config["status_led_pin"], Pin.OUT) + self.status_led = Pin(self.config['status_led_pin'], Pin.OUT) # Bottom status LED is in reverse polarity self.status_led.value(1) # Sensor LEDs @@ -96,7 +96,7 @@ class Sumorobot(object): # When the SumoRobot is not moving if self.prev_speed[LEFT] == 0 and self.prev_speed[RIGHT] == 0: # Calculate battery voltage - battery_voltage = round(self.config["battery_coeff"] * (self.adc_battery.read() * 3.3 / 4096), 2) + battery_voltage = round(self.config['battery_coeff'] * (self.adc_battery.read() * 3.3 / 4096), 2) # Map battery voltage to percentage temp_battery_level = 0.0 + ((100.0 - 0.0) / (4.2 - 3.2)) * (battery_voltage - 3.2) # When battery level changed more than 5 percent @@ -122,7 +122,7 @@ class Sumorobot(object): # Get the sonar value self.sonar_value = self.get_sonar_value() # When the sonar value is small and the ping actually returned - if self.sonar_value < self.config["sonar_threshold"] and self.sonar_value > 0: + if self.sonar_value < self.config['sonar_threshold'] and self.sonar_value > 0: # When not maximum score if self.sonar_score < 5: # Increase the sonar score @@ -145,15 +145,15 @@ class Sumorobot(object): # Function to update the config file def update_config_file(self): # Update the config file - with open("config.part", "w") as config_file: + with open('config.part', 'w') as config_file: config_file.write(ujson.dumps(self.config)) - os.rename("config.part", "config.json") + os.rename('config.part', 'config.json') # Function to update line calibration and write it to the config file def calibrate_line_values(self): # Read the line sensor values - self.config["left_line_value"] = self.adc_line_left.read() - self.config["right_line_value"] = self.adc_line_right.read() + self.config['left_line_value'] = self.adc_line_left.read() + self.config['right_line_value'] = self.adc_line_right.read() # Function to get light inensity from the phototransistors def get_line(self, line): @@ -173,9 +173,9 @@ class Sumorobot(object): # Define feedback LED led = LEFT_LINE if line == LEFT else RIGHT_LINE # Define config prefix - prefix = "left" if line == LEFT else "right" + prefix = 'left' if line == LEFT else 'right' # Check for line - value = abs(self.get_line(line) - self.config[prefix + "_line_value"]) > self.config[prefix + "_line_threshold"] + value = abs(self.get_line(line) - self.config[prefix + '_line_value']) > self.config[prefix + '_line_threshold'] # Show LED feedback self.set_led(led, value) # Update last line direction if line was detected @@ -201,10 +201,10 @@ class Sumorobot(object): self.pwm[servo].duty(0) else: # Define config prefix - prefix = "left" if servo == LEFT else "right" + prefix = 'left' if servo == LEFT else 'right' # -100 ... 100 to min_tuning .. max_tuning - min_tuning = self.config[prefix + "_servo_min_tuning"] - max_tuning = self.config[prefix + "_servo_max_tuning"] + min_tuning = self.config[prefix + '_servo_min_tuning'] + max_tuning = self.config[prefix + '_servo_max_tuning'] self.pwm[servo].duty(int((speed + 100) / 200 * (max_tuning - min_tuning) + min_tuning)) def move(self, dir): @@ -251,20 +251,20 @@ class Sumorobot(object): def get_sensor_scope(self): # TODO: implement sensor value caching - return str(self.get_sonar_value()) + ',' + \ - str(self.get_line(LEFT)) + ',' + \ - str(self.get_line(RIGHT)) + ',' + \ - str(self.bat_charge.value()) + ',' + \ - str(self.get_battery_level()) + return str(self.get_sonar_value()) + ',' \ + + str(self.get_line(LEFT)) + ',' \ + + str(self.get_line(RIGHT)) + ',' \ + + str(self.bat_charge.value()) + ',' \ + + str(self.get_battery_level()) def get_configuration_scope(self): - return str(self.config["sumorobot_name"]) + ',' + \ - str(self.config["firmware_version"]) + ',' + \ - str(self.config["left_line_value"]) + ',' + \ - str(self.config["right_line_value"]) + ',' + \ - str(self.config["left_line_threshold"]) + ',' + \ - str(self.config["right_line_threshold"]) + ',' + \ - str(self.config["sonar_threshold"]) + return str(self.config['sumorobot_name']) + ',' \ + + str(self.config['firmware_version']) + ',' \ + + str(self.config['left_line_value']) + ',' \ + + str(self.config['right_line_value']) + ',' \ + + str(self.config['left_line_threshold']) + ',' \ + + str(self.config['right_line_threshold']) + ',' \ + + str(self.config['sonar_threshold']) def sleep(self, delay): # Check for valid delay diff --git a/main.py b/main.py index 3cdf175..8882b27 100755 --- a/main.py +++ b/main.py @@ -1,4 +1,3 @@ -import os import ujson import struct import _thread @@ -15,7 +14,7 @@ _IRQ_CENTRAL_DISCONNECT = const(2) _IRQ_GATTS_READ_REQUEST = const(4) # Open and parse the config file -with open("config.json", "r") as config_file: +with open('config.json', 'r') as config_file: config = ujson.load(config_file) # Initialize the SumoRobot object @@ -48,7 +47,7 @@ def process(): # Try to execute the Python code try: - python_code = compile(python_code, "snippet", "exec") + python_code = compile(python_code, "snippet", 'exec') exec(python_code) except: print("main.py: the code sent had errors") @@ -108,19 +107,19 @@ def ble_handler(event, data): temp_python_code += cmd else: temp_python_code = b'' - print('main.py: unknown cmd=', cmd) + print("main.py: unknown cmd=" + cmd) conn_handle = None temp_python_code = b'' python_code = b'' # When user code (code.py) exists -if 'code.py' in os.listdir(): - print('main.py: trying to load code.py') +if 'code.py' in root_files: + print("main.py: trying to load code.py") # Try to load the user code try: - with open("code.py", "r") as code: - python_code = compile(code.read(), "snippet", "exec") + with open('code.py', 'r') as code: + python_code = compile(code.read(), "snippet", 'exec') except: print("main.py: code.py compilation failed")