Skip to content

Commit

Permalink
Merge pull request #183 from OctoPrint/rc
Browse files Browse the repository at this point in the history
Bring latest work to master
  • Loading branch information
benlye authored Jan 20, 2021
2 parents 41f5d73 + de4761a commit b521584
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 14 deletions.
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,42 @@ The Firmware Updater plugin can be used to flash pre-compiled firmware images to

## Supported Boards
The plugin 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)
* 'ATmega' family 8-bit MCUs (RAMPS, Sanguinololu, Melzi, Anet, Creality, Ender, Prusa MMU, Prusa CW1 many others)
* 'AT90USB' family 8-bit MCUs (Printrboard)
* 'LPC1768' MCUs (MKS SBASE, SKR v1.1 and v1.3, etc., also SKR Pro v1.1)
* 'SAM' family 32-bit MCUs (Arduino DUE, etc.)
* 'STM32' family 32-bits MCUs with embedded ST serial bootloader (FYSETC Cheetah, **not** SKR Pro)
* 'STM32' family 32-bit MCUs which update from the SD card using the lpc1768 method (SKR Pro v1.1, SKR Mini E3 v2, etc.)

## IMPORTANT: Additional requirements
pyserial needs to be installed on the system

```
sudo apt-get update
sudo apt-get install python-pip
pip install pyserial
```

## Prusa MMU and CW1
Original firmware files for Prusa MMU and CW1 have special in the begining of the file:

For MMU these are:

```
1 ;device = mm-control
2
```

and for CW1:

```
1 ;device = cw1
2
```

Firmware updater now takes care about that, so modifying the files isn't necessary any more.


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
Expand Down Expand Up @@ -104,6 +133,7 @@ Typical MCU/programmer combinations are:
| Atmega1284p | arduino | Anet A series, Creality, Ender, etc. |
| Atmega2560 | wiring | RAMPS, RAMbo, etc. |
| Atmega644p | arduino | Sanguinololu, Melzi |
| Atmega32u4 | avr109 | Prusa MMU, Prusa CW1 |

To locate `avrdude` on most Linux variants (including OctoPi):
* Connect via SSH and run the following: `which avrdude`
Expand Down
2 changes: 2 additions & 0 deletions octoprint_firmwareupdater/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ def get_settings_defaults(self):
"enable_postflash_gcode": None,
"enable_preflash_gcode": None,
"disable_bootloadercheck": None,
"save_url": False,
"last_url": None,
"plugin_version": self._plugin_version
}

Expand Down
107 changes: 105 additions & 2 deletions octoprint_firmwareupdater/methods/avrdude.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import re
import os
import sarge
import serial
import time

try:
import serial.tools.list_ports
from serial.tools import list_ports
except ImportError:
exit("This requires serial module\nInstall with: sudo pip install pyserial")


AVRDUDE_WRITING = "writing flash"
AVRDUDE_VERIFYING = "reading on-chip flash data"
Expand All @@ -13,6 +22,20 @@
WINDOWS_PATTERN = "^[A-z]\:\\\\.+.exe$"
POSIX_PATTERN = "^(\/[^\0/]+)+$"

USB_VID_PID_MK2 = "2c99:0001"
USB_VID_PID_MK3 = "2c99:0002"
USB_VID_PID_MMU_BOOT = "2c99:0003"
USB_VID_PID_MMU_APP = "2c99:0004"
USB_VID_PID_CW1_BOOT = "2c99:0007"
USB_VID_PID_CW1_APP = "2c99:0008"


TARGET_NO_PRUSA = 0
TARGET_MMU = 1
TARGET_CW1 = 2

ser = serial

def _check_avrdude(self):
avrdude_path = self._settings.get(["avrdude_path"])
avrdude_avrmcu = self._settings.get(["avrdude_avrmcu"])
Expand Down Expand Up @@ -61,8 +84,6 @@ def _flash_avrdude(self, firmware=None, printer_port=None):
avrdude_command = avrdude_command.replace("{avrdude}", avrdude_path)
avrdude_command = avrdude_command.replace("{mcu}", avrdude_avrmcu)
avrdude_command = avrdude_command.replace("{programmer}", avrdude_programmer)
avrdude_command = avrdude_command.replace("{port}", printer_port)
avrdude_command = avrdude_command.replace("{firmware}", firmware)

if avrdude_conf is not None and avrdude_conf != "":
avrdude_command = avrdude_command.replace("{conffile}", avrdude_conf)
Expand All @@ -79,9 +100,91 @@ def _flash_avrdude(self, firmware=None, printer_port=None):
else:
avrdude_command = avrdude_command.replace(" {disableverify} ", " ")

if avrdude_programmer is not None and avrdude_programmer == "avr109":
self._logger.info(u"Avrdude_programmer is avr109, check if Prusa MMU or CW1 to be flashed")

target = TARGET_NO_PRUSA

list_ports.comports()

