-----------------------------------------------------------------------------------------
Introduction
-----------------------------------------------------------------------------------------

Firmware built for the MTS Dragonfly includes a bootloader.  This bootloader supports a
simple CLI (Command Line Interface) and is capable of flashing new firmware into the
Dragonfly.  The rest of this document describes those two features in detail.


-----------------------------------------------------------------------------------------
Bootloader CLI (Command Line Interface)
-----------------------------------------------------------------------------------------

The bootloader is equipped with a simple command line interface.  It can be accessed
with the following steps:
    * Connect your favorite terminal program to the virtual serial port provided
      by the USB debug connection between the device and your PC (COMXX on Windows,
      /dev/ttyACMXX on Linux)
    * Set your terminal program to run at 115200 baud
    * Reset the device while holding any key on the keyboard
    * You should see a prompt appear that looks something like "bootloader:>"
    * Your bootloader is now in CLI mode and ready to execute commands (see below)

There are a number of commands the bootloader supports in CLI mode:

    help        
                Print a list of available commands, each with a short description.

    boot        
                Start the application currently saved in the microcontroller's flash.

    upgrade <method>
                Transfer new firmware over serial to external flash, validate the
                new firmware, and flash the new firmware if it is valid. A success
                or failure message will be displayed. Current available methods are
                "simple".
                If using the "simple" method, the python script "send_file.py"
                should be used to stream the firmware from your computer to
                the device.

    transfer <method>
                Transfer new firmware over serial to external flash. Do not
                validate or attempt to flash the new firmware. A success or
                failure message will be displayed.
                If using the "simple" method, the python script "recv_file.py"
                should be used to stream the file from the device to your
                computer.

    send <method> <filename>
                Send a file currently stored in the filesystem on the external
                flash.  Current available methods are "simple".
                If using the "simple" method, the python script "recv_file.py"
                should be used to stream the file from the device to your
                computer.

    recv <method> <filename>
                Receive a file to be stored in the filesystem on the external
                flash.  Current available methods are "simple".
                If using the "simple" method, the python script "send_file.py"
                should be used to stream the file from your computer to the
                device.

    flash       
                Validate new firmware already in external flash and flash it
                if it is valid. A success or failure message will be displayed.

    reset       
                Perform a soft reset of the system.

    delete <filename>
                Delete the specified file from the filesystem if it exists.

    erase       
                Completely erase the external flash.  This is a timed operation
                and takes several seconds to complete.  All data on the external
                flash, including all files in the filesystem, will be totally erased.
                This operation is not reversible.  Data cannot be recovered from this
                operation.


-----------------------------------------------------------------------------------------
Firmware Upgrade Procedure
-----------------------------------------------------------------------------------------

When the device is powered on, the bootloader executes before starting the application
currently saved in the microcontroller's flash.  If the bootloader finds new firmware
in the filesystem on the external flash, it will start the upgrade process.

There is a specific name the new firmware file must have in order for it to be
recognized by the bootloader.  That name is "fw_upgrade.bin".

There is also a log file the bootloader maintains which contains a record of attempted
firmware upgrades.  That file is called "result.txt".

A typical OTA (Over The Air) upgrade might look like the following:
    * User application opens file "fw_upgrade.bin" for writing
    * User application streams new firmware into file
    * User application closes file
    * User application performs a soft reset of the device
    * The bootloader discovers the new firmware
    * The bootloader upgrades the firmware on the device
    * The bootloader performs a soft reset of the device
    * The devices is now running the new firmware
    * The most recent entries in "result.txt" are a record of the attempted firmware
      upgrade

The upgrade process consists of the following steps:
    * Validation of the firmware
        * A CRC32 checksum is read from the end of the firmware
        * A CRC32 checksum is computed from the rest of the firmware
        * These checksums must match in order for the upgrade to continue
    * Backup of the old firmware
        * The current contents of the microcontroller's flash are copied to a file
          in the external flash
        * This operation must succeed in order for the ugprade to continue
    * Flash the new firmware
        * The application sectors of the microcontroller's flash are erased
        * The new application is copied into the microcontroller's flash
    * Cleanup
        * Erase the new firmware file in the external flash
        * Erase the backup firmware file in the external flash
    * Reset
        * The device should start executing the new application upon reset

If flashing the new firmware fails, the bootloader will attempt to restore the old
firmware that was backed up to the external flash.  If that operation also fails, the
bootloader will print an error message to the USB debug port.  However, if the device
gets into this state, it will appear to be locked up because there is no application
in the microcontroller's flash to execute.  In this situation, the bootloader can
still be interrupted and enter CLI mode (as described above).

New firmware can be transferred to the device via the "upgrade" and "transfer"
commands in bootloader CLI mode.  The included script, send_file.py, is the other
side of the file transfer process.  The script and the bootloader use a simple
serial protocol to communicate, allowing the script to stream the new firmware
to the bootloader in small chunks.  The following steps explain how to use this script
to transfer new firmware to the device:
    * Connect the Dragonfly's second serial port to a serial port on your PC.  This
      is the "data port" for the file transfer, while the USB debug port is the
      "command port"
    * Start the send_file.py script with the proper arguments
        python send_file.py -p <data port> -f <new firmware>
    * Put the device in bootloader CLI mode as described above
    * Give either the "upgrade" or "transfer" command
    * You should start to see logging from both the device and the script
    * The script should exit when the transfer is complete
    * The bootloader should print the results of the transfer (success or failure)
    * If you gave the "upgrade" command, the bootloader should continue with the
      validation and flashing steps as described above

The bootloader and python script use a simple serial protocol to communicate.  There
are four command bytes used by both sides:

    SEND    0xAF
    DATA    0x1A
    DONE    0xFA
    ERR     0x1F

When the script is started, and after each chunk it sent, it waits for the SEND command
before transmitting the next chunk.  A chunk is composed of the following parts:

    Type    1 byte
    Size    4 bytes
    Data    Size bytes

When there is no data left to transmit, the script sends a DONE byte.  The bootloader
then knows that all data has been transmitted and it can move on.

If either side encounters an error or receives an unknown packet, an ERR byte will be
transmitted and the transfer will be aborted.

An example of what a successful transfer would look like is as follows:

Script                                      Bootloader
------                                      ----------
Started by user                                 |
Waiting for SEND                                |
    |                                       Enter CLI mode
    |                                           |
    |                                       Give "transfer" command
    |                                           |
    <-------------------------------------- send SEND byte
send DATA byte --------------------------------->
send size (4 bytes) ---------------------------->
send size bytes of data ------------------------>
Waiting for SEND                                |
    |                                       write data to file
    |                                           |
    <-------------------------------------- send SEND byte
send DATA byte --------------------------------->
send size (4 bytes) ---------------------------->
send size bytes of data ------------------------>
Waiting for SEND                                |
    |                                       write data to file
    |                                           |

   ...                                         ...

    |                                           |
    |                                           |
    <-------------------------------------- send SEND byte
send DATA byte --------------------------------->
send size (4 bytes) ---------------------------->
send size bytes of data ------------------------>
Waiting for SEND                                |
    |                                       write data to file
    |                                           |
    <-------------------------------------- send SEND byte
send DATA byte --------------------------------->
send size (4 bytes) ---------------------------->
send size bytes of data ------------------------>
Waiting for SEND                                |
    |                                       write data to file
    |                                           |
    <-------------------------------------- send SEND byte
send DONE byte --------------------------------->
exit
    |                                       return control to user

