PX4Bootloader.h 7.72 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
/*=====================================================================
 
 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
///     @brief PX4 Bootloader Utility routines
///     @author Don Gagne <don@thegagnes.com>

#ifndef PX4Bootloader_H
#define PX4Bootloader_H

31
#include "qextserialport.h"
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

#include <stdint.h>

/// @brief This class is used to communicate with the Bootloader.
class PX4Bootloader : public QObject
{
    Q_OBJECT
    
public:
    explicit PX4Bootloader(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; }

    static const bool warnOnError = true;       ///< call qWarning to log error message on error
    static const bool noWarnOnError = false;    ///< Don't call qWarning on error
    
    /// @brief Write a byte to the port
    ///     @param port Port to write to
    ///     @param data Bytes to write
    ///     @param maxSize Number of bytes to write
    /// @return true: success
55 56
    bool write(QextSerialPort* port, const uint8_t* data, qint64 maxSize);
    bool write(QextSerialPort* port, const uint8_t byte);
57 58 59 60 61 62
    
    /// @brief Read a set of bytes from the port
    ///     @param data Read bytes into this buffer
    ///     @param maxSize Number of bytes to read
    ///     @param warnOnError true: Log error using qWarning
    ///     @param readTimeout Msecs to wait for bytes to become available on port
63
    bool read(QextSerialPort* port, uint8_t* data, qint64 maxSize, bool warnOnError, int readTimeout = _readTimout);
64 65 66
    
    /// @brief Read a PROTO_SYNC command response from the bootloader
    ///     @param responseTimeout Msecs to wait for response bytes to become available on port
67
    bool getCommandResponse(QextSerialPort* port, bool warnOnError, const int responseTimeout = _responseTimeout);
68 69 70 71
    
    /// @brief Send a PROTO_GET_DEVICE command to retrieve a value from the bootloader
    ///     @param param Value to retrieve using INFO_BOARD_* enums
    ///     @param value Returned value
72
    bool getBoardInfo(QextSerialPort* port, uint8_t param, uint32_t& value);
73 74 75 76
    
    /// @brief Send a command to the bootloader
    ///     @param cmd Command to send using PROTO_* enums
    /// @return true: Command sent and valid sync response returned
77
    bool sendCommand(QextSerialPort* port, uint8_t cmd, bool warnOnError, int responseTimeout = _responseTimeout);
78 79
    
    /// @brief Program the board with the specified firmware
80
    bool program(QextSerialPort* port, const QString& firmwareFilename);
81 82 83 84
    
    /// @brief Verify the board flash. How it works depend on bootloader rev
    ///         Rev 2: Read the flash back and compare it against the firmware file
    ///         Rev 3: Compare CRCs for flash and file
85
    bool verify(QextSerialPort* port, const QString firmwareFilename);
86 87 88
    
    /// @brief Read a PROTO_SYNC response from the bootloader
    /// @return true: Valid sync response was received
89
    bool sync(QextSerialPort* port);
90 91 92 93 94
    
    /// @brief Retrieve a set of board info from the bootloader
    ///     @param bootloaderVersion Returned INFO_BL_REV
    ///     @param boardID Returned INFO_BOARD_ID
    ///     @param flashSize Returned INFO_FLASH_SIZE
95
    bool getBoardInfo(QextSerialPort* port, uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize);
96 97
    
    /// @brief Opens a port to the bootloader
98
    bool open(QextSerialPort* port, const QString portName);
99 100
    
    /// @brief Sends a PROTO_REBOOT command to the bootloader
101
    bool sendBootloaderReboot(QextSerialPort* port);
102 103
    
    /// @brief Sends a PROTO_ERASE command to the bootlader
104
    bool erase(QextSerialPort* port);
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
    
signals:
    /// @brief Signals progress indicator for long running bootloader utility routines
    void updateProgramProgress(int curr, int total);
    
private:
    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_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		= 32,   ///< write size for PROTO_PROG_MULTI, must be multiple of 4
141
        READ_MULTI_MAX		= 32    ///< read size for PROTO_READ_MULTI, must be multiple of 4
142 143 144 145
    };
    
    bool _findBootloader(void);
    bool _downloadFirmware(void);
146 147
    bool _bootloaderVerifyRev2(QextSerialPort* port, const QString firmwareFilename);
    bool _bootloaderVerifyRev3(QextSerialPort* port);
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    
    static const int _boardIDPX4FMUV1 = 5;  ///< Board ID for PX4 V1 board
    static const int _boardIDPX4FMUV2 = 9;  ///< Board ID for PX4 V2 board
    static const int _boardIDPX4Flow = 6;   ///< Board ID for PX4 Floaw board
    
    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