From 0e368ce22c6b1c9107f18a82f3cfcb6fec9464f8 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 12 Apr 2019 15:37:36 +0100 Subject: [PATCH 1/6] Initial version with support for LPC1768 Added a method to upload firmware file to the onboard SD card as firmware.bin. --- octoprint_firmwareupdater/__init__.py | 105 +++++++++++++++++- .../static/js/firmwareupdater.js | 73 +++++++++++- .../templates/firmwareupdater_settings.jinja2 | 21 +++- 3 files changed, 191 insertions(+), 8 deletions(-) diff --git a/octoprint_firmwareupdater/__init__.py b/octoprint_firmwareupdater/__init__.py index a262214..959d089 100644 --- a/octoprint_firmwareupdater/__init__.py +++ b/octoprint_firmwareupdater/__init__.py @@ -11,6 +11,7 @@ import time import re import serial +import shutil from serial import SerialException import octoprint.plugin @@ -49,8 +50,8 @@ def __init__(self): def initialize(self): # TODO: make method configurable via new plugin hook "octoprint.plugin.firmwareupdater.flash_methods", # also include prechecks - self._flash_prechecks = dict(avrdude=self._check_avrdude, bossac=self._check_bossac) - self._flash_methods = dict(avrdude=self._flash_avrdude, bossac=self._flash_bossac) + self._flash_prechecks = dict(avrdude=self._check_avrdude, bossac=self._check_bossac, lpc1768=self._check_lpc1768) + self._flash_methods = dict(avrdude=self._flash_avrdude, bossac=self._flash_bossac, lpc1768=self._flash_lpc1768) console_logging_handler = logging.handlers.RotatingFileHandler(self._settings.get_plugin_logfile_path(postfix="console"), maxBytes=2*1024*1024) console_logging_handler.setFormatter(logging.Formatter("%(asctime)s %(message)s")) @@ -476,6 +477,57 @@ def _check_bossac(self): else: return True + def _flash_lpc1768(self, firmware=None, printer_port=None): + assert(firmware is not None) + assert(printer_port is not None) + + lpc1768_path = self._settings.get(["lpc1768_path"]) + working_dir = os.path.dirname(lpc1768_path) + + if not self._unmount_sd(printer_port): + self._logger.error(u"SD unmount failed") + return False + + target_path = lpc1768_path + '/firmware.bin' + self._logger.info(u"Copying firmware to update folder '{}' -> '{}'".format(firmware, target_path)) + + try: + shutil.copyfile(firmware, target_path) + except: + self._logger.exception(u"Flashing failed. Unable to copy file.") + self._send_status("flasherror") + return False + + self._send_status("progress", subtype="boardreset") + self._logger.info(u"Attempting to reset the board") + if not self._reset_lpc1768(printer_port): + self._logger.error(u"Reset failed") + return False + + return True + + def _check_lpc1768(self): + lpc1768_path = self._settings.get(["lpc1768_path"]) + pattern = re.compile("^(\/[^\0/]+)+$") + + if not pattern.match(lpc1768_path): + self._logger.error(u"Firmware folder path is not valid: {path}".format(path=lpc1768_path)) + return False + elif lpc1768_path is None: + self._logger.error(u"Firmware folder path is not set.") + return False + if not os.path.exists(lpc1768_path): + self._logger.error(u"Firmware folder path does not exist: {path}".format(path=lpc1768_path)) + return False + elif not os.path.isdir(lpc1768_path): + self._logger.error(u"Firmware folder path is not a folder: {path}".format(path=lpc1768_path)) + return False + elif not os.access(lpc1768_path, os.W_OK): + self._logger.error(u"Firmware folder path is not writeable: {path}".format(path=lpc1768_path)) + return False + else: + return True + def _reset_1200(self, printer_port=None): assert(printer_port is not None) self._logger.info(u"Toggling '{port}' at 1200bps".format(port=printer_port)) @@ -496,6 +548,54 @@ def _reset_1200(self, printer_port=None): return True + def _reset_lpc1768(self, printer_port=None): + assert(printer_port is not None) + self._logger.info(u"Resetting LPC1768 at '{port}'".format(port=printer_port)) + try: + ser = serial.Serial(port=printer_port, \ + baudrate=9600, \ + parity=serial.PARITY_NONE, \ + stopbits=serial.STOPBITS_ONE , \ + bytesize=serial.EIGHTBITS, \ + timeout=2000) + + # Marlin reset command + ser.write("M997\r") + # Smoothie reset command + ser.write("reset\r") + + ser.close() + time.sleep(10) + + except SerialException as ex: + self._logger.exception(u"Board reset failed: {error}".format(error=str(ex))) + self._send_status("flasherror", message="Board reset failed") + return False + + return True + + def _unmount_sd(self, printer_port=None): + assert(printer_port is not None) + self._logger.info(u"Release the SD Card by sending 'M22' to '{port}'".format(port=printer_port)) + try: + ser = serial.Serial(port=printer_port, \ + baudrate=9600, \ + parity=serial.PARITY_NONE, \ + stopbits=serial.STOPBITS_ONE , \ + bytesize=serial.EIGHTBITS, \ + timeout=2000) + + ser.write("M22\r") + time.sleep(1) + ser.close() + + except SerialException as ex: + self._logger.exception(u"Card unmount failed: {error}".format(error=str(ex))) + self._send_status("flasherror", message="Card unmount failed") + return False + + return True + #~~ SettingsPlugin API def get_settings_defaults(self): @@ -511,6 +611,7 @@ def get_settings_defaults(self): "bossac_path": None, "bossac_commandline": "{bossac} -i -p {port} -U true -e -w {disableverify} -b {firmware} -R", "bossac_disableverify": None, + "lpc1768_path": None, "postflash_delay": "0", "postflash_gcode": None, "run_postflash_gcode": False, diff --git a/octoprint_firmwareupdater/static/js/firmwareupdater.js b/octoprint_firmwareupdater/static/js/firmwareupdater.js index 2eea835..d8b06ef 100644 --- a/octoprint_firmwareupdater/static/js/firmwareupdater.js +++ b/octoprint_firmwareupdater/static/js/firmwareupdater.js @@ -12,6 +12,7 @@ $(function() { self.showAdvancedConfig = ko.observable(false); self.showAvrdudeConfig = ko.observable(false); self.showBossacConfig = ko.observable(false); + self.showLpc1768Config = ko.observable(false); self.showPostflashConfig = ko.observable(false); self.configEnablePostflashDelay = ko.observable(); self.configPostflashDelay = ko.observable(); @@ -53,6 +54,16 @@ $(function() { return self.bossacPathBroken() || self.bossacPathOk(); }); + // Config settings for lpc1768 + self.configLpc1768Path = ko.observable(); + + self.lpc1768PathBroken = ko.observable(false); + self.lpc1768PathOk = ko.observable(false); + self.lpc1768PathText = ko.observable(); + self.lpc1768PathHelpVisible = ko.computed(function() { + return self.lpc1768PathBroken() || self.lpc1768PathOk(); + }); + self.flashPort = ko.observable(undefined); self.firmwareFileName = ko.observable(undefined); @@ -87,14 +98,21 @@ $(function() { self.configFlashMethod.subscribe(function(value) { if(value == 'avrdude') { - self.showBossacConfig(false); self.showAvrdudeConfig(true); + self.showBossacConfig(false); + self.showLpc1768Config(false); } else if(value == 'bossac') { + self.showAvrdudeConfig(false); self.showBossacConfig(true); + self.showLpc1768Config(false); + } else if(value == 'lpc1768'){ self.showAvrdudeConfig(false); - } else { self.showBossacConfig(false); + self.showLpc1768Config(true); + } else { self.showAvrdudeConfig(false); + self.showBossacConfig(false); + self.showLpc1768Config(false); } }); @@ -156,6 +174,10 @@ $(function() { alert = gettext("The bossac path is not configured."); } + if (self.settingsViewModel.settings.plugins.firmwareupdater.flash_method() == "lpc1768" && !self.settingsViewModel.settings.plugins.firmwareupdater.lpc1768_path()) { + alert = gettext("The lpc1768 firmware folder path is not configured."); + } + if (!self.flashPort()) { alert = gettext("The printer port is not selected."); } @@ -313,6 +335,10 @@ $(function() { case "postflashdelay": { message = gettext("Post-flash delay..."); break; + } + case "boardreset": { + message = gettext("Resetting the board..."); + break; } case "reconnecting": { message = gettext("Reconnecting to printer..."); @@ -338,15 +364,18 @@ $(function() { self.showPluginConfig = function() { // Load the general settings + self.configFlashMethod(self.settingsViewModel.settings.plugins.firmwareupdater.flash_method()); self.configPostflashDelay(self.settingsViewModel.settings.plugins.firmwareupdater.postflash_delay()); + self.configPostflashGcode(self.settingsViewModel.settings.plugins.firmwareupdater.postflash_gcode()); + if(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_delay() != 'false') { self.configEnablePostflashDelay(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_delay()); } - self.configFlashMethod(self.settingsViewModel.settings.plugins.firmwareupdater.flash_method()); + if(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_gcode() != 'false') { self.configEnablePostflashGcode(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_gcode()); } - self.configPostflashGcode(self.settingsViewModel.settings.plugins.firmwareupdater.postflash_gcode()); + if(self.settingsViewModel.settings.plugins.firmwareupdater.disable_bootloadercheck() != 'false') { self.configDisableBootloaderCheck(self.settingsViewModel.settings.plugins.firmwareupdater.disable_bootloadercheck()); } @@ -366,6 +395,10 @@ $(function() { self.configBossacPath(self.settingsViewModel.settings.plugins.firmwareupdater.bossac_path()); self.configBossacDisableVerification(self.settingsViewModel.settings.plugins.firmwareupdater.bossac_disableverify()); self.configBossacCommandLine(self.settingsViewModel.settings.plugins.firmwareupdater.bossac_commandline()); + + // Load the lpc1768 settings + self.configLpc1768Path(self.settingsViewModel.settings.plugins.firmwareupdater.lpc1768_path()); + self.configurationDialog.modal(); }; @@ -392,6 +425,7 @@ $(function() { bossac_path: self.configBossacPath(), bossac_disableverify: self.configBossacDisableVerification(), bossac_commandline: self.configBossacCommandLine(), + lpc1768_path: self.configLpc1768Path(), postflash_delay: self.configPostflashDelay(), postflash_gcode: self.configPostflashGcode(), enable_postflash_delay: self.configEnablePostflashDelay(), @@ -526,6 +560,37 @@ $(function() { }) }; + self.testLpc1768Path = function() { + $.ajax({ + url: API_BASEURL + "util/test", + type: "POST", + dataType: "json", + data: JSON.stringify({ + command: "path", + path: self.configLpc1768Path(), + check_type: "path", + check_access: ["r", "w"], + check_writable_dir: "true" + }), + contentType: "application/json; charset=UTF-8", + success: function(response) { + if (!response.result) { + if (!response.exists) { + self.lpc1768PathText(gettext("The path doesn't exist")); + } else if (!response.typeok) { + self.lpc1768PathText(gettext("The path is not a folder")); + } else if (!response.access) { + self.lpc1768PathText(gettext("The path is not writeable")); + } + } else { + self.lpc1768PathText(gettext("The path is valid")); + } + self.lpc1768PathOk(response.result); + self.lpc1768PathBroken(!response.result); + } + }) + }; + self.onSettingsShown = function() { self.inSettingsDialog = true; }; diff --git a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 index 4f9e0cb..34b1d8b 100644 --- a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 +++ b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 @@ -88,6 +88,7 @@ + @@ -150,9 +151,25 @@ + +
+
+ +
+
+ + +
+ +
+
+
+
+ + -
+
@@ -248,7 +265,7 @@
-
+
From 78dc25712eb4aeeb832525ed9fe6b96929ebffb3 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 12 Apr 2019 15:58:20 +0100 Subject: [PATCH 2/6] Update documentation Added lpc1768 instructions --- README.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 89f0081..39a03aa 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ This plugin can be used to flash pre-compiled firmware images to your printer fr

