UF2 is a file format, developed by Microsoft for PXT (also known as Microsoft MakeCode), that is particularly suitable for flashing microcontrollers over MSC (Mass Storage Class; aka removable flash drive).
The list of family IDs is stored in a separate JSON file:
https://github.com/microsoft/uf2/blob/master/utils/uf2families.json
This JSON file is regularly updated. The family_id enum should be kept in
sync with it. For simplicity and consistency, it's strongly recommended to
auto-generate this enum from uf2families.json directly. This was last done
using the following commands:
$ curl -fsSLO https://github.com/microsoft/uf2/raw/90e9741f217f5a40c98ba74d663e408041037578/utils/uf2families.json
$ jq -r '
.[]
| " \(.id | ascii_downcase):\n"
+ " id: \(.short_name | ascii_downcase | gsub("-"; "_"))\n"
+ " doc: \(.description | tojson)"
' uf2families.json
Test files, picked to cover as many different shapes as possible:
num_blocks.family_id::rp2xxx_absolute block that picotool prepends (see the
is_rp2350_e10_block value instance in the block type).file_size rather
than family_id.family_id::rp2040) is moved to the end of the second file, which was
intended for family_id::rp2xxx_absolute (see
https://github.com/raspberrypi/pico-examples/blob/c81c855ffdedc825975a40ba357723a71358ddf0/universal/CMakeLists.txt#L159-L169).flags.is_file_container flag set (for
example
https://github.com/microsoft/pxt-microsoft-boot-sequence/releases/download/v0.0.4/arcade-p0.uf2
is a pure file container for
file_name == "Projects/microsoft-boot-sequence.elf"). Generated by
MakeCode, the only known producer of file container UF2s.This page hosts a formal specification of UF2 (USB Flashing Format) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#![allow(unused_imports)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(irrefutable_let_patterns)]
#![allow(unused_comparisons)]
extern crate kaitai;
use kaitai::*;
use std::convert::{TryFrom, TryInto};
use std::cell::{Ref, Cell, RefCell};
use std::rc::{Rc, Weak};
/**
* UF2 is a file format, developed by Microsoft for PXT (also known as
* Microsoft MakeCode), that is particularly suitable for flashing
* microcontrollers over MSC (Mass Storage Class; aka removable flash drive).
*
* The list of family IDs is stored in a separate JSON file:
*
* <https://github.com/microsoft/uf2/blob/master/utils/uf2families.json>
*
* This JSON file is regularly updated. The `family_id` enum should be kept in
* sync with it. For simplicity and consistency, it's strongly recommended to
* auto-generate this enum from `uf2families.json` directly. This was last done
* using the following commands:
*
* ```bash
* $ curl -fsSLO https://github.com/microsoft/uf2/raw/90e9741f217f5a40c98ba74d663e408041037578/utils/uf2families.json
* $ jq -r '
* .[]
* | " \(.id | ascii_downcase):\n"
* + " id: \(.short_name | ascii_downcase | gsub("-"; "_"))\n"
* + " doc: \(.description | tojson)"
* ' uf2families.json
* ```
*
* Test files, picked to cover as many different shapes as possible:
*
* * <https://micropython.org/download/RPI_PICO/> - a typical case: all blocks
* have the same family ID and `num_blocks`.
* * <https://micropython.org/download/RPI_PICO2/> - these .uf2 files are
* actually two UF2 files concatenated. The first UF2 file is the standalone
* `family_id::rp2xxx_absolute` block that `picotool` prepends (see the
* `is_rp2350_e10_block` value instance in the `block` type).
* * <https://circuitpython.org/downloads> - the builds for SAMD boards (for
* example
* [Feather M0 Express](https://circuitpython.org/board/feather_m0_express/))
* set no flags at all, so the field at offset 28 is read as `file_size` rather
* than `family_id`.
* * <https://github.com/raspberrypi/pico-sdk-prebuilts/releases> -
* [Universal UF2](https://github.com/raspberrypi/pico-examples/blob/c81c855ffdedc825975a40ba357723a71358ddf0/universal/README.md#universal-binary-vs-universal-uf2)
* files, which are again two UF2 files concatenated. What's interesting about
* these is that the last block of the first file (with the family ID
* `family_id::rp2040`) is moved to the end of the second file, which was
* intended for `family_id::rp2xxx_absolute` (see
* <https://github.com/raspberrypi/pico-examples/blob/c81c855ffdedc825975a40ba357723a71358ddf0/universal/CMakeLists.txt#L159-L169>).
* * <https://github.com/microsoft/pxt-microsoft-boot-sequence/releases> - some
* files contain blocks with the `flags.is_file_container` flag set (for
* example
* <https://github.com/microsoft/pxt-microsoft-boot-sequence/releases/download/v0.0.4/arcade-p0.uf2>
* is a pure file container for
* `file_name == "Projects/microsoft-boot-sequence.elf"`). Generated by
* MakeCode, the only known producer of file container UF2s.
* * <https://github.com/umi-eng/uftwo/tree/35bccf75b4f81c43f088696a8c4a9912f1f4104e/uftwo/tests> -
* synthetic test files for features that real firmware doesn't seem to use
* (e.g. MD5 checksums).
* \sa https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md Source
*/
#[derive(Default, Debug, Clone)]
pub struct Uf2 {
pub _root: SharedType<Uf2>,
pub _parent: SharedType<Uf2>,
pub _self: SharedType<Self>,
first_block: RefCell<OptRc<Uf2_Block>>,
blocks: RefCell<Vec<OptRc<Uf2_Block>>>,
_io: RefCell<BytesReader>,
}
impl KStruct for Uf2 {
type Root = Uf2;
type Parent = Uf2;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
let t = Self::read_into::<_, Uf2_Block>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
*self_rc.first_block.borrow_mut() = t;
*self_rc.blocks.borrow_mut() = Vec::new();
let l_blocks = ((*self_rc.first_block().num_blocks()? as u32) - (1 as u32));
for _i in 0..l_blocks {
let t = Self::read_into::<_, Uf2_Block>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
self_rc.blocks.borrow_mut().push(t);
}
Ok(())
}
}
impl Uf2 {
}
impl Uf2 {
pub fn first_block(&self) -> Ref<'_, OptRc<Uf2_Block>> {
self.first_block.borrow()
}
}
impl Uf2 {
pub fn blocks(&self) -> Ref<'_, Vec<OptRc<Uf2_Block>>> {
self.blocks.borrow()
}
}
impl Uf2 {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum Uf2_ExtensionTagType {
/**
* According to the official spec, this type should be used in the last tag
* with `len_tag == 0`, which terminates the list of extension tags.
*/
End,
/**
* Page size of the target device, as a 32-bit unsigned number
*/
PageSize,
/**
* Description of the device for which the firmware file is destined
* (UTF-8)
*/
Description,
/**
* The block is to be ignored. This value doesn't come from the official
* spec, but from the Raspberry Pi Pico SDK. It's written with no value, so
* the whole tag is the 4 bytes `04 e3 57 99`. See the
* `is_rp2350_e10_block` value instance in the `block` type.
* \sa https://github.com/raspberrypi/pico-sdk/blob/98a542c1a62fb549ffb5d66a3e5892b06276b670/src/common/boot_uf2_headers/include/boot/uf2.h#L46 Git tag "2.3.0"
*/
Rp2IgnoreBlock,
/**
* Version of the firmware file, as a UTF-8 semver string
*/
Version,
/**
* SHA-2 checksum of firmware (can be of various sizes)
*/
Sha2Checksum,
/**
* Device type identifier, a refinement of `family_id` meant to identify a
* kind of device rather than only an MCU. 32-bit or 64-bit number. Can be
* a hash of the `extension_tag_type::description` tag.
*/
DeviceTypeId,
Unknown(i64),
}
impl TryFrom<i64> for Uf2_ExtensionTagType {
type Error = KError;
fn try_from(flag: i64) -> KResult<Uf2_ExtensionTagType> {
match flag {
0 => Ok(Uf2_ExtensionTagType::End),
780791 => Ok(Uf2_ExtensionTagType::PageSize),
6622621 => Ok(Uf2_ExtensionTagType::Description),
10049507 => Ok(Uf2_ExtensionTagType::Rp2IgnoreBlock),
10471356 => Ok(Uf2_ExtensionTagType::Version),
11824560 => Ok(Uf2_ExtensionTagType::Sha2Checksum),
13149993 => Ok(Uf2_ExtensionTagType::DeviceTypeId),
_ => Ok(Uf2_ExtensionTagType::Unknown(flag)),
}
}
}
impl From<&Uf2_ExtensionTagType> for i64 {
fn from(v: &Uf2_ExtensionTagType) -> Self {
match *v {
Uf2_ExtensionTagType::End => 0,
Uf2_ExtensionTagType::PageSize => 780791,
Uf2_ExtensionTagType::Description => 6622621,
Uf2_ExtensionTagType::Rp2IgnoreBlock => 10049507,
Uf2_ExtensionTagType::Version => 10471356,
Uf2_ExtensionTagType::Sha2Checksum => 11824560,
Uf2_ExtensionTagType::DeviceTypeId => 13149993,
Uf2_ExtensionTagType::Unknown(v) => v
}
}
}
impl Default for Uf2_ExtensionTagType {
fn default() -> Self { Uf2_ExtensionTagType::Unknown(0) }
}
#[derive(Debug, PartialEq, Clone)]
pub enum Uf2_FamilyId {
/**
* ST STM32L4xx
*/
Stm32l4,
/**
* ST STM32L5xx
*/
Stm32l5,
/**
* ST STM32F411xC
*/
Stm32f411xc,
/**
* M0SENSE BL702
*/
M0sense,
/**
* Microchip (Atmel) ATmega32
*/
Atmega32,
/**
* Microchip (Atmel) SAML21
*/
Saml21,
/**
* Nordic NRF52
*/
Nrf52,
/**
* ESP32
*/
Esp32,
/**
* ST STM32L1xx
*/
Stm32l1,
/**
* ST STM32L0xx
*/
Stm32l0,
/**
* ST STM32WLxx
*/
Stm32wl,
/**
* Realtek AmebaZ RTL8710B
*/
Rtl8710b,
/**
* NXP LPC55xx
*/
Lpc55,
/**
* ESP32-C2
*/
Esp32c2,
/**
* ST STM32F411xE
*/
Stm32f411xe,
/**
* ST STM32G0xx
*/
Stm32g0,
/**
* ESP32-S31
*/
Esp32s31,
/**
* GD32F350
*/
Gd32f350,
/**
* ESP32-H2
*/
Esp32h2,
/**
* Realtek AmebaD RTL8720D
*/
Rtl8720d,
/**
* ESP32-P4
*/
Esp32p4,
/**
* Sipeed MaixPlay-U4(BL618)
*/
MaixplayU4,
/**
* ST STM32G4xx
*/
Stm32g4,
/**
* ST STM32H5xx
*/
Stm32h5,
/**
* LISTENAI CSK300x/400x
*/
Csk4,
/**
* NXP i.MX RT10XX
*/
Mimxrt10xx,
/**
* Xradiotech 809
*/
Xr809,
/**
* ST STM32F7xx
*/
Stm32f7,
/**
* ESP32-C6
*/
Esp32c6,
/**
* Microchip (Atmel) SAMD51
*/
Samd51,
/**
* ST STM32F4xx
*/
Stm32f4,
/**
* Cypress FX2
*/
Fx2,
/**
* ST STM32F2xx
*/
Stm32f2,
/**
* ST STM32F103
*/
Stm32f1,
/**
* Nordic NRF52833
*/
Nrf52833,
/**
* ST STM32F0xx
*/
Stm32f0,
/**
* Beken 7231U/7231T
*/
Bk7231u,
/**
* Microchip (Atmel) SAMD21
*/
Samd21,
/**
* WCH CH32V2xx and CH32V3xx
*/
Ch32v,
/**
* Beken 7251/7252
*/
Bk7251,
/**
* ST STM32F3xx
*/
Stm32f3,
/**
* ST STM32F407
*/
Stm32f407,
/**
* ST STM32H7xx
*/
Stm32h7,
/**
* LISTENAI CSK60xx
*/
Csk6,
/**
* Nordic NRF52832xxAB
*/
Nrf52832xxab,
/**
* ST STM32WBxx
*/
Stm32wb,
/**
* Nordic NRF52832xxAA
*/
Nrf52832xxaa,
/**
* Analog Devices MAX32690
*/
Max32690,
/**
* ESP32-C61
*/
Esp32c61,
/**
* Beken 7231N
*/
Bk7231n,
/**
* Renesas RA4M1
*/
Ra4m1,
/**
* Quansheng UV-K5 V3 amateur radio based on Puya Semiconductor PY32F071
*/
Py32f071Uvk5V3,
/**
* ESP8266
*/
Esp8266,
/**
* NXP KL32L2x
*/
Kl32l2,
/**
* Nordic NRF52820_xxAA
*/
Nrf52820,
/**
* ST STM32F407VG
*/
Stm32f407vg,
/**
* Analog Devices MAX78002
*/
Max78002,
/**
* Renesas RZ/A1LU (R7S7210xx)
*/
Rza1lu,
/**
* GigaDevice GD32VF103
*/
Gd32vf103,
/**
* ESP32-H4
*/
Esp32h4,
/**
* Realtek Ameba1 RTL8710A
*/
Rtl8710a,
/**
* ArteryTek AT32F415
*/
At32f415,
/**
* Nordic NRF52840
*/
Nrf52840,
/**
* ESP32-H21
*/
Esp32h21,
/**
* ESP32-S2
*/
Esp32s2,
/**
* ESP32-S3
*/
Esp32s3,
/**
* ESP32-C3
*/
Esp32c3,
/**
* Analog Devices MAX32650/1/2
*/
Max32650,
/**
* Boufallo 602
*/
Bl602,
/**
* Realtek AmebaZ2 RTL8720C
*/
Rtl8720c,
/**
* Raspberry Pi RP2040
*/
Rp2040,
/**
* Raspberry Pi Microcontrollers: Absolute (unpartitioned) download
*/
Rp2xxxAbsolute,
/**
* Raspberry Pi Microcontrollers: Data partition download
*/
Rp2xxxData,
/**
* Raspberry Pi RP2350, Secure Arm image
*/
Rp2350ArmS,
/**
* Raspberry Pi RP2350, RISC-V image
*/
Rp2350Riscv,
/**
* Raspberry Pi RP2350, Non-secure Arm image
*/
Rp2350ArmNs,
/**
* Analog Devices MAX32665/6
*/
Max32666,
/**
* ESP32-C5
*/
Esp32c5,
Unknown(i64),
}
impl TryFrom<i64> for Uf2_FamilyId {
type Error = KError;
fn try_from(flag: i64) -> KResult<Uf2_FamilyId> {
match flag {
16738585 => Ok(Uf2_FamilyId::Stm32l4),
69471199 => Ok(Uf2_FamilyId::Stm32l5),
114362747 => Ok(Uf2_FamilyId::Stm32f411xc),
299792458 => Ok(Uf2_FamilyId::M0sense),
374814231 => Ok(Uf2_FamilyId::Atmega32),
407992330 => Ok(Uf2_FamilyId::Saml21),
458716255 => Ok(Uf2_FamilyId::Nrf52),
475996592 => Ok(Uf2_FamilyId::Esp32),
505365293 => Ok(Uf2_FamilyId::Stm32l1),
539900561 => Ok(Uf2_FamilyId::Stm32l0),
558239728 => Ok(Uf2_FamilyId::Stm32wl),
585160444 => Ok(Uf2_FamilyId::Rtl8710b),
716994540 => Ok(Uf2_FamilyId::Lpc55),
730387100 => Ok(Uf2_FamilyId::Esp32c2),
767756741 => Ok(Uf2_FamilyId::Stm32f411xe),
806311475 => Ok(Uf2_FamilyId::Stm32g0),
822212545 => Ok(Uf2_FamilyId::Esp32s31),
835856582 => Ok(Uf2_FamilyId::Gd32f350),
858203894 => Ok(Uf2_FamilyId::Esp32h2),
863621090 => Ok(Uf2_FamilyId::Rtl8720d),
1026592404 => Ok(Uf2_FamilyId::Esp32p4),
1265126769 => Ok(Uf2_FamilyId::MaixplayU4),
1282483210 => Ok(Uf2_FamilyId::Stm32g4),
1318001757 => Ok(Uf2_FamilyId::Stm32h5),
1332399698 => Ok(Uf2_FamilyId::Csk4),
1337120189 => Ok(Uf2_FamilyId::Mimxrt10xx),
1374225320 => Ok(Uf2_FamilyId::Xr809),
1404571392 => Ok(Uf2_FamilyId::Stm32f7),
1410195298 => Ok(Uf2_FamilyId::Esp32c6),
1427194976 => Ok(Uf2_FamilyId::Samd51),
1467308631 => Ok(Uf2_FamilyId::Stm32f4),
1511523995 => Ok(Uf2_FamilyId::Fx2),
1561987630 => Ok(Uf2_FamilyId::Stm32f2),
1591873650 => Ok(Uf2_FamilyId::Stm32f1),
1646171002 => Ok(Uf2_FamilyId::Nrf52833),
1685595318 => Ok(Uf2_FamilyId::Stm32f0),
1733968048 => Ok(Uf2_FamilyId::Bk7231u),
1760373640 => Ok(Uf2_FamilyId::Samd21),
1771791084 => Ok(Uf2_FamilyId::Ch32v),
1786956866 => Ok(Uf2_FamilyId::Bk7251),
1803837832 => Ok(Uf2_FamilyId::Stm32f3),
1829315322 => Ok(Uf2_FamilyId::Stm32f407),
1840668802 => Ok(Uf2_FamilyId::Stm32h7),
1853049000 => Ok(Uf2_FamilyId::Csk6),
1869948536 => Ok(Uf2_FamilyId::Nrf52832xxab),
1892771411 => Ok(Uf2_FamilyId::Stm32wb),
1920081230 => Ok(Uf2_FamilyId::Nrf52832xxaa),
1947226634 => Ok(Uf2_FamilyId::Max32690),
2010665156 => Ok(Uf2_FamilyId::Esp32c61),
2067722800 => Ok(Uf2_FamilyId::Bk7231n),
2078840685 => Ok(Uf2_FamilyId::Ra4m1),
2105173743 => Ok(Uf2_FamilyId::Py32f071Uvk5V3),
2125160941 => Ok(Uf2_FamilyId::Esp8266),
2139350931 => Ok(Uf2_FamilyId::Kl32l2),
2181929567 => Ok(Uf2_FamilyId::Nrf52820),
2410701054 => Ok(Uf2_FamilyId::Stm32f407vg),
2446589208 => Ok(Uf2_FamilyId::Max78002),
2501329455 => Ok(Uf2_FamilyId::Rza1lu),
2599435827 => Ok(Uf2_FamilyId::Gd32vf103),
2651564682 => Ok(Uf2_FamilyId::Esp32h4),
2684343619 => Ok(Uf2_FamilyId::Rtl8710a),
2697558926 => Ok(Uf2_FamilyId::At32f415),
2913282112 => Ok(Uf2_FamilyId::Nrf52840),
3067936943 => Ok(Uf2_FamilyId::Esp32h21),
3218951918 => Ok(Uf2_FamilyId::Esp32s2),
3296614247 => Ok(Uf2_FamilyId::Esp32s3),
3559628908 => Ok(Uf2_FamilyId::Esp32c3),
3594487346 => Ok(Uf2_FamilyId::Max32650),
3725750455 => Ok(Uf2_FamilyId::Bl602),
3767498084 => Ok(Uf2_FamilyId::Rtl8720c),
3834380118 => Ok(Uf2_FamilyId::Rp2040),
3834380119 => Ok(Uf2_FamilyId::Rp2xxxAbsolute),
3834380120 => Ok(Uf2_FamilyId::Rp2xxxData),
3834380121 => Ok(Uf2_FamilyId::Rp2350ArmS),
3834380122 => Ok(Uf2_FamilyId::Rp2350Riscv),
3834380123 => Ok(Uf2_FamilyId::Rp2350ArmNs),
4039314801 => Ok(Uf2_FamilyId::Max32666),
4145808195 => Ok(Uf2_FamilyId::Esp32c5),
_ => Ok(Uf2_FamilyId::Unknown(flag)),
}
}
}
impl From<&Uf2_FamilyId> for i64 {
fn from(v: &Uf2_FamilyId) -> Self {
match *v {
Uf2_FamilyId::Stm32l4 => 16738585,
Uf2_FamilyId::Stm32l5 => 69471199,
Uf2_FamilyId::Stm32f411xc => 114362747,
Uf2_FamilyId::M0sense => 299792458,
Uf2_FamilyId::Atmega32 => 374814231,
Uf2_FamilyId::Saml21 => 407992330,
Uf2_FamilyId::Nrf52 => 458716255,
Uf2_FamilyId::Esp32 => 475996592,
Uf2_FamilyId::Stm32l1 => 505365293,
Uf2_FamilyId::Stm32l0 => 539900561,
Uf2_FamilyId::Stm32wl => 558239728,
Uf2_FamilyId::Rtl8710b => 585160444,
Uf2_FamilyId::Lpc55 => 716994540,
Uf2_FamilyId::Esp32c2 => 730387100,
Uf2_FamilyId::Stm32f411xe => 767756741,
Uf2_FamilyId::Stm32g0 => 806311475,
Uf2_FamilyId::Esp32s31 => 822212545,
Uf2_FamilyId::Gd32f350 => 835856582,
Uf2_FamilyId::Esp32h2 => 858203894,
Uf2_FamilyId::Rtl8720d => 863621090,
Uf2_FamilyId::Esp32p4 => 1026592404,
Uf2_FamilyId::MaixplayU4 => 1265126769,
Uf2_FamilyId::Stm32g4 => 1282483210,
Uf2_FamilyId::Stm32h5 => 1318001757,
Uf2_FamilyId::Csk4 => 1332399698,
Uf2_FamilyId::Mimxrt10xx => 1337120189,
Uf2_FamilyId::Xr809 => 1374225320,
Uf2_FamilyId::Stm32f7 => 1404571392,
Uf2_FamilyId::Esp32c6 => 1410195298,
Uf2_FamilyId::Samd51 => 1427194976,
Uf2_FamilyId::Stm32f4 => 1467308631,
Uf2_FamilyId::Fx2 => 1511523995,
Uf2_FamilyId::Stm32f2 => 1561987630,
Uf2_FamilyId::Stm32f1 => 1591873650,
Uf2_FamilyId::Nrf52833 => 1646171002,
Uf2_FamilyId::Stm32f0 => 1685595318,
Uf2_FamilyId::Bk7231u => 1733968048,
Uf2_FamilyId::Samd21 => 1760373640,
Uf2_FamilyId::Ch32v => 1771791084,
Uf2_FamilyId::Bk7251 => 1786956866,
Uf2_FamilyId::Stm32f3 => 1803837832,
Uf2_FamilyId::Stm32f407 => 1829315322,
Uf2_FamilyId::Stm32h7 => 1840668802,
Uf2_FamilyId::Csk6 => 1853049000,
Uf2_FamilyId::Nrf52832xxab => 1869948536,
Uf2_FamilyId::Stm32wb => 1892771411,
Uf2_FamilyId::Nrf52832xxaa => 1920081230,
Uf2_FamilyId::Max32690 => 1947226634,
Uf2_FamilyId::Esp32c61 => 2010665156,
Uf2_FamilyId::Bk7231n => 2067722800,
Uf2_FamilyId::Ra4m1 => 2078840685,
Uf2_FamilyId::Py32f071Uvk5V3 => 2105173743,
Uf2_FamilyId::Esp8266 => 2125160941,
Uf2_FamilyId::Kl32l2 => 2139350931,
Uf2_FamilyId::Nrf52820 => 2181929567,
Uf2_FamilyId::Stm32f407vg => 2410701054,
Uf2_FamilyId::Max78002 => 2446589208,
Uf2_FamilyId::Rza1lu => 2501329455,
Uf2_FamilyId::Gd32vf103 => 2599435827,
Uf2_FamilyId::Esp32h4 => 2651564682,
Uf2_FamilyId::Rtl8710a => 2684343619,
Uf2_FamilyId::At32f415 => 2697558926,
Uf2_FamilyId::Nrf52840 => 2913282112,
Uf2_FamilyId::Esp32h21 => 3067936943,
Uf2_FamilyId::Esp32s2 => 3218951918,
Uf2_FamilyId::Esp32s3 => 3296614247,
Uf2_FamilyId::Esp32c3 => 3559628908,
Uf2_FamilyId::Max32650 => 3594487346,
Uf2_FamilyId::Bl602 => 3725750455,
Uf2_FamilyId::Rtl8720c => 3767498084,
Uf2_FamilyId::Rp2040 => 3834380118,
Uf2_FamilyId::Rp2xxxAbsolute => 3834380119,
Uf2_FamilyId::Rp2xxxData => 3834380120,
Uf2_FamilyId::Rp2350ArmS => 3834380121,
Uf2_FamilyId::Rp2350Riscv => 3834380122,
Uf2_FamilyId::Rp2350ArmNs => 3834380123,
Uf2_FamilyId::Max32666 => 4039314801,
Uf2_FamilyId::Esp32c5 => 4145808195,
Uf2_FamilyId::Unknown(v) => v
}
}
}
impl Default for Uf2_FamilyId {
fn default() -> Self { Uf2_FamilyId::Unknown(0) }
}
#[derive(Default, Debug, Clone)]
pub struct Uf2_Block {
pub _root: SharedType<Uf2>,
pub _parent: SharedType<Uf2>,
pub _self: SharedType<Self>,
magic: RefCell<Vec<u8>>,
second_magic: RefCell<Vec<u8>>,
flags: RefCell<OptRc<Uf2_Flags>>,
target_address: RefCell<u32>,
len_payload: RefCell<u32>,
block_number: RefCell<u32>,
num_blocks_raw: RefCell<u32>,
file_size: RefCell<u32>,
family_id: RefCell<Uf2_FamilyId>,
data: RefCell<OptRc<Uf2_BlockData>>,
final_magic: RefCell<Vec<u8>>,
_io: RefCell<BytesReader>,
data_raw: RefCell<Vec<u8>>,
f_is_rp2350_e10_block: Cell<bool>,
is_rp2350_e10_block: RefCell<bool>,
f_num_blocks: Cell<bool>,
num_blocks: RefCell<u32>,
}
impl KStruct for Uf2_Block {
type Root = Uf2;
type Parent = Uf2;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.magic.borrow_mut() = _io.read_bytes(4 as usize)?.into();
if !(*self_rc.magic() == vec![0x55u8, 0x46u8, 0x32u8, 0xau8]) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::NotEqual, src_path: "/types/block/seq/0".to_string() }));
}
*self_rc.second_magic.borrow_mut() = _io.read_bytes(4 as usize)?.into();
if !(*self_rc.second_magic() == vec![0x57u8, 0x51u8, 0x5du8, 0x9eu8]) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::NotEqual, src_path: "/types/block/seq/1".to_string() }));
}
let t = Self::read_into::<_, Uf2_Flags>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
*self_rc.flags.borrow_mut() = t;
*self_rc.target_address.borrow_mut() = _io.read_u4le()?.into();
let _tmpa = *self_rc.target_address();
if !(((((_tmpa as u32) % (4 as u32)) as i32) == (0 as i32))) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::Expr, src_path: "/types/block/seq/3".to_string() }));
}
*self_rc.len_payload.borrow_mut() = _io.read_u4le()?.into();
let _tmpa = *self_rc.len_payload();
if !(((((_tmpa as u32) % (4 as u32)) as i32) == (0 as i32))) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::Expr, src_path: "/types/block/seq/4".to_string() }));
}
*self_rc.block_number.borrow_mut() = _io.read_u4le()?.into();
*self_rc.num_blocks_raw.borrow_mut() = _io.read_u4le()?.into();
if !(((*self_rc.num_blocks_raw() as i32) >= (((*self_rc.block_number() as u32) + (1 as u32)) as i32))) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::LessThan, src_path: "/types/block/seq/6".to_string() }));
}
if !(*self_rc.flags().has_family_id()?) {
*self_rc.file_size.borrow_mut() = _io.read_u4le()?.into();
}
if *self_rc.flags().has_family_id()? {
*self_rc.family_id.borrow_mut() = (_io.read_u4le()? as i64).try_into()?;
}
*self_rc.data_raw.borrow_mut() = _io.read_bytes(476 as usize)?.into();
let data_raw = self_rc.data_raw.borrow();
let _t_data_raw_io = BytesReader::from(data_raw.clone());
let t = Self::read_into::<BytesReader, Uf2_BlockData>(&_t_data_raw_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
*self_rc.data.borrow_mut() = t;
*self_rc.final_magic.borrow_mut() = _io.read_bytes(4 as usize)?.into();
if !(*self_rc.final_magic() == vec![0x30u8, 0x6fu8, 0xb1u8, 0xau8]) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::NotEqual, src_path: "/types/block/seq/10".to_string() }));
}
Ok(())
}
}
impl Uf2_Block {
/**
* Determines whether this is a block that `picotool` prepends to RP2350
* flash images as a workaround for erratum RP2350-E10 (i.e. a hardware
* bug in the A2 version of the RP2350 boot ROM).
*
* Such a block is always written on its own, but its `num_blocks_raw` is
* set to 2. If we trusted this value, we would attempt to read one block
* too many (which would most likely fail). Therefore, we must correct it
* to 1 before using it.
*
* The conditions for detecting this block come from the
* [`check_abs_block()`](https://github.com/raspberrypi/picotool/blob/6f6458d792b93685a11423b244a585eaa99eafcf/elf2uf2/elf2uf2.cpp#L147)
* function in `picotool`. However, there are some differences:
*
* 1. In Kaitai Struct, we cannot easily check whether all 256 payload
* bytes are set to `0xef`, so we only check the first and last bytes.
* 2. There are .uf2 files in the wild where `flags.has_extension_tags`
* is true, but there are actually no extension tags (the first and
* only tag has a size of 0, which is just a terminator), so our
* condition allows for this case. You can download an example of such
* a .uf2 file here:
* <https://github.com/neednotapply/DC32-cfw/releases/tag/1.69.13.37>
*
* It's worth noting that we cannot require the presence of the
* `extension_tag_type::rp2_ignore_block`
* (`UF2_EXTENSION_RP2_IGNORE_BLOCK`) tag because the UF2 files generated
* by `picotool` prior to
* <https://github.com/raspberrypi/picotool/commit/78c9bd121b09399823b67ee7ea89003ca0d3315f>
* don't have it. Therefore, we check whether this tag is present only if
* `flags.has_extension_tags` is set.
*
* Test .uf2 files with this special block can be downloaded from
* <https://micropython.org/download/RPI_PICO2/>. Note that all the .uf2
* files there are actually two UF2 (sub)files concatenated, and this
* Kaitai Struct implementation parses only one at a time (so in order to
* parse both, you need something like the helper spec `uf2_files.ksy`
* from
* <https://github.com/kaitai-io/kaitai_struct_formats/pull/542#discussion_r3906386820>).
* v1.24.x releases predate the `extension_tag_type::rp2_ignore_block`
* tag, while releases v1.25.0 and later include it.
* \sa https://github.com/raspberrypi/picotool/blob/6f6458d792b93685a11423b244a585eaa99eafcf/elf2uf2/elf2uf2.cpp#L147 Git tag "2.3.0"
* \sa https://github.com/raspberrypi/picotool/commit/78c9bd121b09399823b67ee7ea89003ca0d3315f Source
*/
pub fn is_rp2350_e10_block(
&self
) -> KResult<Ref<'_, bool>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_is_rp2350_e10_block.get() {
return Ok(self.is_rp2350_e10_block.borrow());
}
self.f_is_rp2350_e10_block.set(true);
*self.is_rp2350_e10_block.borrow_mut() = ( (( ((((*self.flags().value() as i32) == (8192 as i32))) || (((*self.flags().value() as i32) == (40960 as i32)))) ) && (*self.family_id() == Uf2_FamilyId::Rp2xxxAbsolute) && (((*self.num_blocks_raw() as u32) == (2 as u32))) && (((*self.block_number() as u32) == (0 as u32))) && (((*self.len_payload() as i32) == (256 as i32))) && (*self.data().payload().first().ok_or(KError::EmptyIterator)? == 239) && (*self.data().payload().last().ok_or(KError::EmptyIterator)? == 239) && ( ((!(*self.flags().has_extension_tags()?)) || (((*self.data().extension_tags()[0 as usize].len_tag() as u8) == (0 as u8))) || ( ((((*self.data().extension_tags()[0 as usize].len_tag() as u8) == (4 as u8))) && (*self.data().extension_tags()[0 as usize].tag_type() == Uf2_ExtensionTagType::Rp2IgnoreBlock)) )) )) ) as bool;
Ok(self.is_rp2350_e10_block.borrow())
}
pub fn num_blocks(
&self
) -> KResult<Ref<'_, u32>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_num_blocks.get() {
return Ok(self.num_blocks.borrow());
}
self.f_num_blocks.set(true);
*self.num_blocks.borrow_mut() = (if *self.is_rp2350_e10_block()? { 1 } else { *self.num_blocks_raw() }) as u32;
Ok(self.num_blocks.borrow())
}
}
impl Uf2_Block {
pub fn magic(&self) -> Ref<'_, Vec<u8>> {
self.magic.borrow()
}
}
impl Uf2_Block {
pub fn second_magic(&self) -> Ref<'_, Vec<u8>> {
self.second_magic.borrow()
}
}
impl Uf2_Block {
pub fn flags(&self) -> Ref<'_, OptRc<Uf2_Flags>> {
self.flags.borrow()
}
}
/**
* Address in flash where `data.payload` should be written, or an offset
* in the file specified by `data.file_name` if `flags.is_file_container`
* is set.
*
* The [official
* spec](https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#payload-sizes)
* says:
*
* > In any event, payload size and target address should always be
* > 4-byte aligned.
*/
impl Uf2_Block {
pub fn target_address(&self) -> Ref<'_, u32> {
self.target_address.borrow()
}
}
/**
* The [official
* spec](https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#payload-sizes)
* says:
*
* > In any event, payload size and target address should always be
* > 4-byte aligned.
*/
impl Uf2_Block {
pub fn len_payload(&self) -> Ref<'_, u32> {
self.len_payload.borrow()
}
}
impl Uf2_Block {
pub fn block_number(&self) -> Ref<'_, u32> {
self.block_number.borrow()
}
}
/**
* Number of blocks that make up the UF2 file to which this block
* belongs. Every block of a file has the same value. It is at least 1
* and every `block_number` in the file must be less than this value
* (which is validated by this Kaitai Struct implementation).
*/
impl Uf2_Block {
pub fn num_blocks_raw(&self) -> Ref<'_, u32> {
self.num_blocks_raw.borrow()
}
}
/**
* Size of the file this block belongs to, but only if
* `flags.is_file_container` is true. Otherwise, the official spec allows
* this field to be set to anything - though in practice, it's always
* zero.
*/
impl Uf2_Block {
pub fn file_size(&self) -> Ref<'_, u32> {
self.file_size.borrow()
}
}
impl Uf2_Block {
pub fn family_id(&self) -> Ref<'_, Uf2_FamilyId> {
self.family_id.borrow()
}
}
impl Uf2_Block {
pub fn data(&self) -> Ref<'_, OptRc<Uf2_BlockData>> {
self.data.borrow()
}
}
impl Uf2_Block {
pub fn final_magic(&self) -> Ref<'_, Vec<u8>> {
self.final_magic.borrow()
}
}
impl Uf2_Block {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
impl Uf2_Block {
pub fn data_raw(&self) -> Ref<'_, Vec<u8>> {
self.data_raw.borrow()
}
}
#[derive(Default, Debug, Clone)]
pub struct Uf2_BlockData {
pub _root: SharedType<Uf2>,
pub _parent: SharedType<Uf2_Block>,
pub _self: SharedType<Self>,
payload: RefCell<Vec<u8>>,
file_name: RefCell<String>,
extension_tags: RefCell<Vec<OptRc<Uf2_ExtensionTag>>>,
_io: RefCell<BytesReader>,
f_md5_checksum: Cell<bool>,
md5_checksum: RefCell<OptRc<Uf2_Md5Checksum>>,
}
impl KStruct for Uf2_BlockData {
type Root = Uf2;
type Parent = Uf2_Block;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.payload.borrow_mut() = _io.read_bytes(*_prc.as_ref().unwrap().len_payload() as usize)?.into();
if *_prc.as_ref().unwrap().flags().is_file_container()? {
*self_rc.file_name.borrow_mut() = bytes_to_str(&_io.read_bytes_term(0, false, true, true)?.into(), "UTF-8")?;
}
if *_prc.as_ref().unwrap().flags().has_extension_tags()? {
*self_rc.extension_tags.borrow_mut() = Vec::new();
{
let mut _i = 0;
while {
let t = Self::read_into::<_, Uf2_ExtensionTag>(&*_io, Some(self_rc._root.clone()), Some(self_rc._self.clone()))?.into();
self_rc.extension_tags.borrow_mut().push(t);
let _t_extension_tags = self_rc.extension_tags.borrow();
let _tmpa = _t_extension_tags.last().unwrap();
_i += 1;
let x = !(((*_tmpa.len_tag() as u8) == (0 as u8)));
x
} {}
}
}
Ok(())
}
}
impl Uf2_BlockData {
/**
* Describes a region that doesn't need to be flashed again if the
* checksum matches.
*
* The [official
* spec](https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#md5-checksum)
* says that "This is currently only used on ESP32", but no real-world
* firmware sample has been found (at least none of the .uf2 files from
* <https://github.com/adafruit/tinyuf2/releases>,
* [MicroPython](https://micropython.org/download/) or
* [CircuitPython](https://circuitpython.org/downloads) contain it). It
* was found only in some synthetic test files, e.g.
* <https://github.com/umi-eng/uftwo/blob/35bccf75b4f81c43f088696a8c4a9912f1f4104e/uftwo/tests/checksum_256.uf2>.
*/
pub fn md5_checksum(
&self
) -> KResult<Ref<'_, OptRc<Uf2_Md5Checksum>>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_md5_checksum.get() {
return Ok(self.md5_checksum.borrow());
}
if *_prc.as_ref().unwrap().flags().has_md5_checksum()? {
let _pos = _io.pos();
_io.seek(((_io.size() as i32) - (24 as i32)) as usize)?;
let t = Self::read_into::<_, Uf2_Md5Checksum>(&*_io, Some(self._root.clone()), Some(self._self.clone()))?.into();
*self.md5_checksum.borrow_mut() = t;
_io.seek(_pos)?;
}
Ok(self.md5_checksum.borrow())
}
}
/**
* The bytes to be written to `_parent.target_address`, which is either
* an address in flash, or an offset in the file specified by `file_name`
* if `_parent.flags.is_file_container` is set.
*/
impl Uf2_BlockData {
pub fn payload(&self) -> Ref<'_, Vec<u8>> {
self.payload.borrow()
}
}
impl Uf2_BlockData {
pub fn file_name(&self) -> Ref<'_, String> {
self.file_name.borrow()
}
}
impl Uf2_BlockData {
pub fn extension_tags(&self) -> Ref<'_, Vec<OptRc<Uf2_ExtensionTag>>> {
self.extension_tags.borrow()
}
}
impl Uf2_BlockData {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
/**
* \sa https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#extension-tags Source
*/
#[derive(Default, Debug, Clone)]
pub struct Uf2_ExtensionTag {
pub _root: SharedType<Uf2>,
pub _parent: SharedType<Uf2_BlockData>,
pub _self: SharedType<Self>,
len_tag: RefCell<u8>,
tag_type: RefCell<Uf2_ExtensionTagType>,
value: RefCell<Vec<u8>>,
padding: RefCell<Vec<u8>>,
_io: RefCell<BytesReader>,
f_len_value: Cell<bool>,
len_value: RefCell<i32>,
f_min_len_tag: Cell<bool>,
min_len_tag: RefCell<i32>,
}
impl KStruct for Uf2_ExtensionTag {
type Root = Uf2;
type Parent = Uf2_BlockData;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.len_tag.borrow_mut() = _io.read_u1()?.into();
let _tmpa = *self_rc.len_tag();
if !( ((((_tmpa as u8) == (0 as u8))) || (((_tmpa as i32) >= (*self_rc.min_len_tag()? as i32)))) ) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::Expr, src_path: "/types/extension_tag/seq/0".to_string() }));
}
*self_rc.tag_type.borrow_mut() = (_io.read_bits_int_le(24)? as i64).try_into()?;
_io.align_to_byte()?;
if ((*self_rc.len_tag() as u8) != (0 as u8)) {
*self_rc.value.borrow_mut() = _io.read_bytes(*self_rc.len_value()? as usize)?.into();
}
*self_rc.padding.borrow_mut() = _io.read_bytes(modulo(-(*self_rc.len_tag()) as i64, 4 as i64) as usize)?.into();
Ok(())
}
}
impl Uf2_ExtensionTag {
pub fn len_value(
&self
) -> KResult<Ref<'_, i32>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_len_value.get() {
return Ok(self.len_value.borrow());
}
self.f_len_value.set(true);
*self.len_value.borrow_mut() = (if ((*self.len_tag() as i32) >= (*self.min_len_tag()? as i32)) { ((*self.len_tag() as i32) - (*self.min_len_tag()? as i32)) } else { 0 }) as i32;
Ok(self.len_value.borrow())
}
pub fn min_len_tag(
&self
) -> KResult<Ref<'_, i32>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_min_len_tag.get() {
return Ok(self.min_len_tag.borrow());
}
self.f_min_len_tag.set(true);
*self.min_len_tag.borrow_mut() = ((1 + 3)) as i32;
Ok(self.min_len_tag.borrow())
}
}
/**
* Total size of the tag in bytes, including this byte and `tag_type`, so
* at least 4. The exception is the last tag which terminates the list -
* it specifies a total size of 0.
*/
impl Uf2_ExtensionTag {
pub fn len_tag(&self) -> Ref<'_, u8> {
self.len_tag.borrow()
}
}
impl Uf2_ExtensionTag {
pub fn tag_type(&self) -> Ref<'_, Uf2_ExtensionTagType> {
self.tag_type.borrow()
}
}
impl Uf2_ExtensionTag {
pub fn value(&self) -> Ref<'_, Vec<u8>> {
self.value.borrow()
}
}
/**
* Tags are 4-byte aligned, so a tag whose size is not a multiple
* of 4 is followed by padding.
*/
impl Uf2_ExtensionTag {
pub fn padding(&self) -> Ref<'_, Vec<u8>> {
self.padding.borrow()
}
}
impl Uf2_ExtensionTag {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
/**
* \sa https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/uf2.h#L43-L47 Source
* \sa https://github.com/raspberrypi/pico-sdk/blob/98a542c1a62fb549ffb5d66a3e5892b06276b670/src/common/boot_uf2_headers/include/boot/uf2.h#L23-L27 Git tag "2.3.0"
*/
#[derive(Default, Debug, Clone)]
pub struct Uf2_Flags {
pub _root: SharedType<Uf2>,
pub _parent: SharedType<Uf2_Block>,
pub _self: SharedType<Self>,
value: RefCell<u32>,
_io: RefCell<BytesReader>,
f_has_extension_tags: Cell<bool>,
has_extension_tags: RefCell<bool>,
f_has_family_id: Cell<bool>,
has_family_id: RefCell<bool>,
f_has_md5_checksum: Cell<bool>,
has_md5_checksum: RefCell<bool>,
f_is_file_container: Cell<bool>,
is_file_container: RefCell<bool>,
f_not_main_flash: Cell<bool>,
not_main_flash: RefCell<bool>,
}
impl KStruct for Uf2_Flags {
type Root = Uf2;
type Parent = Uf2_Block;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.value.borrow_mut() = _io.read_u4le()?.into();
let _tmpa = *self_rc.value();
if !( ((((((_tmpa as i32) & (~61441 as i32)) as i32) == (0 as i32))) && (!( ((*self_rc.is_file_container()?) && (*self_rc.has_extension_tags()?)) ))) ) {
return Err(KError::ValidationFailed(ValidationFailedError { kind: ValidationKind::Expr, src_path: "/types/flags/seq/0".to_string() }));
}
Ok(())
}
}
impl Uf2_Flags {
/**
* Indicates whether extension tags are present after the payload.
*/
pub fn has_extension_tags(
&self
) -> KResult<Ref<'_, bool>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_has_extension_tags.get() {
return Ok(self.has_extension_tags.borrow());
}
self.f_has_extension_tags.set(true);
*self.has_extension_tags.borrow_mut() = (((((*self.value() as i32) & (32768 as i32)) as i32) != (0 as i32))) as bool;
Ok(self.has_extension_tags.borrow())
}
/**
* The field at offset 28 in the block is `family_id` instead of
* `file_size`.
*/
pub fn has_family_id(
&self
) -> KResult<Ref<'_, bool>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_has_family_id.get() {
return Ok(self.has_family_id.borrow());
}
self.f_has_family_id.set(true);
*self.has_family_id.borrow_mut() = (((((*self.value() as i32) & (8192 as i32)) as i32) != (0 as i32))) as bool;
Ok(self.has_family_id.borrow())
}
/**
* Indicates whether `md5_checksum` is present at the end of `data`.
*/
pub fn has_md5_checksum(
&self
) -> KResult<Ref<'_, bool>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_has_md5_checksum.get() {
return Ok(self.has_md5_checksum.borrow());
}
self.f_has_md5_checksum.set(true);
*self.has_md5_checksum.borrow_mut() = (((((*self.value() as i32) & (16384 as i32)) as i32) != (0 as i32))) as bool;
Ok(self.has_md5_checksum.borrow())
}
/**
* When set, the UF2 format is used as a container for regular files
* (akin to a TAR file, or ZIP archive without compression).
*
* `target_address` is the offset in the file where the payload is to be
* written, and `file_size` is the size of that file. The name of the
* destination file is stored in `data.file_name`.
*/
pub fn is_file_container(
&self
) -> KResult<Ref<'_, bool>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_is_file_container.get() {
return Ok(self.is_file_container.borrow());
}
self.f_is_file_container.set(true);
*self.is_file_container.borrow_mut() = (((((*self.value() as i32) & (4096 as i32)) as i32) != (0 as i32))) as bool;
Ok(self.is_file_container.borrow())
}
/**
* Indicates that this block should be skipped when writing the device
* flash. It can be used to store data that does not fit on the device,
* typically embedded source code or debug info.
*/
pub fn not_main_flash(
&self
) -> KResult<Ref<'_, bool>> {
let _io = self._io.borrow();
let _rrc = self._root.get_value().borrow().upgrade();
let _prc = self._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
if self.f_not_main_flash.get() {
return Ok(self.not_main_flash.borrow());
}
self.f_not_main_flash.set(true);
*self.not_main_flash.borrow_mut() = (((((*self.value() as u32) & (1 as u32)) as i32) != (0 as i32))) as bool;
Ok(self.not_main_flash.borrow())
}
}
/**
* Only the five bits that we cover in value instances below are defined,
* and no other bit may be set. The [official
* spec](https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#flags)
* says "Currently, there are five flags defined". If any other flags are
* added in the future, this .ksy spec will need to be updated.
*
* The `is_file_container` and `has_extension_tags` flags disagree about
* what follows the payload in `data` (a file name or a list of extension
* tags), so this Kaitai Struct implementation treats them as mutually
* exclusive and will reject a block that sets both. The official spec
* does not specify how this should be handled, but logically there's a
* conflict, so we've decided to strictly treat it as an error.
*/
impl Uf2_Flags {
pub fn value(&self) -> Ref<'_, u32> {
self.value.borrow()
}
}
impl Uf2_Flags {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}
/**
* \sa https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#md5-checksum Source
*/
#[derive(Default, Debug, Clone)]
pub struct Uf2_Md5Checksum {
pub _root: SharedType<Uf2>,
pub _parent: SharedType<Uf2_BlockData>,
pub _self: SharedType<Self>,
start_address: RefCell<u32>,
len_region: RefCell<u32>,
md5: RefCell<Vec<u8>>,
_io: RefCell<BytesReader>,
}
impl KStruct for Uf2_Md5Checksum {
type Root = Uf2;
type Parent = Uf2_BlockData;
fn read<S: KStream>(
self_rc: &OptRc<Self>,
_io: &S,
_root: SharedType<Self::Root>,
_parent: SharedType<Self::Parent>,
) -> KResult<()> {
*self_rc._io.borrow_mut() = _io.clone();
self_rc._root.set(_root.get());
self_rc._parent.set(_parent.get());
self_rc._self.set(Ok(self_rc.clone()));
let _rrc = self_rc._root.get_value().borrow().upgrade();
let _prc = self_rc._parent.get_value().borrow().upgrade();
let _r = _rrc.as_ref().unwrap();
*self_rc.start_address.borrow_mut() = _io.read_u4le()?.into();
*self_rc.len_region.borrow_mut() = _io.read_u4le()?.into();
*self_rc.md5.borrow_mut() = _io.read_bytes(16 as usize)?.into();
Ok(())
}
}
impl Uf2_Md5Checksum {
}
impl Uf2_Md5Checksum {
pub fn start_address(&self) -> Ref<'_, u32> {
self.start_address.borrow()
}
}
impl Uf2_Md5Checksum {
pub fn len_region(&self) -> Ref<'_, u32> {
self.len_region.borrow()
}
}
impl Uf2_Md5Checksum {
pub fn md5(&self) -> Ref<'_, Vec<u8>> {
self.md5.borrow()
}
}
impl Uf2_Md5Checksum {
pub fn _io(&self) -> Ref<'_, BytesReader> {
self._io.borrow()
}
}