try:
app_port_name = list(list_ports.grep(USB_VID_PID_MMU_APP))[0][0]
self._logger.info(u"MMU found {portname}".format(portname=app_port_name))
target = TARGET_MMU
self._logger.info(u"Patch MMU2 firmware file if necessary")
try:
with open(firmware,"r+") as f:
lines = f.readlines()
f.seek(0)
for i in lines:
if i.strip("\n") != "; device = mm-control" and i != '\n':
f.write(i)
f.truncate()
f.close()
except:
self._logger.info(u"Opening MMU2 firmware file failed")
raise FlashException("Patching MMU firmware file failed")
except:
self._logger.info(u"Target ist not MMU")

try:
app_port_name = list(list_ports.grep(USB_VID_PID_CW1_APP))[0][0]
self._logger.info(u"CW1 found {portname}".format(portname=app_port_name))
target = TARGET_CW1
self._logger.info(u"Patch CW1 firmware file if necessary")
try:
with open(firmware,"r+") as f:
lines = f.readlines()
f.seek(0)
for i in lines:
if i.strip("\n") != "; device = cw1" and i != '\n':
f.write(i)
f.truncate()
f.close()
except:
self._logger.info(u"Opening CW1 firmware file failed")
raise FlashException("Patching CW1 firmware file failed")
except:
self._logger.info(u"Target ist not CW1")

if target != TARGET_NO_PRUSA:
try:
ser = serial.Serial(printer_port, 1200, timeout = 1)
self._logger.info(u"Reset target")
time.sleep(0.05)
ser.close()
except serial.SerialException:
self._logger.info(u"Serial port could not been serviced")
raise FlashException("Error resetting target")

time.sleep(3)

list_ports.comports()

if target == TARGET_MMU:
try:
boot_port_name = list(list_ports.grep(USB_VID_PID_MMU_BOOT))[0][0]
self._logger.info(u"MMU in bootloader")
printer_port = boot_port_name
except:
self._logger.info(u"MMU not in bootloader")
raise FlashException("Reboot MMU to bootloader failed")
elif target == TARGET_CW1:
try:
boot_port_name = list(list_ports.grep(USB_VID_PID_CW1_BOOT))[0][0]
self._logger.info(u"CW1 in bootloader")
printer_port = boot_port_name
except:
self._logger.info(u"CW1 not in bootloader")
raise FlashException("Reboot CW1 to bootloader failed")

avrdude_command = avrdude_command.replace("{port}", printer_port)
avrdude_command = avrdude_command.replace("{firmware}", firmware)

self._logger.info(u"Running '{}' in {}".format(avrdude_command, working_dir))
self._console_logger.info(u"")
self._console_logger.info(avrdude_command)