Firmware Updater

-Works with boards with Atmel AVR family 8-bit MCUs (Atmega1280, Atmega1284p, and Atmega2560) MCUs, and Atmel SAM family 32-bit MCUs (Arduino DUE). +## Works with +* Atmel AVR family 8-bit MCUs (Atmega644, Atmega1280, Atmega1284p, and Atmega2560, etc.) +* Atmel SAM family 32-bit MCUs (Arduino DUE, etc.) +* LPC1768 boards (MKS SBASE, SKR v1.1 and v1.3, etc.) ## Setup @@ -51,6 +54,53 @@ cd BOSSA-1.7.0 sudo cp ~/BOSSA-1.7.0/bin/bossac /usr/local/bin/ ``` +### LPC 1768 Installation +Flashing an LPC1768 board requires that the host can mount the board's on-board SD card to a known mount point in the host filesystem. + +There are several ways to do this, but using [usbmount](https://github.com/rbrito/usbmount) works well and is documented here. It will mount the SD card to `/media/usb`. + +**Note:** The Marlin board configuration must have `USB_SD_ONBOARD` enabled so that the on-board SD card is presented to the host via the USB connection. This seems to be the default configuration for Marlin's LPC1768 boards. It is configured in the board's pins file. + +Once installed, usbmount requires some tweaking to make it work well on the Raspberry Pi. The instructions below assume that you are running OctoPrint on a Raspberry Pi, as the user 'pi'. + +1. Install usbmount + + `sudo apt-get install usbmount` + +2. Configure usbmount so that the mount has the correct permissions for the 'pi' user + + `sudo nano /etc/usbmount/usbmount.conf` + + Find FS_MOUNTOPTIONS and change it to: + + `FS_MOUNTOPTIONS="-fstype=vfat,gid=pi,uid=pi,dmask=0022,fmask=0111` + +3. Configure systemd-udevd so that the mount is accessible + + `sudo systemctl edit systemd-udevd` + + Insert these lines then save and close the file: + ``` + [Service] + MountFlags=shared + ``` + + Then run: + ``` + sudo systemctl daemon-reload + sudo service systemd-udevd --full-restart + ``` + +Once usbmount is installed and configured the LPC1768 on-board SD card should be mounted at `/media/usb` the next time it is plugged in or restarted. + +#### Troubleshooting LPC1768 Uploads +The firmware upload will fail if the SD card is not accessible, either because it is not mounted on the host, or because the printer firmware has control over it. + +Try: +* Reset the board +* Check that the 'Path to firmware folder' 'Test' button gives a successful result +* Use the OctoPrint terminal to send an `M22` command to release the SD card from the firmware + ## Configuration In order to be able to flash firmware we need to select and configure a flash method. Once the flash method is selected additional options will be available. @@ -75,6 +125,9 @@ Typical MCU/programmer combinations are:

