From 07c47cdd5916b10595ec6d14155a569dbab58c1c Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Tue, 21 May 2019 12:26:27 +0100 Subject: [PATCH 1/8] Start adding dfu-programmer as a method --- octoprint_firmwareupdater/__init__.py | 11 ++- .../static/js/firmwareupdater.js | 81 ++++++++++++++++++- .../templates/firmwareupdater_settings.jinja2 | 44 +++++++++- 3 files changed, 131 insertions(+), 5 deletions(-) diff --git a/octoprint_firmwareupdater/__init__.py b/octoprint_firmwareupdater/__init__.py index 3d072e4..5783bff 100644 --- a/octoprint_firmwareupdater/__init__.py +++ b/octoprint_firmwareupdater/__init__.py @@ -210,12 +210,16 @@ def _flash_worker(self, method, firmware, printer_port): self._logger.info("Firmware update started") if not method in self._flash_methods: - self._logger.error("Unsupported flashing method: {}".format(method)) + error_message = "Unsupported flashing method: {}".format(method) + self._logger.error(error_message) + self._send_status("flasherror", message=error_message) return flash_callable = self._flash_methods[method] if not callable(flash_callable): - self._logger.error("Don't have a callable for flashing method {}: {!r}".format(method, flash_callable)) + error_message = "Don't have a callable for flashing method {}: {!r}".format(method, flash_callable) + self._logger.error(error_message) + self._send_status("flasherror", message=error_message) return reconnect = None @@ -743,6 +747,9 @@ 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, + "dfuprog_path": None, + "dfuprog_avrmcu": None, + "dfuprog_commandline": "sudo {dfuprogrammer} {mcu} flash {firmware} --debug-level 10 --force", "lpc1768_path": None, "lpc1768_preflashreset": True, "postflash_delay": "0", diff --git a/octoprint_firmwareupdater/static/js/firmwareupdater.js b/octoprint_firmwareupdater/static/js/firmwareupdater.js index eb36940..b568f2b 100644 --- a/octoprint_firmwareupdater/static/js/firmwareupdater.js +++ b/octoprint_firmwareupdater/static/js/firmwareupdater.js @@ -13,6 +13,7 @@ $(function() { self.showAvrdudeConfig = ko.observable(false); self.showBossacConfig = ko.observable(false); self.showLpc1768Config = ko.observable(false); + self.showDfuConfig = ko.observable(false); self.showPostflashConfig = ko.observable(false); self.configEnablePostflashDelay = ko.observable(); self.configPostflashDelay = ko.observable(); @@ -69,6 +70,17 @@ $(function() { return self.lpc1768PathBroken() || self.lpc1768PathOk(); }); + // Config settings for dfu-programmer + self.configDfuMcu = ko.observable(); + self.configDfuPath = ko.observable(); + self.configDfuCommandLine = ko.observable(); + self.dfuPathBroken = ko.observable(false); + self.dfuPathOk = ko.observable(false); + self.dfuPathText = ko.observable(); + self.dfuPathHelpVisible = ko.computed(function() { + return self.dfuPathBroken() || self.dfuPathOk(); + }); + self.flashPort = ko.observable(undefined); self.firmwareFileName = ko.observable(undefined); @@ -106,18 +118,27 @@ $(function() { self.showAvrdudeConfig(true); self.showBossacConfig(false); self.showLpc1768Config(false); + self.showDfuConfig(false); } else if(value == 'bossac') { self.showAvrdudeConfig(false); self.showBossacConfig(true); self.showLpc1768Config(false); + self.showDfuConfig(false); } else if(value == 'lpc1768'){ self.showAvrdudeConfig(false); self.showBossacConfig(false); self.showLpc1768Config(true); + self.showDfuConfig(false); + } else if(value == 'dfuprogrammer'){ + self.showAvrdudeConfig(false); + self.showBossacConfig(false); + self.showLpc1768Config(false); + self.showDfuConfig(true); } else { self.showAvrdudeConfig(false); self.showBossacConfig(false); self.showLpc1768Config(false); + self.showDfuConfig(false); } }); @@ -183,7 +204,15 @@ $(function() { alert = gettext("The lpc1768 firmware folder path is not configured."); } - if (!self.flashPort()) { + if (self.settingsViewModel.settings.plugins.firmwareupdater.flash_method() == "dfuprogrammer" && !self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_path()) { + alert = gettext("The dfu-programmer path is not configured."); + } + + if (self.settingsViewModel.settings.plugins.firmwareupdater.flash_method() == "dfuprogrammer" && !self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_avrmcu()) { + alert = gettext("The AVR MCU type is not selected."); + } + + if (!self.flashPort() &! self.settingsViewModel.settings.plugins.firmwareupdater.flash_method() == "dfuprogrammer") { alert = gettext("The printer port is not selected."); } @@ -415,6 +444,11 @@ $(function() { self.configBossacDisableVerification(self.settingsViewModel.settings.plugins.firmwareupdater.bossac_disableverify()); self.configBossacCommandLine(self.settingsViewModel.settings.plugins.firmwareupdater.bossac_commandline()); + // Load the dfu-programmer settings + self.configDfuPath(self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_path()); + self.configDfuMcu(self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_avrmcu()); + self.configDfuCommandLine(self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_commandline()); + // Load the lpc1768 settings self.configLpc1768Path(self.settingsViewModel.settings.plugins.firmwareupdater.lpc1768_path()); if(self.settingsViewModel.settings.plugins.firmwareupdater.lpc1768_preflashreset() != 'false') { @@ -446,6 +480,9 @@ $(function() { bossac_path: self.configBossacPath(), bossac_disableverify: self.configBossacDisableVerification(), bossac_commandline: self.configBossacCommandLine(), + dfuprog_path: self.configDfuPath(), + dfuprog_avrmcu: self.configDfuMcu(), + dfuprog_commandline: self.configDfuCommandLine(), lpc1768_path: self.configLpc1768Path(), lpc1768_preflashreset: self.configLpc1768ResetBeforeFlash(), enable_preflash_commandline: self.configEnablePreflashCommandline(), @@ -556,6 +593,48 @@ $(function() { self.configBossacCommandLine("{bossac} -i -p {port} -U true -e -w {disableverify} -b {firmware} -R"); }; + self.testDfuPath = function() { + var filePathRegEx = new RegExp("^(\/[^\0/]+)+$"); + + if (!filePathRegEx.test(self.configDfuPath())) { + self.dfuPathText(gettext("The path is not valid")); + self.dfuPathOk(false); + self.dfuPathBroken(true); + } else { + $.ajax({ + url: API_BASEURL + "util/test", + type: "POST", + dataType: "json", + data: JSON.stringify({ + command: "path", + path: self.configDfuPath(), + check_type: "file", + check_access: "x" + }), + contentType: "application/json; charset=UTF-8", + success: function(response) { + if (!response.result) { + if (!response.exists) { + self.dfuPathText(gettext("The path doesn't exist")); + } else if (!response.typeok) { + self.dfuPathText(gettext("The path is not a file")); + } else if (!response.access) { + self.dfuPathText(gettext("The path is not an executable")); + } + } else { + self.dfuPathText(gettext("The path is valid")); + } + self.dfuPathOk(response.result); + self.dfuPathBroken(!response.result); + } + }) + } + }; + + self.resetDfuCommandLine = function() { + self.configDfuCommandLine("sudo {dfuprogrammer} {mcu} flash {firmware} --debug-level 10 --force"); + }; + self.testAvrdudeConf = function() { $.ajax({ url: API_BASEURL + "util/test", diff --git a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 index 1969e55..95ebffe 100644 --- a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 +++ b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 @@ -88,6 +88,7 @@ + @@ -167,9 +168,35 @@ + +
+
+ +
+ +
+
+
+ +
+
+ + +
+ +
+
+
+
+ + -
+
@@ -275,13 +302,26 @@
+ +
+
+ +
+
+ + +
+ {{ _('Customize the dfu-programmer command line.') }} +
+
+

-
+
From c9f46d35775a771f4266090c04ac6746a1c103e0 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Tue, 21 May 2019 16:23:39 +0100 Subject: [PATCH 2/8] dfu-programmer method tweaks Add backend stuff, make erase command configurable --- octoprint_firmwareupdater/__init__.py | 140 +++++++++++++++++- .../static/js/firmwareupdater.js | 7 + .../templates/firmwareupdater_settings.jinja2 | 14 +- 3 files changed, 155 insertions(+), 6 deletions(-) diff --git a/octoprint_firmwareupdater/__init__.py b/octoprint_firmwareupdater/__init__.py index 5783bff..2de50f7 100644 --- a/octoprint_firmwareupdater/__init__.py +++ b/octoprint_firmwareupdater/__init__.py @@ -39,6 +39,12 @@ class FirmwareupdaterPlugin(octoprint.plugin.BlueprintPlugin, BOSSAC_VERIFYING = "bytes of flash" BOSSAC_NODEVICE = "No device found on" + DFUPROG_ERASING = "Erasing flash" + DFUPROG_WRITING = "Programming" + DFUPROG_VERIFYING = "Reading" + DFUPROG_VALIDATING = "Validating" + DFUPROG_NODEVICE = "no device present" + def __init__(self): self._flash_thread = None @@ -50,8 +56,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, lpc1768=self._check_lpc1768) - self._flash_methods = dict(avrdude=self._flash_avrdude, bossac=self._flash_bossac, lpc1768=self._flash_lpc1768) + self._flash_prechecks = dict(avrdude=self._check_avrdude, bossac=self._check_bossac, dfuprogrammer=self._check_dfuprog, lpc1768=self._check_lpc1768) + self._flash_methods = dict(avrdude=self._flash_avrdude, bossac=self._flash_bossac, dfuprogrammer=self._flash_dfuprog, 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")) @@ -62,7 +68,6 @@ def initialize(self): self._console_logger.setLevel(logging.DEBUG) self._console_logger.propagate = False - # Event handler def on_event(self, event, payload): #self._logger.info("Got event: {}".format(event)) @@ -505,6 +510,132 @@ def _check_bossac(self): else: return True + def _flash_dfuprog(self, firmware=None, printer_port=None): + assert(firmware is not None) + + if not self._erase_dfuprog(): + return False + + dfuprog_path = self._settings.get(["dfuprog_path"]) + dfuprog_avrmcu = self._settings.get(["dfuprog_avrmcu"]) + working_dir = os.path.dirname(dfuprog_path) + + dfuprog_command = self._settings.get(["dfuprog_commandline"]) + dfuprog_command = dfuprog_command.replace("{dfuprogrammer}", dfuprog_path) + dfuprog_command = dfuprog_command.replace("{mcu}", dfuprog_avrmcu) + dfuprog_command = dfuprog_command.replace("{firmware}", firmware) + + import sarge + self._logger.info(u"Running '{}' in {}".format(dfuprog_command, working_dir)) + self._send_status("progress", subtype="writing") + self._console_logger.info(dfuprog_command) + try: + p = sarge.run(dfuprog_command, cwd=working_dir, async=True, stdout=sarge.Capture(buffer_size=1), stderr=sarge.Capture(buffer_size=1)) + p.wait_events() + + while p.returncode is None: + output = p.stderr.read(timeout=0.5) + if not output: + p.commands[0].poll() + continue + + for line in output.split("\n"): + if line.endswith("\r"): + line = line[:-1] + self._console_logger.info(u"> {}".format(line)) + + if self.DFUPROG_WRITING in line: + self._logger.info(u"Writing memory...") + self._send_status("progress", subtype="writing") + if self.DFUPROG_VERIFYING in line: + self._logger.info(u"Verifying memory...") + self._send_status("progress", subtype="verifying") + elif self.DFUPROG_NODEVICE in line: + raise FlashException("No device found") + + if p.returncode == 0: + return True + else: + raise FlashException("dfu-programmer returned code {returncode}".format(returncode=p.returncode)) + + except FlashException as ex: + self._logger.error(u"Flashing failed. {error}.".format(error=ex.reason)) + self._send_status("flasherror", message=ex.reason) + return False + except: + self._logger.exception(u"Flashing failed. Unexpected error.") + self._send_status("flasherror") + return False + + def _erase_dfuprog(self): + dfuprog_path = self._settings.get(["dfuprog_path"]) + dfuprog_avrmcu = self._settings.get(["dfuprog_avrmcu"]) + working_dir = os.path.dirname(dfuprog_path) + + dfuprog_erasecommand = self._settings.get(["dfuprog_erasecommandline"]) + dfuprog_erasecommand = dfuprog_erasecommand.replace("{dfuprogrammer}", dfuprog_path) + dfuprog_erasecommand = dfuprog_erasecommand.replace("{mcu}", dfuprog_avrmcu) + + import sarge + self._logger.info(u"Running '{}' in {}".format(dfuprog_erasecommand, working_dir)) + self._console_logger.info(dfuprog_erasecommand) + try: + p = sarge.run(dfuprog_erasecommand, cwd=working_dir, async=True, stdout=sarge.Capture(buffer_size=1), stderr=sarge.Capture(buffer_size=1)) + p.wait_events() + + while p.returncode is None: + output = p.stderr.read(timeout=0.5) + if not output: + p.commands[0].poll() + continue + + for line in output.split("\n"): + if line.endswith("\r"): + line = line[:-1] + self._console_logger.info(u"> {}".format(line)) + + if self.DFUPROG_ERASING in line: + self._logger.info(u"Erasing memory...") + self._send_status("progress", subtype="erasing") + elif self.DFUPROG_NODEVICE in line: + raise FlashException("No device found") + + if p.returncode == 0: + return True + else: + raise FlashException("dfu-programmer returned code {returncode}".format(returncode=p.returncode)) + + except FlashException as ex: + self._logger.error(u"Erasing failed. {error}.".format(error=ex.reason)) + self._send_status("flasherror", message=ex.reason) + return False + except: + self._logger.exception(u"Erasing failed. Unexpected error.") + self._send_status("flasherror") + return False + + def _check_dfuprog(self): + dfuprog_path = self._settings.get(["dfuprog_path"]) + pattern = re.compile("^(\/[^\0/]+)+$") + + if not pattern.match(dfuprog_path): + self._logger.error(u"Path to dfu-programmer is not valid: {path}".format(path=dfuprog_path)) + return False + elif dfuprog_path is None: + self._logger.error(u"Path to dfu-programmer is not set.") + return False + if not os.path.exists(dfuprog_path): + self._logger.error(u"Path to dfu-programmer does not exist: {path}".format(path=dfuprog_path)) + return False + elif not os.path.isfile(dfuprog_path): + self._logger.error(u"Path to dfu-programmer is not a file: {path}".format(path=dfuprog_path)) + return False + elif not os.access(dfuprog_path, os.X_OK): + self._logger.error(u"Path to dfu-programmer is not executable: {path}".format(path=dfuprog_path)) + return False + else: + return True + def _flash_lpc1768(self, firmware=None, printer_port=None): assert(firmware is not None) assert(printer_port is not None) @@ -749,7 +880,8 @@ def get_settings_defaults(self): "bossac_disableverify": None, "dfuprog_path": None, "dfuprog_avrmcu": None, - "dfuprog_commandline": "sudo {dfuprogrammer} {mcu} flash {firmware} --debug-level 10 --force", + "dfuprog_commandline": "sudo {dfuprogrammer} {mcu} flash {firmware} --debug-level 10", + "dfuprog_erasecommandline": "sudo {dfuprogrammer} {mcu} erase --debug-level 10 --force", "lpc1768_path": None, "lpc1768_preflashreset": True, "postflash_delay": "0", diff --git a/octoprint_firmwareupdater/static/js/firmwareupdater.js b/octoprint_firmwareupdater/static/js/firmwareupdater.js index b568f2b..bc4d79d 100644 --- a/octoprint_firmwareupdater/static/js/firmwareupdater.js +++ b/octoprint_firmwareupdater/static/js/firmwareupdater.js @@ -74,6 +74,7 @@ $(function() { self.configDfuMcu = ko.observable(); self.configDfuPath = ko.observable(); self.configDfuCommandLine = ko.observable(); + self.configDfuEraseCommandLine = ko.observable(); self.dfuPathBroken = ko.observable(false); self.dfuPathOk = ko.observable(false); self.dfuPathText = ko.observable(); @@ -448,6 +449,7 @@ $(function() { self.configDfuPath(self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_path()); self.configDfuMcu(self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_avrmcu()); self.configDfuCommandLine(self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_commandline()); + self.configDfuEraseCommandLine(self.settingsViewModel.settings.plugins.firmwareupdater.dfuprog_erasecommandline()); // Load the lpc1768 settings self.configLpc1768Path(self.settingsViewModel.settings.plugins.firmwareupdater.lpc1768_path()); @@ -483,6 +485,7 @@ $(function() { dfuprog_path: self.configDfuPath(), dfuprog_avrmcu: self.configDfuMcu(), dfuprog_commandline: self.configDfuCommandLine(), + dfuprog_erasecommandline: self.configDfuEraseCommandLine(), lpc1768_path: self.configLpc1768Path(), lpc1768_preflashreset: self.configLpc1768ResetBeforeFlash(), enable_preflash_commandline: self.configEnablePreflashCommandline(), @@ -635,6 +638,10 @@ $(function() { self.configDfuCommandLine("sudo {dfuprogrammer} {mcu} flash {firmware} --debug-level 10 --force"); }; + self.resetDfuEraseCommandLine = function() { + self.configDfuEraseCommandLine("sudo {dfuprogrammer} {mcu} erase --debug-level 10"); + }; + self.testAvrdudeConf = function() { $.ajax({ url: API_BASEURL + "util/test", diff --git a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 index 95ebffe..336be46 100644 --- a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 +++ b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 @@ -305,13 +305,23 @@
- + +
+
+ + +
+ {{ _('Customize the dfu-programmer erase command line.') }} +
+
+
+
- {{ _('Customize the dfu-programmer command line.') }} + {{ _('Customize the dfu-programmer flash command line.') }}
From e28caef8c4c62861c8be63cfc739e3a2ee06dd16 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Tue, 21 May 2019 20:28:02 +0100 Subject: [PATCH 3/8] Doc updates --- README.md | 169 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 105 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index b3b83c7..9bdbc08 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,50 @@ # OctoPrint Firmware Updater - -This plugin can be used to flash pre-compiled firmware images to your printer from a file or URL. - -

Firmware Updater

- -## 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.) - -Please open a Github issue if you would like a new board or MCU to be supported. If it's a new type of board which requires hardware testing please consider making a [donation](#Donations) to help fund the costs. - -## Setup - +The Firmware Updater plugin can be used to flash pre-compiled firmware images to your printer from a local file or URL. + +Firmware Updater + +## Documentation Index +1. [Supported Boards](#supported-boards) +1. [Plugin Installation](#plugin-installation) +1. [ATmega Boards](#atmega-boards) + 1. [Avrdude Installation](#avrdude-installation) + 1. [Avrdude Configuration](#avrdude-configuration) +1. [AT90USB Boards](#at90usb-boards) + 1. [Dfu-programmer Installation](#dfu-programmer-installation) + 1. [Dfu-programmer Configuration](#dfu-programmer-configuration) +1. [LPC1768 Boards](#lpc1768-boards) + 1. [Usbmount Installation](#usbmount-installation) +1. [SAM Boards](#sam-boards) + 1. [Bossac Installation](#bossac-installation) + 1. [Bossac Configuration](#bossac-configuration) +1. [Customizing the Command Lines](#customizing-the-command-lines) +1. [Pre and Post Flash Settings](#pre-and-post-flash-settings) +1. [Flashing](#flashing) +1. [Troubleshooting](#troubleshooting) +1. [Donations](#donations) + +## Supported Boards +The plugn supports a variety of boards, based on the MCU (processor) they have: +* 'ATmega' family 8-bit MCUs (RAMPS, Sanguinololu, Melzi, Anet, Creality, Ender, many others) +* 'AT90USB' family 8-bit MCUs (Printrboard) +* 'LPC1768' MCUs (MKS SBASE, SKR v1.1 and v1.3, etc.) +* 'SAM' family 32-bit MCUs (Arduino DUE, etc.) + +Please open a [Github issue](https://github.com/OctoPrint/OctoPrint-FirmwareUpdater/issues) if you would like a new board or MCU to be supported. If it's a new type of board which requires hardware testing please consider making a [donation](#Donations) to help fund the costs. + +## Plugin Installation Install via the bundled [Plugin Manager](https://github.com/foosel/OctoPrint/wiki/Plugin:-Plugin-Manager) or manually using this URL: - https://github.com/OctoPrint/OctoPrint-FirmwareUpdater/archive/master.zip -The appropriate flashing tool also needs to be installed. For 8-bit MCUs the tool is **avrdude**, for 32-bit MCUs the tool is **bossac**, for LPC1768 an external tool is not needed, but there is additional configuration to get make the on-board SD card accessible. +The appropriate flashing tool for the board type also needs to be installed and configured. For ATmega MCUs the tool is **avrdude**, for AT90USB MCUs the tools is **dfu-programmer**, for SAM MCUs the tool is **bossac**, for LPC1768 an external tool is not needed, but there is additional configuration required to make the on-board SD card accessible. -### AVRDUDE Installation +Plugin settings vary depending on the flashing tool and are documented below. -AVRDUDE needs to be installed on the server where OctoPrint is running. +## ATmega Boards +To flash an ATmega-based board the tool `avrdude` needs to be installed on the OctoPrint host. +### Avrdude Installation #### Raspberry Pi ``` @@ -32,7 +53,6 @@ sudo apt-get install avrdude ``` #### Ubuntu (12.04 - 14.04 - 15.04) - Information about the package needed can be found here [Ubuntu avrdude package](https://launchpad.net/ubuntu/+source/avrdude) ``` @@ -41,10 +61,48 @@ sudo apt-get update sudo apt-get install avrdude ``` -### BOSSAC Installation -Bossac cannot be installed using a package manager as the packaged version is out of date and will not work. Installation from source is straight-forward. +### Avrdude Configuration +

Firmware Updater Settings

+ +The minimum settings are: +* Path to avrdude +* AVR MCU Type +* AVR Programmer Type -#### Raspberry Pi / Ubuntu +Typical MCU/programmer combinations are: + +| AVR MCU | Programmer | Example Board | +| --- | --- | --- | +| Atmega1284p | arduino | Anet A series, Creality, Ender, etc. | +| Atmega2560 | wiring | RAMPS, RAMbo, etc. | +| Atmega644p | arduino | Sanguinololu, Melzi | + +## AT90USB Boards +To flash an AT90USB-based board the tool `dfu-programmer` needs to be installed on the OctoPrint host. + +### Dfu-programmer Installation +A version of `dfu-programmer` can be installed via `apt-get install` but it is outdated. Please build the latest version from [Github](https://github.com/dfu-programmer/dfu-programmer) using these commands: + +``` +cd ~ +sudo apt-get install autoconf libusb-1.0-0-dev +git clone https://github.com/dfu-programmer/dfu-programmer.git +cd dfu-programmer +./bootstrap.sh +./configure +make +sudo make install +``` +If there were no errors `dfu-programmer` should now be installed at /usr/local/bin/dfu-programmer. + +### Dfu-programmer Configuration +Dfu-programmer instuctions.... + +## SAM Boards +To flash a SAM-based board the tool `bossac` needs to be installed on the OctoPrint host. + +### Bossac Installation +Bossac cannot be installed using a package manager as the packaged version is out of date and will not work. Installation from source is straight-forward. ``` cd ~/ @@ -56,15 +114,20 @@ cd BOSSA-1.7.0 sudo cp ~/BOSSA-1.7.0/bin/bossac /usr/local/bin/ ``` -### LPC 1768 Installation +### Bossac Configuration +

Firmware Updater Settings

+The only required setting is the path to the bossac binary. + +## LPC1768 Boards 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`. +There are several ways to do this, but using [usbmount](https://github.com/rbrito/usbmount) works well and is documented below. 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'. +### Usbmount Installation 1. Install usbmount `sudo apt-get install usbmount` @@ -95,6 +158,9 @@ Once installed, usbmount requires some tweaking to make it work well on the Rasp 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. +### LPC1768 Configuration +The only required setting is the path to the firmware update folder. If using usbmount it will probably be `/media/usb`. + #### Minimum Marlin Firmware Version Some boards (e.g. SKR v1.3) have been known to ship with older Marlin firmware which does not support the `M997` command, so must be updated conventionally one time before using the plugin. A board running too-old Marlin firmware will log 'Board reset failed' when attempting to flash from the plugin. @@ -103,46 +169,15 @@ If flashing an existing Marlin installation, the existing firmware must be newer #### 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. - -### AVRDUDE Configuration -

Firmware Updater Settings

- -The minimum settings are: -* Path to avrdude -* AVR MCU Type -* AVR Programmer Type - -Typical MCU/programmer combinations are: - -| AVR MCU | Programmer | Example Board | -| --- | --- | --- | -| Atmega1284p | arduino | Anet A series | -| Atmega2560 | wiring | RAMPS, RAMbo, etc. | -| Atmega644p | arduino | Sanguinololu, Melzi | - -### BOSSAC Configuration -

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. +## Customizing the Command Lines +The command lines for `avrdude`, `bossac`, and `dfu-programmer` 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. | String | Description| | --- | --- | -| `{avrdude}` | Full path to the avrdude executable1 | -| `{bossac}` | Full path to the bossac executable2 | -| `{mcu}` | Avrdude MCU type1 | +| `{avrdude}` | Full path to the `avrdude` executable1 | +| `{bossac}` | Full path to the `bossac` executable2 | +| `{dfuprogrammer}` | Full path to the `dfu-programmer` executable3 | +| `{mcu}` | MCU type4 | | `{programmer}` | Avrdude programmer1 | | `{port}` | COM port the printer is connected to | | `{conffile}` | Full path to the avrdude configuration file1 | @@ -150,8 +185,10 @@ The command lines for avrdude and bossac can be customized by editing the string | `{disableverify}` | Switch to disable write verification | | `{firmware}` | Path to the uploaded firmware file | -1. Avrdude flash method only -2. Bossac dude flash method only +1. avrdude flash method only +2. bossac flash method only +3. dfu-programmer flash method only +4. avrdude and dfu-programmer flash methods #### Command Line Defaults Command lines can be returned to the default by clicking the **Reset** button. @@ -162,7 +199,11 @@ Command lines can be returned to the default by clicking the **Reset** button. ##### Bossac `{bossac} -i -p {port} -U true -e -w {disableverify} -b {firmware} -R` -### Post-flash Settings +##### Dfu-programmer +Erase: `{bossac} -i -p {port} -U true -e -w {disableverify} -b {firmware} -R` +Flash: + +## Pre and Post-flash Settings

Firmware Updater Settings

#### Post-flash Delay #### From 31037798d506a541fb1c37b185a9fd6206560164 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Wed, 22 May 2019 09:28:27 +0100 Subject: [PATCH 4/8] Update firmwareupdater_settings.jinja2 Add link to doc. --- .../templates/firmwareupdater_settings.jinja2 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 index 336be46..f579fd2 100644 --- a/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 +++ b/octoprint_firmwareupdater/templates/firmwareupdater_settings.jinja2 @@ -70,8 +70,9 @@
  • Do not attempt to flash a firmware file which includes a bootloader
  • No warranty is given, and no responsibility can be accepted if there are problems. By using this plugin you accept the associated risks.

    -
    - +   
    Documentation
    +

    Documentation is available on Github

    +