/* sbc_harness/uf2.h - Universal Flashing Format * * Copyright (C) 2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include /* for memcpy(), memcmp() */ #include #define IMPLEMENTATION_FOR_UF2_H YES #include "uf2.h" #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define UF2_FLAG_NOTMAIN 0x00000001 #define UF2_FLAG_CONTAINER 0x00001000 #define UF2_FLAG_FAMILYID 0x00002000 #define UF2_FLAG_MD5SUM 0x00004000 #define UF2_FLAG_EXTENSION 0x00008000 static const uint8_t uf2_magic_beg[8] = { 'U', 'F', '2', '\n', 0x57, 0x51, 0x5D, 0x9E }; static const uint8_t uf2_magic_end[4] = { 0x30, 0x6F, 0xB1, '\n' }; static size_t_and_error uf2_decoder_write(struct uf2_decoder *self, const char *dat, size_t len_in) { assert(self); assert(ctx); if (!len_in) return ERROR_AND(size_t, 0, ERROR_NULL); assert(dat); if (self->seen_err) return ERROR_AND(size_t, 0, error_new(E_POSIX_ESPIPE, "write after error")); size_t len_consumed = 0; while (len_consumed < len_in) { size_t n = MIN(512 - self->len_dat, /* how much we're willing to take */ len_in - len_consumed); /* how much we're being offered */ memcpy(&self->dat[self->dat_len], &dat[len_consumed], n); self->dat_len += n; len_consumed += n; if (self->dat_len != 512) continue; if (memcmp(&self->dat[0], uf2_magic_beg, 8)) { self->seen_err = true; return ERROR_AND(size_t, len_consumed, error_new(E_POSIX_EPROTO, "block does not begin with magic")); } if (memcmp(&self->dat[512-4], uf2_magic_end, 4)) { self->seen_err = true; return ERROR_AND(size_t, len_consumed, error_new(E_POSIX_EPROTO, "block does not end with magic")); } uint32_t flag = uint32le_decode(&self->dat[8]); uint32_t addr = uint32le_decode(&self->dat[12]); uint32_t size = uint32le_decode(&self->dat[16]); uint32_t bnum = uint32le_decode(&self->dat[20]); uint32_t bcnt = uint32le_decode(&self->dat[24]); uint32_t famid = uint32le_decode(&self->dat[28]); uint8_t *data = &self->dat[32]; // TODO } assert(len_consumed == len_in); return ERROR_AND(size_t, len_in, ERROR_NULL); } size_t_and_error uf2_decoder_writev(struct uf2_decoder *self, const struct iovec *iov, int iovcnt) { assert(self); assert(iov); assert(iovcnt); size_t total = 0; for (int i = 0; i < iovcnt; i++) { size_t_and_error r = uf2_decoder_write(self, iov[i].iov_base, iov[i].iov_len); total += r.size_t; if (!ERROR_IS_NULL(r.err)) return ERROR_AND(size_t, total, r.err); } return ERROR_AND(size_t, total, ERROR_NULL); }