Firmware Updater Settings

The only required setting is the path to the bossac binary. +### LPC1768 Configuration +The only required setting is the path to the firmware update folder. If using usbmount it will probably be `/media/usb`. + ### Customizing the Command Lines The command lines for avrdude and bossac can be customized by editing the string in the advanced settings for the flash method. Text in braces (`{}`) will be substituted for preconfigured values if present. From 1067e3d07f2ae19ad194054ca84fc0dbea5222a2 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Wed, 24 Apr 2019 16:05:35 +0100 Subject: [PATCH 3/6] Improve LPC1768 process Reboot board before starting Better reset handling Check for writable mount point Better messages --- octoprint_firmwareupdater/__init__.py | 119 ++++++++++++++++-- .../static/js/firmwareupdater.js | 6 +- 2 files changed, 116 insertions(+), 9 deletions(-) diff --git a/octoprint_firmwareupdater/__init__.py b/octoprint_firmwareupdater/__init__.py index 959d089..27e5770 100644 --- a/octoprint_firmwareupdater/__init__.py +++ b/octoprint_firmwareupdater/__init__.py @@ -484,13 +484,44 @@ def _flash_lpc1768(self, firmware=None, printer_port=None): lpc1768_path = self._settings.get(["lpc1768_path"]) working_dir = os.path.dirname(lpc1768_path) + # reset the board before we try to flash it - should ensure that it's mounted by usbmount + self._send_status("progress", subtype="boardreset") + self._logger.info(u"Pre-flash reset: attempting to reset the board") + if not self._reset_lpc1768(printer_port): + self._logger.error(u"Reset failed") + return False + + # Short wait before we try to relese the SD card + #time.sleep(3) + + # Release the SD card if not self._unmount_sd(printer_port): - self._logger.error(u"SD unmount failed") + self._send_status("flasherror", message="Unable to unmount SD card") + return False + + # loop until the mount is available; timeout after 60s + count = 1 + timeout = 60 + interval = 1 + sdstarttime = time.time() + self._send_status("progress", subtype="waitforsd") + while (time.time() < (sdstarttime + timeout) and not os.access(lpc1768_path, os.W_OK)): + self._logger.debug(u"Waiting for firmware folder path to become available [{}/{}]".format(count, int(timeout / interval))) + count = count + 1 + time.sleep(interval) + + if not os.access(lpc1768_path, os.W_OK): + self._send_status("flasherror", message="Unable to access firmware folder") + self._logger.error(u"Firmware folder path is not writeable: {path}".format(path=lpc1768_path)) return False + self._logger.info(u"Firmware update folder '{}' available for writing after {} seconds".format(lpc1768_path, round((time.time() - sdstarttime),0))) + target_path = lpc1768_path + '/firmware.bin' self._logger.info(u"Copying firmware to update folder '{}' -> '{}'".format(firmware, target_path)) + self._send_status("progress", subtype="writing") + try: shutil.copyfile(firmware, target_path) except: @@ -498,8 +529,7 @@ def _flash_lpc1768(self, firmware=None, printer_port=None): self._send_status("flasherror") return False - self._send_status("progress", subtype="boardreset") - self._logger.info(u"Attempting to reset the board") + self._logger.info(u"Firmware update reset: attempting to reset the board") if not self._reset_lpc1768(printer_port): self._logger.error(u"Reset failed") return False @@ -522,9 +552,6 @@ def _check_lpc1768(self): elif not os.path.isdir(lpc1768_path): self._logger.error(u"Firmware folder path is not a folder: {path}".format(path=lpc1768_path)) return False - elif not os.access(lpc1768_path, os.W_OK): - self._logger.error(u"Firmware folder path is not writeable: {path}".format(path=lpc1768_path)) - return False else: return True @@ -565,18 +592,94 @@ def _reset_lpc1768(self, printer_port=None): ser.write("reset\r") ser.close() - time.sleep(10) except SerialException as ex: self._logger.exception(u"Board reset failed: {error}".format(error=str(ex))) self._send_status("flasherror", message="Board reset failed") return False + if self._wait_for_lpc1768(printer_port): + return True + else: + self._logger.error(u"Board reset failed") + self._send_status("flasherror", message="Board reset failed") + return False + + def _wait_for_lpc1768(self, printer_port=None): + assert(printer_port is not None) + self._logger.info(u"Waiting for LPC1768 at '{port}' to reset".format(port=printer_port)) + + start = time.time() + timeout = 10 + interval = 0.2 + count = 1 + connected = True + + loopstarttime = time.time() + + while (time.time() < (loopstarttime + timeout) and connected): + self._logger.debug(u"Waiting for reset to init [{}/{}]".format(count, int(timeout / interval))) + count = count + 1 + try: + ser = serial.Serial(port=printer_port, \ + baudrate=9600, \ + parity=serial.PARITY_NONE, \ + stopbits=serial.STOPBITS_ONE , \ + bytesize=serial.EIGHTBITS, \ + timeout=2000) + + ser.close() + connected = True + time.sleep(interval) + + except SerialException as ex: + time.sleep(interval) + connected = False + + if connected: + self._logger.error(u"Timeout waiting for board reset to init") + return False + + self._logger.info(u"LPC1768 at '{port}' is resetting".format(port=printer_port)) + + time.sleep(3) + + timeout = 20 + interval = 0.2 + count = 1 + connected = False + + loopstarttime = time.time() + while (time.time() < (loopstarttime + timeout) and not connected): + self._logger.debug(u"Waiting for reset to complete [{}/{}]".format(count, int(timeout / interval))) + count = count + 1 + try: + ser = serial.Serial(port=printer_port, \ + baudrate=9600, \ + parity=serial.PARITY_NONE, \ + stopbits=serial.STOPBITS_ONE , \ + bytesize=serial.EIGHTBITS, \ + timeout=2000) + + ser.close() + connected = True + time.sleep(interval) + + except SerialException as ex: + time.sleep(interval) + connected = False + + if not connected: + self._logger.error(u"Timeout waiting for board reset to complete") + return False + + end = time.time() + self._logger.info(u"LPC1768 at '{port}' reset in {duration} seconds".format(port=printer_port, duration=(round((end - start),2)))) return True def _unmount_sd(self, printer_port=None): assert(printer_port is not None) - self._logger.info(u"Release the SD Card by sending 'M22' to '{port}'".format(port=printer_port)) + self._logger.info(u"Release the firmware lock on the SD Card by sending 'M22' to '{port}'".format(port=printer_port)) try: ser = serial.Serial(port=printer_port, \ baudrate=9600, \ diff --git a/octoprint_firmwareupdater/static/js/firmwareupdater.js b/octoprint_firmwareupdater/static/js/firmwareupdater.js index d8b06ef..a66b350 100644 --- a/octoprint_firmwareupdater/static/js/firmwareupdater.js +++ b/octoprint_firmwareupdater/static/js/firmwareupdater.js @@ -320,6 +320,10 @@ $(function() { message = gettext("Starting flash..."); break; } + case "waitforsd": { + message = gettext("Waiting for SD card to mount on host..."); + break; + } case "writing": { message = gettext("Writing memory..."); break; @@ -336,7 +340,7 @@ $(function() { message = gettext("Post-flash delay..."); break; } - case "boardreset": { + case "boardreset": { message = gettext("Resetting the board..."); break; } From c8cc905f3d7d5275fa3645f4921f2a3ed25a82fe Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Thu, 25 Apr 2019 17:29:24 +0100 Subject: [PATCH 4/6] Add pre-flash and post-flash commands Run system commands on the host before and after flashing. --- octoprint_firmwareupdater/__init__.py | 28 ++++++++++ .../static/js/firmwareupdater.js | 18 ++++++ .../templates/firmwareupdater_settings.jinja2 | 55 ++++++++++++++----- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/octoprint_firmwareupdater/__init__.py b/octoprint_firmwareupdater/__init__.py index 27e5770..ca6fe54 100644 --- a/octoprint_firmwareupdater/__init__.py +++ b/octoprint_firmwareupdater/__init__.py @@ -194,6 +194,18 @@ def _start_flash_process(self, method, hex_file, printer_port): return True def _flash_worker(self, method, firmware, printer_port): + # Run pre-flash commandline here + preflash_command = self._settings.get(["preflash_commandline"]) + if preflash_command is not None and self._settings.get_boolean(["enable_preflash_commandline"]): + self._logger.info("Executing pre-flash commandline '{}'".format(preflash_command)) + try: + r = os.system(preflash_command) + except: + e = sys.exc_info()[0] + self._logger.error("Error executing pre-flash commandline '{}'".format(preflash_command)) + + self._logger.info("Pre-flash command '{}' returned: {}".format(preflash_command, r)) + try: self._logger.info("Firmware update started") @@ -231,6 +243,18 @@ def _flash_worker(self, method, firmware, printer_port): self._console_logger.info(message) self._send_status("success") + # Run post-flash commandline here + postflash_command = self._settings.get(["postflash_commandline"]) + if postflash_command is not None and self._settings.get_boolean(["enable_postflash_commandline"]): + self._logger.info("Executing post-flash commandline '{}'".format(postflash_command)) + try: + r = os.system(postflash_command) + except: + e = sys.exc_info()[0] + self._logger.error("Error executing post-flash commandline '{}'".format(postflash_command)) + + self._logger.info("Post-flash command '{}' returned: {}".format(postflash_command, r)) + postflash_gcode = self._settings.get(["postflash_gcode"]) if postflash_gcode is not None and self._settings.get_boolean(["enable_postflash_gcode"]): self._logger.info(u"Setting run_postflash_gcode flag to true") @@ -718,6 +742,10 @@ def get_settings_defaults(self): "postflash_delay": "0", "postflash_gcode": None, "run_postflash_gcode": False, + "preflash_commandline": None, + "postflash_commandline": None, + "enable_preflash_commandline": None, + "enable_postflash_commandline": None, "enable_postflash_delay": None, "enable_postflash_gcode": None, "disable_bootloadercheck": None diff --git a/octoprint_firmwareupdater/static/js/firmwareupdater.js b/octoprint_firmwareupdater/static/js/firmwareupdater.js index a66b350..2dd4454 100644 --- a/octoprint_firmwareupdater/static/js/firmwareupdater.js +++ b/octoprint_firmwareupdater/static/js/firmwareupdater.js @@ -19,6 +19,10 @@ $(function() { self.configEnablePostflashGcode = ko.observable(); self.configPostflashGcode = ko.observable(); self.configDisableBootloaderCheck = ko.observable(); + self.configEnablePreflashCommandline = ko.observable(); + self.configPreflashCommandline = ko.observable(); + self.configEnablePostflashCommandline = ko.observable(); + self.configPostflashCommandline = ko.observable(); // Config settings for avrdude self.configAvrdudeMcu = ko.observable(); @@ -369,9 +373,19 @@ $(function() { self.showPluginConfig = function() { // Load the general settings self.configFlashMethod(self.settingsViewModel.settings.plugins.firmwareupdater.flash_method()); + self.configPreflashCommandline(self.settingsViewModel.settings.plugins.firmwareupdater.preflash_commandline()); + self.configPostflashCommandline(self.settingsViewModel.settings.plugins.firmwareupdater.postflash_commandline()); self.configPostflashDelay(self.settingsViewModel.settings.plugins.firmwareupdater.postflash_delay()); self.configPostflashGcode(self.settingsViewModel.settings.plugins.firmwareupdater.postflash_gcode()); + if(self.settingsViewModel.settings.plugins.firmwareupdater.enable_preflash_commandline() != 'false') { + self.configEnablePreflashCommandline(self.settingsViewModel.settings.plugins.firmwareupdater.enable_preflash_commandline()); + } + + if(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_commandline() != 'false') { + self.configEnablePostflashCommandline(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_commandline()); + } + if(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_delay() != 'false') { self.configEnablePostflashDelay(self.settingsViewModel.settings.plugins.firmwareupdater.enable_postflash_delay()); } @@ -430,6 +444,10 @@ $(function() { bossac_disableverify: self.configBossacDisableVerification(), bossac_commandline: self.configBossacCommandLine(), lpc1768_path: self.configLpc1768Path(), + enable_preflash_commandline: self.configEnablePreflashCommandline(), + preflash_commandline: self.configPreflashCommandline(), + enable_postflash_commandline: self.configEnablePostflashCommandline(), + postflash_commandline: self.configPostflashCommandline(), postflash_delay: self.configPostflashDelay(), postflash_gcode: self.configPostflashGcode(), enable_postflash_delay: self.configEnablePostflashDelay(), diff --git a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 index 34b1d8b..cb0e56d 100644 --- a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 +++ b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 @@ -265,53 +265,78 @@
+
+
- +
+
- +
- {{ _('If enabled, the firmware update routine will include a post-flashing delay of the specified number of seconds.') }} + {{ _('System command line to execute before flashing.') }}
+ + +
- +
-
- - s + +
+
- {{ _('Number of seconds to delay for in order to allow the controller to boot following flashing.') }} + {{ _('System command line to execute after flashing.') }}
+ + +
- +
-
- + +
+ + seconds
- {{ _('If enabled, any gcode commands set below will be run the first time the printer connects after a firmware flash.') }} + {{ _('Give the board time to boot before allowing OctoPrint to reconnect.') }}
+ + +
+
- {{ _('Gcode commands which will be run when the printer reconnects after firmware is flashed. Separate multi commands with a semi colon.') }} + {{ _('Gcode commands which will be run when the printer reconnects after firmware is flashed. Separate multiple commands with a semi colon.') }}
+
+
+
+ +
+
+ +
+ {{ _('If checked the bootloader warning will be suppressed.') }} +
+
@@ -252,15 +261,21 @@
-
- -
-
- + +
+
+ +
+
+ +
+ {{ _('If checked the board will be reset before a firmware update is attempted. Helps to ensure that the SD card is properly mounted.') }}
- {{ _('If checked the bootloader warning will be suppressed.') }}
+ + +
From 03316f4a4c1f0d6cf1632f1d6872ca3e43930338 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Thu, 25 Apr 2019 09:49:25 +0100 Subject: [PATCH 6/6] Increment version to 1.3.0 Increment version and change author email address --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 19ba3be..23e4f7f 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ plugin_name = "OctoPrint-FirmwareUpdater" # The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module -plugin_version = "1.2.0" +plugin_version = "1.3.0" # The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin # module @@ -24,7 +24,7 @@ plugin_author = "Gina Häußge and Ben Lye, based on work by Nicanor Romero Venier" # The plugin's author's mail address. -plugin_author_email = "gina@octoprint.org" +plugin_author_email = "ben@lye.co.nz" # The plugin's homepage URL. Can be overwritten within OctoPrint's internal data via __plugin_url__ in the plugin module plugin_url = "https://github.com/OctoPrint/OctoPrint-FirmwareUpdater"