/*===================================================================== QGroundControl Open Source Ground Control Station (c) 2009, 2014 QGROUNDCONTROL PROJECT 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 . ======================================================================*/ /// @file /// @brief PX4 Bootloader Utility routines /// @author Don Gagne #ifndef PX4Bootloader_H #define PX4Bootloader_H #include "qextserialport.h" #include /// @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 bool write(QextSerialPort* port, const uint8_t* data, qint64 maxSize); bool write(QextSerialPort* port, const uint8_t byte); /// @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 bool read(QextSerialPort* port, uint8_t* data, qint64 maxSize, bool warnOnError, int readTimeout = _readTimout); /// @brief Read a PROTO_SYNC command response from the bootloader /// @param responseTimeout Msecs to wait for response bytes to become available on port bool getCommandResponse(QextSerialPort* port, bool warnOnError, const int responseTimeout = _responseTimeout); /// @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 bool getBoardInfo(QextSerialPort* port, uint8_t param, uint32_t& value); /// @brief Send a command to the bootloader /// @param cmd Command to send using PROTO_* enums /// @return true: Command sent and valid sync response returned bool sendCommand(QextSerialPort* port, uint8_t cmd, bool warnOnError, int responseTimeout = _responseTimeout); /// @brief Program the board with the specified firmware bool program(QextSerialPort* port, const QString& firmwareFilename); /// @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 bool verify(QextSerialPort* port, const QString firmwareFilename); /// @brief Read a PROTO_SYNC response from the bootloader /// @return true: Valid sync response was received bool sync(QextSerialPort* port); /// @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 bool getBoardInfo(QextSerialPort* port, uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize); /// @brief Opens a port to the bootloader bool open(QextSerialPort* port, const QString portName); /// @brief Sends a PROTO_REBOOT command to the bootloader bool sendBootloaderReboot(QextSerialPort* port); /// @brief Sends a PROTO_ERASE command to the bootlader bool erase(QextSerialPort* port); 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 READ_MULTI_MAX = 32 ///< read size for PROTO_READ_MULTI, must be multiple of 4 }; bool _findBootloader(void); bool _downloadFirmware(void); bool _bootloaderVerifyRev2(QextSerialPort* port, const QString firmwareFilename); bool _bootloaderVerifyRev3(QextSerialPort* port); 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