UF2 (USB Flashing Format): Rust parsing library

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:

File extension

uf2

KS implementation details

License: CC0-1.0

References

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.

Rust source code to parse UF2 (USB Flashing Format)

uf2.rs

// 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()
    }
}