# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
# type: ignore

import kaitaistruct
from kaitaistruct import ReadWriteKaitaiStruct, KaitaiStream, BytesIO
from enum import IntEnum


if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11):
    raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__))

class Uf2(ReadWriteKaitaiStruct):
    """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).
    
    .. seealso::
       Source - https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md
    """

    class ExtensionTagType(IntEnum):
        end = 0
        page_size = 780791
        description = 6622621
        rp2_ignore_block = 10049507
        version = 10471356
        sha2_checksum = 11824560
        device_type_id = 13149993

    class FamilyId(IntEnum):
        stm32l4 = 16738585
        stm32l5 = 69471199
        stm32f411xc = 114362747
        m0sense = 299792458
        atmega32 = 374814231
        saml21 = 407992330
        nrf52 = 458716255
        esp32 = 475996592
        stm32l1 = 505365293
        stm32l0 = 539900561
        stm32wl = 558239728
        rtl8710b = 585160444
        lpc55 = 716994540
        esp32c2 = 730387100
        stm32f411xe = 767756741
        stm32g0 = 806311475
        esp32s31 = 822212545
        gd32f350 = 835856582
        esp32h2 = 858203894
        rtl8720d = 863621090
        esp32p4 = 1026592404
        maixplay_u4 = 1265126769
        stm32g4 = 1282483210
        stm32h5 = 1318001757
        csk4 = 1332399698
        mimxrt10xx = 1337120189
        xr809 = 1374225320
        stm32f7 = 1404571392
        esp32c6 = 1410195298
        samd51 = 1427194976
        stm32f4 = 1467308631
        fx2 = 1511523995
        stm32f2 = 1561987630
        stm32f1 = 1591873650
        nrf52833 = 1646171002
        stm32f0 = 1685595318
        bk7231u = 1733968048
        samd21 = 1760373640
        ch32v = 1771791084
        bk7251 = 1786956866
        stm32f3 = 1803837832
        stm32f407 = 1829315322
        stm32h7 = 1840668802
        csk6 = 1853049000
        nrf52832xxab = 1869948536
        stm32wb = 1892771411
        nrf52832xxaa = 1920081230
        max32690 = 1947226634
        esp32c61 = 2010665156
        bk7231n = 2067722800
        ra4m1 = 2078840685
        py32f071_uvk5_v3 = 2105173743
        esp8266 = 2125160941
        kl32l2 = 2139350931
        nrf52820 = 2181929567
        stm32f407vg = 2410701054
        max78002 = 2446589208
        rza1lu = 2501329455
        gd32vf103 = 2599435827
        esp32h4 = 2651564682
        rtl8710a = 2684343619
        at32f415 = 2697558926
        nrf52840 = 2913282112
        esp32h21 = 3067936943
        esp32s2 = 3218951918
        esp32s3 = 3296614247
        esp32c3 = 3559628908
        max32650 = 3594487346
        bl602 = 3725750455
        rtl8720c = 3767498084
        rp2040 = 3834380118
        rp2xxx_absolute = 3834380119
        rp2xxx_data = 3834380120
        rp2350_arm_s = 3834380121
        rp2350_riscv = 3834380122
        rp2350_arm_ns = 3834380123
        max32666 = 4039314801
        esp32c5 = 4145808195
    def __init__(self, _io=None, _parent=None, _root=None):
        super(Uf2, self).__init__(_io)
        self._parent = _parent
        self._root = _root or self

    def _read(self):
        self.first_block = Uf2.Block(self._io, self, self._root)
        self.first_block._read()
        self.blocks = []
        for i in range(self.first_block.num_blocks - 1):
            _t_blocks = Uf2.Block(self._io, self, self._root)
            try:
                _t_blocks._read()
            finally:
                self.blocks.append(_t_blocks)

        self._dirty = False


    def _fetch_instances(self):
        pass
        self.first_block._fetch_instances()
        for i in range(len(self.blocks)):
            pass
            self.blocks[i]._fetch_instances()



    def _write__seq(self, io=None):
        super(Uf2, self)._write__seq(io)
        self.first_block._write__seq(self._io)
        for i in range(len(self.blocks)):
            pass
            self.blocks[i]._write__seq(self._io)



    def _check(self):
        if self.first_block._root != self._root:
            raise kaitaistruct.ConsistencyError(u"first_block", self._root, self.first_block._root)
        if self.first_block._parent != self:
            raise kaitaistruct.ConsistencyError(u"first_block", self, self.first_block._parent)
        if len(self.blocks) != self.first_block.num_blocks - 1:
            raise kaitaistruct.ConsistencyError(u"blocks", self.first_block.num_blocks - 1, len(self.blocks))
        for i in range(len(self.blocks)):
            pass
            if self.blocks[i]._root != self._root:
                raise kaitaistruct.ConsistencyError(u"blocks", self._root, self.blocks[i]._root)
            if self.blocks[i]._parent != self:
                raise kaitaistruct.ConsistencyError(u"blocks", self, self.blocks[i]._parent)

        self._dirty = False

    class Block(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Uf2.Block, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.magic = self._io.read_bytes(4)
            if not self.magic == b"\x55\x46\x32\x0A":
                raise kaitaistruct.ValidationNotEqualError(b"\x55\x46\x32\x0A", self.magic, self._io, u"/types/block/seq/0")
            self.second_magic = self._io.read_bytes(4)
            if not self.second_magic == b"\x57\x51\x5D\x9E":
                raise kaitaistruct.ValidationNotEqualError(b"\x57\x51\x5D\x9E", self.second_magic, self._io, u"/types/block/seq/1")
            self.flags = Uf2.Flags(self._io, self, self._root)
            self.flags._read()
            self.target_address = self._io.read_u4le()
            _ = self.target_address
            if not _ % 4 == 0:
                raise kaitaistruct.ValidationExprError(self.target_address, self._io, u"/types/block/seq/3")
            self.len_payload = self._io.read_u4le()
            _ = self.len_payload
            if not _ % 4 == 0:
                raise kaitaistruct.ValidationExprError(self.len_payload, self._io, u"/types/block/seq/4")
            self.block_number = self._io.read_u4le()
            self.num_blocks_raw = self._io.read_u4le()
            if not self.num_blocks_raw >= self.block_number + 1:
                raise kaitaistruct.ValidationLessThanError(self.block_number + 1, self.num_blocks_raw, self._io, u"/types/block/seq/6")
            if (not (self.flags.has_family_id)):
                pass
                self.file_size = self._io.read_u4le()

            if self.flags.has_family_id:
                pass
                self.family_id = KaitaiStream.resolve_enum(Uf2.FamilyId, self._io.read_u4le())

            self._raw_data = self._io.read_bytes(476)
            _io__raw_data = KaitaiStream(BytesIO(self._raw_data))
            self.data = Uf2.BlockData(_io__raw_data, self, self._root)
            self.data._read()
            self.final_magic = self._io.read_bytes(4)
            if not self.final_magic == b"\x30\x6F\xB1\x0A":
                raise kaitaistruct.ValidationNotEqualError(b"\x30\x6F\xB1\x0A", self.final_magic, self._io, u"/types/block/seq/10")
            self._dirty = False


        def _fetch_instances(self):
            pass
            self.flags._fetch_instances()
            if (not (self.flags.has_family_id)):
                pass

            if self.flags.has_family_id:
                pass

            self.data._fetch_instances()


        def _write__seq(self, io=None):
            super(Uf2.Block, self)._write__seq(io)
            self._io.write_bytes(self.magic)
            self._io.write_bytes(self.second_magic)
            self.flags._write__seq(self._io)
            self._io.write_u4le(self.target_address)
            self._io.write_u4le(self.len_payload)
            self._io.write_u4le(self.block_number)
            self._io.write_u4le(self.num_blocks_raw)
            if (not (self.flags.has_family_id)):
                pass
                self._io.write_u4le(self.file_size)

            if self.flags.has_family_id:
                pass
                self._io.write_u4le(int(self.family_id))

            _io__raw_data = KaitaiStream(BytesIO(bytearray(476)))
            self._io.add_child_stream(_io__raw_data)
            _pos2 = self._io.pos()
            self._io.seek(self._io.pos() + (476))
            def handler(parent, _io__raw_data=_io__raw_data):
                self._raw_data = _io__raw_data.to_byte_array()
                if len(self._raw_data) != 476:
                    raise kaitaistruct.ConsistencyError(u"raw(data)", 476, len(self._raw_data))
                parent.write_bytes(self._raw_data)
            _io__raw_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
            self.data._write__seq(_io__raw_data)
            self._io.write_bytes(self.final_magic)


        def _check(self):
            if len(self.magic) != 4:
                raise kaitaistruct.ConsistencyError(u"magic", 4, len(self.magic))
            if not self.magic == b"\x55\x46\x32\x0A":
                raise kaitaistruct.ValidationNotEqualError(b"\x55\x46\x32\x0A", self.magic, None, u"/types/block/seq/0")
            if len(self.second_magic) != 4:
                raise kaitaistruct.ConsistencyError(u"second_magic", 4, len(self.second_magic))
            if not self.second_magic == b"\x57\x51\x5D\x9E":
                raise kaitaistruct.ValidationNotEqualError(b"\x57\x51\x5D\x9E", self.second_magic, None, u"/types/block/seq/1")
            if self.flags._root != self._root:
                raise kaitaistruct.ConsistencyError(u"flags", self._root, self.flags._root)
            if self.flags._parent != self:
                raise kaitaistruct.ConsistencyError(u"flags", self, self.flags._parent)
            _ = self.target_address
            if not _ % 4 == 0:
                raise kaitaistruct.ValidationExprError(self.target_address, None, u"/types/block/seq/3")
            _ = self.len_payload
            if not _ % 4 == 0:
                raise kaitaistruct.ValidationExprError(self.len_payload, None, u"/types/block/seq/4")
            if not self.num_blocks_raw >= self.block_number + 1:
                raise kaitaistruct.ValidationLessThanError(self.block_number + 1, self.num_blocks_raw, None, u"/types/block/seq/6")
            if (not (self.flags.has_family_id)):
                pass

            if self.flags.has_family_id:
                pass

            if self.data._root != self._root:
                raise kaitaistruct.ConsistencyError(u"data", self._root, self.data._root)
            if self.data._parent != self:
                raise kaitaistruct.ConsistencyError(u"data", self, self.data._parent)
            if len(self.final_magic) != 4:
                raise kaitaistruct.ConsistencyError(u"final_magic", 4, len(self.final_magic))
            if not self.final_magic == b"\x30\x6F\xB1\x0A":
                raise kaitaistruct.ValidationNotEqualError(b"\x30\x6F\xB1\x0A", self.final_magic, None, u"/types/block/seq/10")
            self._dirty = False

        @property
        def is_rp2350_e10_block(self):
            """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.
            
            .. seealso::
               Git tag "2.3.0" - https://github.com/raspberrypi/picotool/blob/6f6458d792b93685a11423b244a585eaa99eafcf/elf2uf2/elf2uf2.cpp#L147
            
            
            .. seealso::
               Source - https://github.com/raspberrypi/picotool/commit/78c9bd121b09399823b67ee7ea89003ca0d3315f
            """
            if hasattr(self, '_m_is_rp2350_e10_block'):
                return self._m_is_rp2350_e10_block

            self._m_is_rp2350_e10_block =  (( ((self.flags.value == 8192) or (self.flags.value == 40960)) ) and (self.family_id == Uf2.FamilyId.rp2xxx_absolute) and (self.num_blocks_raw == 2) and (self.block_number == 0) and (self.len_payload == 256) and (KaitaiStream.byte_array_index(self.data.payload, 0) == 239) and (KaitaiStream.byte_array_index(self.data.payload, -1) == 239) and ( (((not (self.flags.has_extension_tags))) or (self.data.extension_tags[0].len_tag == 0) or ( ((self.data.extension_tags[0].len_tag == 4) and (self.data.extension_tags[0].tag_type == Uf2.ExtensionTagType.rp2_ignore_block)) )) )) 
            return getattr(self, '_m_is_rp2350_e10_block', None)

        def _invalidate_is_rp2350_e10_block(self):
            del self._m_is_rp2350_e10_block
        @property
        def num_blocks(self):
            if hasattr(self, '_m_num_blocks'):
                return self._m_num_blocks

            self._m_num_blocks = (1 if self.is_rp2350_e10_block else self.num_blocks_raw)
            return getattr(self, '_m_num_blocks', None)

        def _invalidate_num_blocks(self):
            del self._m_num_blocks

    class BlockData(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Uf2.BlockData, self).__init__(_io)
            self._parent = _parent
            self._root = _root
            self._should_write_md5_checksum = False
            self.md5_checksum__enabled = True

        def _read(self):
            self.payload = self._io.read_bytes(self._parent.len_payload)
            if self._parent.flags.is_file_container:
                pass
                self.file_name = (self._io.read_bytes_term(0, False, True, True)).decode(u"UTF-8")

            if self._parent.flags.has_extension_tags:
                pass
                self.extension_tags = []
                i = 0
                while True:
                    _t_extension_tags = Uf2.ExtensionTag(self._io, self, self._root)
                    try:
                        _t_extension_tags._read()
                    finally:
                        _ = _t_extension_tags
                        self.extension_tags.append(_)
                    if _.len_tag == 0:
                        break
                    i += 1

            self._dirty = False


        def _fetch_instances(self):
            pass
            if self._parent.flags.is_file_container:
                pass

            if self._parent.flags.has_extension_tags:
                pass
                for i in range(len(self.extension_tags)):
                    pass
                    self.extension_tags[i]._fetch_instances()


            _ = self.md5_checksum
            if hasattr(self, '_m_md5_checksum'):
                pass
                self._m_md5_checksum._fetch_instances()



        def _write__seq(self, io=None):
            super(Uf2.BlockData, self)._write__seq(io)
            self._should_write_md5_checksum = self.md5_checksum__enabled
            self._io.write_bytes(self.payload)
            if self._parent.flags.is_file_container:
                pass
                self._io.write_bytes((self.file_name).encode(u"UTF-8"))
                self._io.write_u1(0)

            if self._parent.flags.has_extension_tags:
                pass
                for i in range(len(self.extension_tags)):
                    pass
                    self.extension_tags[i]._write__seq(self._io)




        def _check(self):
            if len(self.payload) != self._parent.len_payload:
                raise kaitaistruct.ConsistencyError(u"payload", self._parent.len_payload, len(self.payload))
            if self._parent.flags.is_file_container:
                pass
                if KaitaiStream.byte_array_index_of((self.file_name).encode(u"UTF-8"), 0) != -1:
                    raise kaitaistruct.ConsistencyError(u"file_name", -1, KaitaiStream.byte_array_index_of((self.file_name).encode(u"UTF-8"), 0))

            if self._parent.flags.has_extension_tags:
                pass
                if len(self.extension_tags) == 0:
                    raise kaitaistruct.ConsistencyError(u"extension_tags", 0, len(self.extension_tags))
                for i in range(len(self.extension_tags)):
                    pass
                    if self.extension_tags[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"extension_tags", self._root, self.extension_tags[i]._root)
                    if self.extension_tags[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"extension_tags", self, self.extension_tags[i]._parent)
                    _ = self.extension_tags[i]
                    if (_.len_tag == 0) != (i == len(self.extension_tags) - 1):
                        raise kaitaistruct.ConsistencyError(u"extension_tags", i == len(self.extension_tags) - 1, _.len_tag == 0)


            if self.md5_checksum__enabled:
                pass
                if self._parent.flags.has_md5_checksum:
                    pass
                    if self._m_md5_checksum._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"md5_checksum", self._root, self._m_md5_checksum._root)
                    if self._m_md5_checksum._parent != self:
                        raise kaitaistruct.ConsistencyError(u"md5_checksum", self, self._m_md5_checksum._parent)


            self._dirty = False

        @property
        def md5_checksum(self):
            """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>.
            """
            if self._should_write_md5_checksum:
                self._write_md5_checksum()
            if hasattr(self, '_m_md5_checksum'):
                return self._m_md5_checksum

            if not self.md5_checksum__enabled:
                return None

            if self._parent.flags.has_md5_checksum:
                pass
                _pos = self._io.pos()
                self._io.seek(self._io.size() - 24)
                self._m_md5_checksum = Uf2.Md5Checksum(self._io, self, self._root)
                self._m_md5_checksum._read()
                self._io.seek(_pos)

            return getattr(self, '_m_md5_checksum', None)

        @md5_checksum.setter
        def md5_checksum(self, v):
            self._dirty = True
            self._m_md5_checksum = v

        def _write_md5_checksum(self):
            self._should_write_md5_checksum = False
            if self._parent.flags.has_md5_checksum:
                pass
                _pos = self._io.pos()
                self._io.seek(self._io.size() - 24)
                self._m_md5_checksum._write__seq(self._io)
                self._io.seek(_pos)



    class ExtensionTag(ReadWriteKaitaiStruct):
        """
        .. seealso::
           Source - https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#extension-tags
        """
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Uf2.ExtensionTag, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.len_tag = self._io.read_u1()
            _ = self.len_tag
            if not  ((_ == 0) or (_ >= self.min_len_tag)) :
                raise kaitaistruct.ValidationExprError(self.len_tag, self._io, u"/types/extension_tag/seq/0")
            self.tag_type = KaitaiStream.resolve_enum(Uf2.ExtensionTagType, self._io.read_bits_int_le(24))
            if self.len_tag != 0:
                pass
                self.value = self._io.read_bytes(self.len_value)

            self.padding = self._io.read_bytes(-(self.len_tag) % 4)
            self._dirty = False


        def _fetch_instances(self):
            pass
            if self.len_tag != 0:
                pass



        def _write__seq(self, io=None):
            super(Uf2.ExtensionTag, self)._write__seq(io)
            self._io.write_u1(self.len_tag)
            self._io.write_bits_int_le(24, int(self.tag_type))
            if self.len_tag != 0:
                pass
                self._io.write_bytes(self.value)

            self._io.write_bytes(self.padding)


        def _check(self):
            _ = self.len_tag
            if not  ((_ == 0) or (_ >= self.min_len_tag)) :
                raise kaitaistruct.ValidationExprError(self.len_tag, None, u"/types/extension_tag/seq/0")
            if self.len_tag != 0:
                pass
                if len(self.value) != self.len_value:
                    raise kaitaistruct.ConsistencyError(u"value", self.len_value, len(self.value))

            if len(self.padding) != -(self.len_tag) % 4:
                raise kaitaistruct.ConsistencyError(u"padding", -(self.len_tag) % 4, len(self.padding))
            self._dirty = False

        @property
        def len_value(self):
            if hasattr(self, '_m_len_value'):
                return self._m_len_value

            self._m_len_value = (self.len_tag - self.min_len_tag if self.len_tag >= self.min_len_tag else 0)
            return getattr(self, '_m_len_value', None)

        def _invalidate_len_value(self):
            del self._m_len_value
        @property
        def min_len_tag(self):
            if hasattr(self, '_m_min_len_tag'):
                return self._m_min_len_tag

            self._m_min_len_tag = 1 + 3
            return getattr(self, '_m_min_len_tag', None)

        def _invalidate_min_len_tag(self):
            del self._m_min_len_tag

    class Flags(ReadWriteKaitaiStruct):
        """
        .. seealso::
           Source - https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/uf2.h#L43-L47
        
        
        .. seealso::
           Git tag "2.3.0" - https://github.com/raspberrypi/pico-sdk/blob/98a542c1a62fb549ffb5d66a3e5892b06276b670/src/common/boot_uf2_headers/include/boot/uf2.h#L23-L27
        """
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Uf2.Flags, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.value = self._io.read_u4le()
            _ = self.value
            if not  ((_ & ~61441 == 0) and ((not ( ((self.is_file_container) and (self.has_extension_tags)) )))) :
                raise kaitaistruct.ValidationExprError(self.value, self._io, u"/types/flags/seq/0")
            self._dirty = False


        def _fetch_instances(self):
            pass


        def _write__seq(self, io=None):
            super(Uf2.Flags, self)._write__seq(io)
            self._io.write_u4le(self.value)


        def _check(self):
            _ = self.value
            if not  ((_ & ~61441 == 0) and ((not ( ((self.is_file_container) and (self.has_extension_tags)) )))) :
                raise kaitaistruct.ValidationExprError(self.value, None, u"/types/flags/seq/0")
            self._dirty = False

        @property
        def has_extension_tags(self):
            """Indicates whether extension tags are present after the payload."""
            if hasattr(self, '_m_has_extension_tags'):
                return self._m_has_extension_tags

            self._m_has_extension_tags = self.value & 32768 != 0
            return getattr(self, '_m_has_extension_tags', None)

        def _invalidate_has_extension_tags(self):
            del self._m_has_extension_tags
        @property
        def has_family_id(self):
            """The field at offset 28 in the block is `family_id` instead of
            `file_size`.
            """
            if hasattr(self, '_m_has_family_id'):
                return self._m_has_family_id

            self._m_has_family_id = self.value & 8192 != 0
            return getattr(self, '_m_has_family_id', None)

        def _invalidate_has_family_id(self):
            del self._m_has_family_id
        @property
        def has_md5_checksum(self):
            """Indicates whether `md5_checksum` is present at the end of `data`."""
            if hasattr(self, '_m_has_md5_checksum'):
                return self._m_has_md5_checksum

            self._m_has_md5_checksum = self.value & 16384 != 0
            return getattr(self, '_m_has_md5_checksum', None)

        def _invalidate_has_md5_checksum(self):
            del self._m_has_md5_checksum
        @property
        def is_file_container(self):
            """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`.
            """
            if hasattr(self, '_m_is_file_container'):
                return self._m_is_file_container

            self._m_is_file_container = self.value & 4096 != 0
            return getattr(self, '_m_is_file_container', None)

        def _invalidate_is_file_container(self):
            del self._m_is_file_container
        @property
        def not_main_flash(self):
            """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.
            """
            if hasattr(self, '_m_not_main_flash'):
                return self._m_not_main_flash

            self._m_not_main_flash = self.value & 1 != 0
            return getattr(self, '_m_not_main_flash', None)

        def _invalidate_not_main_flash(self):
            del self._m_not_main_flash

    class Md5Checksum(ReadWriteKaitaiStruct):
        """
        .. seealso::
           Source - https://github.com/microsoft/uf2/blob/90e9741f217f5a40c98ba74d663e408041037578/README.md#md5-checksum
        """
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Uf2.Md5Checksum, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.start_address = self._io.read_u4le()
            self.len_region = self._io.read_u4le()
            self.md5 = self._io.read_bytes(16)
            self._dirty = False


        def _fetch_instances(self):
            pass


        def _write__seq(self, io=None):
            super(Uf2.Md5Checksum, self)._write__seq(io)
            self._io.write_u4le(self.start_address)
            self._io.write_u4le(self.len_region)
            self._io.write_bytes(self.md5)


        def _check(self):
            if len(self.md5) != 16:
                raise kaitaistruct.ConsistencyError(u"md5", 16, len(self.md5))
            self._dirty = False



