/dfu

Primary LanguageC++

dfu

Delta Device Firmware Upgrade codec. In case of question about protocol contact Alari, and about implementation Ilya.

Guide

using namespace dfu

Decoder toolset consists of decode(), which returns decoded chunk, status err, and pointer to next byte past last interpreted. For convenient use in range-based for loop there is seq wrapper, which decodes adjacent items in a sequence one by one. Range safely stops at anything invalid. Encoder can be created with memory provided by user as view, or self-contained template as codec<>. To pass either of those to handler functions use ref and cref. All these classes provide same functionality through CRTP base class, so no overhead of virtual function calls, and no unnecessary pointer to self-contained memory for codec<>. Both de/encoder are fully constexpr.

Examples

Encode

const uint8_t test[17] = {0xde, 0xad, 0xbe, 0xef};

dfu::codec<99> codec;

codec.encode_raw({0x55, 0x66, 0x77});
codec.encode_rep(0x42, 100);
codec.encode_rep(0x66, 1);
codec.encode_arr({0x01, 0x02, 0x03}, 1);
codec.encode_arr(test, 256);
codec.encode_off(-8191, 1024);

dfu::log_seq(codec);

>>>

+-----------HEX-----------+
| 20 55 66 77 35 06 42 01  66 22 00 01 02 03 06 01  | Ufw5.B.f"......|
| ff de ad be ef 00 00 00  00 00 00 00 00 00 00 00  |................|
| 00 00 f7 3f 05 80                                 |...?............|
+--------DIAGNOSTIC-------+
| 1) RAW [        3] 
| 55 66 77                                          |Ufw.............|
| 2) REP [      100] byte 0x42 
| 3) REP [        1] byte 0x66 
| 4) ARR [        3] reps 1 
| 01 02 03                                          |................|
| 5) ARR [       17] reps 256 
| de ad be ef 00 00 00 00  00 00 00 00 00 00 00 00  |................|
| 00                                                |................|
| 6) OLD [     1024] offs -8191 
+-------------------------+

Decode

const uint8_t data[] = {...};
const size_t requested_address = 0x4000;

for (auto chunk : dfu::seq{data}) {
    switch (chunk.type)
    {
    case dfu::type_raw:
        flash_write(chunk.raw, chunk.size);
    break;
    case dfu::type_rep:
        for (size_t i = 0; i < chunk.size; ++i)
            flash_write(&chunk.rep, 1);
    break;
    case dfu::type_arr:
        for (size_t i = 0; i < chunk.arr.reps; ++i)
            flash_write(chunk.arr.data, chunk.size);
    break;
    case dfu::type_off: {
        static uint8_t tmp[512];
        size_t processed = 0;
        size_t base_addr = chunk.off + int(requested_address);
        while (processed < chunk.size) {
            auto len = MIN(chunk.size - processed, sizeof(tmp));
            flash_read_old_fw(base_addr + processed, tmp, len);
            flash_write(tmp, len);
            processed += len;
        }
    }
    break;
    default:
        puts("failure: invalid type");
        return;
    }
}

TODO

  • source
    • dec
    • enc
  • tests
    • dec
    • enc
  • reamde
    • intro
    • guide
    • examples