Browse Source

More tweaks and error handling for the firmware upload.

pyserial_fix
Scott Petersen 9 years ago
parent
commit
8b9a45d4ee
3 changed files with 81 additions and 12 deletions
  1. +26
    -0
      alarmdecoder/devices.py
  2. +45
    -9
      alarmdecoder/util.py
  3. +10
    -3
      bin/ad2-firmwareupload

+ 26
- 0
alarmdecoder/devices.py View File

@@ -559,6 +559,12 @@ class USBDevice(Device):

return ret

def purge(self):
"""
Purges read/write buffers.
"""
self._device.purge_buffers()

def _get_serial_number(self):
"""
Retrieves the FTDI device serial number.
@@ -849,6 +855,13 @@ class SerialDevice(Device):

return ret

def purge(self):
"""
Purges read/write buffers.
"""
self._device.flushInput()
self._device.flushOutput()


class SocketDevice(Device):
"""
@@ -1144,6 +1157,19 @@ class SocketDevice(Device):

return ret

def purge(self):
"""
Purges read/write buffers.
"""
try:
self._device.setblocking(0)
while(self._device.recv(1)):
pass
except socket.error, err:
pass
finally:
self._device.setblocking(1)

def _init_ssl(self):
"""
Initializes our device as an SSL connection.


+ 45
- 9
alarmdecoder/util.py View File

@@ -38,6 +38,19 @@ class InvalidMessageError(Exception):
pass


class UploadError(Exception):
"""
Generic firmware upload error.
"""
pass

class UploadChecksumError(UploadError):
"""
The firmware upload failed due to a checksum error.
"""
pass


class Firmware(object):
"""
Represents firmware for the `AlarmDecoder`_ devices.
@@ -50,10 +63,12 @@ class Firmware(object):
STAGE_LOAD = 3
STAGE_UPLOADING = 4
STAGE_DONE = 5
STAGE_ERROR = 98
STAGE_DEBUG = 99

# FIXME: Rewrite this monstrosity.
@staticmethod
def upload(dev, filename, progress_callback=None):
def upload(dev, filename, progress_callback=None, debug=False):
"""
Uploads firmware to an `AlarmDecoder`_ device.

@@ -70,15 +85,29 @@ class Firmware(object):
Perform the actual firmware upload to the device.
"""
with open(filename) as upload_file:
line_cnt = 0
for line in upload_file:
line_cnt += 1
line = line.rstrip()

if line[0] == ':':
dev.write(line + "\r")
dev.read_line(timeout=5.0, purge_buffer=True)
response = dev.read_line(timeout=5.0, purge_buffer=True)
if debug:
stage_callback(Firmware.STAGE_DEBUG, data="line={0} - line={1} response={2}".format(line_cnt, line, response));

if '!ce' in response:
raise UploadChecksumError("Checksum error on line " + str(line_cnt) + " of " + filename);

if progress_callback is not None:
progress_callback(Firmware.STAGE_UPLOADING)
elif '!no' in response:
raise UploadError("Incorrect data sent to bootloader.")

elif '!ok' in response:
break

else:
if progress_callback is not None:
progress_callback(Firmware.STAGE_UPLOADING)

time.sleep(0.0)

@@ -100,6 +129,8 @@ class Firmware(object):

position = 0

dev.purge()

while timeout_event.reading:
try:
char = dev.read()
@@ -112,7 +143,7 @@ class Firmware(object):
else:
position = 0

except Exception:
except Exception, err:
pass

if timer:
@@ -121,10 +152,10 @@ class Firmware(object):
else:
raise TimeoutError('Timeout while waiting for line terminator.')

def stage_callback(stage):
def stage_callback(stage, **kwargs):
"""Callback to update progress for the specified stage."""
if progress_callback is not None:
progress_callback(stage)
progress_callback(stage, **kwargs)

if dev is None:
raise NoDeviceError('No device specified for firmware upload.')
@@ -152,11 +183,16 @@ class Firmware(object):
stage_callback(Firmware.STAGE_LOAD)
dev.write("=")
read_until('!load', timeout=15.0)

except TimeoutError, err:
retry -= 1
else:
retry = 0

# And finally do the upload.
do_upload()
stage_callback(Firmware.STAGE_DONE)
try:
do_upload()
except UploadError, err:
stage_callback(Firmware.STAGE_ERROR, error=err)
else:
stage_callback(Firmware.STAGE_DONE)

+ 10
- 3
bin/ad2-firmwareupload View File

@@ -1,9 +1,10 @@
#!/usr/bin/env python

import os
import sys, time
import alarmdecoder

def handle_firmware(stage):
def handle_firmware(stage, **kwargs):
if stage == alarmdecoder.util.Firmware.STAGE_START:
handle_firmware.wait_tick = 0
handle_firmware.upload_tick = 0
@@ -30,6 +31,10 @@ def handle_firmware(stage):
sys.stdout.flush()
elif stage == alarmdecoder.util.Firmware.STAGE_DONE:
print "\r\nDone!"
elif stage == alarmdecoder.util.Firmware.STAGE_ERROR:
print "\r\nError: {0}".format(kwargs.get("error", ""))
elif stage == alarmdecoder.util.Firmware.STAGE_DEBUG:
print "\r\nDBG: {0}".format(kwargs.get("data", ""))

def main():
device = '/dev/ttyUSB0'
@@ -47,18 +52,20 @@ def main():
if len(sys.argv) > 3:
baudrate = sys.argv[3]

debug = os.environ.get("ALARMDECODER_DEBUG") is not None

print "Flashing device: {0} - {2} baud\r\nFirmware: {1}".format(device, firmware, baudrate)

if ':' in device:
hostname, port = device.split(':')
dev = alarmdecoder.devices.SocketDevice(interface=(hostname, int(port)))
dev.open()
dev.open(no_reader_thread=True)
else:
dev = alarmdecoder.devices.SerialDevice(interface=device)
dev.open(baudrate=baudrate, no_reader_thread=True)

time.sleep(3)
alarmdecoder.util.Firmware.upload(dev, firmware, handle_firmware)
alarmdecoder.util.Firmware.upload(dev, firmware, handle_firmware, debug=debug)

dev.close()



Loading…
Cancel
Save