Skip to content

Commit

Permalink
Add a firmware upgrade utility.
Browse files Browse the repository at this point in the history
  • Loading branch information
mojocorp committed Nov 9, 2020
1 parent 7bc331b commit 8f162dd
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 14 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ execute_process(
message(STATUS "VERSION: ${MAESTRO_VERSION}")

add_subdirectory(src)
add_subdirectory(firmwares)

if(PYTHON_BINDING)
add_subdirectory(python)
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ The supported devices are:
- Mini Maestro 18-Channel USB Servo Controller (#1354, #1355)
- Mini Maestro 24-Channel USB Servo Controller (#1356, #1357)

## Upgrading Firmware

See the firmwares subdirectory for the instructions.

## Prerequisites

**On all platforms**
Expand Down
10 changes: 10 additions & 0 deletions firmwares/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@


install(FILES
README.md
FirmwareUpgradeUtility.py
usc02a_v1.04.pgm
usc03a_v1.03.pgm
usc03b_v1.03.pgm
usc03c_v1.03.pgm
DESTINATION firmwares)
97 changes: 97 additions & 0 deletions firmwares/FirmwareUpgradeUtility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env python

import sys
import os
import time

try:
import serial
except ImportError:
print(f'Pyserial is not installed for {sys.executable}.')
raise

try:
import serial.tools.list_ports as list_ports
except ImportError:
print(f'The installed version ({sys.VERSION}) of pyserial appears to be too old (Python interpreter {sys.executable}).')
raise

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def find_maestro_devices():
devices = []
for info in list_ports.comports(include_links=False):
port, desc, hwid = info
if 'Pololu' and 'Bootloader' in desc:
devices.append(port)
return sorted(devices)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def progress(count, total, status=''):
bar_len = 60
filled_len = int(round(bar_len * count / float(total)))

percents = round(100.0 * count / float(total), 1)
bar = '=' * filled_len + ' ' * (bar_len - filled_len)

sys.stdout.write('[%s] %s%s %s\r' % (bar, percents, '%', status))
sys.stdout.flush()

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def flash(firmware, serialPort):
# handshake
text=b'fwbootload'
serialPort.write(text)
answer = serialPort.read(len(text))
if answer != text.upper():
sys.exit(f'Expected {text.upper()} got {answer}')

print('Connected to Maestro bootloader.')

print('Erasing existing Maestro firmware...')
serialPort.write(b's')
answer = serialPort.read()

if answer != b'S':
print(f"There was error erasing the old firmware. Expected response 'S' from device but received response {answer}")
raise

print(f"Uploading new firmware...")
Position=0
while Position < len(firmware):
serialPort.flush()
serialPort.write(firmware[Position:Position+1000])
Position+=min(1000, len(firmware) - Position)
progress(Position, len(firmware))

time.sleep(0.2)
answer=serialPort.read(serialPort.in_waiting)

if (len(answer) == 0 or answer[-1] != 124) and serialPort.read() != 124:
print(f"Expected to receive the '|' character, but did not.")

print(f"\nUpload completed successfully.")
serialPort.write(b'*')
time.sleep(0.2)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def main(argv):
print(f'Pololu Maestro firmware upgrade utility\n')
if len(argv) != 2:
sys.exit(f'Usage: {argv[0]} firmware.pgm\n')

with open(argv[1], mode='rb') as file:
firmware = file.read()

devices = find_maestro_devices()

if len(devices) == 0:
sys.exit(f'No Maestro devices in bootloader mode connected.')
if len(devices) > 1:
sys.exit(f'More than one Maestro devices in bootloader mode connected.')

with serial.Serial(devices[0]) as serialPort:
flash(firmware, serialPort)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if __name__ == '__main__':
main(sys.argv)
16 changes: 3 additions & 13 deletions firmwares/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,7 @@ You can determine the version of your Maestro’s firmware by running the Maestr
All of your settings will be reset to default values during the firmware upgrade.

1. Determine which type of Maestro you have either by counting the number of channels or by looking at the name that appears in your Device Manager. There are four types of Maestro: the Micro Maestro 6-Channel USB Servo Controller (usc02a), the Mini Maestro 12-Channel USB Servo Controller (usc03a), the Mini Maestro 18-Channel USB Servo Controller (usc03b), and the Mini Maestro 24-Channel USB Servo Controller (usc03c).
2. Connect your Maestro to a Windows or Linux computer using a USB cable.
3. Run the Maestro Control Center and connect to the Maestro by selecting its serial number in the “Connected to:” drop-down box in the upper left corner.
4. If you were not able to connect to the Maestro using the Maestro Control Center, double-check your USB connection, make sure all other devices are disconnected from the Maestro, and try plugging it into several different USB ports on your computer. If you are still unable to connect to it, see the instructions in Section 4.f.1 for doing a hard bootloader reset.
5. Go to the Device menu and select “Upgrade firmware…”. You will see a message asking you if you are sure you want to proceed: click OK.
6. If you are using Windows XP and see a Found New Hardware Wizard window appear, then you should follow steps 6–8 from Section 3.a to get the bootloader’s driver working.
7. Once the Maestro is in bootloader mode and the bootloader’s drivers are properly installed, the green LED should be blinking in a double heart-beat pattern, and there should be an entry for the bootloader in the “Ports (COM & LPT)” list of your computer’s Device Manager.
8. Go to the window entitled “Firmware Upgrade” that the Maestro Control Center has opened.
9. Click the “Browse…” button and select the firmware file you downloaded. Make sure that the selected file is the right file for your type of Maestro (see steps 2 and 3).
10. Select the COM port corresponding to the bootloader. If you do not know which COM port to select, go to the Device Manager and look in the “Ports (COM & LPT)” section.
11. Click the “Program” button. You will see a message warning you that your device’s firmware is about to be erased and asking you if you are sure you want to proceed: click Yes.
12. It will take a few seconds to erase the Maestro’s existing firmware and load the new firmware. Do not disconnect the Maestro during the upgrade.
13. Once the upgrade is complete, the Firmware Upgrade window will close, the Maestro will disconnect from your computer, and it will reappear. If there is only one Maestro plugged in to your computer, the Maestro Control Center will connect to it. Check the firmware version number and make sure that it now indicates the latest version of the firmware.
2. Start your Maestro in bootloader mode (see Section 4.f.1 from the maestro.pdf).
3. Run the FirmwareUpgradeUtility.py python script

If you have problems during or after the firmware upgrade, then it is possible that you loaded the wrong firmware onto your Maestro or some other problem corrupted the firmware. The solution is to retry the firmware upgrade procedure above. Even if your Maestro is not recognized at all by your computer and you see no sign of life from it, the instructions in step 4 can help you get the Maestro into bootloader mode.
If you have problems during or after the firmware upgrade, then it is possible that you loaded the wrong firmware onto your Maestro or some other problem corrupted the firmware. The solution is to retry the firmware upgrade procedure above.
63 changes: 63 additions & 0 deletions firmwares/upgrade_firmware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env python

import sys
import os
import time
import serial
import maestro

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# chose an implementation, depending on os
#~ if sys.platform == 'cli':
#~ else:
if os.name == 'nt': # sys.platform == 'win32':
from serial.tools.list_ports_windows import comports
elif os.name == 'posix':
from serial.tools.list_ports_posix import comports
#~ elif os.name == 'java':
else:
raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def pololu_devices():
for info in comports(include_links=False):
port, desc, hwid = info
if 'Pololu' in desc:
yield info
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

devices = maestro.getConnectedDevices()

if len(devices) == 0:
sys.exit('No Maestro devices connected')

print("Pololu Maestro firmware upgrade")
for i,device in enumerate(devices):
print(f"{i}: {device.getName()}")
num = input("Enter device number to upgrade: ")

if not num.isdigit() or not 0 <= int(num) < len(devices):
sys.exit('wrong input')

print("Restarting bootloader...")
devices[int(num)].startBootloader()
time.sleep(3)

devices = pololu_devices()
if len(devices) == 0:
sys.exit('No Maestro devices in bootloader mode detected')

for i,(port, desc, hwid) in enumerate(devices):
print(f"{i}: {port}")
print(f" desc: {desc}")
print(f" hwid: {hwid}")

num = input("Enter device number to upgrade: ")
if not num.isdigit() or not 0 <= int(num) < len(devices):
sys.exit('wrong input')

ser = serial.Serial(devices[int(num)].port)
print(ser.name) # check which port was really used
ser.write(b'fwbootload') # write a string
line = ser.readline()
print(line)
ser.close()
2 changes: 1 addition & 1 deletion python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(pybind11)

pybind11_add_module(pymaestro maestro.cpp)
pybind11_add_module(pymaestro maestro.cpp example.py)
target_link_libraries(pymaestro PRIVATE maestro)
set_target_properties(pymaestro PROPERTIES FOLDER "python")
set_target_properties(pymaestro PROPERTIES OUTPUT_NAME "maestro")
Expand Down

0 comments on commit 8f162dd

Please sign in to comment.