Previously, I didn't realize that lpc21isp calculated the checksum in
the interrupt table, so I didn't make Alpaca ISP do that. This caused a
few hours of confusion, followed by a quick change to make Alpaca ISP
calculate the checksum and insert it into the right part of sector 0.
Now programs flashed with Alpaca ISP actually run, so that's good.
A few other changes have been made as well. Flash sectors are now
written in the order that lpc21isp uses, first counting up from sector 1
then ending with sector 0. The first 64 bytes are not compared when
verifying flash. If verification fails, an exception is raised, and if
the package was run as a program, it exits before launching the code on
the microcontroller.
Now Alpaca ISP can verify that the flash was successfully written. It
does a full comparison of the data, which is perhaps a bit heavy-handed
given that we're mostly worried about random bit errors. Maybe I'll
eventually implement a CRC32-based verify routine for faster but less
perfect verification.
Now the code has been split into several files to keep things better
organized. Chip definitions are in chips.py, exceptions are in
exceptions.py, and LPC and friends are in lpc.py. __init__.py has a new
function that provides the best way to create an LPC object, handling
all the boring bits of control, synchronization, and changing the type.
This commit adds a main function to the alpaca_isp package, which will
eventually allow flashing microcontrollers from the command line but for
now mostly parses command-line arguments. There's more work to do
before I can get on with the real flashing (microcontroller-specific
stuff, Intel HEX stuff).
Now that I've implemented the protocol, I see how commands actually give
return values isn't how I thought it would be. Accordingly,
_send_command now only returns the ReturnCode rather than wrapping it in
a list. This allowed me to remove a few [0]s.
As with the other commands that take a range of flash sectors, the end
is optional. I returns None if the sectors are blank, or an offset and
value if the sectors are not blank.
The new prepare_write method provides a Python interface to the P
command. If only one sector needs to be prepared, the end sector number
can be omitted.
Now the ISPError is raised from the _send_command method, not each
caller. There will be a few cases where I need that to not be an
exception, but I can just wrap it in a try block then, so there's no
problem.
Now instead of returning codes, the methods of LPC raise exceptions with
the information the chip returned.
The new read_memory method implements Python bindings for the R command.
The LPC class now has properties for getting and setting echo, baudrate,
and stopbits. Low-level access is now private to avoid letting users
break the public properties.
Also, a new write_ram method implements the W command. If no number of
bytes is specified, the length of the data is used.
Now we have code to connect to the serial port, put the LPC into ISP
mode, unlock the flash, and update echo and serial port settings. The
code's way nicer than lpc21isp so far, which is all I really wanted I
guess.