try:
p = sarge.run(avrdude_command, cwd=working_dir, async_=True, stdout=sarge.Capture(), stderr=sarge.Capture())
p.wait_events()
Expand Down
67 changes: 59 additions & 8 deletions octoprint_firmwareupdater/static/js/firmwareupdater.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ $(function() {
self.configPostflashCommandline = ko.observable();
self.configEnablePreflashGcode = ko.observable();
self.configPreflashGcode = ko.observable();
self.configSaveUrl = ko.observable();
self.configLastUrl = ko.observable();
self.pluginVersion = ko.observable();

// Config settings for avrdude
Expand Down Expand Up @@ -122,6 +124,7 @@ $(function() {
self.isBusy = ko.observable(false);
self.fileFlashButtonText = ko.observable("");
self.urlFlashButtonText = ko.observable("");
self.saving = ko.observable(false);

self.selectFilePath = undefined;
self.configurationDialog = undefined;
Expand All @@ -133,6 +136,13 @@ $(function() {
if (self.loginState.isAdmin() && self.configShowNavbarIcon()) {
self.showFirmwareUpdaterNavbarIcon(true);
}

if (self.settingsViewModel.settings.plugins.firmwareupdater.save_url()) {
self.firmwareFileURL(self.settingsViewModel.settings.plugins.firmwareupdater.last_url());
} else {
self.firmwareFileURL("");
}

self.pluginVersion(self.settingsViewModel.settings.plugins.firmwareupdater.plugin_version());
}

Expand Down Expand Up @@ -322,6 +332,14 @@ $(function() {
return;
}

console.log(self.settingsViewModel.settings.plugins.firmwareupdater.save_url());
console.log(self.firmwareFileURL());
if (self.settingsViewModel.settings.plugins.firmwareupdater.save_url()) {
console.log(self.firmwareFileURL());
self.configLastUrl(self.firmwareFileURL());
self._saveLastUrl();
}

self.isBusy(true);
self.showAlert(false);
self.progressBarText("Flashing firmware...");
Expand Down Expand Up @@ -382,15 +400,23 @@ $(function() {
self.isBusy(false);
self.showAlert(false);
self.firmwareFileName("");
self.firmwareFileURL("");
if (self.settingsViewModel.settings.plugins.firmwareupdater.save_url()) {
self.firmwareFileURL(self.configLastUrl());
} else {
self.firmwareFileURL("");
}
break;
}
case "success": {
self.showPopup("success", gettext("Flashing successful"), "");
self.isBusy(false);
self.showAlert(false);
self.firmwareFileName("");
self.firmwareFileURL("");
if (self.settingsViewModel.settings.plugins.firmwareupdater.save_url()) {
self.firmwareFileURL(self.configLastUrl());
} else {
self.firmwareFileURL("");
}
break;
}
case "progress": {
Expand Down Expand Up @@ -461,6 +487,8 @@ $(function() {
self.configPreflashDelay(self.settingsViewModel.settings.plugins.firmwareupdater.preflash_delay());
self.configPostflashGcode(self.settingsViewModel.settings.plugins.firmwareupdater.postflash_gcode());
self.configPreflashGcode(self.settingsViewModel.settings.plugins.firmwareupdater.preflash_gcode());
self.configSaveUrl(self.settingsViewModel.settings.plugins.firmwareupdater.save_url());
self.configLastUrl(self.settingsViewModel.settings.plugins.firmwareupdater.last_url());

if(self.settingsViewModel.settings.plugins.firmwareupdater.enable_preflash_commandline() != 'false') {
self.configEnablePreflashCommandline(self.settingsViewModel.settings.plugins.firmwareupdater.enable_preflash_commandline());
Expand Down Expand Up @@ -535,13 +563,18 @@ $(function() {

self.onConfigClose = function() {
self._saveConfig();

self.configurationDialog.modal("hide");
self.alertMessage(undefined);
self.showAlert(false);
};

self._saveConfig = function() {
self.saving(true);
var lastUrl;
if (self.settingsViewModel.settings.plugins.firmwareupdater.save_url() &! self.configSaveUrl()) {
self.firmwareFileURL("");
lastUrl = null;
} else {
lastUrl = self.configLastUrl();
}

var data = {
plugins: {
firmwareupdater: {
Expand Down Expand Up @@ -585,13 +618,31 @@ $(function() {
enable_preflash_delay: self.configEnablePreflashDelay(),
enable_postflash_gcode: self.configEnablePostflashGcode(),
enable_preflash_gcode: self.configEnablePreflashGcode(),
disable_bootloadercheck: self.configDisableBootloaderCheck()
disable_bootloadercheck: self.configDisableBootloaderCheck(),
save_url: self.configSaveUrl(),
last_url: lastUrl,
}
}
};
self.settingsViewModel.saveData(data);
self.settingsViewModel.saveData(data).done(function () {
self.configurationDialog.modal("hide");
self.alertMessage(undefined);
self.showAlert(false);
self.saving(false);
});
};

self._saveLastUrl = function() {
var data = {
plugins: {
firmwareupdater: {
last_url: self.firmwareFileURL(),
}
}
};
self.settingsViewModel.saveData(data);
}

self.onConfigHidden = function() {
self.avrdudePathBroken(false);
self.avrdudePathOk(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
<option value=m1280>ATmega1280</option>
<option value=m1284p>ATmega1284p</option>
<option value=m2560>ATmega2560</option>
<option value=atmega32u4>ATmega32u4</option>
</select>
</div>
</div>
Expand All @@ -129,6 +130,7 @@
<select data-bind="value: configAvrdudeProgrammer">
<option value=></option>
<option value=arduino>arduino</option>
<option value=avr109>avr109</option>
<option value=usbasp>usbasp</option>
<option value=stk500v2>stk500v2</option>
<option value=wiring>wiring</option>
Expand Down Expand Up @@ -223,6 +225,15 @@
<span class="help-block">{{ _('Enables a link to the Firmware Updater in the OctoPrint navbar. (Reload after enabling/disabling.)') }}</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Remember URL') }}</label>
<div class="controls">
<div class="input">
<input type="checkbox" class="input-block-level" data-bind="checked: configSaveUrl">
</div>
<span class="help-block">{{ _('Last URL will be remembered when using \'Flash from URL\'.') }}</span>
</div>
</div>
<hr>

<!-- advanced options -->
Expand Down Expand Up @@ -552,7 +563,9 @@
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" data-bind="click: onConfigHidden" aria-hidden="true">{{ _('Cancel') }}</button>
<button class="btn btn-primary" data-bind="click: onConfigClose" aria-hidden="true">{{ _('Save') }}</button>
<button class="btn btn-primary" style="border-color: #04c #04c #002a80;" data-bind="click: onConfigClose, enable: !saving(), css: {disabled: saving()}" aria-hidden="true">
<i class="fas fa-spinner fa-spin" data-bind="visible: saving" style="display: none;"></i>{{ _(' Save') }}
</button>
</div>
</div>
<div id="BootLoaderWarning" class="modal hide fade">
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.7.6"
plugin_version = "1.7.7rc0"

# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
# module
Expand All @@ -33,7 +33,7 @@
plugin_license = "AGPLv3"

# Any additional requirements besides OctoPrint should be listed here
plugin_requires = []
plugin_requires = ["pyserial>=3.5"]

### --------------------------------------------------------------------------------------------------------------------
### More advanced options that you usually shouldn't have to touch follow after this point
Expand Down

0 comments on commit b521584

Please sign in to comment.