diff --git a/companion/src/storage/firmwareinterface.cpp b/companion/src/storage/firmwareinterface.cpp index 922bb8171..03af54579 100644 --- a/companion/src/storage/firmwareinterface.cpp +++ b/companion/src/storage/firmwareinterface.cpp @@ -22,7 +22,6 @@ #include "hexinterface.h" #include "firmwareinterface.h" #include "helpers.h" -#include "storage.h" #include #include @@ -35,6 +34,18 @@ #define EEPR_MARK "EEPR" #define FSIZE_MAX Boards::getFlashSize(Board::BOARD_UNKNOWN) +#define UF2_HEADER_SIZE 32 +#define UF2_BLOCK_SIZE 512 +#define UF2_MAGICSTART0 0x0A324655 +#define UF2_MAGICSTART1 0x9E5D5157 +#define UF2_MAGICEND 0x0AB16F30 +#define UF2_FLAG_NOT_MAIN_FLASH 0x00000001 +#define UF2_FLAG_FILE_CONTAINER 0x00001000 +#define UF2_FLAG_FAMILYID_PRESENT 0x00002000 +#define UF2_FLAG_MD5_CHECKSUM_PRESENT 0x00004000 +#define UF2_FLAG_EXT_FLAGS_PRESENT 0x00008000 + + class RleBitmap { public: @@ -185,6 +196,12 @@ void FirmwareInterface::initFlash(const QByteArray& flashData) if (flashSize > 0) { type = (flash.startsWith("UF2\n") ? FIRMWARE_TYPE_UF2 : FIRMWARE_TYPE_BIN); + if (type == FIRMWARE_TYPE_UF2 && !concatUF2Payloads(flash)) { + qDebug() << "Unable to concatenate UF2 payloads"; + isValidFlag = false; + return; + } + flavour = seekLabel(FW_MARK).remove("edgetx-"); version = seekLabel(VERS_MARK); @@ -484,3 +501,45 @@ unsigned int FirmwareInterface::save(const QString & filename) free(binflash); return flashSize; } + +bool FirmwareInterface::concatUF2Payloads(QByteArray & flashData) +{ + qsizetype flashSize = flashData.size(); + int lastBlock = -1; + UF2_Block uf2Block; + QByteArray out; + QByteArray ba; + qsizetype totalBytesRead = 0; + + do { + ba = flashData.mid(totalBytesRead, UF2_BLOCK_SIZE); + qsizetype bytesRead = ba.size(); + + if (bytesRead < UF2_BLOCK_SIZE) { + qDebug() << "bytes read" << bytesRead << "less than expected" << UF2_BLOCK_SIZE; + break; + } + + totalBytesRead += bytesRead; + + memcpy(&uf2Block, ba.constData(), sizeof(UF2_Block)); + + if (uf2Block.magicStart0 != UF2_MAGICSTART0 || + uf2Block.magicStart1 != UF2_MAGICSTART1 || + uf2Block.magicEnd != UF2_MAGICEND) { + qDebug() << "unexpected magic numbers"; + return false; + } + + if ((int)uf2Block.blockNo != ++lastBlock) { + qDebug() << "Block out of sequence"; + return false; + } + + out.append(ba.mid(UF2_HEADER_SIZE, uf2Block.payloadSize)); + + } while (totalBytesRead < flashSize); + + flashData = out; + return true; +} diff --git a/companion/src/storage/firmwareinterface.h b/companion/src/storage/firmwareinterface.h index 1b72446b6..a2b6ad0b6 100644 --- a/companion/src/storage/firmwareinterface.h +++ b/companion/src/storage/firmwareinterface.h @@ -50,6 +50,20 @@ class FirmwareInterface FIRMWARE_TYPE_UF2 }; + struct UF2_Block { + // 32 byte header + uint32_t magicStart0; // 0x0A324655 ("UF2\n") + uint32_t magicStart1; // 0x9E5D5157 + uint32_t flags; // see cpp defines + uint32_t targetAddr; // Address in flash where the data should be written + uint32_t payloadSize; // Number of bytes used in data (often 256) + uint32_t blockNo; // Sequential block number; starts at 0 + uint32_t numBlocks; // Total number of blocks in file + uint32_t fileSize; // or familyID; + uint8_t data[476]; // Data, padded with zeros + uint32_t magicEnd; // 0x0AB16F30 + }; + explicit FirmwareInterface(const QString &filename, QDialog* parent = nullptr); explicit FirmwareInterface(const QByteArray &flashData, QDialog* parent = nullptr); @@ -95,10 +109,11 @@ class FirmwareInterface bool isValidFlag = false; FirmwareType type; - void initFlash(const QByteArray& flashData); + void initFlash(const QByteArray & flashData); QString seekString(const QString & string); QString seekLabel(const QString & label); void seekSplash(); bool seekSplash(QByteArray sps, QByteArray spe, int size); bool seekSplash(QByteArray splash); + bool concatUF2Payloads(QByteArray & flashData); };