Bootloader.h 6.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/*=====================================================================
 
 QGroundControl Open Source Ground Control Station
 
 (c) 2009, 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 
 This file is part of the QGROUNDCONTROL project
 
 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
 
 ======================================================================*/

/// @file
///     @author Don Gagne <don@thegagnes.com>

#ifndef Bootloader_H
#define Bootloader_H

#include "FirmwareImage.h"

#include "qextserialport.h"

#include <stdint.h>

/// Bootloader Utility routines. Works with PX4 bootloader and 3DR Radio bootloader.
class Bootloader : public QObject
{
    Q_OBJECT
    
public:
    explicit Bootloader(QObject *parent = 0);
    
    /// @brief Returns the error message associated with the last failed call to one of the bootloader
    ///         utility routine below.
    QString errorString(void) { return _errorString; }
    
    /// @brief Opens a port to the bootloader
    bool open(QextSerialPort* port, const QString portName);
    
    /// @brief Read a PROTO_SYNC response from the bootloader
    /// @return true: Valid sync response was received
    bool sync(QextSerialPort* port);
    
    /// @brief Erases the current program
    bool erase(QextSerialPort* port);
    
    /// @brief Program the board with the specified image
    bool program(QextSerialPort* port, const FirmwareImage* image);
    
    /// @brief Verify the board flash.
    bool verify(QextSerialPort* port, const FirmwareImage* image);
    
    /// @brief Retrieve a set of board info from the bootloader of PX4 FMU and PX4 Flow boards
    ///     @param bootloaderVersion Returned INFO_BL_REV
    ///     @param boardID Returned INFO_BOARD_ID
    ///     @param flashSize Returned INFO_FLASH_SIZE
    bool getPX4BoardInfo(QextSerialPort* port, uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize);
    
    /// @brief Retrieve the board id from a 3DR Radio
    bool get3DRRadioBoardId(QextSerialPort* port, uint32_t& boardID);
    
    /// @brief Sends a PROTO_REBOOT command to the bootloader
    bool reboot(QextSerialPort* port);
    
    // Supported bootloader board ids
    static const int boardIDPX4FMUV1 = 5;   ///< PX4 V1 board
    static const int boardIDPX4FMUV2 = 9;   ///< PX4 V2 board
    static const int boardIDPX4Flow = 6;    ///< PX4 Flow board
    static const int boardIDAeroCore = 98;  ///< Gumstix AeroCore board
    static const int boardID3DRRadio = 78;  ///< 3DR Radio
    
signals:
    /// @brief Signals progress indicator for long running bootloader utility routines
    void updateProgress(int curr, int total);
    
private:
    bool _binProgram(QextSerialPort* port, const FirmwareImage* image);
    bool _ihxProgram(QextSerialPort* port, const FirmwareImage* image);
    
    bool _write(QextSerialPort* port, const uint8_t* data, qint64 maxSize);
    bool _write(QextSerialPort* port, const uint8_t byte);
    
    bool _read(QextSerialPort* port, uint8_t* data, qint64 maxSize, int readTimeout = _readTimout);
    
    bool _sendCommand(QextSerialPort* port, uint8_t cmd, int responseTimeout = _responseTimeout);
    bool _getCommandResponse(QextSerialPort* port, const int responseTimeout = _responseTimeout);
    
    bool _getPX4BoardInfo(QextSerialPort* port, uint8_t param, uint32_t& value);
    
    bool _verifyBytes(QextSerialPort* port, const FirmwareImage* image);
    bool _binVerifyBytes(QextSerialPort* port, const FirmwareImage* image);
    bool _ihxVerifyBytes(QextSerialPort* port, const FirmwareImage* image);
    bool _verifyCRC(QextSerialPort* port);

    enum {
        // protocol bytes
        PROTO_INSYNC =          0x12,   ///< 'in sync' byte sent before status
        PROTO_EOC =             0x20,   ///< end of command
        
        // Reply bytes
        PROTO_OK =              0x10,   ///< INSYNC/OK      - 'ok' response
        PROTO_FAILED =          0x11,   ///< INSYNC/FAILED  - 'fail' response
        PROTO_INVALID =         0x13,	///< INSYNC/INVALID - 'invalid' response for bad commands
        
        // Command bytes
        PROTO_GET_SYNC =        0x21,   ///< NOP for re-establishing sync
        PROTO_GET_DEVICE =      0x22,   ///< get device ID bytes
        PROTO_CHIP_ERASE =      0x23,   ///< erase program area and reset program address
        PROTO_LOAD_ADDRESS =    0x24,	///< set next programming address
        PROTO_PROG_MULTI =      0x27,   ///< write bytes at program address and increment
        PROTO_GET_CRC =         0x29,	///< compute & return a CRC
        PROTO_BOOT =            0x30,   ///< boot the application
        
        // Command bytes - Rev 2 boootloader only
        PROTO_CHIP_VERIFY	=   0x24, ///< begin verify mode
        PROTO_READ_MULTI	=   0x28, ///< read bytes at programm address and increment
        
        INFO_BL_REV         =   1,    ///< bootloader protocol revision
        BL_REV_MIN          =   2,    ///< Minimum supported bootlader protocol
        BL_REV_MAX			=   4,    ///< Maximum supported bootloader protocol
        INFO_BOARD_ID		=   2,    ///< board type
        INFO_BOARD_REV		=   3,    ///< board revision
        INFO_FLASH_SIZE		=   4,    ///< max firmware size in bytes
        
        PROG_MULTI_MAX		=   64,   ///< write size for PROTO_PROG_MULTI, must be multiple of 4
        READ_MULTI_MAX		=   255   ///< read size for PROTO_READ_MULTI, must be multiple of 4
    };
    
    uint32_t    _boardID;           ///< board id for currently connected board
    uint32_t    _boardFlashSize;    ///< flash size for currently connected board
    uint32_t    _imageCRC;          ///< CRC for image in currently selected firmware file
    uint32_t    _bootloaderVersion; ///< Bootloader version
    
    QString _firmwareFilename;      ///< Currently selected firmware file to flash
    
    QString _errorString;           ///< Last error
    
    static const int _eraseTimeout = 20000;     ///< Msecs to wait for response from erase command
    static const int _rebootTimeout = 10000;    ///< Msecs to wait for reboot command to cause serial port to disconnect
    static const int _verifyTimeout = 5000;     ///< Msecs to wait for response to PROTO_GET_CRC command
    static const int _readTimout = 2000;        ///< Msecs to wait for read bytes to become avilable
    static const int _responseTimeout = 2000;   ///< Msecs to wait for command response bytes
};

#endif // PX4FirmwareUpgrade_H