From 44db8e50fd264b0cadc597eac792cd8a31638f3a Mon Sep 17 00:00:00 2001 From: teo1747 Date: Mon, 9 Nov 2026 15:58:39 +0100 Subject: [PATCH 01/25] =?UTF-8?q?subsys:=20framed=20byte=20streams=20(SPEC?= =?UTF-8?q?-015=20=C2=A77,=20OBS-019)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M4.3's first piece: the framing every byte-stream transport carries, so one line holds the log, the trace, the crash record, the shell and the update protocol. , behind CONFIG_EMB_FRAME (on by default; an image keeps it only if it calls it): emb_frame_encode() writes COBS(channel, payload, CRC-16) and a zero delimiter into the caller's buffer, EMB_FRAME_ENCODED_MAX(n) bounding it; emb_frame_decode_byte() decodes a stream a byte at a time, from a thread or an interrupt, into the caller's buffer, drops a frame with a bad CRC, a channel above 15 or a cut block (errors) or one longer than the buffer (overruns), and resynchronizes at the next zero. API IDs 165 to 167, after the device model's 149 to 164 (#137). subsys/ holds the subsystems over the kernel, built as emb_subsys (an interface library when none is selected), compiled like the kernel and linked into every image. Kconfig gains its Subsystems menu; CI's clang-format step covers subsys/. tools/transport/frame.py is the host's side, written from the specification: encode, decode, a stream decoder, and a tool printing a port's or a capture's frames by channel. The C tests check the encoder against vectors the host tool produces, so the two sides cannot drift apart. A113 (proposed) settles what SPEC-015 §7 left open: channels 0 to 4 are the system's, 4 the update protocol's as SPEC-019 has it, 5 to 15 the application's; the CRC is CRC-16/IBM-3740 (0x1021, initial 0xFFFF; check value 0x29B1), sent least significant byte first. Checked: test_frame's 7 cases (vectors, the 254-byte run boundary, round trips, resync, overrun, misuse, and a fixed-seed stream of 200 frames with one in eight damaged, the same 383 assertions on every target) pass on native (GCC, Clang, tiny, release, ASan), the MPS2 AN385, AN386 (and tiny), AN500 and AN505, the micro:bit, RV32 virt (GCC, Clang), the Uno and the NUCLEO on EmbSIM; the host tool's 7 tests; clang-tidy 18, 0 findings; the docs build. Signed-off-by: teo1747 --- .github/workflows/ci.yml | 4 +- Kconfig | 1 + changes/feat-transport-frame.md | 8 ++ cmake/emb_kernel.cmake | 1 + cmake/emb_target.cmake | 2 +- docs/specs/AMENDMENTS-M4.md | 1 + include/emb/api_ids.h | 3 + include/emb/frame.h | 136 +++++++++++++++++++ subsys/CMakeLists.txt | 17 +++ subsys/Kconfig | 13 ++ subsys/transport/frame.c | 178 +++++++++++++++++++++++++ tests/conformance/CMakeLists.txt | 3 + tests/conformance/test_frame.c | 220 +++++++++++++++++++++++++++++++ tools/fault/api-ids.json | 18 +++ tools/fault/api-registry.json | 18 +++ tools/transport/frame.py | 161 ++++++++++++++++++++++ tools/transport/test_frame.py | 94 +++++++++++++ 17 files changed, 876 insertions(+), 2 deletions(-) create mode 100644 changes/feat-transport-frame.md create mode 100644 include/emb/frame.h create mode 100644 subsys/CMakeLists.txt create mode 100644 subsys/Kconfig create mode 100644 subsys/transport/frame.c create mode 100644 tests/conformance/test_frame.c create mode 100644 tools/transport/frame.py create mode 100644 tools/transport/test_frame.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f3cfaea..b1120a2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -354,7 +354,7 @@ jobs: packages: clang-format-18 python3-yaml - name: clang-format run: | - find include kernel arch boards soc drivers samples tests \( -name '*.c' -o -name '*.h' \) -print0 \ + find include kernel arch boards soc drivers subsys samples tests \( -name '*.c' -o -name '*.h' \) -print0 \ | xargs -0 clang-format-18 --dry-run -Werror - name: Banned constructs run: python3 -I scripts/check-banned.py @@ -380,6 +380,8 @@ jobs: run: python3 -I -m unittest discover -s tools/esp -p 'test_*.py' -v - name: Debug descriptor reader (OBS-008, A107) run: python3 -I -m unittest discover -s tools/descriptor -p 'test_*.py' -v + - name: Framed byte streams, the host's side (SPEC-015 §7) + run: python3 -I -m unittest discover -s tools/transport -p 'test_*.py' -v - name: UF2 writer (A79) run: python3 -I -m unittest discover -s tools/uf2 -p 'test_*.py' -v - name: Board support matrix (ADR-051, A81) diff --git a/Kconfig b/Kconfig index ab66b3f8..48b2a50c 100644 --- a/Kconfig +++ b/Kconfig @@ -8,3 +8,4 @@ mainmenu "EmbLinkRTOS configuration" source "arch/Kconfig" source "kernel/Kconfig" +source "subsys/Kconfig" diff --git a/changes/feat-transport-frame.md b/changes/feat-transport-frame.md new file mode 100644 index 00000000..cfb643f9 --- /dev/null +++ b/changes/feat-transport-frame.md @@ -0,0 +1,8 @@ +### Added (framed byte streams, 2026-11-09) + +- ``, behind `CONFIG_EMB_FRAME` (on by default): `emb_frame_encode()` writes one frame, COBS over a channel byte, the payload and a CRC-16, ended by a zero; `emb_frame_decode_byte()` decodes a stream byte by byte, from a thread or an interrupt, drops a frame with a bad CRC or one longer than its buffer, counts both, and resynchronizes at the next zero (SPEC-015 §7, OBS-019). It is the framing M4.3's log, trace and crash channels and M4.5's update protocol run over. `tools/transport/frame.py` is the host's side: the same codec, and a tool that prints a serial port's or a capture's frames by channel. +- `subsys/` holds the subsystems over the kernel, built as `emb_subsys` and linked into every image, which keeps only what it calls. + +### Changed (the frame's channels and CRC, 2026-11-09) + +- A113, proposed: channels 0 to 4 are the system's (4 is the update protocol's, as SPEC-019 has it) and 5 to 15 the application's; the CRC is CRC-16/IBM-3740, sent least significant byte first ([amendments](docs/specs/AMENDMENTS-M4.md)). diff --git a/cmake/emb_kernel.cmake b/cmake/emb_kernel.cmake index a2800110..f4a03ec7 100644 --- a/cmake/emb_kernel.cmake +++ b/cmake/emb_kernel.cmake @@ -34,6 +34,7 @@ macro(emb_kernel) add_subdirectory("${EMB_BASE}/include" "${_emb_bin}/include") add_subdirectory("${EMB_BASE}/arch/${CONFIG_EMB_ARCH}" "${_emb_bin}/arch/${CONFIG_EMB_ARCH}") add_subdirectory("${EMB_BASE}/kernel" "${_emb_bin}/kernel") + add_subdirectory("${EMB_BASE}/subsys" "${_emb_bin}/subsys") emb_check_native_abi() add_subdirectory("${EMB_BOARD_DIR}" "${_emb_bin}/boards/${EMB_BOARD}") diff --git a/cmake/emb_target.cmake b/cmake/emb_target.cmake index 45431d23..f1b6bd82 100644 --- a/cmake/emb_target.cmake +++ b/cmake/emb_target.cmake @@ -23,7 +23,7 @@ endfunction() # The image without a run target: emb_add_executable() and emb_add_test() share it. function(_emb_add_image name) add_executable(${name} ${ARGN}) - target_link_libraries(${name} PRIVATE emb_board emb_kernel emb_arch emb_api emb_flags) + target_link_libraries(${name} PRIVATE emb_subsys emb_board emb_kernel emb_arch emb_api emb_flags) if(APPLE) # Apple ld64 spells the map option differently from GNU ld target_link_options(${name} PRIVATE "-Wl,-map,$.map") diff --git a/docs/specs/AMENDMENTS-M4.md b/docs/specs/AMENDMENTS-M4.md index 2ff9bccb..74459703 100644 --- a/docs/specs/AMENDMENTS-M4.md +++ b/docs/specs/AMENDMENTS-M4.md @@ -11,5 +11,6 @@ Changes M4 makes to accepted specifications and requirements, where an accepted | A110 | SPEC-014 §3, SPEC-018 §2.2 | **Power states in the SoC description.** `power.states` entries gain `class` (IDLE, SLEEP, DEEP_SLEEP or OFF), `entry_us`, `exit_us` (replacing `exit_latency_us`), `min_residency_us`, `wake` (the wake sources), `timebase` (what keeps time while the main timer is stopped) and `retains`, beside `loses`. The figures start as the datasheet's and are replaced by measurements (PWR-006). The generator emits the table the policy reads. | `hw/schemas/soc.schema.json`, `hw/gen/emb_hwgen/` (M4.4) | | A111 | SPEC-014 §4, §7, SPEC-019 §3 | **The `boot` key and the image's partitions.** A board may declare `boot: {loader: mcuboot, header_size, mode}`. With it, `flash_partitions` must name `bootloader`, `slot0`, `slot1`, and `scratch` for `mode: swap_scratch`; each partition is whole sectors of the flash's geometry, the slots are equal, and the scratch is at least the largest sector a slot uses. The application links at `slot0` plus `header_size`, and the refusal of an application partition away from the boot base applies only to boards without `boot`. | `hw/gen/emb_hwgen/model.py` (M4.5) | | A112 | SPEC-014 §4, ADR-059 | **The board's system timer.** A board may name `system_timer: `, the SoC timer that keeps tickless time (ADR-059). The generator checks that the peripheral is a timer whose features the port's tickless hooks need (a free-running counter of at least 32 bits and a compare or alarm), and declares the architecture's tickless capability for that board only. | `hw/gen/emb_hwgen/`, `arch/cortex_m/` (M4.4) | +| A113 | SPEC-015 §7, OBS-019, SPEC-019 §6 | **The frame's channels and CRC.** SPEC-015 §7 gave channels 4 to 15 to the application, while SPEC-019 §6 runs the update protocol on channel 4. Channels 0 to 4 become the system's (0 log, 1 trace, 2 crash, 3 shell, 4 update) and 5 to 15 the application's. §7 named a CRC-16 without saying which: it is CRC-16/IBM-3740 (polynomial 0x1021, initial value 0xFFFF, neither reflected, no final XOR; check value 0x29B1), computed over the channel byte and the payload and sent least significant byte first, inside the COBS encoding. A frame whose channel byte is above 15 is dropped as malformed. OBS-019 reads: "…channels 0 log, 1 trace, 2 crash, 3 shell, 4 update, 5 to 15 application; CRC-16/IBM-3740 over the channel and the payload…". *Proposed 2026-11-09 with M4.3's framing, for the project owner's review.* | `include/emb/frame.h`, `subsys/transport/frame.c`, `tools/transport/frame.py` (M4.3) | **Not an amendment:** writing the vector table base (VTOR) at reset is already `emb_arch_early_init()`'s duty in SPEC-011 §4. The Cortex-M port has not done it, because every image so far boots from the boot base; M4.5 implements it for images in a slot (SPEC-019 §3). diff --git a/include/emb/api_ids.h b/include/emb/api_ids.h index e7a000cc..d131c633 100644 --- a/include/emb/api_ids.h +++ b/include/emb/api_ids.h @@ -152,5 +152,8 @@ #define EMB_API_ID_CRASH_RECORD_CLEAR 0x0092u #define EMB_API_ID_TICKS_AT_LEAST 0x0093u #define EMB_API_ID_ISR_STACK_INFO 0x0094u +#define EMB_API_ID_FRAME_ENCODE 0x00A5u +#define EMB_API_ID_FRAME_DECODER_INIT 0x00A6u +#define EMB_API_ID_FRAME_DECODE_BYTE 0x00A7u #endif /* EMB_API_IDS_H */ diff --git a/include/emb/frame.h b/include/emb/frame.h new file mode 100644 index 00000000..e2c4c3c3 --- /dev/null +++ b/include/emb/frame.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* Framed byte streams (SPEC-015 §7, OBS-019): one frame is COBS(channel, payload, CRC-16) + * and a zero delimiter, so a byte-stream transport (a UART, USB CDC, a network socket) + * carries the log, the trace, the crash record, the shell and the update protocol over one + * line, and a decoder that joins mid-stream finds the next frame at the next zero. */ +#ifndef EMB_FRAME_H +#define EMB_FRAME_H + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Channels (SPEC-015 §7, AMENDMENTS-M4 A113): 0 to 4 are the system's, 5 to 15 the + * application's. */ +#define EMB_FRAME_CHANNEL_LOG 0u +#define EMB_FRAME_CHANNEL_TRACE 1u +#define EMB_FRAME_CHANNEL_CRASH 2u +#define EMB_FRAME_CHANNEL_SHELL 3u +#define EMB_FRAME_CHANNEL_UPDATE 4u /* SPEC-019 §6 */ +#define EMB_FRAME_CHANNEL_APP_FIRST 5u +#define EMB_FRAME_CHANNEL_MAX 15u + +/* The channel byte and the CRC-16 around a frame's payload, before COBS. */ +#define EMB_FRAME_OVERHEAD 3u +/* The most bytes emb_frame_encode() writes for a payload of n bytes, the delimiter included: + * COBS adds one code byte per 254 bytes, and one more. */ +#define EMB_FRAME_ENCODED_MAX(n) \ + ((n) + EMB_FRAME_OVERHEAD + (((n) + EMB_FRAME_OVERHEAD) / 254u) + 2u) + +/* A decoded frame: its payload points into the decoder's buffer, valid until the decoder is + * given its next byte. */ +typedef struct emb_frame { + const uint8_t *payload; + size_t len; + uint8_t channel; +} emb_frame_t; + +/* A stream decoder. Its fields are the decoder's; the counters may be read at any time. */ +typedef struct emb_frame_decoder { + uint8_t *buf; /* the caller's: holds one decoded frame, channel and CRC included */ + size_t cap; /* its size in bytes */ + size_t len; /* bytes of the frame so far */ + uint8_t code; /* the current COBS block's code, 0 before the first */ + uint8_t left; /* bytes the block still holds */ + uint8_t dropping; /* the frame overran the buffer: skip to the delimiter */ + uint8_t reserved_; + uint32_t frames; /* good frames delivered */ + uint32_t errors; /* frames dropped for a bad CRC, a channel above 15 or a cut block */ + uint32_t overruns; /* frames dropped for being longer than the buffer */ +} emb_frame_decoder_t; + +/** + * emb_frame_encode() - Encode one frame: COBS(channel, payload, CRC-16) and a delimiter. + * @channel: 0 to EMB_FRAME_CHANNEL_MAX. + * @payload: The payload; may be NULL when @len is 0. + * @len: Its bytes. + * @out: Where the frame goes. + * @cap: @out's size; EMB_FRAME_ENCODED_MAX(@len) is always enough. + * @out_len: Receives the frame's bytes, the delimiter included. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(len) + * @owns none + * @config CONFIG_EMB_FRAME + * @req OBS-019 + * @since 0.3 + * @stable no + * + * The CRC is CRC-16/IBM-3740 (polynomial 0x1021, initial value 0xFFFF, not reflected) over + * the channel byte and the payload, sent least significant byte first. No byte of the frame + * but the last is zero. + * + * Return: EMB_OK; EMB_EINVAL (a channel above 15, or a pointer missing); + * EMB_EOVERFLOW (@cap is too small for the frame). + */ +emb_status_t emb_frame_encode(uint8_t channel, const void *payload, size_t len, uint8_t *out, + size_t cap, size_t *out_len); + +/** + * emb_frame_decoder_init() - Start a stream decoder on a buffer. + * @dec: The decoder. + * @buf: The buffer a decoded frame is kept in: its payload plus EMB_FRAME_OVERHEAD bytes. + * @cap: Its size in bytes. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(1) + * @owns none + * @config CONFIG_EMB_FRAME + * @req OBS-019 + * @since 0.3 + * @stable no + * + * The decoder starts between frames, with its counters at zero. A NULL @dec is ignored. + */ +void emb_frame_decoder_init(emb_frame_decoder_t *dec, uint8_t *buf, size_t cap); + +/** + * emb_frame_decode_byte() - Give a stream decoder its next byte. + * @dec: The decoder. + * @byte: The byte, as the transport received it. + * @frame: Receives the frame when this byte completes a good one. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(len) at a delimiter, for the CRC; O(1) otherwise + * @owns none + * @config CONFIG_EMB_FRAME + * @req OBS-019 + * @since 0.3 + * @stable no + * + * A zero byte ends a frame. A frame with a bad CRC, a channel above 15 or a COBS block cut + * short is dropped and counted in errors; one longer than the buffer is dropped and counted + * in overruns; either way the decoder carries on at the next frame. Zeros between frames are + * ignored, so a sender may start with one to resynchronize a decoder that joined mid-frame. + * + * Return: true when @byte completed a good frame, now in @frame; false otherwise, and false + * for a NULL @dec or @frame. + */ +bool emb_frame_decode_byte(emb_frame_decoder_t *dec, uint8_t byte, emb_frame_t *frame); + +#ifdef __cplusplus +} +#endif + +#endif /* EMB_FRAME_H */ diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt new file mode 100644 index 00000000..3a8e873d --- /dev/null +++ b/subsys/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# emb_subsys: the subsystems over the kernel (transports, and in M4 logging, trace and update), +# each behind its CONFIG_EMB_* symbol, compiled like the kernel and linked into every image, +# which keeps only what it calls. With none selected it is an empty interface library. +set(EMB_SUBSYS_SOURCES) +if(CONFIG_EMB_FRAME) + list(APPEND EMB_SUBSYS_SOURCES transport/frame.c) # SPEC-015 §7 +endif() + +if(EMB_SUBSYS_SOURCES) + add_library(emb_subsys STATIC ${EMB_SUBSYS_SOURCES}) + emb_use_kernel_compiler(emb_subsys) + target_link_libraries(emb_subsys PUBLIC emb_api PRIVATE emb_flags) +else() + add_library(emb_subsys INTERFACE) +endif() diff --git a/subsys/Kconfig b/subsys/Kconfig new file mode 100644 index 00000000..37f9906f --- /dev/null +++ b/subsys/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +menu "Subsystems" + +config EMB_FRAME + bool "Framed byte streams: COBS, a channel and a CRC-16 (SPEC-015 §7)" + default y + help + OBS-019. emb_frame_encode() and a stream decoder that resynchronizes at + each zero delimiter, for the log, trace, crash, shell and update channels + over one byte stream. Linked only into an image that calls it. + +endmenu diff --git a/subsys/transport/frame.c b/subsys/transport/frame.c new file mode 100644 index 00000000..d3841f19 --- /dev/null +++ b/subsys/transport/frame.c @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * Framed byte streams (SPEC-015 §7, OBS-019): COBS over the channel byte, the payload and a + * CRC-16, ended by a zero. Consistent Overhead Byte Stuffing (Cheshire and Baker, 1999) writes + * each run of up to 254 nonzero bytes after a code byte holding the run's length plus one; + * a code below 0xFF stands for a zero after its run, except at the frame's end. + */ +#include + +#define COBS_RUN_MAX 0xFFu /* a code byte: 254 data bytes and no zero after them */ +#define CRC_INIT 0xFFFFu +#define CRC_POLY 0x1021u + +/* CRC-16/IBM-3740, bit by bit: small rather than fast; a frame's CRC is O(len) either way. */ +static uint16_t crc16(uint16_t crc, uint8_t byte) +{ + unsigned bit; + crc = (uint16_t)(crc ^ (uint16_t)((uint16_t)byte << 8)); + for (bit = 0u; bit < 8u; bit++) { /* bounded: eight bits */ + if ((crc & 0x8000u) != 0u) { + crc = (uint16_t)((uint16_t)(crc << 1) ^ CRC_POLY); + } else { + crc = (uint16_t)(crc << 1); + } + } + return crc; +} + +/* The encoder's state: where the open run's code byte goes, and the run's code so far. */ +typedef struct cobs { + uint8_t *out; + size_t pos; /* the next byte to write */ + size_t code; /* the open run's code byte */ + uint8_t run; /* the open run's code: its length plus one */ +} cobs_t; + +static void cobs_put(cobs_t *c, uint8_t byte) +{ + if (byte == 0u) { + c->out[c->code] = c->run; /* the run ends at the zero */ + c->code = c->pos; + c->pos++; + c->run = 1u; + return; + } + c->out[c->pos] = byte; + c->pos++; + c->run++; + if (c->run == COBS_RUN_MAX) { /* a full run: it closes with no zero after it */ + c->out[c->code] = c->run; + c->code = c->pos; + c->pos++; + c->run = 1u; + } +} + +emb_status_t emb_frame_encode(uint8_t channel, const void *payload, size_t len, uint8_t *out, + size_t cap, size_t *out_len) +{ + const uint8_t *p = (const uint8_t *)payload; + cobs_t c; + uint16_t crc = CRC_INIT; + size_t i; + if (channel > EMB_FRAME_CHANNEL_MAX || out == NULL || out_len == NULL || + (payload == NULL && len != 0u)) { + return EMB_EINVAL; + } + /* the bound is computed so that it cannot wrap: a payload this long is refused first */ + if (len > (SIZE_MAX / 2u) || cap < EMB_FRAME_ENCODED_MAX(len)) { + return EMB_EOVERFLOW; + } + c.out = out; + c.code = 0u; + c.pos = 1u; + c.run = 1u; + crc = crc16(crc, channel); + cobs_put(&c, channel); + for (i = 0u; i < len; i++) { /* bounded by len */ + crc = crc16(crc, p[i]); + cobs_put(&c, p[i]); + } + cobs_put(&c, (uint8_t)(crc & 0xFFu)); + cobs_put(&c, (uint8_t)(crc >> 8)); + out[c.code] = c.run; + out[c.pos] = 0u; /* the delimiter */ + *out_len = c.pos + 1u; + return EMB_OK; +} + +void emb_frame_decoder_init(emb_frame_decoder_t *dec, uint8_t *buf, size_t cap) +{ + if (dec == NULL) { + return; + } + dec->buf = buf; + dec->cap = (buf != NULL) ? cap : 0u; + dec->len = 0u; + dec->code = 0u; + dec->left = 0u; + dec->dropping = 0u; + dec->reserved_ = 0u; + dec->frames = 0u; + dec->errors = 0u; + dec->overruns = 0u; +} + +static void keep(emb_frame_decoder_t *dec, uint8_t byte) +{ + if (dec->dropping != 0u) { + return; + } + if (dec->len >= dec->cap) { + dec->dropping = 1u; + dec->overruns++; + return; + } + dec->buf[dec->len] = byte; + dec->len++; +} + +/* A frame ended at a delimiter: whether it is good, and if so, the frame. */ +static bool frame_end(emb_frame_decoder_t *dec, emb_frame_t *frame) +{ + uint16_t crc = CRC_INIT; + size_t i; + size_t n = dec->len; + if (dec->dropping != 0u) { + return false; /* counted when it overran */ + } + if (dec->code == 0u) { + return false; /* no frame: a zero between frames */ + } + if (dec->left != 0u || n < EMB_FRAME_OVERHEAD) { + dec->errors++; /* a block cut short, or too short to hold a channel and a CRC */ + return false; + } + for (i = 0u; i < n - 2u; i++) { /* bounded by the frame's length */ + crc = crc16(crc, dec->buf[i]); + } + if ((uint8_t)(crc & 0xFFu) != dec->buf[n - 2u] || (uint8_t)(crc >> 8) != dec->buf[n - 1u] || + dec->buf[0] > EMB_FRAME_CHANNEL_MAX) { + dec->errors++; + return false; + } + frame->channel = dec->buf[0]; + frame->payload = &dec->buf[1]; + frame->len = n - EMB_FRAME_OVERHEAD; + dec->frames++; + return true; +} + +bool emb_frame_decode_byte(emb_frame_decoder_t *dec, uint8_t byte, emb_frame_t *frame) +{ + bool good; + if (dec == NULL || frame == NULL) { + return false; + } + if (byte == 0u) { + good = frame_end(dec, frame); + dec->len = 0u; + dec->code = 0u; + dec->left = 0u; + dec->dropping = 0u; + return good; + } + if (dec->left == 0u) { /* a code byte: the zero the last run stood for comes first */ + if (dec->code != 0u && dec->code != COBS_RUN_MAX) { + keep(dec, 0u); + } + dec->code = byte; + dec->left = (uint8_t)(byte - 1u); + return false; + } + keep(dec, byte); + dec->left--; + return false; +} diff --git a/tests/conformance/CMakeLists.txt b/tests/conformance/CMakeLists.txt index e86713f4..9b588c8a 100644 --- a/tests/conformance/CMakeLists.txt +++ b/tests/conformance/CMakeLists.txt @@ -39,6 +39,9 @@ endif() if(CONFIG_EMB_TIMER) emb_add_test(test_timer test_timer.c) endif() +if(CONFIG_EMB_FRAME) + emb_add_test(test_frame test_frame.c) # OBS-019 (SPEC-015 §7) +endif() emb_add_test(test_first_execution test_first_execution.c) if(CONFIG_EMB_CRASH_RECORD) emb_add_test(test_crash test_crash.c) diff --git a/tests/conformance/test_frame.c b/tests/conformance/test_frame.c new file mode 100644 index 00000000..c101a1d2 --- /dev/null +++ b/tests/conformance/test_frame.c @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* Framed byte streams (SPEC-015 §7; OBS-019): the encoder against vectors the host tool + * (tools/transport/frame.py) produces from the specification, and the stream decoder's + * resynchronization, CRC and overrun handling. */ +#include + +#include +#include + +/* tools/transport/frame.py's encode(): the same bytes on both sides of the line */ +static const uint8_t v_empty[] = {0x01u, 0x03u, 0xF0u, 0xE1u, 0x00u}; +static const uint8_t v_zero[] = {0x02u, 0x01u, 0x03u, 0x3Eu, 0x2Eu, 0x00u}; +static const uint8_t v_hello[] = {0x09u, 0x02u, 0x68u, 0x65u, 0x6Cu, + 0x6Cu, 0x6Fu, 0x32u, 0x46u, 0x00u}; + +static uint8_t payload[300]; +static uint8_t wire[EMB_FRAME_ENCODED_MAX(300u) + 16u]; +static uint8_t dbuf[300u + EMB_FRAME_OVERHEAD]; +static emb_frame_decoder_t dec; + +static size_t encode(uint8_t ch, const void *p, size_t len) +{ + size_t n = 0u; + EMB_ASSERT_OK(emb_frame_encode(ch, p, len, wire, sizeof(wire), &n)); + return n; +} + +/* Feeds n bytes; returns how many good frames came out, the last in *last. */ +static unsigned feed(const uint8_t *bytes, size_t n, emb_frame_t *last) +{ + unsigned good = 0u; + size_t i; + emb_frame_t f; + for (i = 0u; i < n; i++) { /* bounded by n */ + if (emb_frame_decode_byte(&dec, bytes[i], &f)) { + good++; + *last = f; + } + } + return good; +} + +EMB_TEST(frame_encoding_matches_the_host_tool) +{ + size_t n; + EMB_TEST_REQ("OBS-019"); + n = encode(EMB_FRAME_CHANNEL_LOG, NULL, 0u); + EMB_ASSERT_EQ(n, sizeof(v_empty)); + EMB_ASSERT_TRUE(memcmp(wire, v_empty, n) == 0); + n = encode(EMB_FRAME_CHANNEL_TRACE, "\0", 1u); + EMB_ASSERT_EQ(n, sizeof(v_zero)); + EMB_ASSERT_TRUE(memcmp(wire, v_zero, n) == 0); + n = encode(EMB_FRAME_CHANNEL_CRASH, "hello", 5u); + EMB_ASSERT_EQ(n, sizeof(v_hello)); + EMB_ASSERT_TRUE(memcmp(wire, v_hello, n) == 0); +} + +EMB_TEST(frame_runs_at_the_cobs_boundary) +{ + size_t n; + size_t i; + EMB_TEST_REQ("OBS-019"); + (void)memset(payload, 0x11, sizeof(payload)); + n = encode(7u, payload, 300u); /* a full run of 254, then the rest */ + EMB_ASSERT_EQ(n, 306u); + EMB_ASSERT_EQ(wire[0], 0xFFu); + EMB_ASSERT_EQ(wire[255], 50u); + EMB_ASSERT_EQ(wire[n - 3u], 0x0Bu); /* the CRC, low byte first */ + EMB_ASSERT_EQ(wire[n - 2u], 0xC9u); + (void)memset(payload, 0x22, 253u); + n = encode(5u, payload, 253u); /* the channel and 253 bytes fill a run exactly */ + EMB_ASSERT_EQ(n, 259u); + EMB_ASSERT_EQ(wire[0], 0xFFu); + EMB_ASSERT_EQ(wire[255], 0x03u); + for (i = 0u; i + 1u < n; i++) { /* bounded by the frame: only its last byte is zero */ + if (wire[i] == 0u) { + break; + } + } + EMB_ASSERT_EQ(i, n - 1u); + for (i = 0u; i <= 300u; i += 23u) { /* the bound holds for each length */ + EMB_ASSERT_TRUE(encode(9u, payload, i) <= EMB_FRAME_ENCODED_MAX(i)); + } +} + +EMB_TEST(frame_round_trip_through_the_decoder) +{ + emb_frame_t f = {NULL, 0u, 0u}; + size_t n; + size_t i; + EMB_TEST_REQ("OBS-019"); + for (i = 0u; i < sizeof(payload); i++) { /* every byte value, zeros included */ + payload[i] = (uint8_t)(i * 7u); + } + emb_frame_decoder_init(&dec, dbuf, sizeof(dbuf)); + n = encode(EMB_FRAME_CHANNEL_MAX, payload, sizeof(payload)); + EMB_ASSERT_EQ(feed(wire, n, &f), 1u); + EMB_ASSERT_EQ(f.channel, EMB_FRAME_CHANNEL_MAX); + EMB_ASSERT_EQ(f.len, sizeof(payload)); + EMB_ASSERT_TRUE(memcmp(f.payload, payload, f.len) == 0); + EMB_ASSERT_EQ(feed(v_empty, sizeof(v_empty), &f), 1u); /* an empty payload */ + EMB_ASSERT_EQ(f.len, 0u); + EMB_ASSERT_EQ(feed(v_hello, sizeof(v_hello), &f), 1u); + EMB_ASSERT_EQ(f.channel, EMB_FRAME_CHANNEL_CRASH); + EMB_ASSERT_TRUE(f.len == 5u && memcmp(f.payload, "hello", 5u) == 0); + EMB_ASSERT_EQ(dec.frames, 3u); + EMB_ASSERT_EQ(dec.errors + dec.overruns, 0u); +} + +EMB_TEST(frame_decoder_resynchronizes) +{ + static const uint8_t noise[] = {0x47u, 0x13u, 0x99u, 0x05u}; /* the tail of a lost frame */ + emb_frame_t f = {NULL, 0u, 0u}; + size_t n; + EMB_TEST_REQ("OBS-019"); + emb_frame_decoder_init(&dec, dbuf, sizeof(dbuf)); + EMB_ASSERT_EQ(feed(noise, sizeof(noise), &f), 0u); /* joined mid-frame */ + EMB_ASSERT_EQ(feed(v_hello, sizeof(v_hello), &f), 0u); /* the noise spoils this one */ + EMB_ASSERT_EQ(dec.errors, 1u); + EMB_ASSERT_EQ(feed(v_hello, sizeof(v_hello), &f), 1u); /* and the next is good */ + EMB_ASSERT_EQ(feed((const uint8_t *)"\0\0\0", 3u, &f), 0u); /* zeros between frames */ + EMB_ASSERT_EQ(dec.errors, 1u); + + n = encode(EMB_FRAME_CHANNEL_LOG, "abc", 3u); + wire[2] ^= 0x01u; /* one bit flipped on the line */ + EMB_ASSERT_EQ(feed(wire, n, &f), 0u); + EMB_ASSERT_EQ(dec.errors, 2u); + n = encode(EMB_FRAME_CHANNEL_LOG, "abc", 3u); + EMB_ASSERT_EQ(feed(wire, n - 3u, &f), 0u); /* cut before its CRC and delimiter */ + EMB_ASSERT_EQ(feed((const uint8_t *)"\0", 1u, &f), 0u); + EMB_ASSERT_EQ(dec.errors, 3u); + EMB_ASSERT_EQ(feed(v_zero, sizeof(v_zero), &f), 1u); + EMB_ASSERT_TRUE(f.len == 1u && f.payload[0] == 0u); + + /* a frame whose CRC is right but whose channel byte is above 15 */ + wire[0] = 0x04u; + wire[1] = 0x10u; + wire[2] = 0xC1u; /* CRC-16/IBM-3740 of 0x10 is 0xF3C1: sent C1 F3 */ + wire[3] = 0xF3u; + wire[4] = 0x00u; + EMB_ASSERT_EQ(feed(wire, 5u, &f), 0u); + EMB_ASSERT_EQ(dec.errors, 4u); +} + +EMB_TEST(frame_decoder_drops_an_overrun) +{ + static uint8_t small[8]; + emb_frame_t f = {NULL, 0u, 0u}; + size_t n; + EMB_TEST_REQ("OBS-019"); + emb_frame_decoder_init(&dec, small, sizeof(small)); + (void)memset(payload, 0x33, 20u); + n = encode(6u, payload, 20u); /* 23 bytes decoded: more than the buffer holds */ + EMB_ASSERT_EQ(feed(wire, n, &f), 0u); + EMB_ASSERT_EQ(dec.overruns, 1u); + EMB_ASSERT_EQ(dec.errors, 0u); + EMB_ASSERT_EQ(feed(v_hello, sizeof(v_hello), &f), 1u); /* 8 bytes: it fits */ + EMB_ASSERT_EQ(dec.frames, 1u); +} + +EMB_TEST(frame_misuse_is_refused) +{ + size_t n = 0u; + emb_frame_t f; + EMB_TEST_REQ("OBS-019"); + EMB_ASSERT_STATUS(emb_frame_encode(16u, NULL, 0u, wire, sizeof(wire), &n), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_frame_encode(0u, NULL, 1u, wire, sizeof(wire), &n), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_frame_encode(0u, NULL, 0u, NULL, sizeof(wire), &n), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_frame_encode(0u, NULL, 0u, wire, sizeof(wire), NULL), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_frame_encode(0u, "hello", 5u, wire, 9u, &n), EMB_EOVERFLOW); + EMB_ASSERT_OK(emb_frame_encode(0u, "hello", 5u, wire, EMB_FRAME_ENCODED_MAX(5u), &n)); + emb_frame_decoder_init(NULL, dbuf, sizeof(dbuf)); /* ignored */ + EMB_ASSERT_TRUE(!emb_frame_decode_byte(NULL, 0u, &f)); + EMB_ASSERT_TRUE(!emb_frame_decode_byte(&dec, 0u, NULL)); +} + +/* A fixed-seed generator: the same stream on every target (Numerical Recipes' LCG). */ +static uint32_t rng_state; + +static uint32_t rng(void) +{ + rng_state = (rng_state * 1664525u) + 1013904223u; + return rng_state >> 8; +} + +EMB_TEST(frame_random_stream_with_damage) +{ + emb_frame_t f = {NULL, 0u, 0u}; + unsigned sent_good = 0u; + unsigned got = 0u; + unsigned k; + EMB_TEST_REQ("OBS-019"); + rng_state = 0x0E3B1u; + emb_frame_decoder_init(&dec, dbuf, sizeof(dbuf)); + for (k = 0u; k < 200u; k++) { /* bounded: 200 frames */ + size_t len = (size_t)(rng() % 65u); + size_t i; + size_t n; + uint8_t ch = (uint8_t)(rng() % 16u); + for (i = 0u; i < len; i++) { /* bounded by len */ + payload[i] = (uint8_t)rng(); + } + n = encode(ch, payload, len); + if ((rng() % 8u) == 0u) { /* one frame in eight damaged on the line */ + size_t at = (size_t)(rng() % (uint32_t)(n - 1u)); + wire[at] = (uint8_t)(wire[at] ^ (uint8_t)(1u + (rng() % 255u))); + } else { + sent_good++; + } + got += feed(wire, n, &f); + if (got > 0u && f.len == len && f.channel == ch) { + EMB_ASSERT_TRUE(memcmp(f.payload, payload, len) == 0); + } + } + /* every undamaged frame is recovered, and no damaged one is taken for good */ + EMB_ASSERT_EQ(got, sent_good); + EMB_ASSERT_EQ(dec.frames, sent_good); + EMB_ASSERT_TRUE(dec.errors > 0u); +} diff --git a/tools/fault/api-ids.json b/tools/fault/api-ids.json index dedc478d..458339f8 100644 --- a/tools/fault/api-ids.json +++ b/tools/fault/api-ids.json @@ -889,6 +889,24 @@ "name": "emb_isr_stack_info", "header": "irq.h", "state": "active" + }, + { + "id": 165, + "name": "emb_frame_encode", + "header": "frame.h", + "state": "active" + }, + { + "id": 166, + "name": "emb_frame_decoder_init", + "header": "frame.h", + "state": "active" + }, + { + "id": 167, + "name": "emb_frame_decode_byte", + "header": "frame.h", + "state": "active" } ] } diff --git a/tools/fault/api-registry.json b/tools/fault/api-registry.json index 0e05f6bf..f3d4b1bd 100644 --- a/tools/fault/api-registry.json +++ b/tools/fault/api-registry.json @@ -888,6 +888,24 @@ "name": "emb_isr_stack_info", "header": "irq.h", "state": "active" + }, + { + "id": 165, + "name": "emb_frame_encode", + "header": "frame.h", + "state": "active" + }, + { + "id": 166, + "name": "emb_frame_decoder_init", + "header": "frame.h", + "state": "active" + }, + { + "id": 167, + "name": "emb_frame_decode_byte", + "header": "frame.h", + "state": "active" } ] } diff --git a/tools/transport/frame.py b/tools/transport/frame.py new file mode 100644 index 00000000..c1ceb617 --- /dev/null +++ b/tools/transport/frame.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +"""The host side of the framed byte stream (SPEC-015 §7, OBS-019). + + frame.py [--port /dev/cu.usbmodem1103 --baud 115200 | FILE] [--channel N] [--raw] + +A frame is COBS(channel u8, payload, CRC-16) followed by a zero byte. The CRC is +CRC-16/IBM-3740 (polynomial 0x1021, initial value 0xFFFF, not reflected) over the channel +byte and the payload, sent least significant byte first. Channels 0 log, 1 trace, 2 crash, +3 shell, 4 update; 5 to 15 the application's (AMENDMENTS-M4 A113). + +As a library: encode(), decode() for one frame, and Decoder for a stream, which drops bad +frames and resynchronizes at the next zero, as the target's decoder does. As a tool: prints +each good frame of a stream, from a serial port (pyserial) or a file of captured bytes, and +the counts at the end. +""" +import argparse +import sys + +CHANNEL_MAX = 15 +CHANNELS = {0: "log", 1: "trace", 2: "crash", 3: "shell", 4: "update"} + + +class FrameError(ValueError): + pass + + +def crc16(data, crc=0xFFFF): + for b in data: + crc ^= b << 8 + for _ in range(8): + crc = ((crc << 1) ^ 0x1021) if crc & 0x8000 else (crc << 1) + crc &= 0xFFFF + return crc + + +def cobs_encode(data): + out, run = bytearray(), bytearray() + for b in data: + if b == 0: + out += bytes([len(run) + 1]) + run + run = bytearray() + continue + run.append(b) + if len(run) == 254: + out += bytes([255]) + run + run = bytearray() + out += bytes([len(run) + 1]) + run + return bytes(out) + + +def cobs_decode(data): + out, i = bytearray(), 0 + while i < len(data): + code = data[i] + if code == 0: + raise FrameError("a zero inside a frame") + block = data[i + 1:i + code] + if len(block) != code - 1: + raise FrameError("a block cut short") + out += block + i += code + if code != 255 and i < len(data): + out.append(0) + return bytes(out) + + +def encode(channel, payload=b""): + """One frame's bytes, the delimiter included.""" + if not 0 <= channel <= CHANNEL_MAX: + raise FrameError(f"channel {channel} is above {CHANNEL_MAX}") + body = bytes([channel]) + bytes(payload) + crc = crc16(body) + return cobs_encode(body + bytes([crc & 0xFF, crc >> 8])) + b"\0" + + +def decode(frame): + """(channel, payload) of one frame, with or without its delimiter.""" + raw = cobs_decode(frame[:-1] if frame.endswith(b"\0") else frame) + if len(raw) < 3: + raise FrameError("too short for a channel and a CRC") + crc = crc16(raw[:-2]) + if raw[-2] != crc & 0xFF or raw[-1] != crc >> 8: + raise FrameError("bad CRC") + if raw[0] > CHANNEL_MAX: + raise FrameError(f"channel {raw[0]} is above {CHANNEL_MAX}") + return raw[0], raw[1:-2] + + +class Decoder: + """A stream decoder: feed() bytes as they arrive, get the good frames back.""" + + def __init__(self, max_payload=4096): + self.max = max_payload + 3 + self.buf = bytearray() + self.dropping = False + self.frames = self.errors = self.overruns = 0 + + def feed(self, data): + out = [] + for b in data: + if b != 0: + if not self.dropping: + self.buf.append(b) + if len(self.buf) > self.max * 2: # COBS adds little: this is no frame + self.dropping, self.buf = True, bytearray() + self.overruns += 1 + continue + if self.dropping: + self.dropping = False + elif self.buf: + try: + ch, payload = decode(bytes(self.buf)) + if len(payload) + 3 > self.max: + self.overruns += 1 + else: + out.append((ch, payload)) + self.frames += 1 + except FrameError: + self.errors += 1 + self.buf = bytearray() + return out + + +def main(argv=None): + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("file", nargs="?", help="a file of captured bytes") + ap.add_argument("--port") + ap.add_argument("--baud", type=int, default=115200) + ap.add_argument("--channel", type=int, action="append", help="only these channels") + ap.add_argument("--raw", action="store_true", help="payloads in hexadecimal, not text") + args = ap.parse_args(argv) + if (args.file is None) == (args.port is None): + ap.error("give a file or --port") + dec = Decoder() + + def show(frames): + for ch, payload in frames: + if args.channel and ch not in args.channel: + continue + text = payload.hex() if args.raw else payload.decode("utf-8", "replace").rstrip("\n") + print(f"[{CHANNELS.get(ch, ch)}] {text}", flush=True) + + try: + if args.file: + with open(args.file, "rb") as f: + show(dec.feed(f.read())) + else: + import serial # pyserial, only for a live port + with serial.Serial(args.port, args.baud, timeout=0.2) as s: + while True: + show(dec.feed(s.read(256))) + except KeyboardInterrupt: + pass + print(f"frame: {dec.frames} frames, {dec.errors} errors, {dec.overruns} overruns", file=sys.stderr) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/transport/test_frame.py b/tools/transport/test_frame.py new file mode 100644 index 00000000..10b9d1a4 --- /dev/null +++ b/tools/transport/test_frame.py @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +"""The host's framing (SPEC-015 §7, OBS-019): the vectors tests/conformance/test_frame.c checks +the target's encoder against, round trips, and the stream decoder's resynchronization.""" +import random +import sys +import unittest +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +import frame # noqa: E402 + +# the same bytes as test_frame.c's v_empty, v_zero and v_hello +VECTORS = [ + (0, b"", bytes([0x01, 0x03, 0xF0, 0xE1, 0x00])), + (1, b"\0", bytes([0x02, 0x01, 0x03, 0x3E, 0x2E, 0x00])), + (2, b"hello", bytes([0x09, 0x02, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x32, 0x46, 0x00])), +] + + +class Frame(unittest.TestCase): + def test_crc_check_value(self): + self.assertEqual(frame.crc16(b"123456789"), 0x29B1) # CRC-16/IBM-3740's check + + def test_vectors(self): + for ch, payload, wire in VECTORS: + self.assertEqual(frame.encode(ch, payload), wire) + self.assertEqual(frame.decode(wire), (ch, payload)) + + def test_cobs_boundary(self): + wire = frame.encode(7, bytes([0x11]) * 300) # test_frame.c's frame_runs_at_the_cobs_boundary + self.assertEqual((len(wire), wire[0], wire[255], wire[-3], wire[-2]), (306, 0xFF, 50, 0x0B, 0xC9)) + wire = frame.encode(5, bytes([0x22]) * 253) + self.assertEqual((len(wire), wire[0], wire[255]), (259, 0xFF, 0x03)) + for n in range(0, 800, 7): + wire = frame.encode(3, bytes(n)) + self.assertEqual(wire.count(0), 1) # only the delimiter + self.assertLessEqual(len(wire), n + 3 + (n + 3) // 254 + 2) # EMB_FRAME_ENCODED_MAX + self.assertEqual(frame.decode(wire), (3, bytes(n))) + + def test_refusals(self): + with self.assertRaises(frame.FrameError): + frame.encode(16, b"") + bad = bytearray(frame.encode(0, b"abc")) + bad[2] ^= 1 + with self.assertRaisesRegex(frame.FrameError, "CRC"): + frame.decode(bytes(bad)) + with self.assertRaisesRegex(frame.FrameError, "cut short"): + frame.decode(frame.encode(0, b"abc")[:-3]) + with self.assertRaisesRegex(frame.FrameError, "channel 16"): + frame.decode(bytes([0x04, 0x10, 0xC1, 0xF3, 0x00])) + + def test_stream_resynchronizes(self): + rnd = random.Random(1) + dec = frame.Decoder() + got = dec.feed(b"\x47\x13\x99\x05\x00") # joined mid-frame, then a delimiter + sent = [] + for _ in range(500): + ch, payload = rnd.randrange(16), bytes(rnd.randrange(256) for _ in range(rnd.randrange(80))) + wire = bytearray(frame.encode(ch, payload)) + if rnd.randrange(8) == 0: + at = rnd.randrange(len(wire) - 1) + wire[at] ^= rnd.randrange(1, 256) + else: + sent.append((ch, payload)) + if rnd.randrange(4) == 0: + wire = b"\0" + wire # a sender's leading zero + got += dec.feed(bytes(wire[:5])) + dec.feed(bytes(wire[5:])) # split across reads + self.assertEqual(got, sent) # every undamaged frame, and no damaged one + self.assertEqual(dec.frames, len(sent)) + self.assertGreater(dec.errors, 0) + + def test_overrun(self): + dec = frame.Decoder(max_payload=8) + self.assertEqual(dec.feed(frame.encode(6, bytes([0x33]) * 20)), []) + self.assertEqual(dec.overruns, 1) + self.assertEqual(dec.feed(frame.encode(2, b"hello")), [(2, b"hello")]) + + def test_tool_reads_a_capture(self): + import io + import tempfile + from contextlib import redirect_stdout, redirect_stderr + with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: + f.write(b"\x99\x98\x00" + frame.encode(0, b"boot ok\n") + frame.encode(5, b"\x01\x02")) + out, err = io.StringIO(), io.StringIO() + with redirect_stdout(out), redirect_stderr(err): + self.assertEqual(frame.main([f.name]), 0) + Path(f.name).unlink() + self.assertEqual(out.getvalue().splitlines(), ["[log] boot ok", "[5] \x01\x02"]) + self.assertIn("2 frames, 1 errors, 0 overruns", err.getvalue()) # the noise counts once + + +if __name__ == "__main__": + unittest.main() From d2d72958a2c7aeca7376d6823c19607de219af18 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Mon, 9 Nov 2026 16:06:27 +0100 Subject: [PATCH 02/25] docs: the framing's bound and its interrupt-safe functions CI's lint job: the resource-bound inventory gains frame_bytes, the bytes of one frame, which the caller's buffers bound and the decoder enforces by dropping a longer frame, for emb_frame_encode() and emb_frame_decode_byte(); and the interrupt-safe function table (docs/user/interrupts.md) lists the three framing functions. Every lint step's command passes locally. Signed-off-by: teo1747 --- docs/engineering/resource-bounds.json | 16 ++++++++++++++++ docs/engineering/resource-bounds.md | 3 +++ docs/user/interrupts.md | 5 ++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/engineering/resource-bounds.json b/docs/engineering/resource-bounds.json index f0f8fe44..86081bc6 100644 --- a/docs/engineering/resource-bounds.json +++ b/docs/engineering/resource-bounds.json @@ -162,6 +162,16 @@ "masked": true, "profiles": "CONFIG_EMB_FAULT_ACTION", "evidence": "03 \u00a710; SPEC-011 \u00a714" + }, + { + "id": "frame_bytes", + "input": "bytes of one frame: the payload encoded, or the frame decoded", + "bound": "the caller's: the payload it passes to emb_frame_encode(), and for a decoded frame the decoder's buffer, past which the frame is dropped", + "limit": "application: the buffers the caller gives", + "enforcement": "admission", + "masked": false, + "profiles": "every profile; the CRC is bitwise, eight steps a byte", + "evidence": "SPEC-015 \u00a77; OBS-019; test_frame" } ], "apis": { @@ -418,6 +428,12 @@ "emb_dwork_cancel_sync": [ "waiters", "timeouts" + ], + "emb_frame_encode": [ + "frame_bytes" + ], + "emb_frame_decode_byte": [ + "frame_bytes" ] } } diff --git a/docs/engineering/resource-bounds.md b/docs/engineering/resource-bounds.md index 22cf58b1..351873a7 100644 --- a/docs/engineering/resource-bounds.md +++ b/docs/engineering/resource-bounds.md @@ -22,6 +22,7 @@ Every cost input named by a public function's `@time` annotation, with how it is | **init_table**: entries of the initialization table | the EMB_*_DEFINE objects linked into the image | application, fixed at link time | application | no | prekernel only | KRN-OBJ-009 | | **callbacks**: application callbacks the kernel calls (fault hook, trace sink, foreach visitor) | not bounded by the kernel | application | application | yes | the fault hook and the trace sink can run with interrupts masked; the foreach visitor runs under the scheduler lock | API-017; SPEC-015 | | **port_action**: the port's fault action (halt or reset) | does not return | port | structural | yes | CONFIG_EMB_FAULT_ACTION | 03 §10; SPEC-011 §14 | +| **frame_bytes**: bytes of one frame: the payload encoded, or the frame decoded | the caller's: the payload it passes to emb_frame_encode(), and for a decoded frame the decoder's buffer, past which the frame is dropped | application: the buffers the caller gives | admission | no | every profile; the CRC is bitwise, eight steps a byte | SPEC-015 §7; OBS-019; test_frame | ## Public functions @@ -44,6 +45,8 @@ Every cost input named by a public function's `@time` annotation, with how it is | `emb_event_wait_until()` | O(1) check; O(waiters + timeouts) finite wait enqueue | waiters, timeouts | | `emb_fault()` | O(1) preparation plus trace/hook and the non-returning port action | callbacks, port_action | | `emb_fault_hook()` | the application's | callbacks | +| `emb_frame_decode_byte()` | O(len) at a delimiter, for the CRC; O(1) otherwise | frame_bytes | +| `emb_frame_encode()` | O(len) | frame_bytes | | `emb_isr_stack_info()` | O(stack) scan | stack | | `emb_kernel_init()` | O(init table) | init_table | | `emb_msgq_destroy()` | O(waiters) with EMB_OBJ_ABORT_WAITERS | batch_wake, reschedule | diff --git a/docs/user/interrupts.md b/docs/user/interrupts.md index a53139e6..7a83cfe7 100644 --- a/docs/user/interrupts.md +++ b/docs/user/interrupts.md @@ -45,7 +45,7 @@ Calling anything else from a handler is misuse: in a checked build it faults wit -79 functions, from the headers' `@ctx` tags. +82 functions, from the headers' `@ctx` tags. | Function | Header | Blocks | |---|---|---| @@ -65,6 +65,9 @@ Calling anything else from a handler is misuse: in a checked build it faults wit | `emb_event_set()` | `` | no | | `emb_fault()` | `` | no | | `emb_fault_hook()` | `` | no | +| `emb_frame_decode_byte()` | `` | no | +| `emb_frame_decoder_init()` | `` | no | +| `emb_frame_encode()` | `` | no | | `emb_in_isr()` | `` | no | | `emb_instant_add()` | `` | no | | `emb_instant_before()` | `` | no | From 8cfc819a0046fa6c08f75b6a33b636af033d5155 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 03:52:54 +0100 Subject: [PATCH 03/25] all: the framing's files take the file header tools/dev/file_headers.py --write on the files this branch added before the header (CS-11.1) merged: frame.h, frame.c, the subsystems' build and configuration, the conformance test and the host's codec and its tests. Signed-off-by: teo1747 --- include/emb/frame.h | 23 +++++++++++++++++++---- subsys/CMakeLists.txt | 4 ++++ subsys/Kconfig | 4 ++++ subsys/transport/frame.c | 21 +++++++++++++++++---- tests/conformance/test_frame.c | 19 ++++++++++++++++--- tools/transport/frame.py | 4 ++++ tools/transport/test_frame.py | 4 ++++ 7 files changed, 68 insertions(+), 11 deletions(-) diff --git a/include/emb/frame.h b/include/emb/frame.h index e2c4c3c3..0e34911f 100644 --- a/include/emb/frame.h +++ b/include/emb/frame.h @@ -1,9 +1,24 @@ /* SPDX-License-Identifier: Apache-2.0 */ /* Copyright 2026 Junior Deogracias */ -/* Framed byte streams (SPEC-015 §7, OBS-019): one frame is COBS(channel, payload, CRC-16) - * and a zero delimiter, so a byte-stream transport (a UART, USB CDC, a network socket) - * carries the log, the trace, the crash record, the shell and the update protocol over one - * line, and a decoder that joins mid-stream finds the next frame at the next zero. */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file frame.h + * @brief Framed byte streams (SPEC-015 §7, OBS-019). + * + * @details + * One frame is COBS(channel, payload, CRC-16) and a zero delimiter, so a byte-stream transport (a + * UART, USB CDC, a network socket) carries the log, the trace, the crash record, the shell and the + * update protocol over one line, and a decoder that joins mid-stream finds the next frame at the + * next zero. + * + * @see subsys/transport/frame.c + * @author Junior Deogracias + * @date 2026-11-09 (created) + */ #ifndef EMB_FRAME_H #define EMB_FRAME_H diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 3a8e873d..83274997 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + # emb_subsys: the subsystems over the kernel (transports, and in M4 logging, trace and update), # each behind its CONFIG_EMB_* symbol, compiled like the kernel and linked into every image, # which keeps only what it calls. With none selected it is an empty interface library. diff --git a/subsys/Kconfig b/subsys/Kconfig index 37f9906f..2c3f7d02 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + menu "Subsystems" config EMB_FRAME diff --git a/subsys/transport/frame.c b/subsys/transport/frame.c index d3841f19..9ab6153d 100644 --- a/subsys/transport/frame.c +++ b/subsys/transport/frame.c @@ -1,10 +1,23 @@ /* SPDX-License-Identifier: Apache-2.0 */ /* Copyright 2026 Junior Deogracias */ /* - * Framed byte streams (SPEC-015 §7, OBS-019): COBS over the channel byte, the payload and a - * CRC-16, ended by a zero. Consistent Overhead Byte Stuffing (Cheshire and Baker, 1999) writes - * each run of up to 254 nonzero bytes after a code byte holding the run's length plus one; - * a code below 0xFF stands for a zero after its run, except at the frame's end. + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file frame.c + * @brief Framed byte streams (SPEC-015 §7, OBS-019). + * + * @details + * COBS over the channel byte, the payload and a CRC-16, ended by a zero. Consistent Overhead Byte + * Stuffing (Cheshire and Baker, 1999) writes each run of up to 254 nonzero bytes after a code byte + * holding the run's length plus one; a code below 0xFF stands for a zero after its run, except at + * the frame's end. + * + * @see include/emb/frame.h + * @author Junior Deogracias + * @date 2026-11-09 (created) */ #include diff --git a/tests/conformance/test_frame.c b/tests/conformance/test_frame.c index c101a1d2..6cd25671 100644 --- a/tests/conformance/test_frame.c +++ b/tests/conformance/test_frame.c @@ -1,8 +1,21 @@ /* SPDX-License-Identifier: Apache-2.0 */ /* Copyright 2026 Junior Deogracias */ -/* Framed byte streams (SPEC-015 §7; OBS-019): the encoder against vectors the host tool - * (tools/transport/frame.py) produces from the specification, and the stream decoder's - * resynchronization, CRC and overrun handling. */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file test_frame.c + * @brief Framed byte streams (SPEC-015 §7; OBS-019). + * + * @details + * The encoder against vectors the host tool (tools/transport/frame.py) produces from the + * specification, and the stream decoder's resynchronization, CRC and overrun handling. + * + * @author Junior Deogracias + * @date 2026-11-09 (created) + */ #include #include diff --git a/tools/transport/frame.py b/tools/transport/frame.py index c1ceb617..740b32c7 100644 --- a/tools/transport/frame.py +++ b/tools/transport/frame.py @@ -1,6 +1,10 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 # Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + """The host side of the framed byte stream (SPEC-015 §7, OBS-019). frame.py [--port /dev/cu.usbmodem1103 --baud 115200 | FILE] [--channel N] [--raw] diff --git a/tools/transport/test_frame.py b/tools/transport/test_frame.py index 10b9d1a4..94ddfd48 100644 --- a/tools/transport/test_frame.py +++ b/tools/transport/test_frame.py @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + """The host's framing (SPEC-015 §7, OBS-019): the vectors tests/conformance/test_frame.c checks the target's encoder against, round trips, and the stream decoder's resynchronization.""" import random From b0f54acdf13c9a79ada59f9da318027caf905387 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 03:54:37 +0100 Subject: [PATCH 04/25] subsys: the framing codec's MISRA findings fixed, the rest baselined What parked #139: rule 12.1 (precedence made explicit in every compound condition and the CRC loop's bound), 17.8 (crc16() keeps its argument and works on a local), and cppcheck's variableScope (the decoder's result declared where it is used). What stays is what the tree accepts everywhere for a public API: 11.5 (the payload a const void *), 8.7 (the three public functions) and 2.5 (the channel macros in frame.h), recorded in the baseline. test_frame passes on native Clang. Signed-off-by: teo1747 --- subsys/transport/frame.c | 31 +++++++++++++++--------------- tools/analysis/misra-baseline.json | 7 +++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/subsys/transport/frame.c b/subsys/transport/frame.c index 9ab6153d..7ce401c2 100644 --- a/subsys/transport/frame.c +++ b/subsys/transport/frame.c @@ -29,15 +29,15 @@ static uint16_t crc16(uint16_t crc, uint8_t byte) { unsigned bit; - crc = (uint16_t)(crc ^ (uint16_t)((uint16_t)byte << 8)); + uint16_t c = (uint16_t)(crc ^ (uint16_t)((uint16_t)byte << 8)); for (bit = 0u; bit < 8u; bit++) { /* bounded: eight bits */ - if ((crc & 0x8000u) != 0u) { - crc = (uint16_t)((uint16_t)(crc << 1) ^ CRC_POLY); + if ((c & 0x8000u) != 0u) { + c = (uint16_t)((uint16_t)(c << 1) ^ CRC_POLY); } else { - crc = (uint16_t)(crc << 1); + c = (uint16_t)(c << 1); } } - return crc; + return c; } /* The encoder's state: where the open run's code byte goes, and the run's code so far. */ @@ -75,12 +75,12 @@ emb_status_t emb_frame_encode(uint8_t channel, const void *payload, size_t len, cobs_t c; uint16_t crc = CRC_INIT; size_t i; - if (channel > EMB_FRAME_CHANNEL_MAX || out == NULL || out_len == NULL || - (payload == NULL && len != 0u)) { + if ((channel > EMB_FRAME_CHANNEL_MAX) || (out == NULL) || (out_len == NULL) || + ((payload == NULL) && (len != 0u))) { return EMB_EINVAL; } /* the bound is computed so that it cannot wrap: a payload this long is refused first */ - if (len > (SIZE_MAX / 2u) || cap < EMB_FRAME_ENCODED_MAX(len)) { + if ((len > (SIZE_MAX / 2u)) || (cap < EMB_FRAME_ENCODED_MAX(len))) { return EMB_EOVERFLOW; } c.out = out; @@ -144,15 +144,15 @@ static bool frame_end(emb_frame_decoder_t *dec, emb_frame_t *frame) if (dec->code == 0u) { return false; /* no frame: a zero between frames */ } - if (dec->left != 0u || n < EMB_FRAME_OVERHEAD) { + if ((dec->left != 0u) || (n < EMB_FRAME_OVERHEAD)) { dec->errors++; /* a block cut short, or too short to hold a channel and a CRC */ return false; } - for (i = 0u; i < n - 2u; i++) { /* bounded by the frame's length */ + for (i = 0u; i < (n - 2u); i++) { /* bounded by the frame's length */ crc = crc16(crc, dec->buf[i]); } - if ((uint8_t)(crc & 0xFFu) != dec->buf[n - 2u] || (uint8_t)(crc >> 8) != dec->buf[n - 1u] || - dec->buf[0] > EMB_FRAME_CHANNEL_MAX) { + if (((uint8_t)(crc & 0xFFu) != dec->buf[n - 2u]) || ((uint8_t)(crc >> 8) != dec->buf[n - 1u]) || + (dec->buf[0] > EMB_FRAME_CHANNEL_MAX)) { dec->errors++; return false; } @@ -165,12 +165,11 @@ static bool frame_end(emb_frame_decoder_t *dec, emb_frame_t *frame) bool emb_frame_decode_byte(emb_frame_decoder_t *dec, uint8_t byte, emb_frame_t *frame) { - bool good; - if (dec == NULL || frame == NULL) { + if ((dec == NULL) || (frame == NULL)) { return false; } if (byte == 0u) { - good = frame_end(dec, frame); + bool good = frame_end(dec, frame); dec->len = 0u; dec->code = 0u; dec->left = 0u; @@ -178,7 +177,7 @@ bool emb_frame_decode_byte(emb_frame_decoder_t *dec, uint8_t byte, emb_frame_t * return good; } if (dec->left == 0u) { /* a code byte: the zero the last run stood for comes first */ - if (dec->code != 0u && dec->code != COBS_RUN_MAX) { + if ((dec->code != 0u) && (dec->code != COBS_RUN_MAX)) { keep(dec, 0u); } dec->code = byte; diff --git a/tools/analysis/misra-baseline.json b/tools/analysis/misra-baseline.json index d4c72090..de8746ed 100644 --- a/tools/analysis/misra-baseline.json +++ b/tools/analysis/misra-baseline.json @@ -465,6 +465,9 @@ "include/emb/fault.h": { "misra-c2012-2.4": 1 }, + "include/emb/frame.h": { + "misra-c2012-2.5": 6 + }, "include/emb/irq.h": { "misra-c2012-2.3": 1, "misra-c2012-2.5": 1, @@ -919,5 +922,9 @@ "soc/st/stm32f4/include/emb_stm32_pins.h": { "misra-c2012-20.10": 1, "misra-c2012-8.11": 1 + }, + "subsys/transport/frame.c": { + "misra-c2012-11.5": 1, + "misra-c2012-8.7": 3 } } From a4a53fd1af65337bf813aa728c859803e9d60f03 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 04:00:01 +0100 Subject: [PATCH 05/25] docs: A113 accepted by the project owner The frame's channels (0 log, 1 trace, 2 crash, 3 shell, 4 update, 5 to 15 the application's) and its CRC-16/IBM-3740 over the channel and the payload, low byte first, accepted as written on 2026-11-13. Signed-off-by: teo1747 --- docs/specs/AMENDMENTS-M4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/specs/AMENDMENTS-M4.md b/docs/specs/AMENDMENTS-M4.md index 535f2a1c..a5cd7e0e 100644 --- a/docs/specs/AMENDMENTS-M4.md +++ b/docs/specs/AMENDMENTS-M4.md @@ -11,7 +11,7 @@ Changes M4 makes to accepted specifications and requirements, where an accepted | A110 | SPEC-014 §3, SPEC-018 §2.2 | **Power states in the SoC description.** `power.states` entries gain `class` (IDLE, SLEEP, DEEP_SLEEP or OFF), `entry_us`, `exit_us` (replacing `exit_latency_us`), `min_residency_us`, `wake` (the wake sources), `timebase` (what keeps time while the main timer is stopped) and `retains`, beside `loses`. The figures start as the datasheet's and are replaced by measurements (PWR-006). The generator emits the table the policy reads. | `hw/schemas/soc.schema.json`, `hw/gen/emb_hwgen/` (M4.4) | | A111 | SPEC-014 §4, §7, SPEC-019 §3 | **The `boot` key and the image's partitions.** A board may declare `boot: {loader: mcuboot, header_size, mode}`. With it, `flash_partitions` must name `bootloader`, `slot0`, `slot1`, and `scratch` for `mode: swap_scratch`; each partition is whole sectors of the flash's geometry, the slots are equal, and the scratch is at least the largest sector a slot uses. The application links at `slot0` plus `header_size`, and the refusal of an application partition away from the boot base applies only to boards without `boot`. | `hw/gen/emb_hwgen/model.py` (M4.5) | | A112 | SPEC-014 §4, ADR-059 | **The board's system timer.** A board may name `system_timer: `, the SoC timer that keeps tickless time (ADR-059). The generator checks that the peripheral is a timer whose features the port's tickless hooks need (a free-running counter of at least 32 bits and a compare or alarm), and declares the architecture's tickless capability for that board only. | `hw/gen/emb_hwgen/`, `arch/cortex_m/` (M4.4) | -| A113 | SPEC-015 §7, OBS-019, SPEC-019 §6 | **The frame's channels and CRC.** SPEC-015 §7 gave channels 4 to 15 to the application, while SPEC-019 §6 runs the update protocol on channel 4. Channels 0 to 4 become the system's (0 log, 1 trace, 2 crash, 3 shell, 4 update) and 5 to 15 the application's. §7 named a CRC-16 without saying which: it is CRC-16/IBM-3740 (polynomial 0x1021, initial value 0xFFFF, neither reflected, no final XOR; check value 0x29B1), computed over the channel byte and the payload and sent least significant byte first, inside the COBS encoding. A frame whose channel byte is above 15 is dropped as malformed. OBS-019 reads: "…channels 0 log, 1 trace, 2 crash, 3 shell, 4 update, 5 to 15 application; CRC-16/IBM-3740 over the channel and the payload…". *Proposed 2026-11-09 with M4.3's framing, for the project owner's review.* | `include/emb/frame.h`, `subsys/transport/frame.c`, `tools/transport/frame.py` (M4.3) | +| A113 | SPEC-015 §7, OBS-019, SPEC-019 §6 | **The frame's channels and CRC.** SPEC-015 §7 gave channels 4 to 15 to the application, while SPEC-019 §6 runs the update protocol on channel 4. Channels 0 to 4 become the system's (0 log, 1 trace, 2 crash, 3 shell, 4 update) and 5 to 15 the application's. §7 named a CRC-16 without saying which: it is CRC-16/IBM-3740 (polynomial 0x1021, initial value 0xFFFF, neither reflected, no final XOR; check value 0x29B1), computed over the channel byte and the payload and sent least significant byte first, inside the COBS encoding. A frame whose channel byte is above 15 is dropped as malformed. OBS-019 reads: "…channels 0 log, 1 trace, 2 crash, 3 shell, 4 update, 5 to 15 application; CRC-16/IBM-3740 over the channel and the payload…". *Proposed 2026-11-09 with M4.3's framing; accepted by the project owner on 2026-11-13 ("accept as written").* | `include/emb/frame.h`, `subsys/transport/frame.c`, `tools/transport/frame.py` (M4.3) | | A114 | SPEC-016 §5, §6, SPEC-017 §4 | **Request lanes.** SPEC-016 §5 queued a device's requests in one queue and started only its head, while SPEC-017 §4 has the UART run one write and one read at once. A device gets two lanes (`EMB_DRV_LANES`), each a queue of its own whose head starts whatever the other lane does; a request names its lane (`emb_drv_request_t.lane`, 0 by default, set by the class before submitting). The UART puts writes on lane 0 and reads on lane 1; a class that needs one lane uses lane 0 and behaves as before. Suspend refuses a device with a request on either lane; cancel and completion act on the request's own lane. *Proposed 2026-11-09 with M4.2's UART class, for the project owner's review.* | `include/emb/device.h`, `kernel/device/device.c` (M4.2) | | A115 | SPEC-016 §5, MISRA C:2012 rule 17.2 | **A driver's start returns its status.** A driver's `start()` returned nothing and finished a short request by calling `emb_drv_complete()`, which started the next request, whose `start()` could finish it the same way: a recursion as deep as the queue, and a cycle in the call graph the static stack bound refuses. `start()` now returns `EMB_EBUSY` while the request runs on, the driver completing it later, or the request's final status, with its `done` set, when it finished inside `start()`. The core starts a lane's requests in a loop for as long as each finishes there, and `start()` never calls `emb_drv_complete()` for the request it was given. The UART class's `emb_drv_uart_rx_start()` returns a status for the same reason. *Proposed 2026-11-09 with M4.2's UART class, for the project owner's review.* | `include/emb/device.h`, `kernel/device/device.c`, the drivers' `start()` (M4.2) | | A116 | SPEC-017 §1, §5 (new §5a), SPEC-014 §5, SPEC-011 §11 | **The GPIO class and chip selects.** SPEC-017 §1 left GPIO as the boards' functions until a second driver needed a class; an SPI target's chip select is that need, on both of M4's SoCs. **§5a, the GPIO class:** a controller's lines set up as inputs or outputs (`emb_drv_gpio_configure()`: pulls, open drain, an output's first level), driven and read (`emb_drv_gpio_write()`, `emb_drv_gpio_read()`, the level at the pin), each O(1) and callable from any context; a named line (`emb_drv_gpio_line_t`: controller, number, sense) asserted or released by `emb_drv_gpio_assert()`. The STM32F4's ports and the RP2350's bank 0 (through the SIO) are its drivers; the RP2350's pads have no open drain, which its driver makes with the output enable. **§5, the SPI class:** a target names its chip select, asserted once the controller is set up for it and released after its last frame; `emb_drv_spi_acquire()` and `emb_drv_spi_release()` hold the bus for one target, its chip select asserted across the transfers, with a recursive mutex with priority inheritance (SPEC-016 §6). Other threads' transfers wait within their timeouts, and a transfer for another target is refused with `EMB_EBUSY`. **SPEC-014 §5:** a board's SPI device lists its chip selects (`cs: [PB12]`, or `{pin, active: high}`), each a line of one of the board's GPIO devices: the generator names it `EMB_SOC__CS` and its pin table sets it up as an output, deasserted, at boot. **SPEC-011 §11:** on Cortex-M, `emb_arch_system_reset()` first calls the board's `emb_board_reset_prepare()`, as the Xtensa port does, so a console with a transmit FIFO lets its last line out. *Proposed 2026-11-09 with M4.2's SPI class, for the project owner's review.* | `include/emb/drv_gpio.h`, `include/emb/drv_spi.h`, `kernel/device/{gpio,spi}.c`, `drivers/st/stm32_devices.c`, `drivers/rpi/rp2350_devices.c`, `hw/gen/emb_hwgen/`, `arch/cortex_m/cm_port.c` (M4.2) | From b5d74a3b4f2c31d81b6084be3d2405b6b55cb01d Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 04:21:47 +0100 Subject: [PATCH 06/25] docs: A127, logging, its ring and the console, proposed The owner chose on 2026-11-13 the ring's critical-section reservation over a lock-free one, both backends with the deferred one the default, and the framed console as an option. A127 writes those choices out: the call sites, the record both backends share, identifiers as offsets in a non-allocated section, the ring's reservation, commit, publication and overflow rules, the log thread and the console's frames. Signed-off-by: teo1747 --- docs/specs/AMENDMENTS-M4.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/specs/AMENDMENTS-M4.md b/docs/specs/AMENDMENTS-M4.md index a5cd7e0e..cbdfec3e 100644 --- a/docs/specs/AMENDMENTS-M4.md +++ b/docs/specs/AMENDMENTS-M4.md @@ -23,5 +23,6 @@ Changes M4 makes to accepted specifications and requirements, where an accepted | A122 | SPEC-017 §9, SPEC-014 §3, §4, SPEC-011, SPEC-003 §4 | **The flash class, partitions, and the clock across a stall.** SPEC-017 §9 had flash requests queued and their ends delivered by interrupt on the STM32. Every operation now runs to its end in the caller, under the device's lock: the STM32F446's single bank stalls the CPU's fetches meanwhile, and the RP2350 must hold interrupts off while XIP is off, so a queue would let nothing run. The calls are `emb_drv_flash_read()`, `_program()` and `_erase()` with a timeout for the lock, polled versions without it, `emb_drv_flash_geometry_get()` and `emb_drv_flash_sector()`. A program is read back, and bytes that were not erased give `EMB_EVERIFY`. An erase runs a sector at a time. A flash device's geometry is generated from the SoC's `flash:` and, where the chip is smaller than its window, the board device's `size:`. The RP2350's `flash:` is 4 KiB sectors and 256-byte pages. The board's `flash_partitions` become `` areas, `EMB_FLASH_AREA_`. The NUCLEO-F446RE's app partition shrinks to sectors 0 to 6, with sector 7 as `storage`; the Pico 2 W's gives its last 64 KiB to `storage`. The periodic tick misses its interrupts during an operation, so the Cortex-M port times it by DWT CYCCNT (`emb_cm_stall_begin()`, `emb_cm_stall_end()`, `emb_cm_cycle_count()`). A new kernel hook, `embk_time_ticks_missed()`, adds the ticks that passed at the next tick interrupt; it does nothing in tickless mode, which M4.4 brings to Cortex-M. The generated linker script gains a `.ramfunc` section in RAM, copied with `.data`, where the RP2350's flash routine runs, and the Arm GCC link no longer warns about the writable, executable segment. *Proposed 2026-11-10 with M4.2's flash class, for the project owner's review; the clock's catch-up and the storage partitions chosen by the owner on 2026-11-10.* | `include/emb/drv_flash.h`, `include/emb/flash_area.h`, `kernel/device/flash.c`, `kernel/time/time.c`, `arch/cortex_m/cm_port.c`, `drivers/st/stm32_flash.c`, `drivers/rpi/rp2350_flash.c`, `hw/gen/emb_hwgen/` (M4.2) | | A123 | SPEC-017 §10, SPEC-003 §10, KRN-TIM-031, SPEC-018 | **The RTC class and the wall clock.** SPEC-017 §10's requests become `emb_drv_rtc_get()` and `_set()`, with the time in nanoseconds since the Unix epoch (UTC), the wall clock's unit. There is one alarm per device, its callback in the alarm interrupt, `EMB_EBUSY` while armed, and `_alarm_cancel()`; a `set` disarms it. The backup registers are `_backup_read()` and `_write()`. The wake-up timer, the power policy's wake source, moves to M4.4 with SPEC-018, its only user, where its latency is measured. An alarm never fires before its time. It works at the RTC's resolution, and with a calendar it reaches 28 days ahead. The STM32F4's driver does not wait for the LSE at initialization; the first `set` waits instead. The RP2350 has no calendar: its RTC is the AON timer in POWMAN, milliseconds since the epoch on a 1 kHz tick from the crystal. That tick stops in DORMANT, where M4.4 switches it to LPOSC. SPEC-003 §10's wall clock is implemented: ``, behind `CONFIG_EMB_WALLCLOCK`, which needs 64-bit ticks. It is `EMB_ENOTSET` until it is set, or until a set RTC seeds it when its device starts (`emb_drv_rtc_started()`). `emb_wallclock_adjust()` steps; there is no slewing in M4. *Proposed 2026-11-10 with M4.2's RTC class, for the project owner's review; the wake-up timer's move and the RP2350's crystal tick chosen by the owner on 2026-11-10.* | `include/emb/drv_rtc.h`, `include/emb/wallclock.h`, `kernel/device/rtc.c`, `kernel/time/wallclock.c`, `drivers/st/stm32_rtc.c`, `drivers/rpi/rp2350_aon.c` (M4.2) | | A124 | SPEC-017 §11, SEC-012 | **The entropy class.** A read is `emb_drv_entropy_read(dev, buf, len, &got, timeout)`, assembled from a driver's blocks under the device's lock and one timeout. A timeout keeps the bytes read. A block that fails the source's health test ends the read with `EMB_EHEALTH`, and none of its bytes is delivered. The source's output is conditioned in the class, as NIST SP 800-90B asks of a raw noise source: every 32 bytes read are the SHA-256 of 64 raw, health-tested bytes. `emb_drv_entropy_read_raw()` reads the raw blocks, for measuring the source: on the RP2350 they fail a byte chi-square and a runs test, though they pass the TRNG's own health tests, and their most-common-value min-entropy must reach the 4 bits a byte that conditioning 2:1 needs. Every board defines `emb_board_entropy`: the generated `soc_devices.c` from the description, a hand-written board by hand. It is NULL where the board has no source, and `emb_drv_entropy_board()` then returns `EMB_ENOTSUP`. The native board's source is the host's `getentropy()`. The RP2350's TRNG keeps every health test on, and samples every 200 clocks, from a measurement on the board (`sample_count:` on the device). SPEC-017 §11's evidence changes: the 1 MiB is tested on the board, and a 64 KiB sample with its SHA-256 is archived and checked on the host, in place of archiving the whole MiB. *Proposed 2026-11-12 with M4.2's entropy class, for the project owner's review; the evidence's form, the native board's host source and the conditioning chosen by the owner on 2026-11-12.* | `include/emb/drv_entropy.h`, `kernel/device/entropy.c`, `kernel/device/sha256.c`, `drivers/rpi/rp2350_trng.c`, `boards/native/native/board.c`, `tools/entropy/check.py` (M4.2) | +| A127 | SPEC-015 §2, §7, §9, §12 decision 2, OBS-002, OBS-003, OBS-013, OBS-021, 08 Q13 | **Logging, its ring and the console.** **Call sites (§2.1):** a module is defined once with `EMB_LOG_MODULE_DEFINE(name, level)` and declared in its other files with `EMB_LOG_MODULE_DECLARE(name, level)`; §2.1 had only the declaration, which cannot both define the module and serve a module whose calls span files. `EMB_LOG_ERR`, `_WRN`, `_INF` and `_DBG(name, format, ...)` take at most eight arguments, and the compiler checks each format against its arguments as it checks printf's. A call above its file's level for the module, or above `CONFIG_EMB_LOG_LEVEL_MAX`, compiles to nothing; one above the module's run-time level (`emb_log_level_set()`) returns after one comparison. **One record, two backends (§2.3, §2.4, Q13):** every call packs its arguments into the record of §2.3 in the caller, typed by a signature the compiler computes from their C types with C11's `_Generic` (int, long, long long and their unsigned forms, double, string, pointer). The deferred backend (ADR-009) sends the record and the host formats it; the plain-text backend formats the same record on the target, in the log thread. Neither formats in the caller, so a call costs the same in an interrupt with either backend. **Identifiers (§2.2):** a call site's metadata (format, file, line, level, module, signature) is placed in the section `emb_log`, which the generated linker scripts lay at address 0 as a non-allocated (`INFO`) section. Its bytes stay in the ELF for the decoder and never reach the image. §2.2's `NOLOAD` would drop them from the ELF too. The identifier is the metadata's offset in the section plus 8, so identifiers 0 to 7 are the stream's own: 0 synchronization, 1 `dropped(u16 count)`, 2 `start(build_id[20], tick_hz u32)`, which the log thread sends when it starts. It is 16 bits when the section is under 64 KiB minus 8, else 32. The target computes the width from the section's bounds, so it is fixed at link time, and the decoder computes it from the ELF's section, with no ELF note. A linker without the script places the section as ordinary data, with the same identifiers. The plain-text backend's metadata is ordinary read-only data, and its record carries the metadata's address. **Timestamp:** the kernel clock's ticks, their low 32 bits, at the rate the start record gives. §2.3 used the trace clock, which wraps within seconds on a fast part, while logs can be minutes apart. **The ring (§2.3, §2.5, §12 decision 2):** one ring per CPU, a power-of-two array of `CONFIG_EMB_LOG_RING_SIZE` bytes. *Reservation* is a critical section of a bounded number of instructions: it checks the free space, advances the head by the record's size and writes the record's two-byte header (its length, not yet committed). The producer then copies its record with interrupts enabled and *commits* it by setting the header's committed bit, one byte store after a barrier. *Nested producers:* an interrupt that preempts a producer reserves after it, so records keep the order in which they were reserved. *Publication:* the log thread takes records from the tail in order and stops at the first uncommitted one, and the records after it wait, committed or not, until it is committed. *A preempted record* holds back those after it until its producer runs again; meanwhile the ring fills and later records are dropped. Nothing is overwritten and nothing waits. *Overflow:* a record that does not fit is dropped and counted, and the next record that fits is preceded by the `dropped` record, in the same reservation, so the count stands where the loss was. *Consumer progress:* only the log thread advances the tail, inside the same critical section, since a 16-bit store is not atomic on AVR. A record is at most `EMB_LOG_RECORD_MAX` bytes: strings are cut at `CONFIG_EMB_LOG_STR_MAX` and hexdumps at `CONFIG_EMB_LOG_HEXDUMP_MAX`. This replaces §12 decision 2's lock-free ring. Cortex-M0 and AVR have no compare-and-swap for a lock-free reservation, and one design verified on every port is worth more than a second one. The critical section is bounded by constants, which is what OBS-003 asks. The ring does not survive a reset; `emb_log_flush()` writes out what is committed, polled, from any context, and the fault path calls it. **The log thread (§2.4):** a thread of its own (`CONFIG_EMB_LOG_THREAD_PRIORITY`, by default the lowest application priority, and `CONFIG_EMB_LOG_THREAD_STACK`), woken by a semaphore given when a record lands in an empty ring. It is not the system work queue, whose other items a slow console would hold up. **The console (§7):** a board writes raw bytes with `emb_board_write()`, and `emb_board_puts()` becomes common code. By default the console is plain text: the board's prints and the plain-text backend's lines. With `CONFIG_EMB_CONSOLE_FRAMED` everything on it travels in A113's frames: the board's text on channel 3, the shell's, buffered by line; log records on channel 0; trace on 1; crash records on 2. A frame holds whole records, so each frame's start is a synchronization point, and the synchronization record is left to unframed transports (SWO, the memory channel), which M4.3 does not implement. A thread's frame is written whole under the console's mutex. Text printed from an interrupt, a fault or before the kernel starts is framed and written at once, without the mutex, and can cut a thread's frame; the decoder then drops that frame and counts it. A zero precedes every frame, so bytes that are not a frame (a boot ROM's text, a cut frame) end before it, and `emb monitor` shows them as raw text. The deferred backend needs the framed console; without it the plain-text backend is the one built. **Profiles (§9, Q13):** logging is off until an application turns on `CONFIG_EMB_LOG`. Its backend is then the deferred one where the console is framed and the plain-text one elsewhere, and always the plain-text one on tiny. **OBS-013** reads: "…the identifier being the offset of the call site's metadata in a non-allocated section, plus 8 (16 bits when it fits, else 32)…; over a framed transport each frame starts with a record; the plain-text backend shall share the call sites and the record." *Proposed 2026-11-13 with M4.3's logging. The project owner chose on 2026-11-13 the ring's critical-section reservation over a lock-free one, both backends with the deferred one the default, and the framed console as an option; the rest is for their review.* | `include/emb/log.h`, `include/emb/console.h`, `subsys/logging/log.c`, `subsys/console/console.c`, the boards' `emb_board_write()`, `hw/gen/emb_hwgen/` (the section), `tools/logdec/` (M4.3) | **Not an amendment:** writing the vector table base (VTOR) at reset is already `emb_arch_early_init()`'s duty in SPEC-011 §4. The Cortex-M port has not done it, because every image so far boots from the boot base; M4.5 implements it for images in a slot (SPEC-019 §3). From b160f16a89c6c06287847556f09edfcff7bf87c9 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 04:23:35 +0100 Subject: [PATCH 07/25] subsys: emb_frame_write() sends a frame to a sink as it is encoded The console sends frames from interrupts and faults as well as threads, and a buffer for the encoded frame would be one more thing to share or to put on a small stack. emb_frame_write() reads the payload in place, finding each COBS run's end by looking ahead, and hands the sink a run's bytes in one call. It writes exactly what emb_frame_encode() writes, which the new case checks around the 254-byte run with no zero, zeros inside and a zero last. API id 250. Signed-off-by: teo1747 --- include/emb/api_ids.h | 1 + include/emb/frame.h | 30 ++++++++++++ subsys/transport/frame.c | 89 ++++++++++++++++++++++++++++++++++ tests/conformance/test_frame.c | 65 +++++++++++++++++++++++++ tools/fault/api-ids.json | 6 +++ tools/fault/api-registry.json | 6 +++ 6 files changed, 197 insertions(+) diff --git a/include/emb/api_ids.h b/include/emb/api_ids.h index bed15e9e..1737c42f 100644 --- a/include/emb/api_ids.h +++ b/include/emb/api_ids.h @@ -244,5 +244,6 @@ #define EMB_API_ID_FRAME_ENCODE 0x00F7u #define EMB_API_ID_FRAME_DECODER_INIT 0x00F8u #define EMB_API_ID_FRAME_DECODE_BYTE 0x00F9u +#define EMB_API_ID_FRAME_WRITE 0x00FAu #endif /* EMB_API_IDS_H */ diff --git a/include/emb/frame.h b/include/emb/frame.h index 0e34911f..414d1419 100644 --- a/include/emb/frame.h +++ b/include/emb/frame.h @@ -100,6 +100,36 @@ typedef struct emb_frame_decoder { emb_status_t emb_frame_encode(uint8_t channel, const void *payload, size_t len, uint8_t *out, size_t cap, size_t *out_len); +/* Where emb_frame_write() sends a frame's bytes, a run at a time. */ +typedef void (*emb_frame_sink_t)(void *ctx, const uint8_t *bytes, size_t len); + +/** + * emb_frame_write() - Send one frame to a sink as it is encoded, without a buffer. + * @channel: 0 to EMB_FRAME_CHANNEL_MAX. + * @payload: The payload; may be NULL when @len is 0. + * @len: Its bytes. + * @sink: Receives the frame's bytes in order, the delimiter last; called once per COBS + * run or code byte. + * @ctx: Passed to @sink. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(len) plus @sink's + * @owns none + * @config CONFIG_EMB_FRAME + * @req OBS-019 + * @since 0.3 + * @stable no + * + * Sends the bytes emb_frame_encode() would write, reading the payload in place: a code byte + * is found by looking ahead in the payload for its run's end, so no copy of the frame is + * kept. The payload must not change until this returns. + * + * Return: EMB_OK; EMB_EINVAL (a channel above 15, or a pointer missing). + */ +emb_status_t emb_frame_write(uint8_t channel, const void *payload, size_t len, + emb_frame_sink_t sink, void *ctx); + /** * emb_frame_decoder_init() - Start a stream decoder on a buffer. * @dec: The decoder. diff --git a/subsys/transport/frame.c b/subsys/transport/frame.c index 7ce401c2..c98a5ebf 100644 --- a/subsys/transport/frame.c +++ b/subsys/transport/frame.c @@ -101,6 +101,95 @@ emb_status_t emb_frame_encode(uint8_t channel, const void *payload, size_t len, return EMB_OK; } +/* The frame's bytes before COBS, read in place: the channel, the payload, the CRC (LSB first). */ +typedef struct frame_src { + const uint8_t *payload; + size_t len; /* the payload's */ + uint8_t head; /* the channel */ + uint8_t crc[2]; +} frame_src_t; + +static uint8_t src_byte(const frame_src_t *s, size_t i) +{ + uint8_t b; + if (i == 0u) { + b = s->head; + } else if (i <= s->len) { + b = s->payload[i - 1u]; + } else { + b = s->crc[i - 1u - s->len]; + } + return b; +} + +/* Sends the source's bytes [from, to): the payload's part as one piece, read in place. */ +static void src_send(const frame_src_t *s, size_t from, size_t to, emb_frame_sink_t sink, void *ctx) +{ + size_t lo = from; + size_t hi; + if ((lo == 0u) && (to > 0u)) { + sink(ctx, &s->head, 1u); + lo = 1u; + } + hi = (to < (s->len + 1u)) ? to : (s->len + 1u); + if (lo < hi) { + sink(ctx, &s->payload[lo - 1u], hi - lo); + lo = hi; + } + if (lo < to) { + sink(ctx, &s->crc[lo - 1u - s->len], to - lo); + } +} + +emb_status_t emb_frame_write(uint8_t channel, const void *payload, size_t len, + emb_frame_sink_t sink, void *ctx) +{ + frame_src_t s; + uint16_t crc = CRC_INIT; + size_t total; + size_t i = 0u; + size_t k; + bool more = true; + static const uint8_t delimiter = 0u; + if ((channel > EMB_FRAME_CHANNEL_MAX) || (sink == NULL) || ((payload == NULL) && (len != 0u)) || + (len > (SIZE_MAX / 2u))) { + return EMB_EINVAL; + } + s.payload = (const uint8_t *)payload; + s.len = len; + s.head = channel; + crc = crc16(crc, channel); + for (k = 0u; k < len; k++) { /* bounded by len */ + crc = crc16(crc, s.payload[k]); + } + s.crc[0] = (uint8_t)(crc & 0xFFu); + s.crc[1] = (uint8_t)(crc >> 8); + total = len + EMB_FRAME_OVERHEAD; + /* One run per pass, as cobs_put() makes them: its code byte, then its nonzero bytes. A run + * that a zero ended skips the zero; a full run skips nothing, and when it is the last, an + * empty run follows it, as the encoder writes. */ + while (more) { /* bounded: each pass moves i forward, and the last pass ends at total */ + size_t end = i; + uint8_t code; + while ((end < total) && ((end - i) < (size_t)(COBS_RUN_MAX - 1u)) && + (src_byte(&s, end) != 0u)) { + end++; /* bounded by the run's 254 bytes */ + } + code = (uint8_t)((end - i) + 1u); + sink(ctx, &code, 1u); + src_send(&s, i, end, sink, ctx); + if (code == COBS_RUN_MAX) { + i = end; + } else if (end == total) { + more = false; + } else { + i = end + 1u; + } + } + sink(ctx, &delimiter, 1u); + return EMB_OK; +} + void emb_frame_decoder_init(emb_frame_decoder_t *dec, uint8_t *buf, size_t cap) { if (dec == NULL) { diff --git a/tests/conformance/test_frame.c b/tests/conformance/test_frame.c index 6cd25671..cb9b412e 100644 --- a/tests/conformance/test_frame.c +++ b/tests/conformance/test_frame.c @@ -231,3 +231,68 @@ EMB_TEST(frame_random_stream_with_damage) EMB_ASSERT_EQ(dec.frames, sent_good); EMB_ASSERT_TRUE(dec.errors > 0u); } + +/* emb_frame_write()'s sink: collects the frame, and counts the calls. */ +static uint8_t streamed[EMB_FRAME_ENCODED_MAX(300u) + 16u]; +static size_t streamed_len; +static unsigned sink_calls; + +static void collect(void *ctx, const uint8_t *bytes, size_t len) +{ + (void)ctx; + if ((streamed_len + len) <= sizeof(streamed)) { + (void)memcpy(&streamed[streamed_len], bytes, len); + } + streamed_len += len; + sink_calls++; +} + +EMB_TEST(frame_write_streams_the_encoders_bytes) +{ + /* lengths around COBS's 254-byte run, with no zero, zeros inside, and a zero last */ + static const size_t lens[] = {0u, 1u, 2u, 250u, 251u, 252u, 253u, 254u, 255u, 300u}; + size_t li; + unsigned pattern; + EMB_TEST_REQ("OBS-019"); + for (pattern = 0u; pattern < 3u; pattern++) { /* bounded: three patterns */ + for (li = 0u; li < (sizeof(lens) / sizeof(lens[0])); li++) { /* bounded by the table */ + size_t len = lens[li]; + size_t i; + size_t n; + for (i = 0u; i < len; i++) { /* bounded by len */ + payload[i] = (uint8_t)(1u + (i % 255u)); + if ((pattern == 1u) && ((i % 97u) == 40u)) { + payload[i] = 0u; + } + } + if ((pattern == 2u) && (len > 0u)) { + payload[len - 1u] = 0u; + } + n = encode(EMB_FRAME_CHANNEL_SHELL, payload, len); + streamed_len = 0u; + sink_calls = 0u; + EMB_ASSERT_OK(emb_frame_write(EMB_FRAME_CHANNEL_SHELL, payload, len, collect, NULL)); + EMB_ASSERT_EQ(streamed_len, n); + EMB_ASSERT_TRUE(memcmp(streamed, wire, n) == 0); + } + } + /* a run inside the payload goes to the sink in one piece, not byte by byte */ + for (li = 0u; li < 200u; li++) { /* bounded: 200 bytes */ + payload[li] = 0x55u; + } + sink_calls = 0u; + streamed_len = 0u; + EMB_ASSERT_OK(emb_frame_write(EMB_FRAME_CHANNEL_LOG, payload, 200u, collect, NULL)); + EMB_ASSERT_TRUE(sink_calls <= 6u); +} + +EMB_TEST(frame_write_misuse_is_refused) +{ + EMB_TEST_REQ("OBS-019"); + EMB_ASSERT_STATUS(emb_frame_write(16u, payload, 1u, collect, NULL), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_frame_write(0u, NULL, 1u, collect, NULL), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_frame_write(0u, payload, 1u, NULL, NULL), EMB_EINVAL); + streamed_len = 0u; + EMB_ASSERT_OK(emb_frame_write(0u, NULL, 0u, collect, NULL)); + EMB_ASSERT_EQ(streamed_len, sizeof(v_empty)); +} diff --git a/tools/fault/api-ids.json b/tools/fault/api-ids.json index 115fadfd..aff5586c 100644 --- a/tools/fault/api-ids.json +++ b/tools/fault/api-ids.json @@ -1441,6 +1441,12 @@ "name": "emb_frame_decode_byte", "header": "frame.h", "state": "active" + }, + { + "id": 250, + "name": "emb_frame_write", + "header": "frame.h", + "state": "active" } ] } diff --git a/tools/fault/api-registry.json b/tools/fault/api-registry.json index a60bc8a9..602ec194 100644 --- a/tools/fault/api-registry.json +++ b/tools/fault/api-registry.json @@ -1440,6 +1440,12 @@ "name": "emb_frame_decode_byte", "header": "frame.h", "state": "active" + }, + { + "id": 250, + "name": "emb_frame_write", + "header": "frame.h", + "state": "active" } ] } From 7011cbd0f74c597774f0d73d078fac00e20ceb2c Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 04:44:41 +0100 Subject: [PATCH 08/25] subsys: logging and the console (A127) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logging (SPEC-015 §2): EMB_LOG_ERR() to EMB_LOG_DBG() with a printf format the compiler checks, and up to eight arguments typed by a signature _Generic computes. A call packs its record in the caller, from any context: a bounded critical section reserves its room in the ring, the copy runs with interrupts enabled, one byte store commits it. The log thread takes records in order and stops at one not committed; a record that does not fit is dropped, counted, and announced by the next one that fits. Two backends share the record: the deferred one sends it and tools/logdec formats it on the host from the ELF, where the call sites' metadata lives in a non-allocated section at address 0 (its first 8 bytes empty, so no metadata sits at the null pointer); the plain-text one formats it in the log thread. The console: every board writes raw bytes with emb_board_write(), and emb_board_puts() is common code. With CONFIG_EMB_CONSOLE_FRAMED everything on it travels in frames, a zero before each: text on channel 3, logs on 0. tools/transport/frame.py keeps bytes that are not a frame when they read as text. examples/logging prints the same lines with both backends on QEMU AN386 and RV32 virt (tools/logdec/backends_agree.py); the deferred image is 3 KB smaller. test_log checks the record's layout, the formats, the levels, the drops and an interrupt's record held back by an uncommitted one. API ids 251 to 255. Signed-off-by: teo1747 --- boards/arm/mps2_an385/generated/regions.ld | 11 + boards/arm/mps2_an386/generated/regions.ld | 11 + boards/arm/mps2_an500/generated/regions.ld | 11 + boards/arm/mps2_an505/generated/regions.ld | 11 + boards/bbc/microbit/generated/regions.ld | 11 + boards/espressif/esp32_devkitc/board.c | 10 +- .../esp32_devkitc/include/emb_board.h | 2 + boards/espressif/esp32c3_devkitm1/board.c | 10 +- .../esp32c3_devkitm1/include/emb_board.h | 2 + boards/native/native/board.c | 5 +- boards/native/native/include/emb_board.h | 4 + boards/qemu/riscv32_virt/generated/regions.ld | 11 + boards/rpi/pico2_w/generated/regions.ld | 11 + boards/st/nucleo_f446re/generated/regions.ld | 11 + boards/st/nucleo_f446ze/generated/regions.ld | 11 + cmake/emb_kernel.cmake | 4 + docs/specs/AMENDMENTS-M4.md | 2 +- examples/logging/CMakeLists.txt | 15 + examples/logging/main.c | 77 ++ hw/gen/emb_hwgen/emit.py | 22 + include/emb/api_ids.h | 5 + include/emb/compiler.h | 5 + include/emb/compiler/clang.h | 19 +- include/emb/compiler/gcc.h | 45 +- include/emb/console.h | 66 + include/emb/emb.h | 2 + include/emb/log.h | 402 ++++++ kernel/CMakeLists.txt | 12 +- soc/arm/mps2/board.c | 10 +- soc/arm/mps2/include/emb_board.h | 2 + soc/microchip/atmega/board.c | 10 +- soc/microchip/atmega/include/emb_board.h | 2 + soc/nordic/nrf51/board.c | 10 +- soc/nordic/nrf51/include/emb_board.h | 2 + soc/qemu/virt/board.c | 10 +- soc/qemu/virt/include/emb_board.h | 2 + soc/rpi/rp2350/board.c | 10 +- soc/rpi/rp2350/include/emb_board.h | 2 + soc/st/stm32f4/board.c | 10 +- soc/st/stm32f4/include/emb_board.h | 2 + subsys/CMakeLists.txt | 20 +- subsys/Kconfig | 83 ++ subsys/console/console.c | 109 ++ subsys/include/embs/log.h | 61 + subsys/logging/log.c | 1164 +++++++++++++++++ tests/conformance/CMakeLists.txt | 3 + tests/conformance/test_log.c | 217 +++ tools/fault/api-ids.json | 30 + tools/fault/api-registry.json | 30 + tools/logdec/backends_agree.py | 89 ++ tools/logdec/logdec.py | 368 ++++++ tools/logdec/test_logdec.py | 141 ++ tools/transport/frame.py | 51 + 53 files changed, 3167 insertions(+), 79 deletions(-) create mode 100644 examples/logging/CMakeLists.txt create mode 100644 examples/logging/main.c create mode 100644 include/emb/console.h create mode 100644 include/emb/log.h create mode 100644 subsys/console/console.c create mode 100644 subsys/include/embs/log.h create mode 100644 subsys/logging/log.c create mode 100644 tests/conformance/test_log.c create mode 100644 tools/logdec/backends_agree.py create mode 100644 tools/logdec/logdec.py create mode 100644 tools/logdec/test_logdec.py diff --git a/boards/arm/mps2_an385/generated/regions.ld b/boards/arm/mps2_an385/generated/regions.ld index 2e465693..d8b3e8f3 100644 --- a/boards/arm/mps2_an385/generated/regions.ld +++ b/boards/arm/mps2_an385/generated/regions.ld @@ -90,4 +90,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/arm/mps2_an386/generated/regions.ld b/boards/arm/mps2_an386/generated/regions.ld index c6a36c0d..e3e74b91 100644 --- a/boards/arm/mps2_an386/generated/regions.ld +++ b/boards/arm/mps2_an386/generated/regions.ld @@ -90,4 +90,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/arm/mps2_an500/generated/regions.ld b/boards/arm/mps2_an500/generated/regions.ld index f5eb3c3e..9d284717 100644 --- a/boards/arm/mps2_an500/generated/regions.ld +++ b/boards/arm/mps2_an500/generated/regions.ld @@ -90,4 +90,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/arm/mps2_an505/generated/regions.ld b/boards/arm/mps2_an505/generated/regions.ld index 4741eed5..ad91c829 100644 --- a/boards/arm/mps2_an505/generated/regions.ld +++ b/boards/arm/mps2_an505/generated/regions.ld @@ -90,4 +90,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/bbc/microbit/generated/regions.ld b/boards/bbc/microbit/generated/regions.ld index a688b74b..280ecae9 100644 --- a/boards/bbc/microbit/generated/regions.ld +++ b/boards/bbc/microbit/generated/regions.ld @@ -88,4 +88,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/espressif/esp32_devkitc/board.c b/boards/espressif/esp32_devkitc/board.c index 388bba3a..4fbb19e0 100644 --- a/boards/espressif/esp32_devkitc/board.c +++ b/boards/espressif/esp32_devkitc/board.c @@ -168,11 +168,13 @@ static void put_char(char c) UART_FIFO = (uint32_t)(unsigned char)c; } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - put_char(*s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + put_char(p[i]); } } diff --git a/boards/espressif/esp32_devkitc/include/emb_board.h b/boards/espressif/esp32_devkitc/include/emb_board.h index 26676cb6..e002a886 100644 --- a/boards/espressif/esp32_devkitc/include/emb_board.h +++ b/boards/espressif/esp32_devkitc/include/emb_board.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -31,6 +32,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); EMB_NORETURN void emb_board_exit(int code); void emb_board_fault_report(const emb_fault_info_t *info); diff --git a/boards/espressif/esp32c3_devkitm1/board.c b/boards/espressif/esp32c3_devkitm1/board.c index 277ea43e..ca107e3f 100644 --- a/boards/espressif/esp32c3_devkitm1/board.c +++ b/boards/espressif/esp32c3_devkitm1/board.c @@ -170,11 +170,13 @@ static void put_char(char c) UART_FIFO = (uint32_t)(unsigned char)c; } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - put_char(*s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + put_char(p[i]); } } diff --git a/boards/espressif/esp32c3_devkitm1/include/emb_board.h b/boards/espressif/esp32c3_devkitm1/include/emb_board.h index dadb9934..dc63dc8e 100644 --- a/boards/espressif/esp32c3_devkitm1/include/emb_board.h +++ b/boards/espressif/esp32c3_devkitm1/include/emb_board.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -31,6 +32,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); EMB_NORETURN void emb_board_exit(int code); void emb_board_fault_report(const emb_fault_info_t *info); diff --git a/boards/native/native/board.c b/boards/native/native/board.c index a84fcfaa..4642cbe8 100644 --- a/boards/native/native/board.c +++ b/boards/native/native/board.c @@ -36,10 +36,11 @@ void emb_board_led_toggle(void) /* the host has no LED */ } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { emb_native_host_begin(); - (void)fputs(s, stdout); + (void)fwrite(buf, 1u, len, stdout); emb_native_host_end(); } diff --git a/boards/native/native/include/emb_board.h b/boards/native/native/include/emb_board.h index a79ed096..a204b47a 100644 --- a/boards/native/native/include/emb_board.h +++ b/boards/native/native/include/emb_board.h @@ -17,6 +17,9 @@ #include +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -26,6 +29,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); #ifdef __cplusplus diff --git a/boards/qemu/riscv32_virt/generated/regions.ld b/boards/qemu/riscv32_virt/generated/regions.ld index 37877195..6c150030 100644 --- a/boards/qemu/riscv32_virt/generated/regions.ld +++ b/boards/qemu/riscv32_virt/generated/regions.ld @@ -81,4 +81,15 @@ SECTIONS __emb_test_retained_end = __emb_retained_start; __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_test_retained_start; + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/rpi/pico2_w/generated/regions.ld b/boards/rpi/pico2_w/generated/regions.ld index bac05675..f154ac23 100644 --- a/boards/rpi/pico2_w/generated/regions.ld +++ b/boards/rpi/pico2_w/generated/regions.ld @@ -90,4 +90,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/st/nucleo_f446re/generated/regions.ld b/boards/st/nucleo_f446re/generated/regions.ld index a738529a..a06f788b 100644 --- a/boards/st/nucleo_f446re/generated/regions.ld +++ b/boards/st/nucleo_f446re/generated/regions.ld @@ -93,4 +93,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/boards/st/nucleo_f446ze/generated/regions.ld b/boards/st/nucleo_f446ze/generated/regions.ld index 1248c5f8..90ed03c0 100644 --- a/boards/st/nucleo_f446ze/generated/regions.ld +++ b/boards/st/nucleo_f446ze/generated/regions.ld @@ -93,4 +93,15 @@ SECTIONS __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : { + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + } } diff --git a/cmake/emb_kernel.cmake b/cmake/emb_kernel.cmake index 2a9f1a6e..d24da776 100644 --- a/cmake/emb_kernel.cmake +++ b/cmake/emb_kernel.cmake @@ -41,6 +41,10 @@ macro(emb_kernel) add_subdirectory("${EMB_BASE}/subsys" "${_emb_bin}/subsys") emb_check_native_abi() add_subdirectory("${EMB_BOARD_DIR}" "${_emb_bin}/boards/${EMB_BOARD}") + # emb_board_puts() is the console's (subsys/console, A127), which writes through the board's + # emb_board_write(): the two static libraries need each other, and CMake repeats them + target_link_libraries(emb_board PRIVATE emb_subsys) + target_link_libraries(emb_subsys PRIVATE emb_board emb_kernel emb_kernel_private) # embk/: the build id # the board's QEMU machine, for run_ and the test runner (SIM-002) if(NOT CONFIG_EMB_ARCH STREQUAL "native" AND EMB_BOARD_QEMU_ARGS) diff --git a/docs/specs/AMENDMENTS-M4.md b/docs/specs/AMENDMENTS-M4.md index cbdfec3e..feda251b 100644 --- a/docs/specs/AMENDMENTS-M4.md +++ b/docs/specs/AMENDMENTS-M4.md @@ -23,6 +23,6 @@ Changes M4 makes to accepted specifications and requirements, where an accepted | A122 | SPEC-017 §9, SPEC-014 §3, §4, SPEC-011, SPEC-003 §4 | **The flash class, partitions, and the clock across a stall.** SPEC-017 §9 had flash requests queued and their ends delivered by interrupt on the STM32. Every operation now runs to its end in the caller, under the device's lock: the STM32F446's single bank stalls the CPU's fetches meanwhile, and the RP2350 must hold interrupts off while XIP is off, so a queue would let nothing run. The calls are `emb_drv_flash_read()`, `_program()` and `_erase()` with a timeout for the lock, polled versions without it, `emb_drv_flash_geometry_get()` and `emb_drv_flash_sector()`. A program is read back, and bytes that were not erased give `EMB_EVERIFY`. An erase runs a sector at a time. A flash device's geometry is generated from the SoC's `flash:` and, where the chip is smaller than its window, the board device's `size:`. The RP2350's `flash:` is 4 KiB sectors and 256-byte pages. The board's `flash_partitions` become `` areas, `EMB_FLASH_AREA_`. The NUCLEO-F446RE's app partition shrinks to sectors 0 to 6, with sector 7 as `storage`; the Pico 2 W's gives its last 64 KiB to `storage`. The periodic tick misses its interrupts during an operation, so the Cortex-M port times it by DWT CYCCNT (`emb_cm_stall_begin()`, `emb_cm_stall_end()`, `emb_cm_cycle_count()`). A new kernel hook, `embk_time_ticks_missed()`, adds the ticks that passed at the next tick interrupt; it does nothing in tickless mode, which M4.4 brings to Cortex-M. The generated linker script gains a `.ramfunc` section in RAM, copied with `.data`, where the RP2350's flash routine runs, and the Arm GCC link no longer warns about the writable, executable segment. *Proposed 2026-11-10 with M4.2's flash class, for the project owner's review; the clock's catch-up and the storage partitions chosen by the owner on 2026-11-10.* | `include/emb/drv_flash.h`, `include/emb/flash_area.h`, `kernel/device/flash.c`, `kernel/time/time.c`, `arch/cortex_m/cm_port.c`, `drivers/st/stm32_flash.c`, `drivers/rpi/rp2350_flash.c`, `hw/gen/emb_hwgen/` (M4.2) | | A123 | SPEC-017 §10, SPEC-003 §10, KRN-TIM-031, SPEC-018 | **The RTC class and the wall clock.** SPEC-017 §10's requests become `emb_drv_rtc_get()` and `_set()`, with the time in nanoseconds since the Unix epoch (UTC), the wall clock's unit. There is one alarm per device, its callback in the alarm interrupt, `EMB_EBUSY` while armed, and `_alarm_cancel()`; a `set` disarms it. The backup registers are `_backup_read()` and `_write()`. The wake-up timer, the power policy's wake source, moves to M4.4 with SPEC-018, its only user, where its latency is measured. An alarm never fires before its time. It works at the RTC's resolution, and with a calendar it reaches 28 days ahead. The STM32F4's driver does not wait for the LSE at initialization; the first `set` waits instead. The RP2350 has no calendar: its RTC is the AON timer in POWMAN, milliseconds since the epoch on a 1 kHz tick from the crystal. That tick stops in DORMANT, where M4.4 switches it to LPOSC. SPEC-003 §10's wall clock is implemented: ``, behind `CONFIG_EMB_WALLCLOCK`, which needs 64-bit ticks. It is `EMB_ENOTSET` until it is set, or until a set RTC seeds it when its device starts (`emb_drv_rtc_started()`). `emb_wallclock_adjust()` steps; there is no slewing in M4. *Proposed 2026-11-10 with M4.2's RTC class, for the project owner's review; the wake-up timer's move and the RP2350's crystal tick chosen by the owner on 2026-11-10.* | `include/emb/drv_rtc.h`, `include/emb/wallclock.h`, `kernel/device/rtc.c`, `kernel/time/wallclock.c`, `drivers/st/stm32_rtc.c`, `drivers/rpi/rp2350_aon.c` (M4.2) | | A124 | SPEC-017 §11, SEC-012 | **The entropy class.** A read is `emb_drv_entropy_read(dev, buf, len, &got, timeout)`, assembled from a driver's blocks under the device's lock and one timeout. A timeout keeps the bytes read. A block that fails the source's health test ends the read with `EMB_EHEALTH`, and none of its bytes is delivered. The source's output is conditioned in the class, as NIST SP 800-90B asks of a raw noise source: every 32 bytes read are the SHA-256 of 64 raw, health-tested bytes. `emb_drv_entropy_read_raw()` reads the raw blocks, for measuring the source: on the RP2350 they fail a byte chi-square and a runs test, though they pass the TRNG's own health tests, and their most-common-value min-entropy must reach the 4 bits a byte that conditioning 2:1 needs. Every board defines `emb_board_entropy`: the generated `soc_devices.c` from the description, a hand-written board by hand. It is NULL where the board has no source, and `emb_drv_entropy_board()` then returns `EMB_ENOTSUP`. The native board's source is the host's `getentropy()`. The RP2350's TRNG keeps every health test on, and samples every 200 clocks, from a measurement on the board (`sample_count:` on the device). SPEC-017 §11's evidence changes: the 1 MiB is tested on the board, and a 64 KiB sample with its SHA-256 is archived and checked on the host, in place of archiving the whole MiB. *Proposed 2026-11-12 with M4.2's entropy class, for the project owner's review; the evidence's form, the native board's host source and the conditioning chosen by the owner on 2026-11-12.* | `include/emb/drv_entropy.h`, `kernel/device/entropy.c`, `kernel/device/sha256.c`, `drivers/rpi/rp2350_trng.c`, `boards/native/native/board.c`, `tools/entropy/check.py` (M4.2) | -| A127 | SPEC-015 §2, §7, §9, §12 decision 2, OBS-002, OBS-003, OBS-013, OBS-021, 08 Q13 | **Logging, its ring and the console.** **Call sites (§2.1):** a module is defined once with `EMB_LOG_MODULE_DEFINE(name, level)` and declared in its other files with `EMB_LOG_MODULE_DECLARE(name, level)`; §2.1 had only the declaration, which cannot both define the module and serve a module whose calls span files. `EMB_LOG_ERR`, `_WRN`, `_INF` and `_DBG(name, format, ...)` take at most eight arguments, and the compiler checks each format against its arguments as it checks printf's. A call above its file's level for the module, or above `CONFIG_EMB_LOG_LEVEL_MAX`, compiles to nothing; one above the module's run-time level (`emb_log_level_set()`) returns after one comparison. **One record, two backends (§2.3, §2.4, Q13):** every call packs its arguments into the record of §2.3 in the caller, typed by a signature the compiler computes from their C types with C11's `_Generic` (int, long, long long and their unsigned forms, double, string, pointer). The deferred backend (ADR-009) sends the record and the host formats it; the plain-text backend formats the same record on the target, in the log thread. Neither formats in the caller, so a call costs the same in an interrupt with either backend. **Identifiers (§2.2):** a call site's metadata (format, file, line, level, module, signature) is placed in the section `emb_log`, which the generated linker scripts lay at address 0 as a non-allocated (`INFO`) section. Its bytes stay in the ELF for the decoder and never reach the image. §2.2's `NOLOAD` would drop them from the ELF too. The identifier is the metadata's offset in the section plus 8, so identifiers 0 to 7 are the stream's own: 0 synchronization, 1 `dropped(u16 count)`, 2 `start(build_id[20], tick_hz u32)`, which the log thread sends when it starts. It is 16 bits when the section is under 64 KiB minus 8, else 32. The target computes the width from the section's bounds, so it is fixed at link time, and the decoder computes it from the ELF's section, with no ELF note. A linker without the script places the section as ordinary data, with the same identifiers. The plain-text backend's metadata is ordinary read-only data, and its record carries the metadata's address. **Timestamp:** the kernel clock's ticks, their low 32 bits, at the rate the start record gives. §2.3 used the trace clock, which wraps within seconds on a fast part, while logs can be minutes apart. **The ring (§2.3, §2.5, §12 decision 2):** one ring per CPU, a power-of-two array of `CONFIG_EMB_LOG_RING_SIZE` bytes. *Reservation* is a critical section of a bounded number of instructions: it checks the free space, advances the head by the record's size and writes the record's two-byte header (its length, not yet committed). The producer then copies its record with interrupts enabled and *commits* it by setting the header's committed bit, one byte store after a barrier. *Nested producers:* an interrupt that preempts a producer reserves after it, so records keep the order in which they were reserved. *Publication:* the log thread takes records from the tail in order and stops at the first uncommitted one, and the records after it wait, committed or not, until it is committed. *A preempted record* holds back those after it until its producer runs again; meanwhile the ring fills and later records are dropped. Nothing is overwritten and nothing waits. *Overflow:* a record that does not fit is dropped and counted, and the next record that fits is preceded by the `dropped` record, in the same reservation, so the count stands where the loss was. *Consumer progress:* only the log thread advances the tail, inside the same critical section, since a 16-bit store is not atomic on AVR. A record is at most `EMB_LOG_RECORD_MAX` bytes: strings are cut at `CONFIG_EMB_LOG_STR_MAX` and hexdumps at `CONFIG_EMB_LOG_HEXDUMP_MAX`. This replaces §12 decision 2's lock-free ring. Cortex-M0 and AVR have no compare-and-swap for a lock-free reservation, and one design verified on every port is worth more than a second one. The critical section is bounded by constants, which is what OBS-003 asks. The ring does not survive a reset; `emb_log_flush()` writes out what is committed, polled, from any context, and the fault path calls it. **The log thread (§2.4):** a thread of its own (`CONFIG_EMB_LOG_THREAD_PRIORITY`, by default the lowest application priority, and `CONFIG_EMB_LOG_THREAD_STACK`), woken by a semaphore given when a record lands in an empty ring. It is not the system work queue, whose other items a slow console would hold up. **The console (§7):** a board writes raw bytes with `emb_board_write()`, and `emb_board_puts()` becomes common code. By default the console is plain text: the board's prints and the plain-text backend's lines. With `CONFIG_EMB_CONSOLE_FRAMED` everything on it travels in A113's frames: the board's text on channel 3, the shell's, buffered by line; log records on channel 0; trace on 1; crash records on 2. A frame holds whole records, so each frame's start is a synchronization point, and the synchronization record is left to unframed transports (SWO, the memory channel), which M4.3 does not implement. A thread's frame is written whole under the console's mutex. Text printed from an interrupt, a fault or before the kernel starts is framed and written at once, without the mutex, and can cut a thread's frame; the decoder then drops that frame and counts it. A zero precedes every frame, so bytes that are not a frame (a boot ROM's text, a cut frame) end before it, and `emb monitor` shows them as raw text. The deferred backend needs the framed console; without it the plain-text backend is the one built. **Profiles (§9, Q13):** logging is off until an application turns on `CONFIG_EMB_LOG`. Its backend is then the deferred one where the console is framed and the plain-text one elsewhere, and always the plain-text one on tiny. **OBS-013** reads: "…the identifier being the offset of the call site's metadata in a non-allocated section, plus 8 (16 bits when it fits, else 32)…; over a framed transport each frame starts with a record; the plain-text backend shall share the call sites and the record." *Proposed 2026-11-13 with M4.3's logging. The project owner chose on 2026-11-13 the ring's critical-section reservation over a lock-free one, both backends with the deferred one the default, and the framed console as an option; the rest is for their review.* | `include/emb/log.h`, `include/emb/console.h`, `subsys/logging/log.c`, `subsys/console/console.c`, the boards' `emb_board_write()`, `hw/gen/emb_hwgen/` (the section), `tools/logdec/` (M4.3) | +| A127 | SPEC-015 §2, §7, §9, §12 decision 2, OBS-002, OBS-003, OBS-013, OBS-021, 08 Q13 | **Logging, its ring and the console.** **Call sites (§2.1):** a module is defined once with `EMB_LOG_MODULE_DEFINE(name, level)` and declared in its other files with `EMB_LOG_MODULE_DECLARE(name, level)`; §2.1 had only the declaration, which cannot both define the module and serve a module whose calls span files. `EMB_LOG_ERR`, `_WRN`, `_INF` and `_DBG(name, format, ...)` take at most eight arguments, and the compiler checks each format against its arguments as it checks printf's. A call above its file's level for the module, or above `CONFIG_EMB_LOG_LEVEL_MAX`, compiles to nothing; one above the module's run-time level (`emb_log_level_set()`) returns after one comparison. **One record, two backends (§2.3, §2.4, Q13):** every call packs its arguments into the record of §2.3 in the caller, typed by a signature the compiler computes from their C types with C11's `_Generic` (int, long, long long and their unsigned forms, double, string, pointer). The deferred backend (ADR-009) sends the record and the host formats it; the plain-text backend formats the same record on the target, in the log thread. Neither formats in the caller, so a call costs the same in an interrupt with either backend. **Identifiers (§2.2):** a call site's metadata (format, file, line, level, module, signature) is placed in the section `emb_log`, which the generated linker scripts lay at address 0 as a non-allocated (`INFO`) section. Its bytes stay in the ELF for the decoder and never reach the image. §2.2's `NOLOAD` would drop them from the ELF too. The identifier is the metadata's offset in the section plus 8, so identifiers 0 to 7 are the stream's own: 0 synchronization, 1 `dropped(u16 count)`, 2 `start(build_id[20], tick_ns u32)`, the first record in the ring, which says which image the stream comes from and how long a tick is. It is 16 bits when the section is under 64 KiB minus 8, else 32. The target computes the width from the section's bounds, so it is fixed at link time, and the decoder computes it from the ELF's section, with no ELF note. A linker without the script places the section as ordinary data, with the same identifiers. The plain-text backend's metadata is ordinary read-only data, and its record carries the metadata's address. **Timestamp:** the kernel clock's ticks, their low 32 bits, each tick as long as the start record says. §2.3 used the trace clock, which wraps within seconds on a fast part, while logs can be minutes apart. **The ring (§2.3, §2.5, §12 decision 2):** one ring per CPU, a power-of-two array of `CONFIG_EMB_LOG_RING_SIZE` bytes. *Reservation* is a critical section of a bounded number of instructions: it checks the free space, advances the head by the record's size and writes the record's two-byte header (its length, not yet committed). The producer then copies its record with interrupts enabled and *commits* it by setting the header's committed bit, one byte store after a barrier. *Nested producers:* an interrupt that preempts a producer reserves after it, so records keep the order in which they were reserved. *Publication:* the log thread takes records from the tail in order and stops at the first uncommitted one, and the records after it wait, committed or not, until it is committed. *A preempted record* holds back those after it until its producer runs again; meanwhile the ring fills and later records are dropped. Nothing is overwritten and nothing waits. *Overflow:* a record that does not fit is dropped and counted, and the next record that fits is preceded by the `dropped` record, in the same reservation, so the count stands where the loss was. *Consumer progress:* only the log thread advances the tail, inside the same critical section, since a 16-bit store is not atomic on AVR. A record is at most `EMB_LOG_RECORD_MAX` bytes: strings are cut at `CONFIG_EMB_LOG_STR_MAX` and hexdumps at `CONFIG_EMB_LOG_HEXDUMP_MAX`. This replaces §12 decision 2's lock-free ring. Cortex-M0 and AVR have no compare-and-swap for a lock-free reservation, and one design verified on every port is worth more than a second one. The critical section is bounded by constants, which is what OBS-003 asks. The ring does not survive a reset; `emb_log_flush()` writes out what is committed, polled, from any context, and the fault path calls it. **The log thread (§2.4):** a thread of its own (`CONFIG_EMB_LOG_THREAD_PRIORITY`, by default the lowest application priority, and `CONFIG_EMB_LOG_THREAD_STACK`), woken by a semaphore given when a record lands in an empty ring. It is not the system work queue, whose other items a slow console would hold up. **The console (§7):** a board writes raw bytes with `emb_board_write()`, and `emb_board_puts()` becomes common code. By default the console is plain text: the board's prints and the plain-text backend's lines. With `CONFIG_EMB_CONSOLE_FRAMED` everything on it travels in A113's frames: the board's text on channel 3, the shell's, buffered by line; log records on channel 0; trace on 1; crash records on 2. A frame holds whole records, so each frame's start is a synchronization point, and the synchronization record is left to unframed transports (SWO, the memory channel), which M4.3 does not implement. A thread's frame is written whole under the console's mutex. Text printed from an interrupt, a fault or before the kernel starts is framed and written at once, without the mutex, and can cut a thread's frame; the decoder then drops that frame and counts it. A zero precedes every frame, so bytes that are not a frame (a boot ROM's text, a cut frame) end before it, and `emb monitor` shows them as raw text. The deferred backend needs the framed console; without it the plain-text backend is the one built. **Profiles (§9, Q13):** `CONFIG_EMB_LOG` is on by default and costs nothing until an image calls it: the ring, the thread and the formatter are in `log.c`, which only a call links in, as the system work queue is (ADR-048). The backend is the deferred one where the console is framed and the plain-text one elsewhere, and always the plain-text one on tiny. **OBS-013** reads: "…the identifier being the offset of the call site's metadata in a non-allocated section, plus 8 (16 bits when it fits, else 32)…; over a framed transport each frame starts with a record; the plain-text backend shall share the call sites and the record." *Proposed 2026-11-13 with M4.3's logging. The project owner chose on 2026-11-13 the ring's critical-section reservation over a lock-free one, both backends with the deferred one the default, and the framed console as an option; the rest is for their review.* | `include/emb/log.h`, `include/emb/console.h`, `subsys/logging/log.c`, `subsys/console/console.c`, the boards' `emb_board_write()`, `hw/gen/emb_hwgen/` (the section), `tools/logdec/` (M4.3) | **Not an amendment:** writing the vector table base (VTOR) at reset is already `emb_arch_early_init()`'s duty in SPEC-011 §4. The Cortex-M port has not done it, because every image so far boots from the boot base; M4.5 implements it for images in a slot (SPEC-019 §3). diff --git a/examples/logging/CMakeLists.txt b/examples/logging/CMakeLists.txt new file mode 100644 index 00000000..5826c3df --- /dev/null +++ b/examples/logging/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +cmake_minimum_required(VERSION 3.20) + +set(EmbLinkRTOS_DIR "${CMAKE_CURRENT_LIST_DIR}/../../cmake" CACHE PATH "The RTOS's cmake/ directory") +find_package(EmbLinkRTOS REQUIRED) + +project(logging LANGUAGES C) + +emb_kernel() +emb_add_executable(logging main.c) diff --git a/examples/logging/main.c b/examples/logging/main.c new file mode 100644 index 00000000..b1bb0633 --- /dev/null +++ b/examples/logging/main.c @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file main.c + * @brief Logging, with either backend (SPEC-015 §2, A127). + * + * @details + * One thread logs a fixed set of records, a hexdump and a burst larger than the ring, then sends + * what is left with emb_log_flush() and ends. Built as it is, the console is plain text and the + * log thread formats each record on the target. Built with the framed console, the records are + * sent as they are and tools/logdec formats them on the host from the ELF: + * + * cmake -S examples/logging -B build/logging -DEMB_BOARD=mps2_an386 + * cmake -S examples/logging -B build/logging-framed -DEMB_BOARD=mps2_an386 \ + * -DEMB_SET=EMB_CONSOLE_FRAMED=y + * python3 tools/logdec/logdec.py --elf build/logging-framed/logging.elf console.bin + * + * Both print the same lines (the CI's application job checks it). + * + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include +#include + +#include +#if CONFIG_EMB_ARCH_NATIVE +#include +#endif + +#define BURST 200u /* more records than the ring holds */ + +EMB_LOG_MODULE_DEFINE(app, EMB_LOG_LEVEL_DBG); + +static void logger(void *arg) +{ + static const unsigned char rx[] = {0xDEu, 0xADu, 0xBEu, 0xEFu}; + unsigned i; + (void)arg; + EMB_LOG_INF(app, "logging on %s", EMB_HW_BOARD_NAME); + EMB_LOG_WRN(app, "a %d b %u c %s", -5, 7u, "xyz"); + EMB_LOG_ERR(app, "[%5d|%-5d|%05d|%+d]", 42, 42, 42, 42); + EMB_LOG_INF(app, "%x %X %#x %o %c%%", 255u, 255u, 255u, 8u, 'z'); + EMB_LOG_INF(app, "%lld %llu %ld %lu", -1LL, 18446744073709551615ULL, -70000L, 70000UL); + EMB_LOG_INF(app, "%.2f %.0f %f", 3.14159, 2.5, -0.5); + EMB_LOG_INF(app, "<%.3s|%4s>", "abcdef", "z"); + EMB_LOG_HEXDUMP_INF(app, rx, sizeof(rx), "rx"); + EMB_LOG_DBG(app, "not compiled: above CONFIG_EMB_LOG_LEVEL_MAX"); + /* more than the ring holds while the log thread cannot run: the rest are dropped, and the + * next record that fits says how many */ + for (i = 0u; i < BURST; i++) { + EMB_LOG_INF(app, "burst %u", i); + } + emb_log_flush(); + EMB_LOG_INF(app, "after the burst"); + emb_log_flush(); + emb_board_puts("logging: done\n"); +#if CONFIG_EMB_ARCH_NATIVE + emb_native_exit(0); +#else + emb_board_exit(0); +#endif +} + +EMB_THREAD_DEFINE(logger_thread, logger, NULL, 3u, 1024u, 0u); + +int main(void) +{ + emb_board_init(); + emb_kernel_init(); + emb_kernel_start(); +} diff --git a/hw/gen/emb_hwgen/emit.py b/hw/gen/emb_hwgen/emit.py index c592ced9..28ba6e07 100644 --- a/hw/gen/emb_hwgen/emit.py +++ b/hw/gen/emb_hwgen/emit.py @@ -285,6 +285,17 @@ def board_pins_c(r): __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_isr_stack_end; ASSERT(end <= __emb_test_retained_start, "RAM overflow: .data and .bss reach the retained memory") + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : {{ + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + }} }} """ @@ -367,6 +378,17 @@ def _avr_template(): __emb_test_retained_end = __emb_retained_start; __emb_test_retained_start = __emb_test_retained_end - 32; __stack_top = __emb_test_retained_start; + + /* the log's call sites (A127): kept in the ELF for tools/logdec and out of the image. At + address 0, from which a record's identifier is its metadata's offset plus 8; the first 8 + bytes stay empty, so no metadata is at address 0, the null pointer. Last, since setting + its address moves the location counter. */ + emb_log 0 (INFO) : {{ + __start_emb_log = .; + . += 8; + KEEP(*(emb_log)) + __stop_emb_log = .; + }} }} """ diff --git a/include/emb/api_ids.h b/include/emb/api_ids.h index 1737c42f..2865a203 100644 --- a/include/emb/api_ids.h +++ b/include/emb/api_ids.h @@ -245,5 +245,10 @@ #define EMB_API_ID_FRAME_DECODER_INIT 0x00F8u #define EMB_API_ID_FRAME_DECODE_BYTE 0x00F9u #define EMB_API_ID_FRAME_WRITE 0x00FAu +#define EMB_API_ID_LOG_WRITE 0x00FBu +#define EMB_API_ID_LOG_LEVEL_SET 0x00FCu +#define EMB_API_ID_LOG_FLUSH 0x00FDu +#define EMB_API_ID_LOG_STATS_GET 0x00FEu +#define EMB_API_ID_CONSOLE_FRAME 0x00FFu #endif /* EMB_API_IDS_H */ diff --git a/include/emb/compiler.h b/include/emb/compiler.h index 84312323..12b1ff8e 100644 --- a/include/emb/compiler.h +++ b/include/emb/compiler.h @@ -76,6 +76,11 @@ extern "C" { #ifndef EMB_USED #define EMB_USED #endif +/* The compiler checks a call's arguments against a printf format: argument f is the format, + * a the first checked. EmbCC and unknown compilers check nothing. */ +#ifndef EMB_PRINTF_FORMAT +#define EMB_PRINTF_FORMAT(f, a) +#endif #ifndef EMB_WEAK #define EMB_WEAK #define EMB_HAS_WEAK 0 /* a default definition cannot be overridden */ diff --git a/include/emb/compiler/clang.h b/include/emb/compiler/clang.h index 86dab2d4..98ac0f7f 100644 --- a/include/emb/compiler/clang.h +++ b/include/emb/compiler/clang.h @@ -24,15 +24,16 @@ ((__clang_major__ * 10000) + (__clang_minor__ * 100) + __clang_patchlevel__) /* NOLINTBEGIN(portability-no-assembler,hicpp-no-assembler): CS-1.5, the compiler layer */ -#define EMB_INLINE inline -#define EMB_ALWAYS_INLINE inline __attribute__((always_inline)) -#define EMB_NOINLINE __attribute__((noinline)) -#define EMB_NORETURN __attribute__((noreturn)) -#define EMB_UNUSED __attribute__((unused)) -#define EMB_USED __attribute__((used)) -#define EMB_WEAK __attribute__((weak)) -#define EMB_ALIAS(sym) __attribute__((alias(#sym))) -#define EMB_SECTION(name) __attribute__((section(name))) +#define EMB_INLINE inline +#define EMB_ALWAYS_INLINE inline __attribute__((always_inline)) +#define EMB_NOINLINE __attribute__((noinline)) +#define EMB_NORETURN __attribute__((noreturn)) +#define EMB_UNUSED __attribute__((unused)) +#define EMB_USED __attribute__((used)) +#define EMB_WEAK __attribute__((weak)) +#define EMB_PRINTF_FORMAT(f, a) __attribute__((format(printf, f, a))) +#define EMB_ALIAS(sym) __attribute__((alias(#sym))) +#define EMB_SECTION(name) __attribute__((section(name))) #if defined(__has_feature) #if __has_feature(address_sanitizer) /* Mach-O AddressSanitizer pads section globals with redzones, which a table walk would diff --git a/include/emb/compiler/gcc.h b/include/emb/compiler/gcc.h index 85c52e02..b58a10ac 100644 --- a/include/emb/compiler/gcc.h +++ b/include/emb/compiler/gcc.h @@ -23,28 +23,29 @@ #define EMB_COMPILER_VERSION ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__) /* NOLINTBEGIN(portability-no-assembler,hicpp-no-assembler): CS-1.5, the compiler layer */ -#define EMB_INLINE inline -#define EMB_ALWAYS_INLINE inline __attribute__((always_inline)) -#define EMB_NOINLINE __attribute__((noinline)) -#define EMB_NORETURN __attribute__((noreturn)) -#define EMB_UNUSED __attribute__((unused)) -#define EMB_USED __attribute__((used)) -#define EMB_EXTERNALLY_VISIBLE __attribute__((externally_visible)) -#define EMB_WEAK __attribute__((weak)) -#define EMB_ALIAS(sym) __attribute__((alias(#sym))) -#define EMB_SECTION(name) __attribute__((section(name))) -#define EMB_ALIGNED(n) __attribute__((aligned(n))) -#define EMB_PACKED __attribute__((packed)) -#define EMB_NAKED __attribute__((naked)) -#define EMB_DEPRECATED(msg) __attribute__((deprecated(msg))) -#define EMB_PRINTF_LIKE(f, a) __attribute__((format(printf, f, a))) -#define EMB_LIKELY(x) __builtin_expect(!!(x), 1) -#define EMB_UNLIKELY(x) __builtin_expect(!!(x), 0) -#define EMB_UNREACHABLE() __builtin_unreachable() -#define EMB_COMPILER_BARRIER() __asm__ __volatile__("" ::: "memory") -#define EMB_TRAP() __builtin_trap() -#define EMB_IS_CONSTANT(x) __builtin_constant_p(x) -#define EMB_RETURN_ADDRESS() ((uintptr_t)__builtin_return_address(0)) +#define EMB_INLINE inline +#define EMB_ALWAYS_INLINE inline __attribute__((always_inline)) +#define EMB_NOINLINE __attribute__((noinline)) +#define EMB_NORETURN __attribute__((noreturn)) +#define EMB_UNUSED __attribute__((unused)) +#define EMB_USED __attribute__((used)) +#define EMB_EXTERNALLY_VISIBLE __attribute__((externally_visible)) +#define EMB_WEAK __attribute__((weak)) +#define EMB_PRINTF_FORMAT(f, a) __attribute__((format(printf, f, a))) +#define EMB_ALIAS(sym) __attribute__((alias(#sym))) +#define EMB_SECTION(name) __attribute__((section(name))) +#define EMB_ALIGNED(n) __attribute__((aligned(n))) +#define EMB_PACKED __attribute__((packed)) +#define EMB_NAKED __attribute__((naked)) +#define EMB_DEPRECATED(msg) __attribute__((deprecated(msg))) +#define EMB_PRINTF_LIKE(f, a) __attribute__((format(printf, f, a))) +#define EMB_LIKELY(x) __builtin_expect(!!(x), 1) +#define EMB_UNLIKELY(x) __builtin_expect(!!(x), 0) +#define EMB_UNREACHABLE() __builtin_unreachable() +#define EMB_COMPILER_BARRIER() __asm__ __volatile__("" ::: "memory") +#define EMB_TRAP() __builtin_trap() +#define EMB_IS_CONSTANT(x) __builtin_constant_p(x) +#define EMB_RETURN_ADDRESS() ((uintptr_t)__builtin_return_address(0)) /* NOLINTEND(portability-no-assembler,hicpp-no-assembler) */ #if __GNUC__ >= 7 diff --git a/include/emb/console.h b/include/emb/console.h new file mode 100644 index 00000000..83712701 --- /dev/null +++ b/include/emb/console.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file console.h + * @brief The console: plain text, or every stream in frames (SPEC-015 §7, A127). + * + * @details + * A board writes the console's bytes as they are (emb_board_write()); the board's text goes + * through emb_board_puts(), which is common code. By default the console is plain text. With + * CONFIG_EMB_CONSOLE_FRAMED everything on it travels in A113's frames, each preceded by a zero: + * the board's text on channel 3, log records on 0, trace on 1, crash records on 2. A thread's + * frame is written whole under the console's mutex; one from an interrupt, a fault, a critical + * section or before the kernel starts is written at once, and may cut a thread's frame, which + * the decoder then drops and counts. + * + * @see subsys/console/console.c + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#ifndef EMB_CONSOLE_H +#define EMB_CONSOLE_H + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * emb_console_frame() - Send one frame on the framed console. + * @channel: 0 to EMB_FRAME_CHANNEL_MAX (SPEC-015 §7, A113). + * @payload: The payload; may be NULL when @len is 0. + * @len: Its bytes. + * + * @ctx thread isr prekernel + * @blocks yes, in a thread outside a critical section: for the console, held by another + * thread's frame + * @time O(len) plus the console's line time + * @owns none + * @config CONFIG_EMB_CONSOLE_FRAMED + * @req OBS-019 + * @since 0.3 + * @stable no + * + * The frame is preceded by a zero, so a decoder that saw bytes which were not a frame starts + * this one clean. Polled: the caller sends the bytes. + * + * Return: EMB_OK; EMB_EINVAL (a channel above 15, or a payload missing); EMB_ENOTSUP when + * the console is plain text. + */ +emb_status_t emb_console_frame(uint8_t channel, const void *payload, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* EMB_CONSOLE_H */ diff --git a/include/emb/emb.h b/include/emb/emb.h index a8916536..70c7eaac 100644 --- a/include/emb/emb.h +++ b/include/emb/emb.h @@ -20,6 +20,7 @@ #if CONFIG_EMB_COND #include #endif +#include #include #if CONFIG_EMB_DEVICE #include @@ -55,6 +56,7 @@ #include #include #include +#include #if CONFIG_EMB_MSGQ #include #endif diff --git a/include/emb/log.h b/include/emb/log.h new file mode 100644 index 00000000..697c0256 --- /dev/null +++ b/include/emb/log.h @@ -0,0 +1,402 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file log.h + * @brief Logging: levels, modules, and records packed in the caller (SPEC-015 §2, A127). + * + * @details + * A module is defined once and declared in its other files, each with the most detailed level + * that file compiles: + * + * EMB_LOG_MODULE_DEFINE(sensor, EMB_LOG_LEVEL_INF); (one file) + * EMB_LOG_MODULE_DECLARE(sensor, EMB_LOG_LEVEL_DBG); (the others) + * EMB_LOG_ERR(sensor, "read %u failed: %d", id, status); + * + * A call takes a printf format and at most eight arguments, which the compiler checks against + * it. The call packs its arguments into the log ring as SPEC-015 §2.3's record, typed by a + * signature the compiler computes from their C types: int and the types narrower than int, + * unsigned, long, unsigned long, long long, unsigned long long, double, a string (char *, cut + * at CONFIG_EMB_LOG_STR_MAX) and any other pointer. Nothing is formatted in the caller: the + * deferred backend sends the record and the host formats it from the ELF (tools/logdec); the + * plain-text backend formats it in the log thread. A call costs one comparison when the module's + * run-time level is below it, and nothing at all when its file's level or + * CONFIG_EMB_LOG_LEVEL_MAX is. + * + * Each call site's metadata (format, file, line, level, module, signature) is a constant of its + * own. The deferred backend places it in the section emb_log, which the generated linker scripts + * keep out of the image: its offset in that section, plus 8, is the record's identifier. + * + * @see subsys/logging/log.c + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#ifndef EMB_LOG_H +#define EMB_LOG_H + +#include +#include +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Levels: a call is kept when its level is at most the limit. */ +#define EMB_LOG_LEVEL_NONE 0u +#define EMB_LOG_LEVEL_ERR 1u +#define EMB_LOG_LEVEL_WRN 2u +#define EMB_LOG_LEVEL_INF 3u +#define EMB_LOG_LEVEL_DBG 4u + +/* An argument's type in a call's signature, four bits each, the first argument lowest. */ +#define EMB_LOG_T_END 0u +#define EMB_LOG_T_INT 1u /* int, and the types promoted to it */ +#define EMB_LOG_T_UINT 2u +#define EMB_LOG_T_LONG 3u +#define EMB_LOG_T_ULONG 4u +#define EMB_LOG_T_LLONG 5u +#define EMB_LOG_T_ULLONG 6u +#define EMB_LOG_T_DOUBLE 7u /* float and double */ +#define EMB_LOG_T_STR 8u /* char *: its bytes, cut at CONFIG_EMB_LOG_STR_MAX */ +#define EMB_LOG_T_PTR 9u /* any other pointer: its value */ +#define EMB_LOG_T_HEX 10u /* a hexdump: a pointer and a size_t, cut at _HEXDUMP_MAX */ +#define EMB_LOG_T_BAD 15u /* a type a record cannot carry (long double) */ +#define EMB_LOG_ARGS_MAX 8u + +/* The stream's own records (A127): identifiers 0 to 7. */ +#define EMB_LOG_ID_SYNC 0u /* for unframed transports; not sent in M4.3 */ +#define EMB_LOG_ID_DROPPED 1u /* u16: records dropped since the last record that fitted */ +#define EMB_LOG_ID_START 2u /* the image's build id (20 bytes) and the tick rate (u32) */ +#define EMB_LOG_ID_FIRST 8u /* a call site's: its metadata's offset in emb_log, plus 8 */ + +/* A module: its run-time level, which starts at EMB_LOG_LEVEL_DBG. */ +typedef struct emb_log_module { + uint8_t level; +} emb_log_module_t; + +/* A call site's metadata. With the deferred backend it is in the ELF only, never in the + * image: the target never reads it. tools/logdec reads it with this layout. */ +typedef struct emb_log_meta { + const char *format; + const char *file; /* NULL with the plain-text backend */ + const char *module; /* the module's name */ + uint32_t line; + uint32_t sig; /* EMB_LOG_T_* per argument */ + uint8_t level; + uint8_t reserved_[3]; +} emb_log_meta_t; + +/* What tools/logdec needs to read records, in the emb_log section as emb_log_header. */ +typedef struct emb_log_header { + char magic[4]; /* "EMBL" */ + uint8_t version; /* 1 */ + uint8_t flags; /* bit 0: records carry a timestamp */ + uint8_t long_size; /* sizeof(long): the width of a long argument */ + uint8_t ptr_size; /* sizeof(void *) */ + uint8_t double_size; /* sizeof(double) */ + uint8_t str_max; /* CONFIG_EMB_LOG_STR_MAX */ + uint8_t reserved_[2]; +} emb_log_header_t; + +/* Where a call site's metadata and names go. */ +#if CONFIG_EMB_LOG_DEFERRED +#define EMB_LOG_SECTION_ EMB_SECTION(EMB_TABLE_SECTION("emb_log")) +#else +#define EMB_LOG_SECTION_ +#endif + +/* A call site's file, which only the deferred backend keeps. */ +#if CONFIG_EMB_LOG_DEFERRED +#ifdef __FILE_NAME__ +#define EMB_LOG_FILE_ __FILE_NAME__ +#else +#define EMB_LOG_FILE_ __FILE__ +#endif +#endif + +/* The most detailed level compiled at all. */ +#if CONFIG_EMB_LOG +#define EMB_LOG_LEVEL_LIMIT_ CONFIG_EMB_LOG_LEVEL_MAX +#else +#define EMB_LOG_LEVEL_LIMIT_ 0 +#endif + +/* NOLINTBEGIN(bugprone-macro-parentheses): MISRA Dev CS-12 rule 20.7, `m` is a token */ + +/** + * EMB_LOG_MODULE_DEFINE() - Define a log module, once, in one file. + * @m: The module's name, an identifier. + * @lvl: The most detailed level this file compiles for it. + */ +#if CONFIG_EMB_LOG +#define EMB_LOG_MODULE_DEFINE(m, lvl) \ + EMB_LOG_SECTION_ const char emb_log_name_##m##_[] = #m; \ + emb_log_module_t emb_log_module_##m##_ = {EMB_LOG_LEVEL_DBG}; \ + enum { \ + emb_log_file_level_##m##_ = (lvl) \ + } +#else +#define EMB_LOG_MODULE_DEFINE(m, lvl) \ + enum { \ + emb_log_file_level_##m##_ = (lvl) \ + } +#endif + +/** + * EMB_LOG_MODULE_DECLARE() - Use a module defined in another file. + * @m: The module's name. + * @lvl: The most detailed level this file compiles for it. + */ +#if CONFIG_EMB_LOG +#define EMB_LOG_MODULE_DECLARE(m, lvl) \ + extern EMB_LOG_SECTION_ const char emb_log_name_##m##_[]; \ + extern emb_log_module_t emb_log_module_##m##_; \ + enum { \ + emb_log_file_level_##m##_ = (lvl) \ + } +#else +#define EMB_LOG_MODULE_DECLARE(m, lvl) EMB_LOG_MODULE_DEFINE(m, lvl) +#endif + +/* The module's run-time state, for emb_log_level_set(). */ +#define EMB_LOG_MODULE(m) (&emb_log_module_##m##_) + +/* Calls, each with a format and at most eight arguments. */ +#define EMB_LOG_ERR(m, ...) EMB_LOG_AT_(EMB_LOG_LEVEL_ERR, m, __VA_ARGS__) +#define EMB_LOG_WRN(m, ...) EMB_LOG_AT_(EMB_LOG_LEVEL_WRN, m, __VA_ARGS__) +#define EMB_LOG_INF(m, ...) EMB_LOG_AT_(EMB_LOG_LEVEL_INF, m, __VA_ARGS__) +#define EMB_LOG_DBG(m, ...) EMB_LOG_AT_(EMB_LOG_LEVEL_DBG, m, __VA_ARGS__) + +/* A hexdump of len bytes at buf, with a label (a string literal, no arguments). */ +#define EMB_LOG_HEXDUMP_ERR(m, buf, len, label) EMB_LOG_HEX_(EMB_LOG_LEVEL_ERR, m, buf, len, label) +#define EMB_LOG_HEXDUMP_WRN(m, buf, len, label) EMB_LOG_HEX_(EMB_LOG_LEVEL_WRN, m, buf, len, label) +#define EMB_LOG_HEXDUMP_INF(m, buf, len, label) EMB_LOG_HEX_(EMB_LOG_LEVEL_INF, m, buf, len, label) +#define EMB_LOG_HEXDUMP_DBG(m, buf, len, label) EMB_LOG_HEX_(EMB_LOG_LEVEL_DBG, m, buf, len, label) + +/* ---- the call site (internal) ------------------------------------------------------- */ + +/* Whether a level is compiled for a module in this file: constant, so the call vanishes. */ +#define EMB_LOG_ON_(lvl, m) \ + (((unsigned)(lvl) <= (unsigned)emb_log_file_level_##m##_) && \ + ((unsigned)(lvl) <= (unsigned)EMB_LOG_LEVEL_LIMIT_)) + +#if CONFIG_EMB_LOG_DEFERRED +#define EMB_LOG_META_(lvl, m, fmt, sig) \ + static EMB_LOG_SECTION_ const char emb_log_fmt_[] = fmt; \ + static EMB_LOG_SECTION_ const char emb_log_file_[] = EMB_LOG_FILE_; \ + static EMB_LOG_SECTION_ const emb_log_meta_t emb_log_meta_ = { \ + emb_log_fmt_, emb_log_file_, emb_log_name_##m##_, (uint32_t)__LINE__, (sig), (lvl), {0u}} +#else +#define EMB_LOG_META_(lvl, m, fmt, sig) \ + static const char emb_log_fmt_[] = fmt; \ + static const emb_log_meta_t emb_log_meta_ = { \ + emb_log_fmt_, NULL, emb_log_name_##m##_, (uint32_t)__LINE__, (sig), (lvl), {0u}} +#endif + +#if CONFIG_EMB_LOG +#define EMB_LOG_AT_(lvl, m, ...) \ + do { \ + if (EMB_LOG_ON_(lvl, m)) { \ + EMB_LOG_META_(lvl, m, EMB_LOG_FIRST_(__VA_ARGS__), EMB_LOG_SIG_(__VA_ARGS__)); \ + (void)sizeof(emb_log_format_check_(__VA_ARGS__), 0); \ + if ((uint8_t)(lvl) <= emb_log_module_##m##_.level) { \ + emb_log_write(&emb_log_meta_, \ + EMB_LOG_SIG_(__VA_ARGS__) EMB_LOG_REST_(__VA_ARGS__)); \ + } \ + } \ + } while (0) + +#define EMB_LOG_HEX_(lvl, m, buf, len, label) \ + do { \ + if (EMB_LOG_ON_(lvl, m)) { \ + EMB_LOG_META_(lvl, m, label, EMB_LOG_T_HEX); \ + if ((uint8_t)(lvl) <= emb_log_module_##m##_.level) { \ + emb_log_write(&emb_log_meta_, EMB_LOG_T_HEX, (const void *)(buf), (size_t)(len)); \ + } \ + } \ + } while (0) +#else +/* logging off: the arguments are still checked against the format, and nothing is emitted */ +#define EMB_LOG_AT_(lvl, m, ...) \ + do { \ + (void)sizeof(emb_log_format_check_(__VA_ARGS__), 0); \ + (void)emb_log_file_level_##m##_; \ + } while (0) +#define EMB_LOG_HEX_(lvl, m, buf, len, label) \ + do { \ + (void)sizeof((buf), (len), 0); \ + } while (0) +#endif + +/* NOLINTEND(bugprone-macro-parentheses) */ + +/* The argument count (the format included, so at least one) and the pieces of a call. */ +#define EMB_LOG_CAT_(a, b) EMB_LOG_CAT_I_(a, b) +#define EMB_LOG_CAT_I_(a, b) a##b +#define EMB_LOG_NARG_(...) EMB_LOG_NARG_I_(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define EMB_LOG_NARG_I_(a1, a2, a3, a4, a5, a6, a7, a8, a9, n, ...) n +#define EMB_LOG_FIRST_(...) EMB_LOG_FIRST_I_(__VA_ARGS__, 0) +#define EMB_LOG_FIRST_I_(f, ...) f +#define EMB_LOG_SIG_(...) EMB_LOG_CAT_(EMB_LOG_SIG_, EMB_LOG_NARG_(__VA_ARGS__))(__VA_ARGS__) +#define EMB_LOG_REST_(...) EMB_LOG_CAT_(EMB_LOG_REST_, EMB_LOG_NARG_(__VA_ARGS__))(__VA_ARGS__) + +/* An argument's type code, from its C type after the default argument promotions. */ +#define EMB_LOG_T_(x) \ + _Generic((x), \ + _Bool: EMB_LOG_T_INT, \ + char: EMB_LOG_T_INT, \ + signed char: EMB_LOG_T_INT, \ + unsigned char: EMB_LOG_T_INT, \ + short: EMB_LOG_T_INT, \ + unsigned short: ((sizeof(unsigned short) < sizeof(int)) ? EMB_LOG_T_INT : EMB_LOG_T_UINT), \ + int: EMB_LOG_T_INT, \ + unsigned int: EMB_LOG_T_UINT, \ + long: EMB_LOG_T_LONG, \ + unsigned long: EMB_LOG_T_ULONG, \ + long long: EMB_LOG_T_LLONG, \ + unsigned long long: EMB_LOG_T_ULLONG, \ + float: EMB_LOG_T_DOUBLE, \ + double: EMB_LOG_T_DOUBLE, \ + long double: EMB_LOG_T_BAD, \ + char *: EMB_LOG_T_STR, \ + const char *: EMB_LOG_T_STR, \ + default: EMB_LOG_T_PTR) +#define EMB_LOG_S_(x, i) ((uint32_t)EMB_LOG_T_(x) << (4u * (i))) + +#define EMB_LOG_SIG_1(f) 0u +#define EMB_LOG_SIG_2(f, a) EMB_LOG_S_(a, 0u) +#define EMB_LOG_SIG_3(f, a, b) (EMB_LOG_S_(a, 0u) | EMB_LOG_S_(b, 1u)) +#define EMB_LOG_SIG_4(f, a, b, c) (EMB_LOG_SIG_3(f, a, b) | EMB_LOG_S_(c, 2u)) +#define EMB_LOG_SIG_5(f, a, b, c, d) (EMB_LOG_SIG_4(f, a, b, c) | EMB_LOG_S_(d, 3u)) +#define EMB_LOG_SIG_6(f, a, b, c, d, e) (EMB_LOG_SIG_5(f, a, b, c, d) | EMB_LOG_S_(e, 4u)) +#define EMB_LOG_SIG_7(f, a, b, c, d, e, g) (EMB_LOG_SIG_6(f, a, b, c, d, e) | EMB_LOG_S_(g, 5u)) +#define EMB_LOG_SIG_8(f, a, b, c, d, e, g, h) \ + (EMB_LOG_SIG_7(f, a, b, c, d, e, g) | EMB_LOG_S_(h, 6u)) +#define EMB_LOG_SIG_9(f, a, b, c, d, e, g, h, k) \ + (EMB_LOG_SIG_8(f, a, b, c, d, e, g, h) | EMB_LOG_S_(k, 7u)) + +#define EMB_LOG_REST_1(f) +#define EMB_LOG_REST_2(f, a) , (a) +#define EMB_LOG_REST_3(f, a, b) , (a), (b) +#define EMB_LOG_REST_4(f, a, b, c) , (a), (b), (c) +#define EMB_LOG_REST_5(f, a, b, c, d) , (a), (b), (c), (d) +#define EMB_LOG_REST_6(f, a, b, c, d, e) , (a), (b), (c), (d), (e) +#define EMB_LOG_REST_7(f, a, b, c, d, e, g) , (a), (b), (c), (d), (e), (g) +#define EMB_LOG_REST_8(f, a, b, c, d, e, g, h) , (a), (b), (c), (d), (e), (g), (h) +#define EMB_LOG_REST_9(f, a, b, c, d, e, g, h, k) , (a), (b), (c), (d), (e), (g), (h), (k) + +/** + * emb_log_format_check_() - Never called or defined: how a call's format is checked. + * @format: The call's format. + * @...: Its arguments. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(1): it appears only inside sizeof, so no code is emitted + * @owns none + * @config CONFIG_EMB_LOG + * @req OBS-001 + * @since 0.3 + * @stable no + * + * The log macros name it inside sizeof with the call's format and arguments, so the compiler + * checks them as it checks printf's, and nothing is evaluated. + */ +void emb_log_format_check_(const char *format, ...) EMB_PRINTF_FORMAT(1, 2); + +/** + * emb_log_write() - Pack one record into the log ring: what a call site calls. + * @meta: The call site's metadata. + * @sig: Its arguments' types, EMB_LOG_T_* four bits each. + * @...: The arguments, as @sig types them. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(1) critical section to reserve; O(arguments plus their strings) copy outside it + * @owns none + * @config CONFIG_EMB_LOG + * @req OBS-001 OBS-003 OBS-013 + * @since 0.3 + * @stable no + * + * Reserves the record's room in the ring with interrupts masked for a bounded number of + * instructions, copies the arguments with interrupts enabled, then commits the record. A record + * that does not fit is dropped and counted; the next one that fits is preceded by a record of + * the count (A127). Nothing waits and nothing is formatted here. + */ +void emb_log_write(const emb_log_meta_t *meta, uint32_t sig, ...); + +/** + * emb_log_level_set() - Set a module's run-time level. + * @module: EMB_LOG_MODULE(name). + * @level: EMB_LOG_LEVEL_NONE to EMB_LOG_LEVEL_DBG: calls above it return at once. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(1) + * @owns none + * @config CONFIG_EMB_LOG + * @req OBS-002 + * @since 0.3 + * @stable no + * + * Return: EMB_OK; EMB_EINVAL for a NULL @module or a level above EMB_LOG_LEVEL_DBG. + */ +emb_status_t emb_log_level_set(emb_log_module_t *module, uint8_t level); + +/** + * emb_log_flush() - Send every committed record now, polled. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(records in the ring) plus the console's line time + * @owns none + * @config CONFIG_EMB_LOG + * @req OBS-003 + * @since 0.3 + * @stable no + * + * For a fault's last words and for tests: takes the records the log thread has not, in order, + * up to the first one not yet committed, and sends them from the caller. + */ +void emb_log_flush(void); + +/* The ring's counters. */ +typedef struct emb_log_stats { + uint32_t records; /* committed */ + uint32_t dropped; /* refused for want of room */ + uint32_t sent; /* taken from the ring and sent */ + uint32_t high_water; /* the most bytes the ring held */ +} emb_log_stats_t; + +/** + * emb_log_stats_get() - The log ring's counters. + * @out: Receives them, read together. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(1) + * @owns none + * @config CONFIG_EMB_LOG + * @req OBS-003 + * @since 0.3 + * @stable no + * + * Return: EMB_OK; EMB_EINVAL for a NULL @out. + */ +emb_status_t emb_log_stats_get(emb_log_stats_t *out); + +#ifdef __cplusplus +} +#endif + +#endif /* EMB_LOG_H */ diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index a8901aa1..9a9c3ad8 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -93,9 +93,10 @@ if(CONFIG_EMB_DEBUG_DESCRIPTOR) list(APPEND EMB_KERNEL_SOURCES debug/descriptor.c) endif() -if(CONFIG_EMB_CRASH_RECORD) - # The build identity (A72): SHA-1 over the commit, whether tracked files differ from it, the - # configuration hash and the toolchain, fixed at configure time. +if(CONFIG_EMB_CRASH_RECORD OR CONFIG_EMB_LOG_DEFERRED) + # The build identity (A72), which the deferred log's start record carries too (A127): SHA-1 + # over the commit, whether tracked files differ from it, the configuration hash and the + # toolchain, fixed at configure time. execute_process(COMMAND git rev-parse HEAD WORKING_DIRECTORY "${EMB_BASE}" OUTPUT_VARIABLE _emb_commit OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE _emb_git ERROR_QUIET) @@ -124,7 +125,10 @@ if(CONFIG_EMB_CRASH_RECORD) set(EMB_BUILD_ID "${_emb_build_id}" CACHE INTERNAL "the image's build identity (A72)") file(GENERATE OUTPUT "${EMB_GENERATED_DIR}/build_id.c" CONTENT "/* SPDX-License-Identifier: Apache-2.0 */\n/* Generated by kernel/CMakeLists.txt: ${_emb_commit}, configuration ${EMB_CONFIG_HASH}, toolchain ${_emb_toolchain}. */\n#include \n\nEMB_FLASH_CONST uint8_t emb_build_id[EMB_CRASH_BUILD_ID_SIZE] = {${_emb_bytes}};\n") - list(APPEND EMB_KERNEL_SOURCES fault/crash.c "${EMB_GENERATED_DIR}/build_id.c") + list(APPEND EMB_KERNEL_SOURCES "${EMB_GENERATED_DIR}/build_id.c") + if(CONFIG_EMB_CRASH_RECORD) + list(APPEND EMB_KERNEL_SOURCES fault/crash.c) + endif() endif() add_library(emb_kernel STATIC ${EMB_KERNEL_SOURCES}) diff --git a/soc/arm/mps2/board.c b/soc/arm/mps2/board.c index f698c05b..609416ff 100644 --- a/soc/arm/mps2/board.c +++ b/soc/arm/mps2/board.c @@ -43,11 +43,13 @@ void emb_board_led_toggle(void) FPGAIO_LED = led_state; /* LED0 (QEMU models the register) */ } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - emb_cmsdk_uart_putc(EMB_HW_CONSOLE_BASE, *s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + emb_cmsdk_uart_putc(EMB_HW_CONSOLE_BASE, p[i]); } } diff --git a/soc/arm/mps2/include/emb_board.h b/soc/arm/mps2/include/emb_board.h index 0b43e849..f111a376 100644 --- a/soc/arm/mps2/include/emb_board.h +++ b/soc/arm/mps2/include/emb_board.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); EMB_NORETURN void emb_board_exit(int code); void emb_board_fault_report(const emb_fault_info_t *info); diff --git a/soc/microchip/atmega/board.c b/soc/microchip/atmega/board.c index 0be8bd54..c8c3bb34 100644 --- a/soc/microchip/atmega/board.c +++ b/soc/microchip/atmega/board.c @@ -39,11 +39,13 @@ void emb_board_led_toggle(void) #endif } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - emb_avr_usart_putc(EMB_HW_CONSOLE_BASE, *s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + emb_avr_usart_putc(EMB_HW_CONSOLE_BASE, p[i]); } } diff --git a/soc/microchip/atmega/include/emb_board.h b/soc/microchip/atmega/include/emb_board.h index b6dec3df..3bdfef18 100644 --- a/soc/microchip/atmega/include/emb_board.h +++ b/soc/microchip/atmega/include/emb_board.h @@ -21,6 +21,7 @@ #include +#include #include #include @@ -34,6 +35,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); /* The end of an image (a benchmark's, after BENCH_END): no host to report the code to, so the * CPU stops with its interrupts masked; the last character still leaves the USART. */ diff --git a/soc/nordic/nrf51/board.c b/soc/nordic/nrf51/board.c index 983d2140..46db4cd2 100644 --- a/soc/nordic/nrf51/board.c +++ b/soc/nordic/nrf51/board.c @@ -55,11 +55,13 @@ static void put_char(char c) REG(UART_TXDRDY) = 0u; } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - put_char(*s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + put_char(p[i]); } } diff --git a/soc/nordic/nrf51/include/emb_board.h b/soc/nordic/nrf51/include/emb_board.h index f1c83af4..9d99ea32 100644 --- a/soc/nordic/nrf51/include/emb_board.h +++ b/soc/nordic/nrf51/include/emb_board.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); EMB_NORETURN void emb_board_exit(int code); void emb_board_fault_report(const emb_fault_info_t *info); diff --git a/soc/qemu/virt/board.c b/soc/qemu/virt/board.c index bf19f9f7..aa29f756 100644 --- a/soc/qemu/virt/board.c +++ b/soc/qemu/virt/board.c @@ -42,11 +42,13 @@ static void put_char(char c) UART_THR = (uint8_t)c; } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - put_char(*s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + put_char(p[i]); } } diff --git a/soc/qemu/virt/include/emb_board.h b/soc/qemu/virt/include/emb_board.h index e34654fd..532f4bba 100644 --- a/soc/qemu/virt/include/emb_board.h +++ b/soc/qemu/virt/include/emb_board.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -31,6 +32,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); EMB_NORETURN void emb_board_exit(int code); void emb_board_fault_report(const emb_fault_info_t *info); diff --git a/soc/rpi/rp2350/board.c b/soc/rpi/rp2350/board.c index 62db30af..84c5ba7c 100644 --- a/soc/rpi/rp2350/board.c +++ b/soc/rpi/rp2350/board.c @@ -54,11 +54,13 @@ void emb_board_led_toggle(void) /* the Pico 2 W's LED is on its wireless chip, which has no driver yet */ } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - emb_pl011_putc(EMB_HW_CONSOLE_BASE, *s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + emb_pl011_putc(EMB_HW_CONSOLE_BASE, p[i]); } } diff --git a/soc/rpi/rp2350/include/emb_board.h b/soc/rpi/rp2350/include/emb_board.h index 3f69b435..3768cb73 100644 --- a/soc/rpi/rp2350/include/emb_board.h +++ b/soc/rpi/rp2350/include/emb_board.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); EMB_NORETURN void emb_board_exit(int code); void emb_board_fault_report(const emb_fault_info_t *info); diff --git a/soc/st/stm32f4/board.c b/soc/st/stm32f4/board.c index 5320a092..c7e70f09 100644 --- a/soc/st/stm32f4/board.c +++ b/soc/st/stm32f4/board.c @@ -54,11 +54,13 @@ void emb_board_led_toggle(void) #endif } -void emb_board_puts(const char *s) +/* The console's bytes as they are (A127): emb_board_puts() and the framed console call it. */ +void emb_board_write(const void *buf, size_t len) { - while (*s != '\0') { /* bounded by the string */ - emb_stm32_usart_putc(EMB_HW_CONSOLE_BASE, *s); - s++; + const char *p = (const char *)buf; + size_t i; + for (i = 0u; i < len; i++) { /* bounded by len */ + emb_stm32_usart_putc(EMB_HW_CONSOLE_BASE, p[i]); } } diff --git a/soc/st/stm32f4/include/emb_board.h b/soc/st/stm32f4/include/emb_board.h index f50111c4..88433901 100644 --- a/soc/st/stm32f4/include/emb_board.h +++ b/soc/st/stm32f4/include/emb_board.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ extern "C" { void emb_board_init(void); void emb_board_led_toggle(void); void emb_board_puts(const char *s); +void emb_board_write(const void *buf, size_t len); /* raw bytes (A127) */ void emb_board_put_u32(uint32_t v); EMB_NORETURN void emb_board_exit(int code); void emb_board_fault_report(const emb_fault_info_t *info); diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 83274997..3424a5be 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -6,16 +6,18 @@ # emb_subsys: the subsystems over the kernel (transports, and in M4 logging, trace and update), # each behind its CONFIG_EMB_* symbol, compiled like the kernel and linked into every image, -# which keeps only what it calls. With none selected it is an empty interface library. -set(EMB_SUBSYS_SOURCES) +# which keeps only what it calls. The console is always there: emb_board_puts(), plain or +# framed (A127). +set(EMB_SUBSYS_SOURCES console/console.c) if(CONFIG_EMB_FRAME) list(APPEND EMB_SUBSYS_SOURCES transport/frame.c) # SPEC-015 §7 endif() - -if(EMB_SUBSYS_SOURCES) - add_library(emb_subsys STATIC ${EMB_SUBSYS_SOURCES}) - emb_use_kernel_compiler(emb_subsys) - target_link_libraries(emb_subsys PUBLIC emb_api PRIVATE emb_flags) -else() - add_library(emb_subsys INTERFACE) +if(CONFIG_EMB_LOG) + list(APPEND EMB_SUBSYS_SOURCES logging/log.c) # SPEC-015 §2, A127 endif() + +add_library(emb_subsys STATIC ${EMB_SUBSYS_SOURCES}) +emb_use_kernel_compiler(emb_subsys) +# embs/: the subsystems' own headers, for their tests (not an application interface) +target_include_directories(emb_subsys PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(emb_subsys PUBLIC emb_api PRIVATE emb_flags) diff --git a/subsys/Kconfig b/subsys/Kconfig index 2c3f7d02..3fc6b265 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -14,4 +14,87 @@ config EMB_FRAME each zero delimiter, for the log, trace, crash, shell and update channels over one byte stream. Linked only into an image that calls it. +config EMB_CONSOLE_FRAMED + bool "Framed console: every stream on the console in frames (A127)" + depends on EMB_FRAME && EMB_MUTEX + default n + help + Everything on the console travels in SPEC-015 §7 frames, each preceded + by a zero: the board's text on channel 3, log records on 0, trace on 1, + crash records on 2. `emb monitor` decodes and shows them. Off, the + console is plain text, which the test runners and any terminal read. + +config EMB_LOG + bool "Logging (SPEC-015 §2, A127), linked only when a call references it" + depends on EMB_SEM + default y + help + EMB_LOG_ERR() to EMB_LOG_DBG(): a call packs its arguments into a + ring in the caller, from any context and without waiting, and a log + thread sends the records on. Records that do not fit are dropped and + counted (OBS-003). The ring and the thread come with the first call: + an image that logs nothing has neither. + +if EMB_LOG + +choice EMB_LOG_BACKEND + prompt "Log backend (08 Q13)" + default EMB_LOG_DEFERRED if EMB_CONSOLE_FRAMED && !EMB_PROFILE_TINY + default EMB_LOG_TEXT + +config EMB_LOG_DEFERRED + bool "Deferred: the record is sent and the host formats it from the ELF (ADR-009)" + depends on EMB_CONSOLE_FRAMED && !EMB_ARCH_AVR + +config EMB_LOG_TEXT + bool "Plain text: the log thread formats the record on the target" + +endchoice + +config EMB_LOG_LEVEL_MAX + int "Most detailed level compiled: 1 errors, 2 warnings, 3 information, 4 debug" + default 3 + range 0 4 + +config EMB_LOG_RING_SIZE + int "Log ring, bytes (a power of two)" + default 256 if EMB_PROFILE_TINY + default 1024 + range 64 65536 + +config EMB_LOG_STR_MAX + int "Longest string argument a record keeps, bytes" + default 16 if EMB_PROFILE_TINY + default 32 + range 1 255 + +config EMB_LOG_HEXDUMP_MAX + int "Longest hexdump a record keeps, bytes" + default 16 if EMB_PROFILE_TINY + default 64 + range 1 1024 + +config EMB_LOG_TIMESTAMP + bool "Records carry the kernel clock's ticks" + default y + +config EMB_LOG_THREAD_PRIORITY + int "Log thread priority; 0 selects the lowest application priority" + default 0 + range 0 255 + +config EMB_LOG_THREAD_STACK + int "Log thread stack, bytes" + default 1024 + range EMB_ARCH_STACK_MIN 65536 + +config EMB_LOG_LINE_MAX + int "Longest line the plain-text backend formats, bytes" + depends on EMB_LOG_TEXT + default 64 if EMB_PROFILE_TINY + default 128 + range 16 1024 + +endif # EMB_LOG + endmenu diff --git a/subsys/console/console.c b/subsys/console/console.c new file mode 100644 index 00000000..5906baf2 --- /dev/null +++ b/subsys/console/console.c @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file console.c + * @brief The console: the board's text, plain or framed (SPEC-015 §7, A127). + * + * @details + * emb_board_puts() is the same on every board: plain, it writes the text as it is; framed, it + * sends the text as one frame on the shell's channel. A frame is written through + * emb_frame_write(), which reads its payload in place, so the console keeps no frame buffer. + * + * @see include/emb/console.h + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include +#include +#include + +#include + +#if CONFIG_EMB_CONSOLE_FRAMED +#include +#include +#include +#include +#include +#include +#include + +#include +#endif + +#if CONFIG_EMB_CONSOLE_FRAMED + +#if CONFIG_EMB_MUTEX_INHERIT +#define CONSOLE_PROTOCOL EMB_MUTEX_INHERIT +#else +#define CONSOLE_PROTOCOL EMB_MUTEX_NONE +#endif + +/* One thread's frame at a time on the line. */ +EMB_MUTEX_DEFINE(console_mutex, CONSOLE_PROTOCOL, 0u, 0u); + +static void console_sink(void *ctx, const uint8_t *bytes, size_t len) +{ + (void)ctx; + emb_board_write(bytes, len); +} + +/* A thread outside any critical section waits for the console; anywhere else the frame goes at + * once, since nothing there may wait. */ +static bool console_may_wait(void) +{ + return (emb_context() == EMB_CONTEXT_THREAD) && !emb_irq_is_locked() && + (emb_sched_lock_depth() == 0u); +} + +emb_status_t emb_console_frame(uint8_t channel, const void *payload, size_t len) +{ + static const uint8_t lead = 0u; + bool locked = false; + emb_status_t st; + if ((channel > EMB_FRAME_CHANNEL_MAX) || ((payload == NULL) && (len != 0u))) { + return EMB_EINVAL; + } + if (console_may_wait()) { + locked = (emb_mutex_lock(console_mutex, EMB_WAIT_FOREVER) == EMB_OK); + } + emb_board_write(&lead, 1u); /* ends whatever came before that was not a frame */ + st = emb_frame_write(channel, payload, len, console_sink, NULL); + if (locked) { + (void)emb_mutex_unlock(console_mutex); + } + return st; +} + +#else + +emb_status_t emb_console_frame(uint8_t channel, const void *payload, size_t len) +{ + (void)channel; + (void)payload; + (void)len; + return EMB_ENOTSUP; +} + +#endif /* CONFIG_EMB_CONSOLE_FRAMED */ + +void emb_board_puts(const char *s) +{ + size_t n = 0u; + if (s == NULL) { + return; + } + while (s[n] != '\0') { /* bounded by the string */ + n++; + } +#if CONFIG_EMB_CONSOLE_FRAMED + (void)emb_console_frame(EMB_FRAME_CHANNEL_SHELL, s, n); +#else + emb_board_write(s, n); +#endif +} diff --git a/subsys/include/embs/log.h b/subsys/include/embs/log.h new file mode 100644 index 00000000..09d83e16 --- /dev/null +++ b/subsys/include/embs/log.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file log.h + * @brief The log ring's steps, for the subsystem's tests (A127). + * + * @details + * emb_log_write() is a reservation, the record's bytes, and a commit; the log thread takes + * records and, with the plain-text backend, formats each as a line. These are those steps on + * their own, so a test can hold a record uncommitted while an interrupt writes after it, or read + * the ring itself. Not an application interface. + * + * @see subsys/logging/log.c + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#ifndef EMBS_LOG_H +#define EMBS_LOG_H + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Reserves a record of len bytes (a dropped record first, written and committed, when records + * were lost); *pos is the record's. False when it does not fit: dropped and counted. */ +bool embs_log_reserve(uint32_t len, uint32_t *pos); + +/* Writes len bytes of the reserved record at pos, from its first byte. */ +void embs_log_put(uint32_t pos, const void *bytes, uint32_t len); + +/* Commits the record of len bytes at pos. */ +void embs_log_commit(uint32_t pos, uint32_t len); + +/* Takes the oldest record, if committed and no longer than cap; its length, else 0. */ +size_t embs_log_take(uint8_t *buf, size_t cap); + +/* The identifier's width in a record: 2 or 4 with the deferred backend, a pointer's with the + * plain-text one. */ +uint32_t embs_log_id_bytes(void); + +#if CONFIG_EMB_LOG_TEXT +/* Formats a record as the plain-text backend sends it, the newline included; its length. */ +size_t embs_log_line(const uint8_t *rec, size_t n, char *line, size_t cap); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EMBS_LOG_H */ diff --git a/subsys/logging/log.c b/subsys/logging/log.c new file mode 100644 index 00000000..ae2ae07f --- /dev/null +++ b/subsys/logging/log.c @@ -0,0 +1,1164 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file log.c + * @brief The log ring, its producers and its consumers (SPEC-015 §2, A127). + * + * @details + * The ring is a power-of-two byte array of records, each a two-byte header (its length, and the + * committed bit in the second byte) and SPEC-015 §2.3's record: the identifier, the timestamp, + * the arguments. + * + * A producer reserves a record's room with interrupts masked for a bounded number of + * instructions (the free space, the head, the header), copies the record with interrupts enabled + * and commits it with one byte store. A producer that preempts another reserves after it, so the + * ring keeps the order of reservation. Records that do not fit are dropped and counted, and the + * next record that fits brings a dropped record before it. + * + * A consumer takes the record at the tail when it is committed and stops at the first that is + * not. It claims the record in a critical section, copies it out with interrupts enabled, and + * advances the tail only if no other consumer claimed meanwhile; one that did (emb_log_flush() + * from an interrupt over the log thread) took the record itself, and the first looks again. The + * free space ends at the tail, so a record being copied is never overwritten. + * + * @see include/emb/log.h + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include +#include + +#if CONFIG_EMB_LOG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if CONFIG_EMB_LOG_DEFERRED +#include /* emb_build_id */ +#endif + +#include +#include + +/* ---- sizes ------------------------------------------------------------------------- */ + +#define RING_SIZE ((uint32_t)CONFIG_EMB_LOG_RING_SIZE) +#define RING_MASK (RING_SIZE - 1u) +#define HDR_BYTES 2u +#define HDR_COMMITTED 0x80u +#define LEN_HI_MASK 0x7Fu + +#if CONFIG_EMB_LOG_DEFERRED +#define ID_MAX 4u +#else +#define ID_MAX ((uint32_t)sizeof(void *)) /* the plain-text record carries its metadata's address \ + */ +#endif +#if CONFIG_EMB_LOG_TIMESTAMP +#define TS_BYTES 4u +#else +#define TS_BYTES 0u +#endif +#define STR_MAX ((uint32_t)CONFIG_EMB_LOG_STR_MAX) +#define HEX_MAX ((uint32_t)CONFIG_EMB_LOG_HEXDUMP_MAX) +#define ARG_BYTES_MAX (((STR_MAX + 1u) > 8u) ? (STR_MAX + 1u) : 8u) +#define ARGS_BYTES_MAX \ + (((EMB_LOG_ARGS_MAX * ARG_BYTES_MAX) > (HEX_MAX + 2u)) ? (EMB_LOG_ARGS_MAX * ARG_BYTES_MAX) \ + : (HEX_MAX + 2u)) +#define RECORD_MAX (ID_MAX + TS_BYTES + ARGS_BYTES_MAX) +#define DROPPED_MAX (ID_MAX + TS_BYTES + 2u) /* the dropped record, at its widest */ + +/* A consumer's batch: whole records, at least the largest. */ +#define BATCH_MAX ((RECORD_MAX > 128u) ? RECORD_MAX : 128u) + +EMB_STATIC_ASSERT((RING_SIZE & RING_MASK) == 0u, "CONFIG_EMB_LOG_RING_SIZE is a power of two"); +EMB_STATIC_ASSERT(RECORD_MAX <= 0x7FFFu, "a record's length fits its header"); +EMB_STATIC_ASSERT(((2u * HDR_BYTES) + RECORD_MAX + DROPPED_MAX) <= RING_SIZE, + "the log ring holds the largest record and a dropped record"); + +#if CONFIG_EMB_LOG_THREAD_PRIORITY == 0 +#define LOG_PRIORITY EMB_PRIORITY_MIN +#else +#define LOG_PRIORITY ((uint8_t)CONFIG_EMB_LOG_THREAD_PRIORITY) +EMB_STATIC_ASSERT(CONFIG_EMB_LOG_THREAD_PRIORITY < CONFIG_EMB_PRIORITY_COUNT, + "CONFIG_EMB_LOG_THREAD_PRIORITY is not an application priority"); +#endif + +/* ---- the ring ---------------------------------------------------------------------- */ + +static uint8_t ring[RING_SIZE]; +/* Lock domain: the critical section (emb_irq_lock), for every variable below. */ +static uint32_t ring_head; /* the next byte to reserve */ +static uint32_t ring_tail; /* the oldest byte not taken: the free space ends here */ +static uint32_t ring_claims; /* moved by each consumer's claim, so a preempted one can tell */ +static uint32_t ring_lost; /* records refused since the last one that fitted */ +static emb_log_stats_t ring_stats; +static bool log_ready; /* the log thread's semaphore exists */ +static bool flushing; /* emb_log_flush() is sending: a nested one leaves it to it */ +static emb_sem_t log_sem; + +static void ring_set(uint32_t pos, uint8_t b) +{ + ring[pos & RING_MASK] = b; +} + +static uint8_t ring_at(uint32_t pos) +{ + return ring[pos & RING_MASK]; +} + +/* A record's header, its committed bit clear. */ +static void hdr_write(uint32_t pos, uint32_t len) +{ + ring_set(pos, (uint8_t)(len & 0xFFu)); + ring_set(pos + 1u, (uint8_t)((len >> 8) & LEN_HI_MASK)); +} + +/* Writes a record's bytes in place, wrapping at the ring's end. */ +typedef struct rec_writer { + uint32_t pos; +} rec_writer_t; + +static void put8(rec_writer_t *w, uint8_t b) +{ + ring_set(w->pos, b); + w->pos++; +} + +static void put_le(rec_writer_t *w, uint64_t v, uint32_t bytes) +{ + uint32_t i; + for (i = 0u; i < bytes; i++) { /* bounded: at most eight bytes */ + put8(w, (uint8_t)(v >> (8u * i))); + } +} + +static void log_wake(void) +{ + if (log_ready && (emb_context() != EMB_CONTEXT_PREKERNEL)) { + (void)emb_sem_give(log_sem); /* binary and saturating: a wake already pending stays one */ + } +} + +static uint32_t now_ticks(void) +{ + return (uint32_t)emb_time_now().ticks; +} + +/* + * Reserves room for a record of len bytes, and before it for a dropped record when records were + * lost. In the critical section: the free space, the headers, the head, and the timestamp, so + * timestamps grow in the ring's order. + */ +static bool ring_reserve(uint32_t len, uint32_t dropped_len, uint32_t *pos, uint32_t *lost, + uint32_t *ts) +{ + emb_irq_key_t key = emb_irq_lock(); + uint32_t used = ring_head - ring_tail; + uint32_t extra = (ring_lost != 0u) ? (HDR_BYTES + dropped_len) : 0u; + uint32_t need = extra + HDR_BYTES + len; + bool ok = need <= (RING_SIZE - used); + if (ok) { + *pos = ring_head; + *lost = ring_lost; + ring_lost = 0u; + if (extra != 0u) { + hdr_write(ring_head, dropped_len); + } + hdr_write(ring_head + extra, len); + ring_head += need; + if ((used + need) > ring_stats.high_water) { + ring_stats.high_water = used + need; + } + *ts = now_ticks(); + } else { + if (ring_lost != UINT32_MAX) { + ring_lost++; + } + ring_stats.dropped++; + } + emb_irq_unlock(key); + return ok; +} + +/* Sets the record's committed bit, its bytes written before it; wakes the log thread when the + * record is the oldest, which the thread may be waiting on. */ +static void ring_commit(uint32_t pos, uint32_t len) +{ + emb_irq_key_t key; + bool at_tail; + EMB_COMPILER_BARRIER(); /* the record's bytes before the bit that publishes them */ + ring_set(pos + 1u, (uint8_t)(((len >> 8) & LEN_HI_MASK) | HDR_COMMITTED)); + key = emb_irq_lock(); + ring_stats.records++; + at_tail = pos == ring_tail; + emb_irq_unlock(key); + if (at_tail) { + log_wake(); + } +} + +/* ---- records ----------------------------------------------------------------------- */ + +#if CONFIG_EMB_LOG_DEFERRED +EMB_TABLE_BOUNDS(const uint8_t, emb_log); + +/* What tools/logdec reads first: in the ELF only, as the call sites' metadata. */ +EMB_LOG_SECTION_ const emb_log_header_t emb_log_header + EMB_USED = {{'E', 'M', 'B', 'L'}, + 1u, + (uint8_t)(CONFIG_EMB_LOG_TIMESTAMP ? 1u : 0u), + (uint8_t)sizeof(long), + (uint8_t)sizeof(void *), + (uint8_t)sizeof(double), + (uint8_t)CONFIG_EMB_LOG_STR_MAX, + {0u, 0u}}; + +/* 16-bit identifiers while the section is under 64 KiB minus EMB_LOG_ID_FIRST, else 32: fixed + * when the image is linked, and the decoder computes the same from the ELF. */ +static uint32_t id_bytes(void) +{ + uintptr_t size = (uintptr_t)EMB_TABLE_STOP(emb_log) - (uintptr_t)EMB_TABLE_START(emb_log); + return (size <= (uintptr_t)(0xFFFFu - EMB_LOG_ID_FIRST)) ? 2u : 4u; +} + +static uint64_t record_id(const emb_log_meta_t *meta) +{ + return (uint64_t)((uintptr_t)meta - (uintptr_t)EMB_TABLE_START(emb_log)) + EMB_LOG_ID_FIRST; +} +#else +static uint32_t id_bytes(void) +{ + return ID_MAX; +} + +static uint64_t record_id(const emb_log_meta_t *meta) +{ + return (uint64_t)(uintptr_t)meta; +} +#endif + +/* The dropped record: an identifier, the timestamp, a 16-bit count. */ +static uint32_t dropped_bytes(void) +{ + return id_bytes() + TS_BYTES + 2u; +} + +static void put_head(rec_writer_t *w, uint64_t id, uint32_t ts) +{ + put_le(w, id, id_bytes()); +#if CONFIG_EMB_LOG_TIMESTAMP + put_le(w, ts, 4u); +#else + (void)ts; +#endif +} + +static uint32_t str_len(const char *s) +{ + uint32_t n = 0u; + if (s != NULL) { + while ((n < STR_MAX) && (s[n] != '\0')) { /* bounded by CONFIG_EMB_LOG_STR_MAX */ + n++; + } + } + return n; +} + +static uint32_t sig_at(uint32_t sig, uint32_t k) +{ + return (sig >> (4u * k)) & 0xFu; +} + +/* The arguments' bytes, read from a copy of the argument list. A type the record cannot carry + * ends the arguments: the decoder stops at it too. */ +static uint32_t args_size(uint32_t sig, va_list *ap) +{ + uint32_t size = 0u; + uint32_t k; + for (k = 0u; k < EMB_LOG_ARGS_MAX; k++) { /* bounded: eight arguments */ + uint32_t t = sig_at(sig, k); + if ((t == EMB_LOG_T_END) || (t > EMB_LOG_T_HEX)) { + break; + } + switch (t) { + case EMB_LOG_T_INT: + (void)va_arg(*ap, int); + size += 4u; + break; + case EMB_LOG_T_UINT: + (void)va_arg(*ap, unsigned int); + size += 4u; + break; + case EMB_LOG_T_LONG: + (void)va_arg(*ap, long); + size += (uint32_t)sizeof(long); + break; + case EMB_LOG_T_ULONG: + (void)va_arg(*ap, unsigned long); + size += (uint32_t)sizeof(long); + break; + case EMB_LOG_T_LLONG: + (void)va_arg(*ap, long long); + size += 8u; + break; + case EMB_LOG_T_ULLONG: + (void)va_arg(*ap, unsigned long long); + size += 8u; + break; + case EMB_LOG_T_DOUBLE: + (void)va_arg(*ap, double); + size += (uint32_t)sizeof(double); + break; + case EMB_LOG_T_STR: + size += 1u + str_len(va_arg(*ap, const char *)); + break; + case EMB_LOG_T_PTR: + (void)va_arg(*ap, void *); + size += (uint32_t)sizeof(void *); + break; + default: { /* EMB_LOG_T_HEX: a pointer and a length */ + size_t n; + (void)va_arg(*ap, const void *); + n = va_arg(*ap, size_t); + size += 2u + ((n < HEX_MAX) ? (uint32_t)n : HEX_MAX); + break; + } + } + } + return size; +} + +static void put_bytes(rec_writer_t *w, const void *src, uint32_t n) +{ + const uint8_t *p = (const uint8_t *)src; + uint32_t i; + for (i = 0u; i < n; i++) { /* bounded by n */ + put8(w, p[i]); + } +} + +static void args_write(rec_writer_t *w, uint32_t sig, va_list *ap) +{ + uint32_t k; + for (k = 0u; k < EMB_LOG_ARGS_MAX; k++) { /* bounded: eight arguments */ + uint32_t t = sig_at(sig, k); + if ((t == EMB_LOG_T_END) || (t > EMB_LOG_T_HEX)) { + break; + } + switch (t) { + case EMB_LOG_T_INT: + put_le(w, (uint64_t)(int64_t)va_arg(*ap, int), 4u); + break; + case EMB_LOG_T_UINT: + put_le(w, (uint64_t)va_arg(*ap, unsigned int), 4u); + break; + case EMB_LOG_T_LONG: + put_le(w, (uint64_t)(int64_t)va_arg(*ap, long), (uint32_t)sizeof(long)); + break; + case EMB_LOG_T_ULONG: + put_le(w, (uint64_t)va_arg(*ap, unsigned long), (uint32_t)sizeof(long)); + break; + case EMB_LOG_T_LLONG: + put_le(w, (uint64_t)va_arg(*ap, long long), 8u); + break; + case EMB_LOG_T_ULLONG: + put_le(w, (uint64_t)va_arg(*ap, unsigned long long), 8u); + break; + case EMB_LOG_T_DOUBLE: { + double d = va_arg(*ap, double); + put_bytes(w, &d, (uint32_t)sizeof(double)); /* little-endian on every port */ + break; + } + case EMB_LOG_T_STR: { + const char *s = va_arg(*ap, const char *); + uint32_t n = str_len(s); + put8(w, (uint8_t)n); + put_bytes(w, s, n); + break; + } + case EMB_LOG_T_PTR: + put_le(w, (uint64_t)(uintptr_t)va_arg(*ap, void *), (uint32_t)sizeof(void *)); + break; + default: { /* EMB_LOG_T_HEX */ + const void *p = va_arg(*ap, const void *); + size_t len = va_arg(*ap, size_t); + uint32_t n = (len < HEX_MAX) ? (uint32_t)len : HEX_MAX; + put_le(w, n, 2u); + if (p != NULL) { + put_bytes(w, p, n); + } else { + uint32_t i; + for (i = 0u; i < n; i++) { /* bounded by HEX_MAX: nothing to dump, zeros */ + put8(w, 0u); + } + } + break; + } + } + } +} + +/* A dropped record: its count saturates at 65535. */ +static void put_dropped(uint32_t pos, uint32_t lost, uint32_t ts) +{ + rec_writer_t w; + w.pos = pos + HDR_BYTES; + put_head(&w, EMB_LOG_ID_DROPPED, ts); + put_le(&w, (lost < 0xFFFFu) ? lost : 0xFFFFu, 2u); + ring_commit(pos, dropped_bytes()); +} + +void emb_log_write(const emb_log_meta_t *meta, uint32_t sig, ...) +{ + va_list ap; + va_list sizing; + uint32_t len; + uint32_t pos = 0u; + uint32_t lost = 0u; + uint32_t ts = 0u; + if (meta == NULL) { + return; + } + va_start(ap, sig); + va_copy(sizing, ap); + len = id_bytes() + TS_BYTES + args_size(sig, &sizing); + va_end(sizing); + if (ring_reserve(len, dropped_bytes(), &pos, &lost, &ts)) { + rec_writer_t w; + if (lost != 0u) { + put_dropped(pos, lost, ts); + pos += HDR_BYTES + dropped_bytes(); + } + w.pos = pos + HDR_BYTES; + put_head(&w, record_id(meta), ts); + args_write(&w, sig, &ap); + ring_commit(pos, len); + } + va_end(ap); +} + +emb_status_t emb_log_level_set(emb_log_module_t *module, uint8_t level) +{ + if ((module == NULL) || (level > EMB_LOG_LEVEL_DBG)) { + return EMB_EINVAL; + } + module->level = level; /* one byte: a call reads the old level or the new */ + return EMB_OK; +} + +emb_status_t emb_log_stats_get(emb_log_stats_t *out) +{ + emb_irq_key_t key; + if (out == NULL) { + return EMB_EINVAL; + } + key = emb_irq_lock(); + *out = ring_stats; + emb_irq_unlock(key); + return EMB_OK; +} + +/* ---- consumers --------------------------------------------------------------------- */ + +typedef enum take_result { + TAKE_NONE, /* the ring is empty, or its oldest record is not committed */ + TAKE_TOO_BIG, /* the oldest record does not fit in what is left of the buffer */ + TAKE_DONE +} take_result_t; + +/* Takes the oldest record, if committed, into buf (cap bytes); its length in *len. */ +static take_result_t ring_take(uint8_t *buf, uint32_t cap, uint32_t *len) +{ + for (;;) { /* bounded: a retry means another consumer took the record meanwhile */ + emb_irq_key_t key = emb_irq_lock(); + uint32_t at = ring_tail; + uint32_t claim; + uint32_t n; + uint32_t i; + uint8_t hi; + bool taken; + if (ring_head == at) { + emb_irq_unlock(key); + return TAKE_NONE; + } + hi = ring_at(at + 1u); + if ((hi & HDR_COMMITTED) == 0u) { + emb_irq_unlock(key); + return TAKE_NONE; /* in order: the records after it wait for it */ + } + n = (uint32_t)ring_at(at) | ((uint32_t)(hi & LEN_HI_MASK) << 8); + if (n > cap) { + emb_irq_unlock(key); + return TAKE_TOO_BIG; + } + ring_claims++; + claim = ring_claims; + emb_irq_unlock(key); + for (i = 0u; i < n; i++) { /* bounded by the record; producers stay out of it */ + buf[i] = ring_at(at + HDR_BYTES + i); + } + key = emb_irq_lock(); + taken = (ring_claims == claim) && (ring_tail == at); + if (taken) { + ring_tail = at + HDR_BYTES + n; + ring_stats.sent++; + } + emb_irq_unlock(key); + if (taken) { + *len = n; + return TAKE_DONE; + } + } +} + +#if CONFIG_EMB_LOG_DEFERRED + +typedef struct consumer { + uint8_t batch[BATCH_MAX]; +} consumer_t; + +/* Sends the committed records as frames on the log channel, each holding whole records. */ +static void drain(consumer_t *c) +{ + uint32_t n = 0u; + for (;;) { /* bounded: each pass takes a record or sends the batch, until none is left */ + uint32_t len = 0u; + take_result_t r = ring_take(&c->batch[n], BATCH_MAX - n, &len); + if (r == TAKE_DONE) { + n += len; + } else if ((r == TAKE_TOO_BIG) && (n != 0u)) { + (void)emb_console_frame(EMB_FRAME_CHANNEL_LOG, c->batch, n); + n = 0u; + } else { + break; + } + } + if (n != 0u) { + (void)emb_console_frame(EMB_FRAME_CHANNEL_LOG, c->batch, n); + } +} + +/* The stream's first record: the image it comes from, and the clock's tick. */ +static void put_start(void) +{ + uint32_t len = id_bytes() + TS_BYTES + EMB_CRASH_BUILD_ID_SIZE + 4u; + uint32_t pos = 0u; + uint32_t lost = 0u; + uint32_t ts = 0u; + if (ring_reserve(len, dropped_bytes(), &pos, &lost, &ts)) { + rec_writer_t w; + uint32_t i; + if (lost != 0u) { + put_dropped(pos, lost, ts); + pos += HDR_BYTES + dropped_bytes(); + } + w.pos = pos + HDR_BYTES; + put_head(&w, EMB_LOG_ID_START, ts); + for (i = 0u; i < EMB_CRASH_BUILD_ID_SIZE; i++) { /* bounded: 20 bytes */ + put8(&w, EMB_FLASH_READ_U8(&emb_build_id[i])); + } + put_le(&w, (uint32_t)CONFIG_EMB_TICK_NS, 4u); + ring_commit(pos, len); + } +} + +#else /* CONFIG_EMB_LOG_TEXT */ + +typedef struct consumer { + uint8_t rec[RECORD_MAX]; + char line[CONFIG_EMB_LOG_LINE_MAX]; +} consumer_t; + +/* A line being formatted: room is its size less one, kept for the newline. */ +typedef struct out { + char *buf; + uint32_t len; + uint32_t room; +} out_t; + +static void out_c(out_t *o, char c) +{ + if (o->len < o->room) { + o->buf[o->len] = c; + o->len++; + } +} + +static void out_n(out_t *o, const char *s, uint32_t n) +{ + uint32_t i; + for (i = 0u; i < n; i++) { /* bounded by n */ + out_c(o, s[i]); + } +} + +static void out_z(out_t *o, const char *s) +{ + uint32_t i = 0u; + while ((s[i] != '\0') && (o->len < o->room)) { /* bounded by the line */ + out_c(o, s[i]); + i++; + } +} + +static void out_pad(out_t *o, char c, uint32_t n) +{ + uint32_t i; + for (i = 0u; (i < n) && (o->len < o->room); i++) { /* bounded by the line */ + out_c(o, c); + } +} + +/* A record's arguments, read in order. */ +typedef struct rd { + const uint8_t *p; + uint32_t n; + uint32_t at; +} rd_t; + +static uint64_t rd_le(rd_t *r, uint32_t bytes) +{ + uint64_t v = 0u; + uint32_t i; + for (i = 0u; (i < bytes) && (r->at < r->n); i++) { /* bounded: at most eight bytes */ + v |= (uint64_t)r->p[r->at] << (8u * i); + r->at++; + } + return v; +} + +static int64_t sign_extend(uint64_t v, uint32_t bytes) +{ + uint64_t sign = (uint64_t)1u << ((8u * bytes) - 1u); + return (bytes >= 8u) ? (int64_t)v : (int64_t)((v ^ sign) - sign); +} + +/* A conversion's flags, width and precision. */ +typedef struct spec { + uint32_t width; + int32_t prec; /* -1: none */ + bool left; + bool zero; + bool plus; + bool space; + bool alt; +} spec_t; + +/* Writes digits, a sign and a prefix within the conversion's width. */ +static void out_field(out_t *o, const spec_t *sp, const char *sign, const char *digits, uint32_t nd) +{ + uint32_t ns = 0u; + uint32_t zeros = 0u; + uint32_t total; + while (sign[ns] != '\0') { /* bounded: at most "-0x" */ + ns++; + } + if ((sp->prec >= 0) && ((uint32_t)sp->prec > nd)) { + zeros = (uint32_t)sp->prec - nd; + } + total = ns + zeros + nd; + if ((sp->zero) && (!sp->left) && (sp->prec < 0) && (sp->width > total)) { + zeros += sp->width - total; + total = sp->width; + } + if ((!sp->left) && (sp->width > total)) { + out_pad(o, ' ', sp->width - total); + } + out_z(o, sign); + out_pad(o, '0', zeros); + out_n(o, digits, nd); + if (sp->left && (sp->width > total)) { + out_pad(o, ' ', sp->width - total); + } +} + +static uint32_t to_digits(uint64_t v, uint32_t base, bool upper, char *buf) +{ + char tmp[24]; + uint32_t n = 0u; + uint32_t i; + const char *set = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + do { /* bounded: at most 22 digits of a 64-bit value */ + tmp[n] = set[v % base]; + n++; + v /= base; + } while (v != 0u); + for (i = 0u; i < n; i++) { /* bounded by n */ + buf[i] = tmp[n - 1u - i]; + } + return n; +} + +static void out_int(out_t *o, const spec_t *sp, int64_t sv, uint64_t uv, char conv) +{ + char digits[24]; + uint32_t nd; + const char *sign = ""; + if ((conv == 'd') || (conv == 'i')) { + uint64_t mag = (sv < 0) ? (0u - (uint64_t)sv) : (uint64_t)sv; + sign = (sv < 0) ? "-" : (sp->plus ? "+" : (sp->space ? " " : "")); + nd = to_digits(mag, 10u, false, digits); + } else if ((conv == 'x') || (conv == 'X')) { + nd = to_digits(uv, 16u, conv == 'X', digits); + sign = (sp->alt && (uv != 0u)) ? ((conv == 'X') ? "0X" : "0x") : ""; + } else if (conv == 'o') { + nd = to_digits(uv, 8u, false, digits); + sign = (sp->alt && (uv != 0u)) ? "0" : ""; + } else if (conv == 'p') { + nd = to_digits(uv, 16u, false, digits); + sign = "0x"; + } else { + nd = to_digits(uv, 10u, false, digits); + } + if ((sp->prec == 0) && (uv == 0u) && (sv == 0) && (conv != 'p')) { + nd = 0u; /* printf: a zero with precision 0 has no digits */ + } + out_field(o, sp, sign, digits, nd); +} + +/* Fixed point for %f (and %e and %g, which print as %f here): up to nine decimals. */ +static void out_double(out_t *o, const spec_t *sp, double d) +{ + static const uint32_t pow10[10] = {1u, 10u, 100u, 1000u, 10000u, + 100000u, 1000000u, 10000000u, 100000000u, 1000000000u}; + char digits[40]; + uint32_t nd; + uint32_t prec = (sp->prec < 0) ? 6u : (((uint32_t)sp->prec > 9u) ? 9u : (uint32_t)sp->prec); + const char *sign = ""; + uint64_t ip; + uint64_t fp; + bool neg = d < 0.0; + if (d != d) { /* NaN */ + out_field(o, sp, "", "nan", 3u); + return; + } + if (neg) { + d = -d; + } + sign = neg ? "-" : (sp->plus ? "+" : (sp->space ? " " : "")); + if (d >= 1.8e19) { /* beyond a 64-bit integer part, infinity included */ + out_field(o, sp, sign, "inf", 3u); + return; + } + ip = (uint64_t)d; + { + /* to the nearest, an exact half to the even neighbour, as printf rounds */ + double x = (d - (double)ip) * (double)pow10[prec]; + double rest; + fp = (uint64_t)x; + rest = x - (double)fp; + if ((rest > 0.5) || ((rest == 0.5) && (((prec == 0u) ? ip : fp) & 1u) != 0u)) { + if (prec == 0u) { + ip++; + } else { + fp++; + } + } + } + if (fp >= pow10[prec]) { + ip++; + fp -= pow10[prec]; + } + nd = to_digits(ip, 10u, false, digits); + if ((prec != 0u) || sp->alt) { + digits[nd] = '.'; + nd++; + } + if (prec != 0u) { + char frac[12]; + uint32_t nf = to_digits(fp, 10u, false, frac); + uint32_t i; + for (i = nf; i < prec; i++) { /* bounded: nine decimals */ + digits[nd] = '0'; + nd++; + } + for (i = 0u; i < nf; i++) { /* bounded by nf */ + digits[nd] = frac[i]; + nd++; + } + } + { + spec_t fs = *sp; + fs.prec = -1; /* the precision is spent on the decimals */ + out_field(o, &fs, sign, digits, nd); + } +} + +static bool is_digit(char c) +{ + return (c >= '0') && (c <= '9'); +} + +/* One argument's value, as its signature types it. */ +typedef struct arg { + uint64_t u; + int64_t s; + double d; + const uint8_t *str; + uint32_t str_len; + uint32_t type; +} arg_t; + +static void arg_read(rd_t *r, uint32_t type, arg_t *a) +{ + uint32_t w = 4u; + a->type = type; + a->u = 0u; + a->s = 0; + a->d = 0.0; + a->str = NULL; + a->str_len = 0u; + switch (type) { + case EMB_LOG_T_INT: + case EMB_LOG_T_UINT: + w = 4u; + break; + case EMB_LOG_T_LONG: + case EMB_LOG_T_ULONG: + w = (uint32_t)sizeof(long); + break; + case EMB_LOG_T_LLONG: + case EMB_LOG_T_ULLONG: + w = 8u; + break; + case EMB_LOG_T_PTR: + w = (uint32_t)sizeof(void *); + break; + case EMB_LOG_T_DOUBLE: { + double d = 0.0; + uint8_t *dp = (uint8_t *)&d; + uint32_t i; + for (i = 0u; (i < (uint32_t)sizeof(double)) && (r->at < r->n); i++) { /* bounded */ + dp[i] = r->p[r->at]; + r->at++; + } + a->d = d; + return; + } + case EMB_LOG_T_STR: + a->str_len = (uint32_t)rd_le(r, 1u); + a->str = &r->p[r->at]; + if ((r->at + a->str_len) > r->n) { + a->str_len = r->n - r->at; + } + r->at += a->str_len; + return; + default: + return; /* the end, or a type the record does not carry */ + } + a->u = rd_le(r, w); + a->s = ((type == EMB_LOG_T_INT) || (type == EMB_LOG_T_LONG) || (type == EMB_LOG_T_LLONG)) + ? sign_extend(a->u, w) + : (int64_t)a->u; +} + +/* The length modifiers that narrow a value: hh and h. */ +static void narrow(arg_t *a, uint32_t h, char conv) +{ + if (h == 0u) { + return; + } + a->u &= (h == 2u) ? 0xFFu : 0xFFFFu; + if ((conv == 'd') || (conv == 'i')) { + a->s = sign_extend(a->u, h == 2u ? 1u : 2u); + } else { + a->s = (int64_t)a->u; + } +} + +static void format(out_t *o, const char *fmt, uint32_t sig, rd_t *r) +{ + uint32_t k = 0u; + uint32_t i = 0u; + while (fmt[i] != '\0') { /* bounded by the format */ + spec_t sp = {0u, -1, false, false, false, false, false}; + uint32_t h = 0u; + arg_t a; + char conv; + if (fmt[i] != '%') { + out_c(o, fmt[i]); + i++; + continue; + } + i++; + if (fmt[i] == '%') { + out_c(o, '%'); + i++; + continue; + } + for (;;) { /* bounded by the format: its flags */ + char f = fmt[i]; + if (f == '-') { + sp.left = true; + } else if (f == '0') { + sp.zero = true; + } else if (f == '+') { + sp.plus = true; + } else if (f == ' ') { + sp.space = true; + } else if (f == '#') { + sp.alt = true; + } else { + break; + } + i++; + } + while (is_digit(fmt[i])) { /* bounded by the format */ + sp.width = (sp.width * 10u) + (uint32_t)(fmt[i] - '0'); + i++; + } + if (fmt[i] == '.') { + i++; + sp.prec = 0; + while (is_digit(fmt[i])) { /* bounded by the format */ + sp.prec = (sp.prec * 10) + (int32_t)(fmt[i] - '0'); + i++; + } + } + while ((fmt[i] == 'h') || (fmt[i] == 'l') || (fmt[i] == 'z') || (fmt[i] == 'j') || + (fmt[i] == 't') || (fmt[i] == 'L')) { /* bounded by the format */ + if (fmt[i] == 'h') { + h++; + } + i++; + } + conv = fmt[i]; + if (conv == '\0') { + break; + } + i++; + if (sp.width > o->room) { + sp.width = o->room; + } + arg_read(r, (k < EMB_LOG_ARGS_MAX) ? sig_at(sig, k) : EMB_LOG_T_END, &a); + k++; + if ((conv == 's') && (a.type == EMB_LOG_T_STR)) { + uint32_t n = a.str_len; + spec_t ss = sp; + if ((sp.prec >= 0) && ((uint32_t)sp.prec < n)) { + n = (uint32_t)sp.prec; + } + ss.prec = -1; + ss.zero = false; + out_field(o, &ss, "", (const char *)a.str, n); + } else if (conv == 'c') { + char ch = (char)a.u; + spec_t cs = sp; + cs.prec = -1; + out_field(o, &cs, "", &ch, 1u); + } else if ((conv == 'f') || (conv == 'F') || (conv == 'e') || (conv == 'E') || + (conv == 'g') || (conv == 'G')) { + out_double(o, &sp, (a.type == EMB_LOG_T_DOUBLE) ? a.d : (double)a.s); + } else { + narrow(&a, h, conv); + out_int(o, &sp, a.s, a.u, conv); + } + } +} + +static void line_send(const char *line, uint32_t n) +{ +#if CONFIG_EMB_CONSOLE_FRAMED + (void)emb_console_frame(EMB_FRAME_CHANNEL_SHELL, line, n); +#else + emb_board_write(line, n); +#endif +} + +/* "[seconds.milliseconds] E module: message" */ +static void line_head(out_t *o, uint32_t ts, char level, const char *module) +{ +#if CONFIG_EMB_LOG_TIMESTAMP + uint64_t ms = ((uint64_t)ts * (uint64_t)CONFIG_EMB_TICK_NS) / 1000000u; + spec_t sp = {3u, -1, false, true, false, false, false}; + spec_t plain = {0u, -1, false, false, false, false, false}; + out_c(o, '['); + out_int(o, &plain, (int64_t)(ms / 1000u), ms / 1000u, 'u'); + out_c(o, '.'); + out_int(o, &sp, (int64_t)(ms % 1000u), ms % 1000u, 'u'); + out_z(o, "] "); +#else + (void)ts; +#endif + out_c(o, level); + out_c(o, ' '); + out_z(o, module); + out_z(o, ": "); +} + +size_t embs_log_line(const uint8_t *rec, size_t n, char *line, size_t cap) +{ + static const char levels[] = "?EWID"; + out_t o; + rd_t r; + uintptr_t id; + uint32_t ts; + if ((rec == NULL) || (line == NULL) || (cap < 2u)) { + return 0u; + } + o.buf = line; + o.len = 0u; + o.room = (cap > 0xFFFFu) ? 0xFFFEu : (uint32_t)(cap - 1u); + r.p = rec; + r.n = (n > 0xFFFFu) ? 0xFFFFu : (uint32_t)n; + r.at = 0u; + id = (uintptr_t)rd_le(&r, ID_MAX); + ts = (uint32_t)rd_le(&r, TS_BYTES); + if (id == EMB_LOG_ID_DROPPED) { + line_head(&o, ts, 'W', "emb_log"); + format(&o, "%u records dropped", EMB_LOG_T_UINT, &r); + } else if (id >= EMB_LOG_ID_FIRST) { + const emb_log_meta_t *m = (const emb_log_meta_t *)id; + line_head(&o, ts, levels[(m->level <= EMB_LOG_LEVEL_DBG) ? m->level : 0u], m->module); + if (m->sig == EMB_LOG_T_HEX) { + uint32_t len = (uint32_t)rd_le(&r, 2u); + uint32_t i; + spec_t sp = {2u, -1, false, true, false, false, false}; + out_z(&o, m->format); + out_c(&o, ':'); + for (i = 0u; (i < len) && (r.at < r.n); i++) { /* bounded by the record */ + out_c(&o, ' '); + out_int(&o, &sp, 0, r.p[r.at], 'x'); + r.at++; + } + } else { + format(&o, m->format, m->sig, &r); + } + } else { + return 0u; /* the stream's own records that only the deferred backend sends */ + } + o.buf[o.len] = '\n'; + o.len++; + return o.len; +} + +/* Formats and sends the committed records, one line each. */ +static void drain(consumer_t *c) +{ + uint32_t n = 0u; + while (ring_take(c->rec, RECORD_MAX, &n) == TAKE_DONE) { /* bounded by the ring */ + size_t len = embs_log_line(c->rec, n, c->line, sizeof(c->line)); + if (len != 0u) { + line_send(c->line, (uint32_t)len); + } + } +} + +#endif /* CONFIG_EMB_LOG_DEFERRED */ + +/* ---- the steps, for tests (embs/log.h) ------------------------------------------- */ + +bool embs_log_reserve(uint32_t len, uint32_t *pos) +{ + uint32_t p = 0u; + uint32_t lost = 0u; + uint32_t ts = 0u; + if ((pos == NULL) || (len > RECORD_MAX) || + !ring_reserve(len, dropped_bytes(), &p, &lost, &ts)) { + return false; + } + if (lost != 0u) { + put_dropped(p, lost, ts); + p += HDR_BYTES + dropped_bytes(); + } + *pos = p; + return true; +} + +void embs_log_put(uint32_t pos, const void *bytes, uint32_t len) +{ + rec_writer_t w; + w.pos = pos + HDR_BYTES; + put_bytes(&w, bytes, len); +} + +void embs_log_commit(uint32_t pos, uint32_t len) +{ + ring_commit(pos, len); +} + +size_t embs_log_take(uint8_t *buf, size_t cap) +{ + uint32_t n = 0u; + uint32_t c = (cap > 0xFFFFu) ? 0xFFFFu : (uint32_t)cap; + return ((buf != NULL) && (ring_take(buf, c, &n) == TAKE_DONE)) ? (size_t)n : 0u; +} + +uint32_t embs_log_id_bytes(void) +{ + return id_bytes(); +} + +/* ---- the log thread and the flush ------------------------------------------------- */ + +static consumer_t thread_consumer; +static consumer_t flush_consumer; +static emb_sem_storage_t log_sem_storage; +static emb_thread_storage_t log_thread_storage; +EMB_THREAD_STACK(log_stack, CONFIG_EMB_LOG_THREAD_STACK); + +static void log_thread(void *arg) +{ + (void)arg; + for (;;) { /* bounded: the thread serves the ring for as long as the system runs */ + (void)emb_sem_take(log_sem, EMB_WAIT_FOREVER); + drain(&thread_consumer); + } +} + +void emb_log_flush(void) +{ + emb_irq_key_t key = emb_irq_lock(); + bool busy = flushing; + flushing = true; + emb_irq_unlock(key); + if (busy) { + return; /* a flush this one interrupted sends everything */ + } + drain(&flush_consumer); + key = emb_irq_lock(); + flushing = false; + emb_irq_unlock(key); +} + +static void log_init(void) +{ + emb_sem_attr_t sa; + emb_thread_attr_t ta; + emb_thread_t th; + emb_sem_attr_binary(&sa, true); /* available: the thread first sends what came before it */ + sa.name = "emb_log"; + (void)emb_check_status(emb_sem_init(&log_sem_storage, &sa, &log_sem), "emb_log semaphore"); + log_ready = true; +#if CONFIG_EMB_LOG_DEFERRED + put_start(); +#endif + emb_thread_attr_default(&ta); + ta.name = "emb_log"; + ta.stack = log_stack; + ta.stack_size = sizeof(log_stack); + ta.priority = LOG_PRIORITY; + (void)emb_check_status(emb_thread_init(&log_thread_storage, &ta, log_thread, NULL, &th), + "emb_log thread"); + (void)emb_check_status(emb_thread_start(th), "emb_log thread"); +} +EMB_INIT_TABLE_ENTRY(log_init); + +#endif /* CONFIG_EMB_LOG */ diff --git a/tests/conformance/CMakeLists.txt b/tests/conformance/CMakeLists.txt index d328fbc4..dd044826 100644 --- a/tests/conformance/CMakeLists.txt +++ b/tests/conformance/CMakeLists.txt @@ -49,6 +49,9 @@ endif() if(CONFIG_EMB_FRAME) emb_add_test(test_frame test_frame.c) # OBS-019 (SPEC-015 §7) endif() +if(CONFIG_EMB_LOG) + emb_add_test(test_log test_log.c) # OBS-001..003, OBS-013 (SPEC-015 §2, A127) +endif() if(CONFIG_EMB_DEVICE) emb_add_test(test_device test_device.c) # devices and driver requests (SPEC-016) if(CONFIG_EMB_DRV_UART) diff --git a/tests/conformance/test_log.c b/tests/conformance/test_log.c new file mode 100644 index 00000000..9bfe553c --- /dev/null +++ b/tests/conformance/test_log.c @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file test_log.c + * @brief Logging: the record, the levels, the ring's order and drops (SPEC-015 §2, A127). + * + * @details + * The cases read the ring themselves (embs/log.h) while the log thread, at the lowest priority, + * cannot run: none of them blocks. With the plain-text backend each record is also formatted as + * the thread would send it. + * + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include + +#include +#include +#include + +EMB_LOG_MODULE_DEFINE(t, EMB_LOG_LEVEL_INF); + +static uint8_t rec[512]; +static char line[256]; + +/* Empties the ring: records from earlier cases or from the start. */ +static void drain(void) +{ + while (embs_log_take(rec, sizeof(rec)) != 0u) { /* bounded by the ring */ + } +} + +static size_t take(void) +{ + return embs_log_take(rec, sizeof(rec)); +} + +#if CONFIG_EMB_LOG_TEXT +/* The line the plain-text backend sends for the oldest record, after its timestamp. */ +static const char *take_line(void) +{ + size_t n = take(); + size_t len; + const char *body; + if (n == 0u) { + return ""; + } + len = embs_log_line(rec, n, line, sizeof(line)); + line[(len < sizeof(line)) ? len : (sizeof(line) - 1u)] = '\0'; + body = strstr(line, "] "); + return (body != NULL) ? (body + 2) : line; +} + +#define EXPECT_LINE(want) EMB_ASSERT_TRUE(strcmp(take_line(), (want)) == 0) +#endif + +EMB_TEST(log_record_layout) +{ + size_t n; + uint32_t idb = embs_log_id_bytes(); + uint32_t ts = CONFIG_EMB_LOG_TIMESTAMP ? 4u : 0u; + EMB_TEST_REQ("OBS-013"); + drain(); + EMB_LOG_INF(t, "a %d b %u c %s", -5, 7u, "xyz"); + n = take(); + /* the identifier, the timestamp, then int -5 and unsigned 7 as four bytes each and the + * string as its length and its bytes */ + EMB_ASSERT_EQ(n, idb + ts + 4u + 4u + 1u + 3u); + EMB_ASSERT_TRUE(memcmp(&rec[idb + ts], "\xFB\xFF\xFF\xFF\x07\x00\x00\x00\x03xyz", 12u) == 0); + EMB_ASSERT_EQ(take(), 0u); +} + +#if CONFIG_EMB_LOG_TEXT +EMB_TEST(log_text_formats) +{ + static const uint8_t bytes[] = {0xDEu, 0xADu, 0xBEu, 0xEFu}; + static const char long_str[] = "0123456789012345678901234567890123456789"; + int local = 0; + char want[64]; + EMB_TEST_REQ("OBS-013"); + drain(); + EMB_LOG_INF(t, "a %d b %u c %s", -5, 7u, "xyz"); + EXPECT_LINE("I t: a -5 b 7 c xyz\n"); + EMB_LOG_WRN(t, "[%5d|%-5d|%05d|%+d]", 42, 42, 42, 42); + EXPECT_LINE("W t: [ 42|42 |00042|+42]\n"); + EMB_LOG_ERR(t, "%x %X %#x %o %c%%", 255u, 255u, 255u, 8u, 'z'); + EXPECT_LINE("E t: ff FF 0xff 10 z%\n"); + EMB_LOG_INF(t, "%lld %llu %ld %lu", -1LL, 18446744073709551615ULL, -70000L, 70000UL); + EXPECT_LINE("I t: -1 18446744073709551615 -70000 70000\n"); + EMB_LOG_INF(t, "%.2f %.0f %.0f %f", 3.14159, 2.5, 3.5, -0.5); /* a half to the even */ + EXPECT_LINE("I t: 3.14 2 4 -0.500000\n"); + EMB_LOG_INF(t, "%hhx %hd", 0x1FF, 70000); + EXPECT_LINE("I t: ff 4464\n"); + EMB_LOG_INF(t, "<%.3s|%4s>", "abcdef", "z"); + EXPECT_LINE("I t: \n"); + EMB_LOG_INF(t, "%s", long_str); /* cut at CONFIG_EMB_LOG_STR_MAX */ + (void)memcpy(want, "I t: ", 5u); + (void)memcpy(&want[5], long_str, CONFIG_EMB_LOG_STR_MAX); + want[5 + CONFIG_EMB_LOG_STR_MAX] = '\n'; + want[6 + CONFIG_EMB_LOG_STR_MAX] = '\0'; + EXPECT_LINE(want); + EMB_LOG_HEXDUMP_INF(t, bytes, sizeof(bytes), "rx"); + EXPECT_LINE("I t: rx: de ad be ef\n"); + EMB_LOG_INF(t, "%p", (void *)&local); + EMB_ASSERT_TRUE(strncmp(take_line(), "I t: 0x", 7u) == 0); + EMB_LOG_INF(t, "no arguments"); + EXPECT_LINE("I t: no arguments\n"); +} +#endif + +EMB_TEST(log_levels_compile_and_run_time) +{ + EMB_TEST_REQ("OBS-002"); + drain(); + EMB_LOG_DBG(t, "compiled out: above the file's level for t"); + EMB_ASSERT_EQ(take(), 0u); + EMB_ASSERT_OK(emb_log_level_set(EMB_LOG_MODULE(t), EMB_LOG_LEVEL_ERR)); + EMB_LOG_WRN(t, "above the run-time level"); + EMB_ASSERT_EQ(take(), 0u); + EMB_LOG_ERR(t, "kept"); + EMB_ASSERT_TRUE(take() != 0u); + EMB_ASSERT_OK(emb_log_level_set(EMB_LOG_MODULE(t), EMB_LOG_LEVEL_DBG)); + EMB_LOG_INF(t, "kept again"); + EMB_ASSERT_TRUE(take() != 0u); + EMB_ASSERT_STATUS(emb_log_level_set(NULL, EMB_LOG_LEVEL_ERR), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_log_level_set(EMB_LOG_MODULE(t), 5u), EMB_EINVAL); + EMB_ASSERT_STATUS(emb_log_stats_get(NULL), EMB_EINVAL); +} + +EMB_TEST(log_overflow_drops_and_counts) +{ + emb_log_stats_t before; + emb_log_stats_t after; + uint32_t i; + uint32_t kept = 0u; + uint32_t dropped; + uint32_t idb = embs_log_id_bytes(); + uint32_t ts = CONFIG_EMB_LOG_TIMESTAMP ? 4u : 0u; + EMB_TEST_REQ("OBS-003"); + drain(); + EMB_ASSERT_OK(emb_log_stats_get(&before)); + for (i = 0u; i < 400u; i++) { /* bounded: more records than the ring holds */ + EMB_LOG_INF(t, "fill %u", i); + } + EMB_ASSERT_OK(emb_log_stats_get(&after)); + dropped = after.dropped - before.dropped; + EMB_ASSERT_TRUE(dropped > 0u); + EMB_ASSERT_EQ(after.records - before.records + dropped, 400u); + EMB_ASSERT_TRUE(after.high_water <= CONFIG_EMB_LOG_RING_SIZE); + /* the records kept are the first ones, in order: nothing is overwritten */ + while (take() != 0u) { /* bounded by the ring */ + uint32_t v = (uint32_t)rec[idb + ts] | ((uint32_t)rec[idb + ts + 1u] << 8); + EMB_ASSERT_EQ(v, kept); + kept++; + } + EMB_ASSERT_EQ(kept + dropped, 400u); + /* the next record that fits comes after a record of the count */ + EMB_LOG_INF(t, "after"); + EMB_ASSERT_EQ(take(), idb + ts + 2u); + EMB_ASSERT_EQ((uint32_t)rec[0], EMB_LOG_ID_DROPPED); + EMB_ASSERT_EQ((uint32_t)rec[idb + ts] | ((uint32_t)rec[idb + ts + 1u] << 8), dropped); + EMB_ASSERT_TRUE(take() != 0u); + EMB_ASSERT_EQ(take(), 0u); +} + +/* An interrupt that logs while a thread's record is reserved and not yet committed. */ +static void isr_logs(void *arg) +{ + (void)arg; + EMB_LOG_INF(t, "isr %u", 9u); +} + +EMB_TEST(log_isr_record_waits_for_the_one_before_it) +{ + static const uint8_t held[6] = {1u, 2u, 3u, 4u, 5u, 6u}; + uint32_t pos = 0u; + size_t n; + EMB_TEST_REQ("OBS-003"); + drain(); + EMB_ASSERT_TRUE(embs_log_reserve(sizeof(held), &pos)); + emb_test_irq_connect(0u, isr_logs, NULL); + emb_test_irq_raise(0u); + emb_test_irq_settle(); + /* the interrupt's record is committed, after one that is not: nothing is published */ + EMB_ASSERT_EQ(take(), 0u); + embs_log_put(pos, held, sizeof(held)); + embs_log_commit(pos, sizeof(held)); + n = take(); + EMB_ASSERT_EQ(n, sizeof(held)); + EMB_ASSERT_TRUE(memcmp(rec, held, sizeof(held)) == 0); +#if CONFIG_EMB_LOG_TEXT + EXPECT_LINE("I t: isr 9\n"); +#else + EMB_ASSERT_TRUE(take() != 0u); +#endif + EMB_ASSERT_EQ(take(), 0u); +} + +EMB_TEST(log_flush_sends_what_is_committed) +{ + emb_log_stats_t before; + emb_log_stats_t after; + EMB_TEST_REQ("OBS-003"); + drain(); + EMB_ASSERT_OK(emb_log_stats_get(&before)); + EMB_LOG_INF(t, "flushed %d", 1); + EMB_LOG_INF(t, "flushed %d", 2); + emb_log_flush(); + EMB_ASSERT_OK(emb_log_stats_get(&after)); + EMB_ASSERT_EQ(after.sent - before.sent, 2u); + EMB_ASSERT_EQ(take(), 0u); +} diff --git a/tools/fault/api-ids.json b/tools/fault/api-ids.json index aff5586c..bd11805f 100644 --- a/tools/fault/api-ids.json +++ b/tools/fault/api-ids.json @@ -1447,6 +1447,36 @@ "name": "emb_frame_write", "header": "frame.h", "state": "active" + }, + { + "id": 251, + "name": "emb_log_write", + "header": "log.h", + "state": "active" + }, + { + "id": 252, + "name": "emb_log_level_set", + "header": "log.h", + "state": "active" + }, + { + "id": 253, + "name": "emb_log_flush", + "header": "log.h", + "state": "active" + }, + { + "id": 254, + "name": "emb_log_stats_get", + "header": "log.h", + "state": "active" + }, + { + "id": 255, + "name": "emb_console_frame", + "header": "console.h", + "state": "active" } ] } diff --git a/tools/fault/api-registry.json b/tools/fault/api-registry.json index 602ec194..ac0f2f51 100644 --- a/tools/fault/api-registry.json +++ b/tools/fault/api-registry.json @@ -1446,6 +1446,36 @@ "name": "emb_frame_write", "header": "frame.h", "state": "active" + }, + { + "id": 251, + "name": "emb_log_write", + "header": "log.h", + "state": "active" + }, + { + "id": 252, + "name": "emb_log_level_set", + "header": "log.h", + "state": "active" + }, + { + "id": 253, + "name": "emb_log_flush", + "header": "log.h", + "state": "active" + }, + { + "id": 254, + "name": "emb_log_stats_get", + "header": "log.h", + "state": "active" + }, + { + "id": 255, + "name": "emb_console_frame", + "header": "console.h", + "state": "active" } ] } diff --git a/tools/logdec/backends_agree.py b/tools/logdec/backends_agree.py new file mode 100644 index 00000000..271514c5 --- /dev/null +++ b/tools/logdec/backends_agree.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +"""Check that examples/logging prints the same lines with both log backends (A127). + + backends_agree.py --plain plain.log --framed framed.bin --elf framed.elf [--burst 200] + +The plain-text build's console against the framed build's, decoded with tools/logdec from its +ELF: after the timestamps, the lines must be the same in the same order. The burst is the +exception: each build keeps as many of its records as its ring holds (a deferred record is +smaller), so each must keep the first ones, in order, and count the rest as dropped. +""" +import argparse +import io +import re +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +import logdec # noqa: E402 + +STAMP = re.compile(r"^\[\d+\.\d{3}\] ") +BURST = re.compile(r"^I app: burst (\d+)$") +DROPPED = re.compile(r"^W emb_log: (\d+) records dropped$") + + +def split(text, burst, name): + """The lines without their timestamps, and the burst's records checked and set aside.""" + rest, kept, dropped = [], [], 0 + for raw in text.splitlines(): + line = STAMP.sub("", raw) + m = BURST.match(line) + if m: + kept.append(int(m.group(1))) + continue + m = DROPPED.match(line) + if m: + dropped += int(m.group(1)) + continue + rest.append(line) + problems = [] + if kept != list(range(len(kept))): + problems.append(f"{name}: the burst's records are not its first ones in order: {kept[:8]}...") + if len(kept) + dropped != burst: + problems.append(f"{name}: {len(kept)} burst records kept and {dropped} dropped, not {burst}") + if not kept or not dropped: + problems.append(f"{name}: the burst should both fill the ring and overflow it") + return rest, problems + + +def main(argv=None): + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--plain", required=True, help="the plain-text build's console") + ap.add_argument("--framed", required=True, help="the framed build's console, as captured") + ap.add_argument("--elf", required=True, help="the framed build's ELF") + ap.add_argument("--burst", type=int, default=200) + args = ap.parse_args(argv) + plain = Path(args.plain).read_bytes().decode(errors="replace") + out = io.StringIO() + stats = logdec.decode_stream(logdec.LogDb(args.elf), Path(args.framed).read_bytes(), out) + a, pa = split(plain, args.burst, "plain") + b, pb = split(out.getvalue(), args.burst, "framed") + problems = pa + pb + if not stats["started"]: + problems.append("framed: no start record") + if stats["errors"] or stats["overruns"]: + problems.append(f"framed: {stats['errors']} damaged frames, {stats['overruns']} too long") + if a != b: + problems.append("the lines differ:") + for i in range(max(len(a), len(b))): + x = a[i] if i < len(a) else "(none)" + y = b[i] if i < len(b) else "(none)" + if x != y: + problems.append(f" line {i + 1}: plain {x!r}, framed {y!r}") + if "logging: done" not in a: + problems.append("the run did not end") + for p in problems: + print(p, file=sys.stderr) + if not problems: + print(f"backends agree: {len(a)} lines, and the burst checked in both") + return 1 if problems else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/logdec/logdec.py b/tools/logdec/logdec.py new file mode 100644 index 00000000..6e0e1fd3 --- /dev/null +++ b/tools/logdec/logdec.py @@ -0,0 +1,368 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +"""Decode deferred log records with the image's ELF (SPEC-015 §2.5, OBS-020, A127). + + logdec.py --elf build/app/app.elf console.bin # a framed console capture + some-capture | logdec.py --elf app.elf - # from standard input + logdec.py --elf app.elf --records payload.bin # bare records, without frames + +A call site's metadata is in the ELF's emb_log section, at the record's identifier less 8; the +section never reaches the image (A127). Records arrive on channel 0 of SPEC-015 §7's frames, +whole records to a frame. The console's text on channel 3, and bytes that are not a frame, are +printed as they are. The stream's start record names the image's build id: a stream from +another image is refused (exit 3). +""" +import argparse +import struct +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE.parent / "transport")) +import frame as framing # noqa: E402 + +ID_SYNC, ID_DROPPED, ID_START, ID_FIRST = 0, 1, 2, 8 +T_END, T_INT, T_UINT, T_LONG, T_ULONG, T_LLONG, T_ULLONG, T_DOUBLE, T_STR, T_PTR, T_HEX = range(11) +LEVELS = "?EWID" +CH_LOG, CH_TRACE, CH_CRASH, CH_SHELL = 0, 1, 2, 3 + + +class LogError(Exception): + pass + + +class Elf: + """The sections and symbols of an ELF file: enough to read the log's metadata.""" + + def __init__(self, path): + self.data = data = Path(path).read_bytes() + if data[:4] != b"\x7fELF": + raise LogError(f"{path}: not an ELF file (a native image on macOS is Mach-O: " + "decode a Linux or embedded build)") + self.cls = data[4] + self.end = "<" if data[5] == 1 else ">" + e = self.end + if self.cls == 1: + shoff, = struct.unpack_from(e + "I", data, 0x20) + shentsize, shnum, shstrndx = struct.unpack_from(e + "HHH", data, 0x2E) + fmt, self.ptr = e + "IIIIIIIIII", 4 + else: + shoff, = struct.unpack_from(e + "Q", data, 0x28) + shentsize, shnum, shstrndx = struct.unpack_from(e + "HHH", data, 0x3A) + fmt, self.ptr = e + "IIQQQQIIQQ", 8 + self.machine, = struct.unpack_from(e + "H", data, 18) + raw = [struct.unpack_from(fmt, data, shoff + i * shentsize) for i in range(shnum)] + names = raw[shstrndx] + self.sections = [] + for s in raw: + n = data[names[4] + s[0]:data.index(b"\0", names[4] + s[0])].decode() + self.sections.append({"name": n, "type": s[1], "addr": s[3], "offset": s[4], "size": s[5], + "link": s[6]}) + self.symbols = {} + for s in self.sections: + if s["type"] != 2: # SHT_SYMTAB + continue + strtab = self.sections[s["link"]] + size = 16 if self.cls == 1 else 24 + for off in range(s["offset"], s["offset"] + s["size"], size): + if self.cls == 1: + st_name, value, sz, _, _, shndx = struct.unpack_from(e + "IIIBBH", data, off) + else: + st_name, _, _, shndx, value, sz = struct.unpack_from(e + "IBBHQQ", data, off) + at = strtab["offset"] + st_name + name = data[at:data.index(b"\0", at)].decode(errors="replace") + if name and shndx not in (0, 0xFFF1): + self.symbols.setdefault(name, (value, sz, shndx)) + + def section(self, name): + return next((s for s in self.sections if s["name"] == name), None) + + def read(self, addr, size, within=None): + """Bytes at an address: in the given section, else in any section that holds them.""" + for s in ([within] if within else []) + self.sections: + if s and s["type"] != 8 and s["addr"] <= addr and addr + size <= s["addr"] + s["size"] \ + and (s["addr"] != 0 or s is within): + at = s["offset"] + addr - s["addr"] + return self.data[at:at + size] + raise LogError(f"no section holds 0x{addr:x}") + + def cstring(self, addr, within=None): + for s in ([within] if within else []) + self.sections: + if s and s["type"] != 8 and s["addr"] <= addr < s["addr"] + s["size"] \ + and (s["addr"] != 0 or s is within): + at = s["offset"] + addr - s["addr"] + return self.data[at:self.data.index(b"\0", at)].decode(errors="replace") + return "?" + + def symbol_bytes(self, name): + if name not in self.symbols: + return None + value, size, shndx = self.symbols[name] + sec = self.sections[shndx] + at = sec["offset"] + value - sec["addr"] + return self.data[at:at + size] + + +class Meta: + def __init__(self, fmt, file, module, line, sig, level): + self.format, self.file, self.module, self.line, self.sig, self.level = fmt, file, module, line, sig, level + + +class LogDb: + """The image's call sites and the record layout, from its ELF.""" + + def __init__(self, elf_path): + self.elf = elf = Elf(elf_path) + self.sec = sec = elf.section("emb_log") + if sec is None: + raise LogError(f"{elf_path}: no emb_log section: built with the plain-text backend, " + "or nothing logs") + start = elf.symbols.get("__start_emb_log", (sec["addr"],))[0] + stop = elf.symbols.get("__stop_emb_log", (sec["addr"] + sec["size"],))[0] + self.base = start + self.id_bytes = 2 if (stop - start) <= 0xFFFF - ID_FIRST else 4 + hdr = elf.symbol_bytes("emb_log_header") + if hdr is None or hdr[:4] != b"EMBL": + raise LogError(f"{elf_path}: no emb_log_header") + self.version, flags, self.long_size, self.ptr_size, self.double_size, self.str_max = hdr[4:10] + self.timestamps = bool(flags & 1) + self.build_id = elf.symbol_bytes("emb_build_id") + self.end = elf.end + self._metas = {} + + def meta(self, rid): + if rid in self._metas: + return self._metas[rid] + p, e = self.ptr_size, self.end + raw = self.elf.read(self.base + rid - ID_FIRST, 3 * p + 9, self.sec) + pf = e + ("I" if p == 4 else "Q") + fmt, file, module = (struct.unpack_from(pf, raw, i * p)[0] for i in range(3)) + line, sig = struct.unpack_from(e + "II", raw, 3 * p) + level = raw[3 * p + 8] + m = Meta(self.elf.cstring(fmt, self.sec), self.elf.cstring(file, self.sec) if file else "", + self.elf.cstring(module, self.sec), line, sig, level) + self._metas[rid] = m + return m + + +# ---------------------------------------------------------------------------- formatting + +def _signed(v, bits): + return v - (1 << bits) if v >> (bits - 1) else v + + +def format_c(fmt, args): + """printf's subset the target uses (SPEC-015 §2.1), with the arguments a record carries: + (type, value) pairs, ints already sized.""" + out, i, k = [], 0, 0 + while i < len(fmt): + c = fmt[i] + if c != "%": + out.append(c) + i += 1 + continue + j = i + 1 + if j < len(fmt) and fmt[j] == "%": + out.append("%") + i = j + 1 + continue + flags = "" + while j < len(fmt) and fmt[j] in "-0+ #": + flags += fmt[j] + j += 1 + width = "" + while j < len(fmt) and fmt[j].isdigit(): + width += fmt[j] + j += 1 + prec = None + if j < len(fmt) and fmt[j] == ".": + j += 1 + p = "" + while j < len(fmt) and fmt[j].isdigit(): + p += fmt[j] + j += 1 + prec = int(p or "0") + h = 0 + while j < len(fmt) and fmt[j] in "hlzjtL": + h += fmt[j] == "h" + j += 1 + if j >= len(fmt): + break + conv = fmt[j] + i = j + 1 + t, v, bits = args[k] if k < len(args) else (T_END, 0, 32) + k += 1 + spec = "%" + flags + width + ("" if prec is None else f".{prec}") + if conv == "s": + s = v if isinstance(v, str) else str(v) + out.append(("%" + flags.replace("0", "") + width + ("" if prec is None else f".{prec}") + "s") % s) + elif conv == "c": + out.append(("%" + flags.replace("0", "") + width + "c") % chr(v & 0xFF)) + elif conv in "fFeEgG": + # the target prints %e and %g as %f (A127): the same here, for the same lines + d = float(v) + p = 6 if prec is None else min(prec, 9) + out.append(("%" + flags + width + f".{p}f") % d) + elif conv == "p": + s = format(v, "x") + out.append(("%" + flags.replace("0", "").replace("#", "") + width + "s") % ("0x" + s)) + else: + if h: + bits = 8 if h >= 2 else 16 + v &= (1 << bits) - 1 + if conv in "di": + v = _signed(v, bits) + if conv in "di": + if t in (T_UINT, T_ULONG, T_ULLONG, T_PTR) and not h: + v = _signed(v & ((1 << bits) - 1), bits) + out.append((spec + "d") % v) + else: + v &= (1 << bits) - 1 + if conv == "u": + out.append((spec + "d") % v) + elif conv in "xXo": + out.append((spec + conv) % v) + else: + out.append((spec + "d") % v) + return "".join(out) + + +class Stream: + """Records to text lines, with the image's metadata.""" + + def __init__(self, db, where=False, tick_ns=None): + self.db = db + self.where = where + self.tick_ns = tick_ns + self.started = False + + def _ts(self, ticks): + if ticks is None or not self.tick_ns: + return "" + ms = ticks * self.tick_ns // 1_000_000 + return f"[{ms // 1000}.{ms % 1000:03d}] " + + def records(self, payload): + """The lines of one frame's records.""" + db, at, lines = self.db, 0, [] + le = "<" if db.end == "<" else ">" + + def take(n): + nonlocal at + if at + n > len(payload): + raise LogError("a record cut short") + b = payload[at:at + n] + at += n + return b + + def uint(n): + return int.from_bytes(take(n), "little" if le == "<" else "big") + + while at < len(payload): + rid = uint(db.id_bytes) + ts = uint(4) if db.timestamps else None + if rid == ID_START: + build_id = take(20) + self.tick_ns = uint(4) + if db.build_id is not None and build_id != db.build_id: + raise LogError(f"the stream is from build {build_id.hex()}, the ELF is " + f"{db.build_id.hex()}: decode it with its own ELF") + self.started = True + continue + if rid == ID_DROPPED: + lines.append(f"{self._ts(ts)}W emb_log: {uint(2)} records dropped") + continue + if rid == ID_SYNC: + continue + if rid < ID_FIRST: + raise LogError(f"record {rid}: an identifier the stream reserves") + m = db.meta(rid) + head = f"{self._ts(ts)}{LEVELS[m.level] if m.level < len(LEVELS) else '?'} {m.module}: " + if m.sig == T_HEX: + n = uint(2) + text = m.format + ":" + "".join(f" {b:02x}" for b in take(n)) + else: + args = [] + for k in range(8): + t = (m.sig >> (4 * k)) & 0xF + if t == T_END or t > T_HEX: + break + if t in (T_INT, T_UINT): + args.append((t, uint(4), 32)) + elif t in (T_LONG, T_ULONG): + args.append((t, uint(db.long_size), 8 * db.long_size)) + elif t in (T_LLONG, T_ULLONG): + args.append((t, uint(8), 64)) + elif t == T_PTR: + args.append((t, uint(db.ptr_size), 8 * db.ptr_size)) + elif t == T_DOUBLE: + raw = take(db.double_size) + f = "" + f[1], raw)[0], 64)) + elif t == T_STR: + n = uint(1) + args.append((t, take(n).decode(errors="replace"), 0)) + for idx, (t, v, bits) in enumerate(args): + if t in (T_INT, T_LONG, T_LLONG): + args[idx] = (t, _signed(v, bits), bits) + text = format_c(m.format, args) + where = f" ({m.file}:{m.line})" if self.where else "" + lines.append(head + text + where) + return lines + + +def decode_stream(db, data, out, where=False): + """A framed console capture: log records decoded, the console's text and stray bytes as + they are. Returns the stream's counters.""" + stream = Stream(db, where) + dec = framing.Decoder(max_payload=4096) + for kind, a, b in dec.feed_all(data) + dec.finish(): + if kind == "raw": + text = a.decode(errors="replace") + if text.strip(): + out.write(text if text.endswith("\n") else text + "\n") + continue + ch, payload = a, b + if ch == CH_LOG: + for line in stream.records(payload): + out.write(line + "\n") + elif ch == CH_SHELL: + out.write(payload.decode(errors="replace")) + else: + out.write(f"(channel {ch}: {len(payload)} bytes)\n") + return {"frames": dec.frames, "errors": dec.errors, "overruns": dec.overruns, + "started": stream.started} + + +def main(argv=None): + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--elf", required=True, help="the image the stream comes from") + ap.add_argument("input", nargs="?", default="-", help="a capture of the console, or - for stdin") + ap.add_argument("--records", action="store_true", help="the input is bare records, not frames") + ap.add_argument("--where", action="store_true", help="append each call site's file and line") + ap.add_argument("--tick-ns", type=int, help="the tick's length, when the stream has no start record") + args = ap.parse_args(argv) + try: + db = LogDb(args.elf) + data = sys.stdin.buffer.read() if args.input == "-" else Path(args.input).read_bytes() + if args.records: + for line in Stream(db, args.where, args.tick_ns).records(data): + print(line) + return 0 + stats = decode_stream(db, data, sys.stdout, args.where) + except LogError as e: + print(f"logdec: {e}", file=sys.stderr) + return 3 if "build" in str(e) else 2 + if stats["errors"] or stats["overruns"]: + print(f"logdec: {stats['frames']} frames, {stats['errors']} damaged, {stats['overruns']} too long", + file=sys.stderr) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/logdec/test_logdec.py b/tools/logdec/test_logdec.py new file mode 100644 index 00000000..b0933e69 --- /dev/null +++ b/tools/logdec/test_logdec.py @@ -0,0 +1,141 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +"""tools/logdec: the record layout, printf's subset, the stream's own records and the frames +around them (A127). The images' own streams are checked end to end by backends_agree.py.""" +import io +import struct +import sys +import unittest +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +sys.path.insert(0, str(HERE.parent / "transport")) +import frame # noqa: E402 +import logdec # noqa: E402 +from logdec import T_INT, T_UINT, T_LONG, T_LLONG, T_ULLONG, T_DOUBLE, T_STR, T_PTR, T_HEX # noqa: E402 + + +def sig(*types): + return sum(t << (4 * i) for i, t in enumerate(types)) + + +class FakeDb: + """A 32-bit little-endian image's layout, with call sites by identifier.""" + + def __init__(self, metas, build_id=b"\x11" * 20): + self.id_bytes, self.timestamps = 2, True + self.long_size, self.ptr_size, self.double_size, self.str_max = 4, 4, 8, 32 + self.end, self.build_id, self.metas = "<", build_id, metas + + def meta(self, rid): + return self.metas[rid] + + +def record(rid, ts, *fields): + out = struct.pack("", (T_STR, "abcdef", 0), (T_STR, "z", 0), (T_STR, "y", 0)), + "") + self.assertEqual(self.f("%c%%", (T_INT, ord("z"), 32)), "z%") + self.assertEqual(self.f("%p", (T_PTR, 0x20001000, 32)), "0x20001000") + + def test_doubles_as_the_target_prints_them(self): + self.assertEqual(self.f("%.2f %.0f %.0f %f", (T_DOUBLE, 3.14159, 64), (T_DOUBLE, 2.5, 64), + (T_DOUBLE, 3.5, 64), (T_DOUBLE, -0.5, 64)), "3.14 2 4 -0.500000") + self.assertEqual(self.f("%e", (T_DOUBLE, 1.5, 64)), "1.500000") # %e prints as %f (A127) + + def test_missing_arguments_do_not_raise(self): + self.assertEqual(self.f("%d %s", (T_INT, 1, 32)), "1 0") + + +class Records(unittest.TestCase): + def setUp(self): + self.db = FakeDb({ + 8: logdec.Meta("a %d b %u c %s", "main.c", "app", 10, sig(T_INT, T_UINT, T_STR), 3), + 40: logdec.Meta("rx", "main.c", "app", 11, T_HEX, 4), + 72: logdec.Meta("%f %p", "main.c", "net", 12, sig(T_DOUBLE, T_PTR), 1), + }) + + def test_a_frame_of_records(self): + payload = (record(2, 0, b"\x11" * 20, u32(1_000_000)) # start: 1 ms ticks + + record(8, 1234, u32(-5), u32(7), b"\x03xyz") + + record(40, 1235, struct.pack(" self.max * 2: + if _texty(self.buf): + out.append(("raw", bytes(self.buf), None)) + else: + self.overruns += 1 + self.buf = bytearray() + continue + self.dropping = False + if self.buf: + out.extend(self._end()) + self.buf = bytearray() + return out + + def finish(self): + """The bytes after the last zero, when they read as text.""" + out = [("raw", bytes(self.buf), None)] if self.buf and _texty(self.buf) else [] + self.buf = bytearray() + return out + + def _end(self): + try: + ch, payload = decode(bytes(self.buf)) + except FrameError: + if _texty(self.buf): + return [("raw", bytes(self.buf), None)] + self.errors += 1 + return [] + if len(payload) + 3 > self.max: + self.overruns += 1 + return [] + self.frames += 1 + return [("frame", ch, payload)] + + +def _texty(buf): + """Whether bytes read as text: printable ASCII, tabs and line ends, at least nine in ten.""" + if not buf: + return False + good = sum(1 for b in buf if 32 <= b < 127 or b in (9, 10, 13)) + return good * 10 >= len(buf) * 9 + def main(argv=None): ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) From 27f21dc50a2ed4f0e8437d3ef92c69ffa5c03bd5 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 04:45:43 +0100 Subject: [PATCH 09/25] ci: logging prints the same lines with both backends, on three targets The application job builds examples/logging plain and framed for the native board, the MPS2 AN386 and RV32 virt, runs each, decodes the framed console with tools/logdec and compares the lines with backends_agree.py. The log decoder's own tests run with the other host tools'. A native Linux image is position-independent, so logdec reads a pointer the file holds as zero from its RELATIVE relocation. Signed-off-by: teo1747 --- .github/workflows/ci.yml | 28 ++++++++++++++++++++++++++++ tools/logdec/logdec.py | 31 ++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2f56356..20e68434 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -386,6 +386,8 @@ jobs: run: python3 -I -m unittest discover -s tools/descriptor -p 'test_*.py' -v - name: Framed byte streams, the host's side (SPEC-015 §7) run: python3 -I -m unittest discover -s tools/transport -p 'test_*.py' -v + - name: Log decoder's tests (A127) + run: python3 -I -m unittest discover -s tools/logdec -p 'test_*.py' -v - name: EmbSIM runner, its project mode (SIM-002) run: python3 -I -m unittest discover -s tools/embsim -p 'test_*.py' -v - name: UF2 writer (A79) @@ -839,6 +841,32 @@ jobs: --qemu-args "-M mps2-an386 -semihosting-config enable=on,target=native -kernel" build/blinky-mps2_an386/blinky.elf python3 -I tools/qemu/run_qemu.py --qemu qemu-system-riscv32 --until "blinky: off" --timeout 60 \ --qemu-args "-M virt -bios none -kernel" build/blinky-riscv32_virt/blinky.elf + - name: Logging with both backends print the same lines (A127) + run: | + cp -r examples/logging "$RUNNER_TEMP/logging" + for b in native mps2_an386 riscv32_virt; do + cmake -S "$RUNNER_TEMP/logging" -B "build/logging-$b" -G Ninja -DEmbLinkRTOS_DIR="$PWD/cmake" -DEMB_BOARD=$b + cmake --build "build/logging-$b" + cmake -S "$RUNNER_TEMP/logging" -B "build/logging-$b-framed" -G Ninja -DEmbLinkRTOS_DIR="$PWD/cmake" \ + -DEMB_BOARD=$b -DEMB_SET=EMB_CONSOLE_FRAMED=y + cmake --build "build/logging-$b-framed" + done + build/logging-native/logging > logging-native.log + build/logging-native-framed/logging > logging-native-framed.bin + for v in "" -framed; do + timeout 60 qemu-system-arm -M mps2-an386 -semihosting-config enable=on,target=native -nographic \ + -monitor none -serial stdio -kernel "build/logging-mps2_an386$v/logging.elf" > "logging-mps2_an386$v.bin" + timeout 60 qemu-system-riscv32 -M virt -bios none -nographic -monitor none -serial stdio \ + -kernel "build/logging-riscv32_virt$v/logging.elf" > "logging-riscv32_virt$v.bin" + done + mv logging-mps2_an386.bin logging-mps2_an386.log + mv logging-riscv32_virt.bin logging-riscv32_virt.log + python3 -I tools/logdec/backends_agree.py --plain logging-native.log --framed logging-native-framed.bin \ + --elf build/logging-native-framed/logging + for b in mps2_an386 riscv32_virt; do + python3 -I tools/logdec/backends_agree.py --plain "logging-$b.log" --framed "logging-$b-framed.bin" \ + --elf "build/logging-$b-framed/logging.elf" + done - name: Build the reference controller for both NUCLEO-F446 boards (it runs on the board, not here) run: | cp -r examples/controller "$RUNNER_TEMP/controller" diff --git a/tools/logdec/logdec.py b/tools/logdec/logdec.py index 6e0e1fd3..69f12118 100644 --- a/tools/logdec/logdec.py +++ b/tools/logdec/logdec.py @@ -79,6 +79,32 @@ def __init__(self, path): if name and shndx not in (0, 0xFFF1): self.symbols.setdefault(name, (value, sz, shndx)) + # R_*_RELATIVE by machine: x86-64, AArch64, RISC-V (RELA: the value is the addend) + RELATIVE = {62: 8, 183: 1027, 243: 3} + + def relative_addends(self): + """A position-independent image's pointers, which the file may hold as zeros with the value + in a RELATIVE relocation's addend (Linux native builds are PIE): {address: value}.""" + kind = self.RELATIVE.get(self.machine) + out = {} + if kind is None: + return out + e = self.end + for s in self.sections: + if s["type"] != 4: # SHT_RELA + continue + size = 12 if self.cls == 1 else 24 + for off in range(s["offset"], s["offset"] + s["size"], size): + if self.cls == 1: + r_offset, r_info, r_addend = struct.unpack_from(e + "IIi", self.data, off) + rtype = r_info & 0xFF + else: + r_offset, r_info, r_addend = struct.unpack_from(e + "QQq", self.data, off) + rtype = r_info & 0xFFFFFFFF + if rtype == kind: + out[r_offset] = r_addend + return out + def section(self, name): return next((s for s in self.sections if s["name"] == name), None) @@ -133,6 +159,7 @@ def __init__(self, elf_path): self.timestamps = bool(flags & 1) self.build_id = elf.symbol_bytes("emb_build_id") self.end = elf.end + self._relative = elf.relative_addends() self._metas = {} def meta(self, rid): @@ -141,7 +168,9 @@ def meta(self, rid): p, e = self.ptr_size, self.end raw = self.elf.read(self.base + rid - ID_FIRST, 3 * p + 9, self.sec) pf = e + ("I" if p == 4 else "Q") - fmt, file, module = (struct.unpack_from(pf, raw, i * p)[0] for i in range(3)) + at = self.base + rid - ID_FIRST + fmt, file, module = (struct.unpack_from(pf, raw, i * p)[0] or self._relative.get(at + i * p, 0) + for i in range(3)) line, sig = struct.unpack_from(e + "II", raw, 3 * p) level = raw[3 * p + 8] m = Meta(self.elf.cstring(fmt, self.sec), self.elf.cstring(file, self.sec) if file else "", From 9af19156051f00798879d906bb6f1b07d71acef1 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 04:53:24 +0100 Subject: [PATCH 10/25] subsys: logging fits the tiny profile and builds on every port On the table scheduler each priority holds one thread, so a log thread took the test runner's: CONFIG_EMB_LOG_THREAD is off there, and the application sends the records with emb_log_flush(). The plain-text backend's call sites live in program memory on a Harvard core and are read through EMB_FLASH_READ_* (EMB_FLASH_READ_U32 is new); CONFIG_EMB_LOG_FLOAT, off on tiny, leaves out on-target %f. Logging is not offered on AVR in M4.3: the formatter and its stack do not fit the Uno's 2 KB beside a test. size_t is 16 bits on AVR: the conversions are explicit. test_log passed a uint32_t to %u, which is unsigned long on Arm and RISC-V newlib; Doxygen learns EMB_PRINTF_FORMAT. Signed-off-by: teo1747 --- docs/Doxyfile | 5 +- docs/specs/AMENDMENTS-M4.md | 2 +- include/emb/compiler.h | 1 + include/emb/compiler/clang.h | 1 + include/emb/compiler/gcc.h | 1 + include/emb/frame.h | 2 +- include/emb/log.h | 32 ++++++----- subsys/Kconfig | 29 +++++++++- subsys/logging/log.c | 107 +++++++++++++++++++++++++---------- tests/conformance/test_log.c | 10 +++- 10 files changed, 137 insertions(+), 53 deletions(-) diff --git a/docs/Doxyfile b/docs/Doxyfile index 1e29e135..e58d4be9 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -26,11 +26,12 @@ ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES PREDEFINED = "EMB_DECLARE_HANDLE(name)=struct name { uintptr_t raw; }" \ - "EMB_ALIGNED(n)=" \ + "EMB_ALIGNED(n)=" "EMB_PRINTF_FORMAT(f,a)=" \ EMB_NORETURN= EMB_INLINE=inline EMB_ALWAYS_INLINE=inline \ CONFIG_EMB_SEM=1 CONFIG_EMB_MUTEX=1 CONFIG_EMB_NOTIFY=1 \ CONFIG_EMB_IRQ_DYNAMIC=1 CONFIG_EMB_TLS_SLOTS=1 CONFIG_EMB_THREAD_LIST=1 \ - CONFIG_EMB_STACK_STATS=1 CONFIG_EMB_STATUS_NAMES=1 CONFIG_EMB_TRACE=1 + CONFIG_EMB_STACK_STATS=1 CONFIG_EMB_STATUS_NAMES=1 CONFIG_EMB_TRACE=1 \ + CONFIG_EMB_LOG=1 ALIASES = "ctx=Context:" "blocks=Blocking:" "time=Timing:" "owns=Ownership:" \ "config=Configuration:" "req=Requirements:" "since=Since:" "stable=Stability:" \ "isr-note=ISR note:" diff --git a/docs/specs/AMENDMENTS-M4.md b/docs/specs/AMENDMENTS-M4.md index feda251b..363f4878 100644 --- a/docs/specs/AMENDMENTS-M4.md +++ b/docs/specs/AMENDMENTS-M4.md @@ -23,6 +23,6 @@ Changes M4 makes to accepted specifications and requirements, where an accepted | A122 | SPEC-017 §9, SPEC-014 §3, §4, SPEC-011, SPEC-003 §4 | **The flash class, partitions, and the clock across a stall.** SPEC-017 §9 had flash requests queued and their ends delivered by interrupt on the STM32. Every operation now runs to its end in the caller, under the device's lock: the STM32F446's single bank stalls the CPU's fetches meanwhile, and the RP2350 must hold interrupts off while XIP is off, so a queue would let nothing run. The calls are `emb_drv_flash_read()`, `_program()` and `_erase()` with a timeout for the lock, polled versions without it, `emb_drv_flash_geometry_get()` and `emb_drv_flash_sector()`. A program is read back, and bytes that were not erased give `EMB_EVERIFY`. An erase runs a sector at a time. A flash device's geometry is generated from the SoC's `flash:` and, where the chip is smaller than its window, the board device's `size:`. The RP2350's `flash:` is 4 KiB sectors and 256-byte pages. The board's `flash_partitions` become `` areas, `EMB_FLASH_AREA_`. The NUCLEO-F446RE's app partition shrinks to sectors 0 to 6, with sector 7 as `storage`; the Pico 2 W's gives its last 64 KiB to `storage`. The periodic tick misses its interrupts during an operation, so the Cortex-M port times it by DWT CYCCNT (`emb_cm_stall_begin()`, `emb_cm_stall_end()`, `emb_cm_cycle_count()`). A new kernel hook, `embk_time_ticks_missed()`, adds the ticks that passed at the next tick interrupt; it does nothing in tickless mode, which M4.4 brings to Cortex-M. The generated linker script gains a `.ramfunc` section in RAM, copied with `.data`, where the RP2350's flash routine runs, and the Arm GCC link no longer warns about the writable, executable segment. *Proposed 2026-11-10 with M4.2's flash class, for the project owner's review; the clock's catch-up and the storage partitions chosen by the owner on 2026-11-10.* | `include/emb/drv_flash.h`, `include/emb/flash_area.h`, `kernel/device/flash.c`, `kernel/time/time.c`, `arch/cortex_m/cm_port.c`, `drivers/st/stm32_flash.c`, `drivers/rpi/rp2350_flash.c`, `hw/gen/emb_hwgen/` (M4.2) | | A123 | SPEC-017 §10, SPEC-003 §10, KRN-TIM-031, SPEC-018 | **The RTC class and the wall clock.** SPEC-017 §10's requests become `emb_drv_rtc_get()` and `_set()`, with the time in nanoseconds since the Unix epoch (UTC), the wall clock's unit. There is one alarm per device, its callback in the alarm interrupt, `EMB_EBUSY` while armed, and `_alarm_cancel()`; a `set` disarms it. The backup registers are `_backup_read()` and `_write()`. The wake-up timer, the power policy's wake source, moves to M4.4 with SPEC-018, its only user, where its latency is measured. An alarm never fires before its time. It works at the RTC's resolution, and with a calendar it reaches 28 days ahead. The STM32F4's driver does not wait for the LSE at initialization; the first `set` waits instead. The RP2350 has no calendar: its RTC is the AON timer in POWMAN, milliseconds since the epoch on a 1 kHz tick from the crystal. That tick stops in DORMANT, where M4.4 switches it to LPOSC. SPEC-003 §10's wall clock is implemented: ``, behind `CONFIG_EMB_WALLCLOCK`, which needs 64-bit ticks. It is `EMB_ENOTSET` until it is set, or until a set RTC seeds it when its device starts (`emb_drv_rtc_started()`). `emb_wallclock_adjust()` steps; there is no slewing in M4. *Proposed 2026-11-10 with M4.2's RTC class, for the project owner's review; the wake-up timer's move and the RP2350's crystal tick chosen by the owner on 2026-11-10.* | `include/emb/drv_rtc.h`, `include/emb/wallclock.h`, `kernel/device/rtc.c`, `kernel/time/wallclock.c`, `drivers/st/stm32_rtc.c`, `drivers/rpi/rp2350_aon.c` (M4.2) | | A124 | SPEC-017 §11, SEC-012 | **The entropy class.** A read is `emb_drv_entropy_read(dev, buf, len, &got, timeout)`, assembled from a driver's blocks under the device's lock and one timeout. A timeout keeps the bytes read. A block that fails the source's health test ends the read with `EMB_EHEALTH`, and none of its bytes is delivered. The source's output is conditioned in the class, as NIST SP 800-90B asks of a raw noise source: every 32 bytes read are the SHA-256 of 64 raw, health-tested bytes. `emb_drv_entropy_read_raw()` reads the raw blocks, for measuring the source: on the RP2350 they fail a byte chi-square and a runs test, though they pass the TRNG's own health tests, and their most-common-value min-entropy must reach the 4 bits a byte that conditioning 2:1 needs. Every board defines `emb_board_entropy`: the generated `soc_devices.c` from the description, a hand-written board by hand. It is NULL where the board has no source, and `emb_drv_entropy_board()` then returns `EMB_ENOTSUP`. The native board's source is the host's `getentropy()`. The RP2350's TRNG keeps every health test on, and samples every 200 clocks, from a measurement on the board (`sample_count:` on the device). SPEC-017 §11's evidence changes: the 1 MiB is tested on the board, and a 64 KiB sample with its SHA-256 is archived and checked on the host, in place of archiving the whole MiB. *Proposed 2026-11-12 with M4.2's entropy class, for the project owner's review; the evidence's form, the native board's host source and the conditioning chosen by the owner on 2026-11-12.* | `include/emb/drv_entropy.h`, `kernel/device/entropy.c`, `kernel/device/sha256.c`, `drivers/rpi/rp2350_trng.c`, `boards/native/native/board.c`, `tools/entropy/check.py` (M4.2) | -| A127 | SPEC-015 §2, §7, §9, §12 decision 2, OBS-002, OBS-003, OBS-013, OBS-021, 08 Q13 | **Logging, its ring and the console.** **Call sites (§2.1):** a module is defined once with `EMB_LOG_MODULE_DEFINE(name, level)` and declared in its other files with `EMB_LOG_MODULE_DECLARE(name, level)`; §2.1 had only the declaration, which cannot both define the module and serve a module whose calls span files. `EMB_LOG_ERR`, `_WRN`, `_INF` and `_DBG(name, format, ...)` take at most eight arguments, and the compiler checks each format against its arguments as it checks printf's. A call above its file's level for the module, or above `CONFIG_EMB_LOG_LEVEL_MAX`, compiles to nothing; one above the module's run-time level (`emb_log_level_set()`) returns after one comparison. **One record, two backends (§2.3, §2.4, Q13):** every call packs its arguments into the record of §2.3 in the caller, typed by a signature the compiler computes from their C types with C11's `_Generic` (int, long, long long and their unsigned forms, double, string, pointer). The deferred backend (ADR-009) sends the record and the host formats it; the plain-text backend formats the same record on the target, in the log thread. Neither formats in the caller, so a call costs the same in an interrupt with either backend. **Identifiers (§2.2):** a call site's metadata (format, file, line, level, module, signature) is placed in the section `emb_log`, which the generated linker scripts lay at address 0 as a non-allocated (`INFO`) section. Its bytes stay in the ELF for the decoder and never reach the image. §2.2's `NOLOAD` would drop them from the ELF too. The identifier is the metadata's offset in the section plus 8, so identifiers 0 to 7 are the stream's own: 0 synchronization, 1 `dropped(u16 count)`, 2 `start(build_id[20], tick_ns u32)`, the first record in the ring, which says which image the stream comes from and how long a tick is. It is 16 bits when the section is under 64 KiB minus 8, else 32. The target computes the width from the section's bounds, so it is fixed at link time, and the decoder computes it from the ELF's section, with no ELF note. A linker without the script places the section as ordinary data, with the same identifiers. The plain-text backend's metadata is ordinary read-only data, and its record carries the metadata's address. **Timestamp:** the kernel clock's ticks, their low 32 bits, each tick as long as the start record says. §2.3 used the trace clock, which wraps within seconds on a fast part, while logs can be minutes apart. **The ring (§2.3, §2.5, §12 decision 2):** one ring per CPU, a power-of-two array of `CONFIG_EMB_LOG_RING_SIZE` bytes. *Reservation* is a critical section of a bounded number of instructions: it checks the free space, advances the head by the record's size and writes the record's two-byte header (its length, not yet committed). The producer then copies its record with interrupts enabled and *commits* it by setting the header's committed bit, one byte store after a barrier. *Nested producers:* an interrupt that preempts a producer reserves after it, so records keep the order in which they were reserved. *Publication:* the log thread takes records from the tail in order and stops at the first uncommitted one, and the records after it wait, committed or not, until it is committed. *A preempted record* holds back those after it until its producer runs again; meanwhile the ring fills and later records are dropped. Nothing is overwritten and nothing waits. *Overflow:* a record that does not fit is dropped and counted, and the next record that fits is preceded by the `dropped` record, in the same reservation, so the count stands where the loss was. *Consumer progress:* only the log thread advances the tail, inside the same critical section, since a 16-bit store is not atomic on AVR. A record is at most `EMB_LOG_RECORD_MAX` bytes: strings are cut at `CONFIG_EMB_LOG_STR_MAX` and hexdumps at `CONFIG_EMB_LOG_HEXDUMP_MAX`. This replaces §12 decision 2's lock-free ring. Cortex-M0 and AVR have no compare-and-swap for a lock-free reservation, and one design verified on every port is worth more than a second one. The critical section is bounded by constants, which is what OBS-003 asks. The ring does not survive a reset; `emb_log_flush()` writes out what is committed, polled, from any context, and the fault path calls it. **The log thread (§2.4):** a thread of its own (`CONFIG_EMB_LOG_THREAD_PRIORITY`, by default the lowest application priority, and `CONFIG_EMB_LOG_THREAD_STACK`), woken by a semaphore given when a record lands in an empty ring. It is not the system work queue, whose other items a slow console would hold up. **The console (§7):** a board writes raw bytes with `emb_board_write()`, and `emb_board_puts()` becomes common code. By default the console is plain text: the board's prints and the plain-text backend's lines. With `CONFIG_EMB_CONSOLE_FRAMED` everything on it travels in A113's frames: the board's text on channel 3, the shell's, buffered by line; log records on channel 0; trace on 1; crash records on 2. A frame holds whole records, so each frame's start is a synchronization point, and the synchronization record is left to unframed transports (SWO, the memory channel), which M4.3 does not implement. A thread's frame is written whole under the console's mutex. Text printed from an interrupt, a fault or before the kernel starts is framed and written at once, without the mutex, and can cut a thread's frame; the decoder then drops that frame and counts it. A zero precedes every frame, so bytes that are not a frame (a boot ROM's text, a cut frame) end before it, and `emb monitor` shows them as raw text. The deferred backend needs the framed console; without it the plain-text backend is the one built. **Profiles (§9, Q13):** `CONFIG_EMB_LOG` is on by default and costs nothing until an image calls it: the ring, the thread and the formatter are in `log.c`, which only a call links in, as the system work queue is (ADR-048). The backend is the deferred one where the console is framed and the plain-text one elsewhere, and always the plain-text one on tiny. **OBS-013** reads: "…the identifier being the offset of the call site's metadata in a non-allocated section, plus 8 (16 bits when it fits, else 32)…; over a framed transport each frame starts with a record; the plain-text backend shall share the call sites and the record." *Proposed 2026-11-13 with M4.3's logging. The project owner chose on 2026-11-13 the ring's critical-section reservation over a lock-free one, both backends with the deferred one the default, and the framed console as an option; the rest is for their review.* | `include/emb/log.h`, `include/emb/console.h`, `subsys/logging/log.c`, `subsys/console/console.c`, the boards' `emb_board_write()`, `hw/gen/emb_hwgen/` (the section), `tools/logdec/` (M4.3) | +| A127 | SPEC-015 §2, §7, §9, §12 decision 2, OBS-002, OBS-003, OBS-013, OBS-021, 08 Q13 | **Logging, its ring and the console.** **Call sites (§2.1):** a module is defined once with `EMB_LOG_MODULE_DEFINE(name, level)` and declared in its other files with `EMB_LOG_MODULE_DECLARE(name, level)`; §2.1 had only the declaration, which cannot both define the module and serve a module whose calls span files. `EMB_LOG_ERR`, `_WRN`, `_INF` and `_DBG(name, format, ...)` take at most eight arguments, and the compiler checks each format against its arguments as it checks printf's. A call above its file's level for the module, or above `CONFIG_EMB_LOG_LEVEL_MAX`, compiles to nothing; one above the module's run-time level (`emb_log_level_set()`) returns after one comparison. **One record, two backends (§2.3, §2.4, Q13):** every call packs its arguments into the record of §2.3 in the caller, typed by a signature the compiler computes from their C types with C11's `_Generic` (int, long, long long and their unsigned forms, double, string, pointer). The deferred backend (ADR-009) sends the record and the host formats it; the plain-text backend formats the same record on the target, in the log thread. Neither formats in the caller, so a call costs the same in an interrupt with either backend. **Identifiers (§2.2):** a call site's metadata (format, file, line, level, module, signature) is placed in the section `emb_log`, which the generated linker scripts lay at address 0 as a non-allocated (`INFO`) section. Its bytes stay in the ELF for the decoder and never reach the image. §2.2's `NOLOAD` would drop them from the ELF too. The identifier is the metadata's offset in the section plus 8, so identifiers 0 to 7 are the stream's own: 0 synchronization, 1 `dropped(u16 count)`, 2 `start(build_id[20], tick_ns u32)`, the first record in the ring, which says which image the stream comes from and how long a tick is. It is 16 bits when the section is under 64 KiB minus 8, else 32. The target computes the width from the section's bounds, so it is fixed at link time, and the decoder computes it from the ELF's section, with no ELF note. A linker without the script places the section as ordinary data, with the same identifiers. The plain-text backend's metadata is ordinary read-only data, and its record carries the metadata's address. **Timestamp:** the kernel clock's ticks, their low 32 bits, each tick as long as the start record says. §2.3 used the trace clock, which wraps within seconds on a fast part, while logs can be minutes apart. **The ring (§2.3, §2.5, §12 decision 2):** one ring per CPU, a power-of-two array of `CONFIG_EMB_LOG_RING_SIZE` bytes. *Reservation* is a critical section of a bounded number of instructions: it checks the free space, advances the head by the record's size and writes the record's two-byte header (its length, not yet committed). The producer then copies its record with interrupts enabled and *commits* it by setting the header's committed bit, one byte store after a barrier. *Nested producers:* an interrupt that preempts a producer reserves after it, so records keep the order in which they were reserved. *Publication:* the log thread takes records from the tail in order and stops at the first uncommitted one, and the records after it wait, committed or not, until it is committed. *A preempted record* holds back those after it until its producer runs again; meanwhile the ring fills and later records are dropped. Nothing is overwritten and nothing waits. *Overflow:* a record that does not fit is dropped and counted, and the next record that fits is preceded by the `dropped` record, in the same reservation, so the count stands where the loss was. *Consumer progress:* only the log thread advances the tail, inside the same critical section, since a 16-bit store is not atomic on AVR. A record is at most `EMB_LOG_RECORD_MAX` bytes: strings are cut at `CONFIG_EMB_LOG_STR_MAX` and hexdumps at `CONFIG_EMB_LOG_HEXDUMP_MAX`. This replaces §12 decision 2's lock-free ring. Cortex-M0 and AVR have no compare-and-swap for a lock-free reservation, and one design verified on every port is worth more than a second one. The critical section is bounded by constants, which is what OBS-003 asks. The ring does not survive a reset; `emb_log_flush()` writes out what is committed, polled, from any context, and the fault path calls it. **The log thread (§2.4):** a thread of its own (`CONFIG_EMB_LOG_THREAD_PRIORITY`, by default the lowest application priority, and `CONFIG_EMB_LOG_THREAD_STACK`), woken by a semaphore given when a record lands in an empty ring. It is not the system work queue, whose other items a slow console would hold up. On the table scheduler (tiny), whose priorities hold one thread each, there is no log thread by default (`CONFIG_EMB_LOG_THREAD`): the application sends the records with `emb_log_flush()` from a thread of its own. **The console (§7):** a board writes raw bytes with `emb_board_write()`, and `emb_board_puts()` becomes common code. By default the console is plain text: the board's prints and the plain-text backend's lines. With `CONFIG_EMB_CONSOLE_FRAMED` everything on it travels in A113's frames: the board's text on channel 3, the shell's, buffered by line; log records on channel 0; trace on 1; crash records on 2. A frame holds whole records, so each frame's start is a synchronization point, and the synchronization record is left to unframed transports (SWO, the memory channel), which M4.3 does not implement. A thread's frame is written whole under the console's mutex. Text printed from an interrupt, a fault or before the kernel starts is framed and written at once, without the mutex, and can cut a thread's frame; the decoder then drops that frame and counts it. A zero precedes every frame, so bytes that are not a frame (a boot ROM's text, a cut frame) end before it, and `emb monitor` shows them as raw text. The deferred backend needs the framed console; without it the plain-text backend is the one built. **Profiles (§9, Q13):** `CONFIG_EMB_LOG` is on by default and costs nothing until an image calls it: the ring, the thread and the formatter are in `log.c`, which only a call links in, as the system work queue is (ADR-048). The backend is the deferred one where the console is framed and the plain-text one elsewhere, and always the plain-text one on tiny, where `%f` is not formatted on the target by default (`CONFIG_EMB_LOG_FLOAT`). Logging is not offered on AVR in M4.3: the plain-text formatter and its stack do not fit the Uno's 2 KB of RAM beside the test framework, though its metadata and formats are already read from program memory. **OBS-013** reads: "…the identifier being the offset of the call site's metadata in a non-allocated section, plus 8 (16 bits when it fits, else 32)…; over a framed transport each frame starts with a record; the plain-text backend shall share the call sites and the record." *Proposed 2026-11-13 with M4.3's logging. The project owner chose on 2026-11-13 the ring's critical-section reservation over a lock-free one, both backends with the deferred one the default, and the framed console as an option; the rest is for their review.* | `include/emb/log.h`, `include/emb/console.h`, `subsys/logging/log.c`, `subsys/console/console.c`, the boards' `emb_board_write()`, `hw/gen/emb_hwgen/` (the section), `tools/logdec/` (M4.3) | **Not an amendment:** writing the vector table base (VTOR) at reset is already `emb_arch_early_init()`'s duty in SPEC-011 §4. The Cortex-M port has not done it, because every image so far boots from the boot base; M4.5 implements it for images in a slot (SPEC-019 §3). diff --git a/include/emb/compiler.h b/include/emb/compiler.h index 12b1ff8e..6f1dd3f9 100644 --- a/include/emb/compiler.h +++ b/include/emb/compiler.h @@ -163,6 +163,7 @@ extern "C" { #define EMB_FLASH_CONST const #define EMB_FLASH_READ_U8(p) (*(p)) #define EMB_FLASH_READ_U16(p) (*(p)) +#define EMB_FLASH_READ_U32(p) (*(p)) #define EMB_FLASH_READ_PTR(p) (*(p)) #define EMB_FLASH_READ_FNPTR(pp) ((uintptr_t)(*(pp))) #endif diff --git a/include/emb/compiler/clang.h b/include/emb/compiler/clang.h index 98ac0f7f..4a9dafa5 100644 --- a/include/emb/compiler/clang.h +++ b/include/emb/compiler/clang.h @@ -81,6 +81,7 @@ #define EMB_FLASH_CONST const __ATTR_PROGMEM__ #define EMB_FLASH_READ_U8(p) pgm_read_byte(p) #define EMB_FLASH_READ_U16(p) pgm_read_word(p) +#define EMB_FLASH_READ_U32(p) pgm_read_dword(p) #define EMB_FLASH_READ_PTR(p) ((void *)pgm_read_word(p)) #define EMB_FLASH_READ_FNPTR(pp) ((uintptr_t)pgm_read_word(pp)) #define EMB_TABLE_SECTION(name) ".progmem." name diff --git a/include/emb/compiler/gcc.h b/include/emb/compiler/gcc.h index b58a10ac..7c8a3921 100644 --- a/include/emb/compiler/gcc.h +++ b/include/emb/compiler/gcc.h @@ -74,6 +74,7 @@ #define EMB_FLASH_CONST const __attribute__((__progmem__)) #define EMB_FLASH_READ_U8(p) pgm_read_byte(p) #define EMB_FLASH_READ_U16(p) pgm_read_word(p) +#define EMB_FLASH_READ_U32(p) pgm_read_dword(p) #define EMB_FLASH_READ_PTR(p) ((void *)pgm_read_word(p)) #define EMB_FLASH_READ_FNPTR(pp) ((uintptr_t)pgm_read_word(pp)) #define EMB_TABLE_SECTION(name) ".progmem." name diff --git a/include/emb/frame.h b/include/emb/frame.h index 414d1419..75d33737 100644 --- a/include/emb/frame.h +++ b/include/emb/frame.h @@ -114,7 +114,7 @@ typedef void (*emb_frame_sink_t)(void *ctx, const uint8_t *bytes, size_t len); * * @ctx thread isr prekernel * @blocks no - * @time O(len) plus @sink's + * @time O(len) plus the sink's * @owns none * @config CONFIG_EMB_FRAME * @req OBS-019 diff --git a/include/emb/log.h b/include/emb/log.h index 697c0256..0760eaad 100644 --- a/include/emb/log.h +++ b/include/emb/log.h @@ -107,11 +107,13 @@ typedef struct emb_log_header { uint8_t reserved_[2]; } emb_log_header_t; -/* Where a call site's metadata and names go. */ +/* Where a call site's metadata and names go: the emb_log section with the deferred backend, + * read-only data with the plain-text one, in program memory on a Harvard core (SPEC-012 §8). */ #if CONFIG_EMB_LOG_DEFERRED #define EMB_LOG_SECTION_ EMB_SECTION(EMB_TABLE_SECTION("emb_log")) +#define EMB_LOG_CONST_ const EMB_LOG_SECTION_ #else -#define EMB_LOG_SECTION_ +#define EMB_LOG_CONST_ EMB_FLASH_CONST #endif /* A call site's file, which only the deferred backend keeps. */ @@ -139,7 +141,7 @@ typedef struct emb_log_header { */ #if CONFIG_EMB_LOG #define EMB_LOG_MODULE_DEFINE(m, lvl) \ - EMB_LOG_SECTION_ const char emb_log_name_##m##_[] = #m; \ + EMB_LOG_CONST_ char emb_log_name_##m##_[] = #m; \ emb_log_module_t emb_log_module_##m##_ = {EMB_LOG_LEVEL_DBG}; \ enum { \ emb_log_file_level_##m##_ = (lvl) \ @@ -157,11 +159,11 @@ typedef struct emb_log_header { * @lvl: The most detailed level this file compiles for it. */ #if CONFIG_EMB_LOG -#define EMB_LOG_MODULE_DECLARE(m, lvl) \ - extern EMB_LOG_SECTION_ const char emb_log_name_##m##_[]; \ - extern emb_log_module_t emb_log_module_##m##_; \ - enum { \ - emb_log_file_level_##m##_ = (lvl) \ +#define EMB_LOG_MODULE_DECLARE(m, lvl) \ + extern EMB_LOG_CONST_ char emb_log_name_##m##_[]; \ + extern emb_log_module_t emb_log_module_##m##_; \ + enum { \ + emb_log_file_level_##m##_ = (lvl) \ } #else #define EMB_LOG_MODULE_DECLARE(m, lvl) EMB_LOG_MODULE_DEFINE(m, lvl) @@ -190,15 +192,15 @@ typedef struct emb_log_header { ((unsigned)(lvl) <= (unsigned)EMB_LOG_LEVEL_LIMIT_)) #if CONFIG_EMB_LOG_DEFERRED -#define EMB_LOG_META_(lvl, m, fmt, sig) \ - static EMB_LOG_SECTION_ const char emb_log_fmt_[] = fmt; \ - static EMB_LOG_SECTION_ const char emb_log_file_[] = EMB_LOG_FILE_; \ - static EMB_LOG_SECTION_ const emb_log_meta_t emb_log_meta_ = { \ +#define EMB_LOG_META_(lvl, m, fmt, sig) \ + static EMB_LOG_CONST_ char emb_log_fmt_[] = fmt; \ + static EMB_LOG_CONST_ char emb_log_file_[] = EMB_LOG_FILE_; \ + static EMB_LOG_CONST_ emb_log_meta_t emb_log_meta_ = { \ emb_log_fmt_, emb_log_file_, emb_log_name_##m##_, (uint32_t)__LINE__, (sig), (lvl), {0u}} #else -#define EMB_LOG_META_(lvl, m, fmt, sig) \ - static const char emb_log_fmt_[] = fmt; \ - static const emb_log_meta_t emb_log_meta_ = { \ +#define EMB_LOG_META_(lvl, m, fmt, sig) \ + static EMB_LOG_CONST_ char emb_log_fmt_[] = fmt; \ + static EMB_LOG_CONST_ emb_log_meta_t emb_log_meta_ = { \ emb_log_fmt_, NULL, emb_log_name_##m##_, (uint32_t)__LINE__, (sig), (lvl), {0u}} #endif diff --git a/subsys/Kconfig b/subsys/Kconfig index 3fc6b265..f3141f42 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -26,14 +26,15 @@ config EMB_CONSOLE_FRAMED config EMB_LOG bool "Logging (SPEC-015 §2, A127), linked only when a call references it" - depends on EMB_SEM + depends on !EMB_ARCH_AVR default y help EMB_LOG_ERR() to EMB_LOG_DBG(): a call packs its arguments into a ring in the caller, from any context and without waiting, and a log thread sends the records on. Records that do not fit are dropped and counted (OBS-003). The ring and the thread come with the first call: - an image that logs nothing has neither. + an image that logs nothing has neither. Not on AVR in M4.3: the + formatter and its stack do not fit the Uno's 2 KB beside a test. if EMB_LOG @@ -78,16 +79,40 @@ config EMB_LOG_TIMESTAMP bool "Records carry the kernel clock's ticks" default y +config EMB_LOG_THREAD + bool "A log thread sends the records" + depends on EMB_SEM + default n if EMB_SCHED_TABLE + default y + help + Off, the records leave only when the application calls + emb_log_flush(), from a thread of its own. The table scheduler's + priorities hold one thread each, so a log thread would take one of + the application's: there it is off by default. + config EMB_LOG_THREAD_PRIORITY int "Log thread priority; 0 selects the lowest application priority" + depends on EMB_LOG_THREAD default 0 range 0 255 config EMB_LOG_THREAD_STACK int "Log thread stack, bytes" + depends on EMB_LOG_THREAD default 1024 range EMB_ARCH_STACK_MIN 65536 +config EMB_LOG_FLOAT + bool "The plain-text backend formats %f, %e and %g" + depends on EMB_LOG_TEXT + default n if EMB_PROFILE_TINY + default y + help + Off, a floating-point conversion prints as "(float)" and the + formatter carries no floating-point code: on a small part it is the + largest piece. The deferred backend formats on the host and needs + nothing on the target. + config EMB_LOG_LINE_MAX int "Longest line the plain-text backend formats, bytes" depends on EMB_LOG_TEXT diff --git a/subsys/logging/log.c b/subsys/logging/log.c index ae2ae07f..cd2c2e62 100644 --- a/subsys/logging/log.c +++ b/subsys/logging/log.c @@ -67,8 +67,9 @@ #if CONFIG_EMB_LOG_DEFERRED #define ID_MAX 4u #else -#define ID_MAX ((uint32_t)sizeof(void *)) /* the plain-text record carries its metadata's address \ - */ +#define ID_MAX \ + ((uint32_t)sizeof(void *)) /* the plain-text record carries its metadata's address \ + */ #endif #if CONFIG_EMB_LOG_TIMESTAMP #define TS_BYTES 4u @@ -92,6 +93,7 @@ EMB_STATIC_ASSERT(RECORD_MAX <= 0x7FFFu, "a record's length fits its header"); EMB_STATIC_ASSERT(((2u * HDR_BYTES) + RECORD_MAX + DROPPED_MAX) <= RING_SIZE, "the log ring holds the largest record and a dropped record"); +#if CONFIG_EMB_LOG_THREAD #if CONFIG_EMB_LOG_THREAD_PRIORITY == 0 #define LOG_PRIORITY EMB_PRIORITY_MIN #else @@ -99,6 +101,7 @@ EMB_STATIC_ASSERT(((2u * HDR_BYTES) + RECORD_MAX + DROPPED_MAX) <= RING_SIZE, EMB_STATIC_ASSERT(CONFIG_EMB_LOG_THREAD_PRIORITY < CONFIG_EMB_PRIORITY_COUNT, "CONFIG_EMB_LOG_THREAD_PRIORITY is not an application priority"); #endif +#endif /* ---- the ring ---------------------------------------------------------------------- */ @@ -109,9 +112,11 @@ static uint32_t ring_tail; /* the oldest byte not taken: the free space ends h static uint32_t ring_claims; /* moved by each consumer's claim, so a preempted one can tell */ static uint32_t ring_lost; /* records refused since the last one that fitted */ static emb_log_stats_t ring_stats; +static bool flushing; /* emb_log_flush() is sending: a nested one leaves it to it */ +#if CONFIG_EMB_LOG_THREAD static bool log_ready; /* the log thread's semaphore exists */ -static bool flushing; /* emb_log_flush() is sending: a nested one leaves it to it */ static emb_sem_t log_sem; +#endif static void ring_set(uint32_t pos, uint8_t b) { @@ -151,9 +156,11 @@ static void put_le(rec_writer_t *w, uint64_t v, uint32_t bytes) static void log_wake(void) { +#if CONFIG_EMB_LOG_THREAD if (log_ready && (emb_context() != EMB_CONTEXT_PREKERNEL)) { (void)emb_sem_give(log_sem); /* binary and saturating: a wake already pending stays one */ } +#endif } static uint32_t now_ticks(void) @@ -626,6 +633,22 @@ static void out_pad(out_t *o, char c, uint32_t n) } } +/* A character of a format or a module's name: in program memory on a Harvard core. */ +static char fch(const char *s, uint32_t i) +{ + return (char)EMB_FLASH_READ_U8((const uint8_t *)&s[i]); +} + +/* A name from program memory, as out_z(). */ +static void out_zf(out_t *o, const char *s) +{ + uint32_t i = 0u; + while ((fch(s, i) != '\0') && (o->len < o->room)) { /* bounded by the line */ + out_c(o, fch(s, i)); + i++; + } +} + /* A record's arguments, read in order. */ typedef struct rd { const uint8_t *p; @@ -733,6 +756,7 @@ static void out_int(out_t *o, const spec_t *sp, int64_t sv, uint64_t uv, char co out_field(o, sp, sign, digits, nd); } +#if CONFIG_EMB_LOG_FLOAT /* Fixed point for %f (and %e and %g, which print as %f here): up to nine decimals. */ static void out_double(out_t *o, const spec_t *sp, double d) { @@ -800,6 +824,7 @@ static void out_double(out_t *o, const spec_t *sp, double d) out_field(o, &fs, sign, digits, nd); } } +#endif static bool is_digit(char c) { @@ -887,24 +912,24 @@ static void format(out_t *o, const char *fmt, uint32_t sig, rd_t *r) { uint32_t k = 0u; uint32_t i = 0u; - while (fmt[i] != '\0') { /* bounded by the format */ + while (fch(fmt, i) != '\0') { /* bounded by the format */ spec_t sp = {0u, -1, false, false, false, false, false}; uint32_t h = 0u; arg_t a; char conv; - if (fmt[i] != '%') { - out_c(o, fmt[i]); + if (fch(fmt, i) != '%') { + out_c(o, fch(fmt, i)); i++; continue; } i++; - if (fmt[i] == '%') { + if (fch(fmt, i) == '%') { out_c(o, '%'); i++; continue; } for (;;) { /* bounded by the format: its flags */ - char f = fmt[i]; + char f = fch(fmt, i); if (f == '-') { sp.left = true; } else if (f == '0') { @@ -920,26 +945,27 @@ static void format(out_t *o, const char *fmt, uint32_t sig, rd_t *r) } i++; } - while (is_digit(fmt[i])) { /* bounded by the format */ - sp.width = (sp.width * 10u) + (uint32_t)(fmt[i] - '0'); + while (is_digit(fch(fmt, i))) { /* bounded by the format */ + sp.width = (sp.width * 10u) + (uint32_t)(fch(fmt, i) - '0'); i++; } - if (fmt[i] == '.') { + if (fch(fmt, i) == '.') { i++; sp.prec = 0; - while (is_digit(fmt[i])) { /* bounded by the format */ - sp.prec = (sp.prec * 10) + (int32_t)(fmt[i] - '0'); + while (is_digit(fch(fmt, i))) { /* bounded by the format */ + sp.prec = (sp.prec * 10) + (int32_t)(fch(fmt, i) - '0'); i++; } } - while ((fmt[i] == 'h') || (fmt[i] == 'l') || (fmt[i] == 'z') || (fmt[i] == 'j') || - (fmt[i] == 't') || (fmt[i] == 'L')) { /* bounded by the format */ - if (fmt[i] == 'h') { + while ((fch(fmt, i) == 'h') || (fch(fmt, i) == 'l') || (fch(fmt, i) == 'z') || + (fch(fmt, i) == 'j') || (fch(fmt, i) == 't') || + (fch(fmt, i) == 'L')) { /* bounded by the format */ + if (fch(fmt, i) == 'h') { h++; } i++; } - conv = fmt[i]; + conv = fch(fmt, i); if (conv == '\0') { break; } @@ -965,7 +991,11 @@ static void format(out_t *o, const char *fmt, uint32_t sig, rd_t *r) out_field(o, &cs, "", &ch, 1u); } else if ((conv == 'f') || (conv == 'F') || (conv == 'e') || (conv == 'E') || (conv == 'g') || (conv == 'G')) { +#if CONFIG_EMB_LOG_FLOAT out_double(o, &sp, (a.type == EMB_LOG_T_DOUBLE) ? a.d : (double)a.s); +#else + out_z(o, "(float)"); /* CONFIG_EMB_LOG_FLOAT is off */ +#endif } else { narrow(&a, h, conv); out_int(o, &sp, a.s, a.u, conv); @@ -978,12 +1008,12 @@ static void line_send(const char *line, uint32_t n) #if CONFIG_EMB_CONSOLE_FRAMED (void)emb_console_frame(EMB_FRAME_CHANNEL_SHELL, line, n); #else - emb_board_write(line, n); + emb_board_write(line, (size_t)n); #endif } /* "[seconds.milliseconds] E module: message" */ -static void line_head(out_t *o, uint32_t ts, char level, const char *module) +static void line_head(out_t *o, uint32_t ts, char level, const char *module, bool module_in_flash) { #if CONFIG_EMB_LOG_TIMESTAMP uint64_t ms = ((uint64_t)ts * (uint64_t)CONFIG_EMB_TICK_NS) / 1000000u; @@ -999,7 +1029,11 @@ static void line_head(out_t *o, uint32_t ts, char level, const char *module) #endif out_c(o, level); out_c(o, ' '); - out_z(o, module); + if (module_in_flash) { + out_zf(o, module); + } else { + out_z(o, module); + } out_z(o, ": "); } @@ -1022,16 +1056,24 @@ size_t embs_log_line(const uint8_t *rec, size_t n, char *line, size_t cap) id = (uintptr_t)rd_le(&r, ID_MAX); ts = (uint32_t)rd_le(&r, TS_BYTES); if (id == EMB_LOG_ID_DROPPED) { - line_head(&o, ts, 'W', "emb_log"); - format(&o, "%u records dropped", EMB_LOG_T_UINT, &r); + spec_t plain = {0u, -1, false, false, false, false, false}; + uint64_t lost = rd_le(&r, 2u); + line_head(&o, ts, 'W', "emb_log", false); + out_int(&o, &plain, (int64_t)lost, lost, 'u'); + out_z(&o, " records dropped"); } else if (id >= EMB_LOG_ID_FIRST) { + /* the call site's metadata: in program memory on a Harvard core */ const emb_log_meta_t *m = (const emb_log_meta_t *)id; - line_head(&o, ts, levels[(m->level <= EMB_LOG_LEVEL_DBG) ? m->level : 0u], m->module); - if (m->sig == EMB_LOG_T_HEX) { + uint8_t level = EMB_FLASH_READ_U8(&m->level); + uint32_t sig = EMB_FLASH_READ_U32(&m->sig); + const char *fmt = (const char *)EMB_FLASH_READ_PTR(&m->format); + const char *module = (const char *)EMB_FLASH_READ_PTR(&m->module); + line_head(&o, ts, levels[(level <= EMB_LOG_LEVEL_DBG) ? level : 0u], module, true); + if (sig == EMB_LOG_T_HEX) { uint32_t len = (uint32_t)rd_le(&r, 2u); uint32_t i; spec_t sp = {2u, -1, false, true, false, false, false}; - out_z(&o, m->format); + out_zf(&o, fmt); out_c(&o, ':'); for (i = 0u; (i < len) && (r.at < r.n); i++) { /* bounded by the record */ out_c(&o, ' '); @@ -1039,14 +1081,14 @@ size_t embs_log_line(const uint8_t *rec, size_t n, char *line, size_t cap) r.at++; } } else { - format(&o, m->format, m->sig, &r); + format(&o, fmt, sig, &r); } } else { return 0u; /* the stream's own records that only the deferred backend sends */ } o.buf[o.len] = '\n'; o.len++; - return o.len; + return (size_t)o.len; } /* Formats and sends the committed records, one line each. */ @@ -1054,7 +1096,7 @@ static void drain(consumer_t *c) { uint32_t n = 0u; while (ring_take(c->rec, RECORD_MAX, &n) == TAKE_DONE) { /* bounded by the ring */ - size_t len = embs_log_line(c->rec, n, c->line, sizeof(c->line)); + size_t len = embs_log_line(c->rec, (size_t)n, c->line, sizeof(c->line)); if (len != 0u) { line_send(c->line, (uint32_t)len); } @@ -1108,8 +1150,10 @@ uint32_t embs_log_id_bytes(void) /* ---- the log thread and the flush ------------------------------------------------- */ -static consumer_t thread_consumer; static consumer_t flush_consumer; + +#if CONFIG_EMB_LOG_THREAD +static consumer_t thread_consumer; static emb_sem_storage_t log_sem_storage; static emb_thread_storage_t log_thread_storage; EMB_THREAD_STACK(log_stack, CONFIG_EMB_LOG_THREAD_STACK); @@ -1122,6 +1166,7 @@ static void log_thread(void *arg) drain(&thread_consumer); } } +#endif void emb_log_flush(void) { @@ -1140,6 +1185,7 @@ void emb_log_flush(void) static void log_init(void) { +#if CONFIG_EMB_LOG_THREAD emb_sem_attr_t sa; emb_thread_attr_t ta; emb_thread_t th; @@ -1147,9 +1193,11 @@ static void log_init(void) sa.name = "emb_log"; (void)emb_check_status(emb_sem_init(&log_sem_storage, &sa, &log_sem), "emb_log semaphore"); log_ready = true; +#endif #if CONFIG_EMB_LOG_DEFERRED put_start(); #endif +#if CONFIG_EMB_LOG_THREAD emb_thread_attr_default(&ta); ta.name = "emb_log"; ta.stack = log_stack; @@ -1158,6 +1206,7 @@ static void log_init(void) (void)emb_check_status(emb_thread_init(&log_thread_storage, &ta, log_thread, NULL, &th), "emb_log thread"); (void)emb_check_status(emb_thread_start(th), "emb_log thread"); +#endif } EMB_INIT_TABLE_ENTRY(log_init); diff --git a/tests/conformance/test_log.c b/tests/conformance/test_log.c index 9bfe553c..4c1fccf3 100644 --- a/tests/conformance/test_log.c +++ b/tests/conformance/test_log.c @@ -25,8 +25,8 @@ EMB_LOG_MODULE_DEFINE(t, EMB_LOG_LEVEL_INF); -static uint8_t rec[512]; -static char line[256]; +static uint8_t rec[160]; /* the cases' records are short */ +static char line[128]; /* Empties the ring: records from earlier cases or from the start. */ static void drain(void) @@ -93,7 +93,11 @@ EMB_TEST(log_text_formats) EMB_LOG_INF(t, "%lld %llu %ld %lu", -1LL, 18446744073709551615ULL, -70000L, 70000UL); EXPECT_LINE("I t: -1 18446744073709551615 -70000 70000\n"); EMB_LOG_INF(t, "%.2f %.0f %.0f %f", 3.14159, 2.5, 3.5, -0.5); /* a half to the even */ +#if CONFIG_EMB_LOG_FLOAT EXPECT_LINE("I t: 3.14 2 4 -0.500000\n"); +#else + EXPECT_LINE("I t: (float) (float) (float) (float)\n"); +#endif EMB_LOG_INF(t, "%hhx %hd", 0x1FF, 70000); EXPECT_LINE("I t: ff 4464\n"); EMB_LOG_INF(t, "<%.3s|%4s>", "abcdef", "z"); @@ -136,7 +140,7 @@ EMB_TEST(log_overflow_drops_and_counts) { emb_log_stats_t before; emb_log_stats_t after; - uint32_t i; + unsigned i; uint32_t kept = 0u; uint32_t dropped; uint32_t idb = embs_log_id_bytes(); From ba8820b713f6c233d792441c03cac61377b47038 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:02:25 +0100 Subject: [PATCH 11/25] subsys: the trace ring, and CTF written on the host (A128) emb_trace_start() makes a RAM ring the trace sink: each kernel event becomes a 20-byte record with the cycle counter's time, written in the critical section the event is in. The ring keeps the newest events and numbers them, so a reader knows what was overwritten. emb_trace_dump() sends it on the framed console's channel 1, the threads' names first; CONFIG_EMB_TRACE_STREAM has a thread send new events every period. tools/trace/trace.py extends the counter across its wraps and writes a CTF 1.8 trace and Chrome's JSON for Perfetto; CI checks that Babeltrace 2 reads the trace examples/tracing dumps under QEMU. The tracing example ran on the NUCLEO-F446RE: 256 events over 16 ms at the cycle counter's resolution. Also for the checks: the log and console functions' bounds are in the resource-bound inventory, and every new public function has a fault registry id (256 to 260). Signed-off-by: teo1747 --- .github/workflows/ci.yml | 18 +- docs/engineering/resource-bounds.json | 59 +++++ docs/engineering/resource-bounds.md | 9 + docs/specs/AMENDMENTS-M4.md | 1 + examples/tracing/CMakeLists.txt | 17 ++ examples/tracing/main.c | 88 +++++++ include/emb/api_ids.h | 5 + include/emb/log.h | 2 +- include/emb/trace.h | 92 ++++++- subsys/CMakeLists.txt | 3 + subsys/Kconfig | 44 ++++ subsys/include/embs/trace.h | 39 +++ subsys/trace/ring.c | 337 ++++++++++++++++++++++++++ tests/conformance/CMakeLists.txt | 3 + tests/conformance/test_trace_ring.c | 121 +++++++++ tools/fault/api-ids.json | 30 +++ tools/fault/api-registry.json | 30 +++ tools/trace/test_trace.py | 101 ++++++++ tools/trace/trace.py | 304 +++++++++++++++++++++++ 19 files changed, 1299 insertions(+), 4 deletions(-) create mode 100644 examples/tracing/CMakeLists.txt create mode 100644 examples/tracing/main.c create mode 100644 subsys/include/embs/trace.h create mode 100644 subsys/trace/ring.c create mode 100644 tests/conformance/test_trace_ring.c create mode 100644 tools/trace/test_trace.py create mode 100644 tools/trace/trace.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20e68434..54640275 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -388,6 +388,8 @@ jobs: run: python3 -I -m unittest discover -s tools/transport -p 'test_*.py' -v - name: Log decoder's tests (A127) run: python3 -I -m unittest discover -s tools/logdec -p 'test_*.py' -v + - name: Trace converter's tests (A128) + run: python3 -I -m unittest discover -s tools/trace -p 'test_*.py' -v - name: EmbSIM runner, its project mode (SIM-002) run: python3 -I -m unittest discover -s tools/embsim -p 'test_*.py' -v - name: UF2 writer (A79) @@ -811,7 +813,7 @@ jobs: timeout-minutes: 15 uses: ./.github/actions/apt-install # archives cached, then scripts/ci-apt-install.sh with: - packages: ninja-build gcc-arm-none-eabi libnewlib-arm-none-eabi qemu-system-arm gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf qemu-system-misc gcc-avr avr-libc binutils-avr python3-yaml + packages: ninja-build gcc-arm-none-eabi libnewlib-arm-none-eabi qemu-system-arm gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf qemu-system-misc gcc-avr avr-libc binutils-avr python3-yaml babeltrace2 - name: Copy the examples out of the tree run: | cp -r examples/hello_app "$RUNNER_TEMP/hello_app" @@ -867,6 +869,20 @@ jobs: python3 -I tools/logdec/backends_agree.py --plain "logging-$b.log" --framed "logging-$b-framed.bin" \ --elf "build/logging-$b-framed/logging.elf" done + - name: The trace ring dumped under QEMU, turned into CTF that Babeltrace 2 reads (A128) + run: | + cp -r examples/tracing "$RUNNER_TEMP/tracing" + cmake -S "$RUNNER_TEMP/tracing" -B build/tracing-mps2_an386 -G Ninja -DEmbLinkRTOS_DIR="$PWD/cmake" \ + -DEMB_BOARD=mps2_an386 + cmake --build build/tracing-mps2_an386 + timeout 60 qemu-system-arm -M mps2-an386 -semihosting-config enable=on,target=native -nographic \ + -monitor none -serial stdio -kernel build/tracing-mps2_an386/tracing.elf > tracing.bin + python3 -I tools/trace/trace.py tracing.bin --ctf build/trace-ctf --perfetto build/trace.json + babeltrace2 build/trace-ctf > trace-ctf.txt + n=$(wc -l < trace-ctf.txt) + echo "babeltrace2 read $n events"; head -5 trace-ctf.txt + test "$n" -ge 100 + python3 -I -c "import json; d = json.load(open('build/trace.json')); assert len(d['traceEvents']) >= 100" - name: Build the reference controller for both NUCLEO-F446 boards (it runs on the board, not here) run: | cp -r examples/controller "$RUNNER_TEMP/controller" diff --git a/docs/engineering/resource-bounds.json b/docs/engineering/resource-bounds.json index 3c8e53c2..0c847817 100644 --- a/docs/engineering/resource-bounds.json +++ b/docs/engineering/resource-bounds.json @@ -302,6 +302,46 @@ "masked": false, "profiles": "every profile; the CRC is bitwise, eight steps a byte", "evidence": "SPEC-015 \u00a77; OBS-019; test_frame" + }, + { + "id": "console_line", + "input": "the console's line time: bytes written polled at its baud rate", + "bound": "the frame's bytes, each one character time (87 us at 115200 baud)", + "limit": "application: what it sends, and the board's console rate", + "enforcement": "application", + "masked": false, + "profiles": "every profile; a thread holds the console's mutex while it writes a frame, so other threads' frames wait (A127)", + "evidence": "SPEC-015 \u00a77; A127" + }, + { + "id": "log_record", + "input": "one log record's bytes: its arguments, strings and hexdump", + "bound": "at most eight arguments; a string cut at CONFIG_EMB_LOG_STR_MAX, a hexdump at CONFIG_EMB_LOG_HEXDUMP_MAX", + "limit": "configuration: CONFIG_EMB_LOG_STR_MAX, CONFIG_EMB_LOG_HEXDUMP_MAX", + "enforcement": "configuration", + "masked": false, + "profiles": "every profile with logging; the reservation is the only masked part, a bounded number of instructions", + "evidence": "SPEC-015 \u00a72.3; OBS-003; A127; test_log" + }, + { + "id": "log_ring", + "input": "records in the log ring", + "bound": "the ring's bytes: CONFIG_EMB_LOG_RING_SIZE", + "limit": "configuration: CONFIG_EMB_LOG_RING_SIZE", + "enforcement": "configuration", + "masked": false, + "profiles": "every profile with logging; a record is copied out with interrupts enabled", + "evidence": "SPEC-015 \u00a72.3; A127; test_log" + }, + { + "id": "trace_ring", + "input": "events in the trace ring", + "bound": "CONFIG_EMB_TRACE_RING_EVENTS, each 20 bytes", + "limit": "configuration: CONFIG_EMB_TRACE_RING_EVENTS", + "enforcement": "configuration", + "masked": false, + "profiles": "every profile with the trace ring; an event is read with interrupts masked, 20 bytes at a time", + "evidence": "SPEC-015 \u00a73; A128; test_trace_ring" } ], "apis": { @@ -805,6 +845,25 @@ ], "emb_frame_decode_byte": [ "frame_bytes" + ], + "emb_console_frame": [ + "frame_bytes", + "console_line" + ], + "emb_frame_write": [ + "frame_bytes", + "callbacks" + ], + "emb_log_flush": [ + "log_ring", + "console_line" + ], + "emb_log_write": [ + "log_record" + ], + "emb_trace_dump": [ + "trace_ring", + "console_line" ] } } diff --git a/docs/engineering/resource-bounds.md b/docs/engineering/resource-bounds.md index a2db6151..c3f4ad79 100644 --- a/docs/engineering/resource-bounds.md +++ b/docs/engineering/resource-bounds.md @@ -36,6 +36,10 @@ Every cost input named by a public function's `@time` annotation, with how it is | **rtc_oscillator**: an RTC set: the wait for its oscillator after power-up, and for the hardware to take a fraction of a second | 3 s for the oscillator, in 10 ms sleeps: the STM32F446's LSE starts within 2 s (its datasheet), and the RP2350's tick is the crystal's, already running; 100 ms for the STM32F446's shift of the subseconds, in 1 ms sleeps, measured at some 23 ms | the driver's wait | structural | no | base with CONFIG_EMB_DRV_RTC; the caller sleeps between checks | SPEC-017 §10, A123; test_rtc_board | | **entropy_bytes**: bytes of one entropy read | the caller's: the length it passes, read a block at a time within its timeout; a block the source's health test fails ends the read | application | application | no | base with CONFIG_EMB_DRV_ENTROPY; the read waits for each block on the driver's semaphore | SPEC-017 §11, A124; test_entropy, test_entropy_board | | **frame_bytes**: bytes of one frame: the payload encoded, or the frame decoded | the caller's: the payload it passes to emb_frame_encode(), and for a decoded frame the decoder's buffer, past which the frame is dropped | application: the buffers the caller gives | admission | no | every profile; the CRC is bitwise, eight steps a byte | SPEC-015 §7; OBS-019; test_frame | +| **console_line**: the console's line time: bytes written polled at its baud rate | the frame's bytes, each one character time (87 us at 115200 baud) | application: what it sends, and the board's console rate | application | no | every profile; a thread holds the console's mutex while it writes a frame, so other threads' frames wait (A127) | SPEC-015 §7; A127 | +| **log_record**: one log record's bytes: its arguments, strings and hexdump | at most eight arguments; a string cut at CONFIG_EMB_LOG_STR_MAX, a hexdump at CONFIG_EMB_LOG_HEXDUMP_MAX | configuration: CONFIG_EMB_LOG_STR_MAX, CONFIG_EMB_LOG_HEXDUMP_MAX | configuration | no | every profile with logging; the reservation is the only masked part, a bounded number of instructions | SPEC-015 §2.3; OBS-003; A127; test_log | +| **log_ring**: records in the log ring | the ring's bytes: CONFIG_EMB_LOG_RING_SIZE | configuration: CONFIG_EMB_LOG_RING_SIZE | configuration | no | every profile with logging; a record is copied out with interrupts enabled | SPEC-015 §2.3; A127; test_log | +| **trace_ring**: events in the trace ring | CONFIG_EMB_TRACE_RING_EVENTS, each 20 bytes | configuration: CONFIG_EMB_TRACE_RING_EVENTS | configuration | no | every profile with the trace ring; an event is read with interrupts masked, 20 bytes at a time | SPEC-015 §3; A128; test_trace_ring | ## Public functions @@ -47,6 +51,7 @@ Every cost input named by a public function's `@time` annotation, with how it is | `emb_cond_signal()` | O(1) selection, plus profile-specific timeout removal and scheduling | timeouts, reschedule | | `emb_cond_wait()` | O(waiters + timeouts) enqueue, a full mutex release, then the cost of emb_mutex_lock() | waiters, timeouts, owned, pi_depth, reschedule | | `emb_cond_wait_until()` | as emb_cond_wait() | waiters, timeouts, owned, pi_depth, reschedule | +| `emb_console_frame()` | O(len) plus the console's line time | frame_bytes, console_line | | `emb_device_init()` | O(dependencies) plus the driver's init | device_deps, drivers | | `emb_device_init_list()` | O(count) plus the drivers' init | devices, device_deps, drivers | | `emb_device_resume()` | O(1) plus the driver's resume | drivers | @@ -109,8 +114,11 @@ Every cost input named by a public function's `@time` annotation, with how it is | `emb_flash_area_read()` | O(flash_bytes) plus the lock's priority inheritance | flash_bytes, drivers, owned, waiters, pi_depth, timeouts | | `emb_frame_decode_byte()` | O(len) at a delimiter, for the CRC; O(1) otherwise | frame_bytes | | `emb_frame_encode()` | O(len) | frame_bytes | +| `emb_frame_write()` | O(len) plus the sink's | frame_bytes, callbacks | | `emb_isr_stack_info()` | O(stack) scan | stack | | `emb_kernel_init()` | O(init table) | init_table | +| `emb_log_flush()` | O(records in the ring) plus the console's line time | log_ring, console_line | +| `emb_log_write()` | O(1) critical section to reserve; O(arguments plus their strings) copy outside it | log_record | | `emb_msgq_destroy()` | O(waiters) with EMB_OBJ_ABORT_WAITERS | batch_wake, reschedule | | `emb_msgq_init()` | O(1); O(active message queues) list lookup with CONFIG_EMB_OBJ_LIST | active_objects | | `emb_msgq_peek()` | O(1) plus an item copy | item_copy | @@ -147,6 +155,7 @@ Every cost input named by a public function's `@time` annotation, with how it is | `emb_timer_start_at()` | O(armed timers) insertion | armed_timers | | `emb_timer_start_periodic()` | O(armed timers) insertion | armed_timers | | `emb_timer_stop_sync()` | O(1); O(waiters + timeouts) finite wait enqueue | waiters, timeouts | +| `emb_trace_dump()` | O(events in the ring) plus the console's line time | trace_ring, console_line | | `emb_wdog_start()` | O(1); O(active timers) list lookup with CONFIG_EMB_OBJ_LIST | active_objects | | `emb_wdog_unwatch()` | O(wdog_parties): the list walked to unlink it | wdog_parties | | `emb_work_cancel_sync()` | O(1); O(waiters + timeouts) finite wait enqueue | waiters, timeouts | diff --git a/docs/specs/AMENDMENTS-M4.md b/docs/specs/AMENDMENTS-M4.md index 363f4878..db8d99d7 100644 --- a/docs/specs/AMENDMENTS-M4.md +++ b/docs/specs/AMENDMENTS-M4.md @@ -24,5 +24,6 @@ Changes M4 makes to accepted specifications and requirements, where an accepted | A123 | SPEC-017 §10, SPEC-003 §10, KRN-TIM-031, SPEC-018 | **The RTC class and the wall clock.** SPEC-017 §10's requests become `emb_drv_rtc_get()` and `_set()`, with the time in nanoseconds since the Unix epoch (UTC), the wall clock's unit. There is one alarm per device, its callback in the alarm interrupt, `EMB_EBUSY` while armed, and `_alarm_cancel()`; a `set` disarms it. The backup registers are `_backup_read()` and `_write()`. The wake-up timer, the power policy's wake source, moves to M4.4 with SPEC-018, its only user, where its latency is measured. An alarm never fires before its time. It works at the RTC's resolution, and with a calendar it reaches 28 days ahead. The STM32F4's driver does not wait for the LSE at initialization; the first `set` waits instead. The RP2350 has no calendar: its RTC is the AON timer in POWMAN, milliseconds since the epoch on a 1 kHz tick from the crystal. That tick stops in DORMANT, where M4.4 switches it to LPOSC. SPEC-003 §10's wall clock is implemented: ``, behind `CONFIG_EMB_WALLCLOCK`, which needs 64-bit ticks. It is `EMB_ENOTSET` until it is set, or until a set RTC seeds it when its device starts (`emb_drv_rtc_started()`). `emb_wallclock_adjust()` steps; there is no slewing in M4. *Proposed 2026-11-10 with M4.2's RTC class, for the project owner's review; the wake-up timer's move and the RP2350's crystal tick chosen by the owner on 2026-11-10.* | `include/emb/drv_rtc.h`, `include/emb/wallclock.h`, `kernel/device/rtc.c`, `kernel/time/wallclock.c`, `drivers/st/stm32_rtc.c`, `drivers/rpi/rp2350_aon.c` (M4.2) | | A124 | SPEC-017 §11, SEC-012 | **The entropy class.** A read is `emb_drv_entropy_read(dev, buf, len, &got, timeout)`, assembled from a driver's blocks under the device's lock and one timeout. A timeout keeps the bytes read. A block that fails the source's health test ends the read with `EMB_EHEALTH`, and none of its bytes is delivered. The source's output is conditioned in the class, as NIST SP 800-90B asks of a raw noise source: every 32 bytes read are the SHA-256 of 64 raw, health-tested bytes. `emb_drv_entropy_read_raw()` reads the raw blocks, for measuring the source: on the RP2350 they fail a byte chi-square and a runs test, though they pass the TRNG's own health tests, and their most-common-value min-entropy must reach the 4 bits a byte that conditioning 2:1 needs. Every board defines `emb_board_entropy`: the generated `soc_devices.c` from the description, a hand-written board by hand. It is NULL where the board has no source, and `emb_drv_entropy_board()` then returns `EMB_ENOTSUP`. The native board's source is the host's `getentropy()`. The RP2350's TRNG keeps every health test on, and samples every 200 clocks, from a measurement on the board (`sample_count:` on the device). SPEC-017 §11's evidence changes: the 1 MiB is tested on the board, and a 64 KiB sample with its SHA-256 is archived and checked on the host, in place of archiving the whole MiB. *Proposed 2026-11-12 with M4.2's entropy class, for the project owner's review; the evidence's form, the native board's host source and the conditioning chosen by the owner on 2026-11-12.* | `include/emb/drv_entropy.h`, `kernel/device/entropy.c`, `kernel/device/sha256.c`, `drivers/rpi/rp2350_trng.c`, `boards/native/native/board.c`, `tools/entropy/check.py` (M4.2) | | A127 | SPEC-015 §2, §7, §9, §12 decision 2, OBS-002, OBS-003, OBS-013, OBS-021, 08 Q13 | **Logging, its ring and the console.** **Call sites (§2.1):** a module is defined once with `EMB_LOG_MODULE_DEFINE(name, level)` and declared in its other files with `EMB_LOG_MODULE_DECLARE(name, level)`; §2.1 had only the declaration, which cannot both define the module and serve a module whose calls span files. `EMB_LOG_ERR`, `_WRN`, `_INF` and `_DBG(name, format, ...)` take at most eight arguments, and the compiler checks each format against its arguments as it checks printf's. A call above its file's level for the module, or above `CONFIG_EMB_LOG_LEVEL_MAX`, compiles to nothing; one above the module's run-time level (`emb_log_level_set()`) returns after one comparison. **One record, two backends (§2.3, §2.4, Q13):** every call packs its arguments into the record of §2.3 in the caller, typed by a signature the compiler computes from their C types with C11's `_Generic` (int, long, long long and their unsigned forms, double, string, pointer). The deferred backend (ADR-009) sends the record and the host formats it; the plain-text backend formats the same record on the target, in the log thread. Neither formats in the caller, so a call costs the same in an interrupt with either backend. **Identifiers (§2.2):** a call site's metadata (format, file, line, level, module, signature) is placed in the section `emb_log`, which the generated linker scripts lay at address 0 as a non-allocated (`INFO`) section. Its bytes stay in the ELF for the decoder and never reach the image. §2.2's `NOLOAD` would drop them from the ELF too. The identifier is the metadata's offset in the section plus 8, so identifiers 0 to 7 are the stream's own: 0 synchronization, 1 `dropped(u16 count)`, 2 `start(build_id[20], tick_ns u32)`, the first record in the ring, which says which image the stream comes from and how long a tick is. It is 16 bits when the section is under 64 KiB minus 8, else 32. The target computes the width from the section's bounds, so it is fixed at link time, and the decoder computes it from the ELF's section, with no ELF note. A linker without the script places the section as ordinary data, with the same identifiers. The plain-text backend's metadata is ordinary read-only data, and its record carries the metadata's address. **Timestamp:** the kernel clock's ticks, their low 32 bits, each tick as long as the start record says. §2.3 used the trace clock, which wraps within seconds on a fast part, while logs can be minutes apart. **The ring (§2.3, §2.5, §12 decision 2):** one ring per CPU, a power-of-two array of `CONFIG_EMB_LOG_RING_SIZE` bytes. *Reservation* is a critical section of a bounded number of instructions: it checks the free space, advances the head by the record's size and writes the record's two-byte header (its length, not yet committed). The producer then copies its record with interrupts enabled and *commits* it by setting the header's committed bit, one byte store after a barrier. *Nested producers:* an interrupt that preempts a producer reserves after it, so records keep the order in which they were reserved. *Publication:* the log thread takes records from the tail in order and stops at the first uncommitted one, and the records after it wait, committed or not, until it is committed. *A preempted record* holds back those after it until its producer runs again; meanwhile the ring fills and later records are dropped. Nothing is overwritten and nothing waits. *Overflow:* a record that does not fit is dropped and counted, and the next record that fits is preceded by the `dropped` record, in the same reservation, so the count stands where the loss was. *Consumer progress:* only the log thread advances the tail, inside the same critical section, since a 16-bit store is not atomic on AVR. A record is at most `EMB_LOG_RECORD_MAX` bytes: strings are cut at `CONFIG_EMB_LOG_STR_MAX` and hexdumps at `CONFIG_EMB_LOG_HEXDUMP_MAX`. This replaces §12 decision 2's lock-free ring. Cortex-M0 and AVR have no compare-and-swap for a lock-free reservation, and one design verified on every port is worth more than a second one. The critical section is bounded by constants, which is what OBS-003 asks. The ring does not survive a reset; `emb_log_flush()` writes out what is committed, polled, from any context, and the fault path calls it. **The log thread (§2.4):** a thread of its own (`CONFIG_EMB_LOG_THREAD_PRIORITY`, by default the lowest application priority, and `CONFIG_EMB_LOG_THREAD_STACK`), woken by a semaphore given when a record lands in an empty ring. It is not the system work queue, whose other items a slow console would hold up. On the table scheduler (tiny), whose priorities hold one thread each, there is no log thread by default (`CONFIG_EMB_LOG_THREAD`): the application sends the records with `emb_log_flush()` from a thread of its own. **The console (§7):** a board writes raw bytes with `emb_board_write()`, and `emb_board_puts()` becomes common code. By default the console is plain text: the board's prints and the plain-text backend's lines. With `CONFIG_EMB_CONSOLE_FRAMED` everything on it travels in A113's frames: the board's text on channel 3, the shell's, buffered by line; log records on channel 0; trace on 1; crash records on 2. A frame holds whole records, so each frame's start is a synchronization point, and the synchronization record is left to unframed transports (SWO, the memory channel), which M4.3 does not implement. A thread's frame is written whole under the console's mutex. Text printed from an interrupt, a fault or before the kernel starts is framed and written at once, without the mutex, and can cut a thread's frame; the decoder then drops that frame and counts it. A zero precedes every frame, so bytes that are not a frame (a boot ROM's text, a cut frame) end before it, and `emb monitor` shows them as raw text. The deferred backend needs the framed console; without it the plain-text backend is the one built. **Profiles (§9, Q13):** `CONFIG_EMB_LOG` is on by default and costs nothing until an image calls it: the ring, the thread and the formatter are in `log.c`, which only a call links in, as the system work queue is (ADR-048). The backend is the deferred one where the console is framed and the plain-text one elsewhere, and always the plain-text one on tiny, where `%f` is not formatted on the target by default (`CONFIG_EMB_LOG_FLOAT`). Logging is not offered on AVR in M4.3: the plain-text formatter and its stack do not fit the Uno's 2 KB of RAM beside the test framework, though its metadata and formats are already read from program memory. **OBS-013** reads: "…the identifier being the offset of the call site's metadata in a non-allocated section, plus 8 (16 bits when it fits, else 32)…; over a framed transport each frame starts with a record; the plain-text backend shall share the call sites and the record." *Proposed 2026-11-13 with M4.3's logging. The project owner chose on 2026-11-13 the ring's critical-section reservation over a lock-free one, both backends with the deferred one the default, and the framed console as an option; the rest is for their review.* | `include/emb/log.h`, `include/emb/console.h`, `subsys/logging/log.c`, `subsys/console/console.c`, the boards' `emb_board_write()`, `hw/gen/emb_hwgen/` (the section), `tools/logdec/` (M4.3) | +| A128 | SPEC-015 §3, §12 decisions 2 and 3, OBS-005, OBS-006, OBS-007, OBS-014, OBS-015, 08 Q12 | **The trace ring, and CTF written on the host.** As the project owner chose for Q12, the target keeps compact records and the host writes CTF. **The ring (§3.2):** with `CONFIG_EMB_TRACE_RING`, `emb_trace_start()` makes a RAM ring the trace sink (`emb_trace_set_sink()`), and the image links the ring only when it calls that. Each kernel event becomes a 20-byte record (time, id, CPU, context, three 32-bit arguments), written in the critical section the event happens in. The ring keeps the newest `CONFIG_EMB_TRACE_RING_EVENTS`, a full ring overwriting the oldest: a snapshot, the flight recorder's shape. Events are numbered from the start, event *n* in slot *n* modulo the size, so a reader knows what it missed. `emb_trace_stop()` freezes it for a dump. This replaces §3.2's packets on the target and §12 decision 2's lock-free ring: one store under the critical section the event is already in costs less than reserving. **The clock (§3.4):** `emb_arch_cycles()`, the port's cycle counter, its low 32 bits. The host extends it across its wraps, so two consecutive events must be less than half its period apart (11.9 s at 180 MHz); the periodic clock's tick events keep them so. Tickless Cortex-M (M4.4) adds a clock record before that bound. **On the line (§3.3):** `emb_trace_dump()` sends the ring, oldest first, on the framed console's channel 1 (A127). The streaming option (`CONFIG_EMB_TRACE_STREAM`) has a thread send the new events every `CONFIG_EMB_TRACE_STREAM_MS`. Its own sending is traced too, and the period bounds it; events the ring overwrote before they were sent are counted. A packet is a 16-byte header (version 1, kind, count, the first event's number, the counter's rate in Hz, the events lost so far) and whole events. Another kind carries the threads' indexes and names, sent first from a thread. **The host (§3.5, OBS-006):** `tools/trace/trace.py` extends the times and writes a CTF 1.8 trace (TSDL metadata with the counter as its clock, and one stream whose packets carry `events_discarded`), which Babeltrace 2 reads in CI. It also writes Chrome's JSON for Perfetto: a track per thread from the switches, one for interrupts, the rest as instant events. **The catalogue (§3.1, OBS-014):** stays the `emb_trace_id` enum in `include/emb/trace.h`, whose names and notes the tool reads; `hw/trace_events.yaml`, classes and generated emitters remain for the full catalogue. *Proposed 2026-11-13 with M4.3's trace. The project owner chose on 2026-11-13 compact records on the target and CTF written on the host; the rest is for their review.* | `include/emb/trace.h`, `subsys/trace/ring.c`, `tools/trace/trace.py`, `examples/tracing` (M4.3) | **Not an amendment:** writing the vector table base (VTOR) at reset is already `emb_arch_early_init()`'s duty in SPEC-011 §4. The Cortex-M port has not done it, because every image so far boots from the boot base; M4.5 implements it for images in a slot (SPEC-019 §3). diff --git a/examples/tracing/CMakeLists.txt b/examples/tracing/CMakeLists.txt new file mode 100644 index 00000000..85b58882 --- /dev/null +++ b/examples/tracing/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +cmake_minimum_required(VERSION 3.20) + +set(EmbLinkRTOS_DIR "${CMAKE_CURRENT_LIST_DIR}/../../cmake" CACHE PATH "The RTOS's cmake/ directory") +# the kernel's trace points and the framed console, which carries the trace on channel 1 (A128) +set(EMB_SET "EMB_TRACE=y;EMB_CONSOLE_FRAMED=y" CACHE STRING "Symbol overrides") +find_package(EmbLinkRTOS REQUIRED) + +project(tracing LANGUAGES C) + +emb_kernel() +emb_add_executable(tracing main.c) diff --git a/examples/tracing/main.c b/examples/tracing/main.c new file mode 100644 index 00000000..13f1bbbf --- /dev/null +++ b/examples/tracing/main.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file main.c + * @brief The trace ring: a few threads' events, dumped and turned into CTF (SPEC-015 §3, A128). + * + * @details + * A producer sends readings to a consumer through a message queue every millisecond, and the + * consumer signals a semaphore for every fourth. The trace ring records the kernel's events for + * 20 ms; the ring is then dumped on the framed console's channel 1 and the image ends: + * + * cmake -S examples/tracing -B build/tracing -DEMB_BOARD=mps2_an386 + * python3 tools/trace/trace.py console.bin --ctf build/trace --perfetto build/trace.json + * babeltrace2 build/trace + * + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include + +#include +#if CONFIG_EMB_ARCH_NATIVE +#include +#endif + +EMB_MSGQ_DEFINE(readings, sizeof(uint32_t), 4u, 0u); +EMB_SEM_DEFINE(fourth, 0u, 100u); + +static void producer(void *arg) +{ + emb_instant_t next = emb_time_now(); + uint32_t seq = 0u; + (void)arg; + for (;;) { + next = emb_instant_add(next, EMB_MS(1)); + (void)emb_thread_sleep_until(next); + seq++; + (void)emb_msgq_send(readings, &seq, EMB_NO_WAIT); + } +} + +static void consumer(void *arg) +{ + uint32_t v; + (void)arg; + for (;;) { + if ((emb_msgq_receive(readings, &v, EMB_WAIT_FOREVER) == EMB_OK) && ((v % 4u) == 0u)) { + (void)emb_sem_give(fourth); + } + } +} + +static void control(void *arg) +{ + emb_trace_stats_t st; + (void)arg; + EMB_CHECK(emb_trace_start()); + (void)emb_thread_sleep(EMB_MS(20)); + emb_trace_stop(); + EMB_CHECK(emb_trace_dump()); + EMB_CHECK(emb_trace_stats_get(&st)); + emb_board_puts("tracing: "); + emb_board_put_u32(st.recorded); + emb_board_puts(" events recorded, "); + emb_board_put_u32(st.sent); + emb_board_puts(" sent\ntracing: done\n"); +#if CONFIG_EMB_ARCH_NATIVE + emb_native_exit(0); +#else + emb_board_exit(0); +#endif +} + +EMB_THREAD_DEFINE(producer_thread, producer, NULL, 3u, 1024u, 0u); +EMB_THREAD_DEFINE(consumer_thread, consumer, NULL, 2u, 1024u, 0u); +EMB_THREAD_DEFINE(control_thread, control, NULL, 4u, 1024u, 0u); + +int main(void) +{ + emb_board_init(); + emb_kernel_init(); + emb_kernel_start(); +} diff --git a/include/emb/api_ids.h b/include/emb/api_ids.h index 2865a203..5febecd4 100644 --- a/include/emb/api_ids.h +++ b/include/emb/api_ids.h @@ -250,5 +250,10 @@ #define EMB_API_ID_LOG_FLUSH 0x00FDu #define EMB_API_ID_LOG_STATS_GET 0x00FEu #define EMB_API_ID_CONSOLE_FRAME 0x00FFu +#define EMB_API_ID_LOG_FORMAT_CHECK_ 0x0100u +#define EMB_API_ID_TRACE_START 0x0101u +#define EMB_API_ID_TRACE_STOP 0x0102u +#define EMB_API_ID_TRACE_DUMP 0x0103u +#define EMB_API_ID_TRACE_STATS_GET 0x0104u #endif /* EMB_API_IDS_H */ diff --git a/include/emb/log.h b/include/emb/log.h index 0760eaad..a82b53f6 100644 --- a/include/emb/log.h +++ b/include/emb/log.h @@ -303,7 +303,7 @@ typedef struct emb_log_header { * * @ctx thread isr prekernel * @blocks no - * @time O(1): it appears only inside sizeof, so no code is emitted + * @time O(1) * @owns none * @config CONFIG_EMB_LOG * @req OBS-001 diff --git a/include/emb/trace.h b/include/emb/trace.h index 2dba15f5..bcaa9812 100644 --- a/include/emb/trace.h +++ b/include/emb/trace.h @@ -11,8 +11,9 @@ * * @details * With CONFIG_EMB_TRACE every kernel event is delivered to one registered sink; the native port's - * test harness forwards them to the reference-model bridge (SPEC-013 §8). The CTF encoding and the - * packetized rings of SPEC-015 come with the observability milestone. + * test harness forwards them to the reference-model bridge (SPEC-013 §8). The trace ring (A128) + * is the other sink: events kept as compact records in RAM, dumped or streamed framed on + * channel 1, which tools/trace turns into CTF and Perfetto's JSON on the host. * * @see kernel/trace/trace.c * @author Junior Deogracias @@ -21,6 +22,7 @@ #ifndef EMB_TRACE_H #define EMB_TRACE_H +#include #include #ifdef __cplusplus @@ -105,6 +107,92 @@ typedef void (*emb_trace_sink_t)(const emb_trace_event_t *event, void *ctx); */ void emb_trace_set_sink(emb_trace_sink_t sink, void *ctx); +/* ---- the trace ring (A128) -------------------------------------------------------- */ + +/* A ring's event as it is kept and sent: 20 bytes, little-endian. */ +#define EMB_TRACE_RECORD_SIZE 20u + +/* A channel-1 packet's kind (A128). */ +#define EMB_TRACE_PACKET_EVENTS 0u /* events, oldest first */ +#define EMB_TRACE_PACKET_NAMES 1u /* threads' indexes and names */ + +typedef struct emb_trace_stats { + uint32_t recorded; /* events written into the ring since emb_trace_start() */ + uint32_t overwritten; /* events the ring dropped, oldest first, before they were sent */ + uint32_t sent; /* events sent on channel 1 */ +} emb_trace_stats_t; + +/** + * emb_trace_start() - Record the kernel's events into the trace ring. + * + * @ctx prekernel thread + * @blocks no + * @time O(1) + * @owns none + * @config CONFIG_EMB_TRACE_RING + * @req OBS-005 OBS-007 + * @since 0.3 + * @stable no + * + * The ring becomes the trace sink (emb_trace_set_sink()): each event is written into it in the + * critical section it happens in, as a 20-byte record with the cycle counter's time. A full + * ring overwrites its oldest events, counted. Calling it links the ring into the image. + * + * Return: EMB_OK. + */ +emb_status_t emb_trace_start(void); + +/** + * emb_trace_stop() - Stop recording: the ring keeps what it holds, for a dump. + * + * @ctx prekernel thread isr + * @blocks no + * @time O(1) + * @owns none + * @config CONFIG_EMB_TRACE_RING + * @req OBS-007 + * @since 0.3 + * @stable no + */ +void emb_trace_stop(void); + +/** + * emb_trace_dump() - Send the ring's events on the framed console's channel 1. + * + * @ctx thread isr prekernel + * @blocks yes, in a thread: for the console + * @time O(events in the ring) plus the console's line time + * @owns none + * @config CONFIG_EMB_TRACE_RING CONFIG_EMB_CONSOLE_FRAMED + * @req OBS-007 + * @since 0.3 + * @stable no + * + * The snapshot of SPEC-015 §3.3: from a thread, a packet of the threads' names first; then the + * events in the ring when it is called, oldest first, in packets of whole events. Events that + * happen while it sends are not in this dump. + * + * Return: EMB_OK; EMB_ENOTSUP when the console is plain text. + */ +emb_status_t emb_trace_dump(void); + +/** + * emb_trace_stats_get() - The trace ring's counters. + * @out: Receives them, read together. + * + * @ctx thread isr prekernel + * @blocks no + * @time O(1) + * @owns none + * @config CONFIG_EMB_TRACE_RING + * @req OBS-005 + * @since 0.3 + * @stable no + * + * Return: EMB_OK; EMB_EINVAL for a NULL @out. + */ +emb_status_t emb_trace_stats_get(emb_trace_stats_t *out); + #ifdef __cplusplus } #endif diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 3424a5be..ac4058b9 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -15,6 +15,9 @@ endif() if(CONFIG_EMB_LOG) list(APPEND EMB_SUBSYS_SOURCES logging/log.c) # SPEC-015 §2, A127 endif() +if(CONFIG_EMB_TRACE_RING) + list(APPEND EMB_SUBSYS_SOURCES trace/ring.c) # SPEC-015 §3, A128 +endif() add_library(emb_subsys STATIC ${EMB_SUBSYS_SOURCES}) emb_use_kernel_compiler(emb_subsys) diff --git a/subsys/Kconfig b/subsys/Kconfig index f3141f42..e96ffcd6 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -122,4 +122,48 @@ config EMB_LOG_LINE_MAX endif # EMB_LOG +config EMB_TRACE_RING + bool "Trace ring: the kernel's events in RAM, sent on channel 1 (A128)" + depends on EMB_TRACE + default y + help + emb_trace_start() makes the ring the trace sink: each kernel event is + kept as a 20-byte record with the cycle counter's time, the newest + overwriting the oldest. emb_trace_dump() sends them framed on channel + 1, and tools/trace writes CTF and Perfetto's JSON from them. Linked + only when the application calls emb_trace_start(). + +if EMB_TRACE_RING + +config EMB_TRACE_RING_EVENTS + int "Events the ring keeps (a power of two)" + default 64 if EMB_PROFILE_TINY + default 256 + range 8 65536 + +config EMB_TRACE_STREAM + bool "Stream: a thread sends the events as they come, every period" + depends on EMB_CONSOLE_FRAMED + default n + +config EMB_TRACE_STREAM_MS + int "Stream period, milliseconds" + depends on EMB_TRACE_STREAM + default 100 + range 1 60000 + +config EMB_TRACE_STREAM_PRIORITY + int "Stream thread priority; 0 selects the lowest application priority" + depends on EMB_TRACE_STREAM + default 0 + range 0 255 + +config EMB_TRACE_STREAM_STACK + int "Stream thread stack, bytes" + depends on EMB_TRACE_STREAM + default 1024 + range EMB_ARCH_STACK_MIN 65536 + +endif # EMB_TRACE_RING + endmenu diff --git a/subsys/include/embs/trace.h b/subsys/include/embs/trace.h new file mode 100644 index 00000000..bd6722d2 --- /dev/null +++ b/subsys/include/embs/trace.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file trace.h + * @brief The trace ring's events by number, for the dump, the stream and the tests (A128). + * + * @see subsys/trace/ring.c + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#ifndef EMBS_TRACE_H +#define EMBS_TRACE_H + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The number the next event will have: events are numbered from emb_trace_start(). */ +uint32_t embs_trace_next(void); + +/* Copies event @seq as it is sent (20 bytes, little-endian: time, id, cpu, context, a0 to a2); + * false when the ring no longer holds it, or never did. */ +bool embs_trace_read(uint32_t seq, uint8_t out[EMB_TRACE_RECORD_SIZE]); + +#ifdef __cplusplus +} +#endif + +#endif /* EMBS_TRACE_H */ diff --git a/subsys/trace/ring.c b/subsys/trace/ring.c new file mode 100644 index 00000000..6d25d3b3 --- /dev/null +++ b/subsys/trace/ring.c @@ -0,0 +1,337 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file ring.c + * @brief The trace ring: the kernel's events in RAM, dumped or streamed on channel 1 (A128). + * + * @details + * The ring is the trace sink: each event is written as a 20-byte record in the critical section + * it happens in, with the cycle counter's time. The ring keeps the newest events; a full ring + * overwrites the oldest, and a reader that finds its next event overwritten counts the loss. + * Events are numbered from emb_trace_start(): event n is in slot n modulo the ring's size. + * + * A packet on channel 1 is a 16-byte header (version, kind, count, the first event's number, + * the cycle counter's rate, the events lost so far) and its events or the threads' names. The + * host (tools/trace) builds CTF's packets and Perfetto's tracks from them: the target formats + * nothing (08 Q12). + * + * @see include/emb/trace.h + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include +#include + +#if CONFIG_EMB_TRACE_RING + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define RING_EVENTS ((uint32_t)CONFIG_EMB_TRACE_RING_EVENTS) +#define RING_MASK (RING_EVENTS - 1u) +EMB_STATIC_ASSERT((RING_EVENTS & RING_MASK) == 0u, + "CONFIG_EMB_TRACE_RING_EVENTS is a power of two"); + +#define PACKET_HEADER 16u +#define PACKET_EVENTS 12u /* a frame's payload of 256 bytes at most */ +#define PACKET_VERSION 1u +#define NAME_MAX 15u +#define NAMES_PAYLOAD_MAX 240u + +typedef struct trace_rec { + uint32_t ts; + uint16_t id; + uint8_t cpu; + uint8_t context; + uint32_t a[3]; +} trace_rec_t; + +static trace_rec_t ring[RING_EVENTS]; +/* Lock domain: the critical section (emb_irq_lock), for every variable below. */ +static uint32_t ring_next; /* the next event's number: events [next - size, next) are kept */ +static bool recording; +static emb_trace_stats_t ring_stats; + +static void ring_sink(const emb_trace_event_t *ev, void *ctx) +{ + emb_irq_key_t key; + trace_rec_t *r; + (void)ctx; + key = emb_irq_lock(); + if (recording) { + r = &ring[ring_next & RING_MASK]; + r->ts = (uint32_t)emb_arch_cycles(); + r->id = ev->id; + r->cpu = ev->cpu; + r->context = ev->context; + r->a[0] = (uint32_t)ev->a0; + r->a[1] = (uint32_t)ev->a1; + r->a[2] = (uint32_t)ev->a2; + ring_next++; + ring_stats.recorded++; + } + emb_irq_unlock(key); +} + +emb_status_t emb_trace_start(void) +{ + emb_irq_key_t key = emb_irq_lock(); + recording = true; + emb_irq_unlock(key); + emb_trace_set_sink(ring_sink, NULL); + return EMB_OK; +} + +void emb_trace_stop(void) +{ + emb_irq_key_t key = emb_irq_lock(); + recording = false; + emb_irq_unlock(key); +} + +emb_status_t emb_trace_stats_get(emb_trace_stats_t *out) +{ + emb_irq_key_t key; + if (out == NULL) { + return EMB_EINVAL; + } + key = emb_irq_lock(); + *out = ring_stats; + emb_irq_unlock(key); + return EMB_OK; +} + +uint32_t embs_trace_next(void) +{ + emb_irq_key_t key = emb_irq_lock(); + uint32_t n = ring_next; + emb_irq_unlock(key); + return n; +} + +bool embs_trace_read(uint32_t seq, uint8_t out[EMB_TRACE_RECORD_SIZE]) +{ + emb_irq_key_t key = emb_irq_lock(); + bool kept = ((ring_next - seq) - 1u) < RING_EVENTS; /* seq in [next - size, next) */ + if (kept) { + const trace_rec_t *r = &ring[seq & RING_MASK]; + uint32_t i; + uint32_t k; + uint32_t w[5]; + w[0] = r->ts; + w[1] = (uint32_t)r->id | ((uint32_t)r->cpu << 16) | ((uint32_t)r->context << 24); + w[2] = r->a[0]; + w[3] = r->a[1]; + w[4] = r->a[2]; + for (i = 0u; i < 5u; i++) { /* bounded: five words, little-endian */ + for (k = 0u; k < 4u; k++) { + out[(4u * i) + k] = (uint8_t)(w[i] >> (8u * k)); + } + } + } + emb_irq_unlock(key); + return kept; +} + +/* ---- packets ------------------------------------------------------------------------ */ + +static void put_u16(uint8_t *p, uint32_t v) +{ + p[0] = (uint8_t)v; + p[1] = (uint8_t)(v >> 8); +} + +static void put_u32(uint8_t *p, uint32_t v) +{ + put_u16(p, v); + put_u16(&p[2], v >> 16); +} + +static void packet_header(uint8_t *p, uint32_t kind, uint32_t count, uint32_t first) +{ + emb_trace_stats_t s; + (void)emb_trace_stats_get(&s); + p[0] = (uint8_t)PACKET_VERSION; + p[1] = (uint8_t)kind; + put_u16(&p[2], count); + put_u32(&p[4], first); + put_u32(&p[8], emb_arch_cycles_hz()); + put_u32(&p[12], s.overwritten); +} + +/* The events from *from up to (not including) end, in packets of consecutive events; *from moves + * past them. Events the ring overwrote before they were read are counted and skipped. */ +static void send_events(uint8_t *packet, uint32_t *from, uint32_t end) +{ + uint8_t *slot = &packet[PACKET_HEADER]; + while (*from != end) { /* bounded: each pass moves *from at least one event on */ + uint32_t first; + uint32_t n = 0u; + while ((*from != end) && !embs_trace_read(*from, slot)) { /* bounded by end */ + emb_irq_key_t key = emb_irq_lock(); + ring_stats.overwritten++; + emb_irq_unlock(key); + (*from)++; + } + first = *from; + while ((n < PACKET_EVENTS) && (*from != end) && + embs_trace_read(*from, &slot[n * EMB_TRACE_RECORD_SIZE])) { /* bounded by a packet */ + n++; + (*from)++; + } + if (n != 0u) { + emb_irq_key_t key; + packet_header(packet, EMB_TRACE_PACKET_EVENTS, n, first); + (void)emb_console_frame(EMB_FRAME_CHANNEL_TRACE, packet, + PACKET_HEADER + (n * EMB_TRACE_RECORD_SIZE)); + key = emb_irq_lock(); + ring_stats.sent += n; + emb_irq_unlock(key); + } + } +} + +#if CONFIG_EMB_THREAD_LIST && CONFIG_EMB_OBJ_NAMES +typedef struct names { + uint8_t *packet; + uint32_t len; + uint32_t count; +} names_t; + +static void name_one(emb_thread_t thread, void *arg) +{ + names_t *n = (names_t *)arg; + const char *name = emb_thread_name(thread); + uint32_t len = 0u; + uint32_t i; + while ((len < NAME_MAX) && (name != NULL) && (name[len] != '\0')) { /* bounded */ + len++; + } + if ((n->len + 2u + len) > NAMES_PAYLOAD_MAX) { + return; /* the packet is full: the rest stay "thread " on the host */ + } + n->packet[n->len] = emb_thread_index(thread); + n->packet[n->len + 1u] = (uint8_t)len; + for (i = 0u; i < len; i++) { /* bounded by NAME_MAX */ + n->packet[n->len + 2u + i] = (uint8_t)name[i]; + } + n->len += 2u + len; + n->count++; +} + +/* The threads' names, so the host shows names rather than indexes: from a thread only, where the + * thread list may be walked. */ +static void send_names(uint8_t *packet) +{ + names_t n; + n.packet = packet; + n.len = PACKET_HEADER; + n.count = 0u; + emb_thread_foreach(name_one, &n); + packet_header(packet, EMB_TRACE_PACKET_NAMES, n.count, 0u); + (void)emb_console_frame(EMB_FRAME_CHANNEL_TRACE, packet, n.len); +} +#endif + +static uint8_t dump_packet[PACKET_HEADER + (PACKET_EVENTS * EMB_TRACE_RECORD_SIZE)]; +static bool dumping; + +emb_status_t emb_trace_dump(void) +{ + uint32_t end; + uint32_t from; + emb_irq_key_t key; + bool busy; + if (!CONFIG_EMB_CONSOLE_FRAMED) { + return EMB_ENOTSUP; + } + key = emb_irq_lock(); + busy = dumping; + dumping = true; + end = ring_next; + emb_irq_unlock(key); + if (busy) { + return EMB_OK; /* a dump this one interrupted is sending the ring */ + } +#if CONFIG_EMB_THREAD_LIST && CONFIG_EMB_OBJ_NAMES + if ((emb_context() == EMB_CONTEXT_THREAD) && !emb_irq_is_locked()) { + send_names(dump_packet); + } +#endif + from = (end > RING_EVENTS) ? (end - RING_EVENTS) : 0u; + send_events(dump_packet, &from, end); + key = emb_irq_lock(); + dumping = false; + emb_irq_unlock(key); + return EMB_OK; +} + +/* ---- streaming ---------------------------------------------------------------------- */ + +#if CONFIG_EMB_TRACE_STREAM +static uint8_t stream_packet[PACKET_HEADER + (PACKET_EVENTS * EMB_TRACE_RECORD_SIZE)]; +static emb_thread_storage_t stream_storage; +EMB_THREAD_STACK(stream_stack, CONFIG_EMB_TRACE_STREAM_STACK); + +/* Sends the events since its last pass, every CONFIG_EMB_TRACE_STREAM_MS: what it causes itself + * (its wake-up, the console's lock) is traced too, and the period bounds it. */ +static void stream_thread(void *arg) +{ + uint32_t from = embs_trace_next(); + emb_instant_t next = emb_time_now(); + (void)arg; +#if CONFIG_EMB_THREAD_LIST && CONFIG_EMB_OBJ_NAMES + send_names(stream_packet); +#endif + for (;;) { /* bounded: the thread serves the ring for as long as the system runs */ + uint32_t end; + next = emb_instant_add(next, EMB_MS(CONFIG_EMB_TRACE_STREAM_MS)); + (void)emb_thread_sleep_until(next); + end = embs_trace_next(); + if ((end - from) > RING_EVENTS) { /* lapped: what was overwritten is lost */ + emb_irq_key_t key = emb_irq_lock(); + ring_stats.overwritten += (end - from) - RING_EVENTS; + emb_irq_unlock(key); + from = end - RING_EVENTS; + } + send_events(stream_packet, &from, end); + } +} + +static void stream_init(void) +{ + emb_thread_attr_t ta; + emb_thread_t th; + emb_thread_attr_default(&ta); + ta.name = "emb_trace"; + ta.stack = stream_stack; + ta.stack_size = sizeof(stream_stack); +#if CONFIG_EMB_TRACE_STREAM_PRIORITY == 0 + ta.priority = EMB_PRIORITY_MIN; +#else + ta.priority = (uint8_t)CONFIG_EMB_TRACE_STREAM_PRIORITY; +#endif + (void)emb_check_status(emb_thread_init(&stream_storage, &ta, stream_thread, NULL, &th), + "emb_trace stream thread"); + (void)emb_check_status(emb_thread_start(th), "emb_trace stream thread"); +} +EMB_INIT_TABLE_ENTRY(stream_init); +#endif + +#endif /* CONFIG_EMB_TRACE_RING */ diff --git a/tests/conformance/CMakeLists.txt b/tests/conformance/CMakeLists.txt index dd044826..4348cba2 100644 --- a/tests/conformance/CMakeLists.txt +++ b/tests/conformance/CMakeLists.txt @@ -52,6 +52,9 @@ endif() if(CONFIG_EMB_LOG) emb_add_test(test_log test_log.c) # OBS-001..003, OBS-013 (SPEC-015 §2, A127) endif() +if(CONFIG_EMB_TRACE_RING) + emb_add_test(test_trace_ring test_trace_ring.c) # OBS-005, OBS-007 (SPEC-015 §3, A128) +endif() if(CONFIG_EMB_DEVICE) emb_add_test(test_device test_device.c) # devices and driver requests (SPEC-016) if(CONFIG_EMB_DRV_UART) diff --git a/tests/conformance/test_trace_ring.c b/tests/conformance/test_trace_ring.c new file mode 100644 index 00000000..b3527e5f --- /dev/null +++ b/tests/conformance/test_trace_ring.c @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file test_trace_ring.c + * @brief The trace ring: what it keeps, in what order, and what it drops (SPEC-015 §3, A128). + * + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include +#include + +#include +#include +#include + +EMB_SEM_DEFINE(probe, 0u, 1000u); + +static uint8_t rec[EMB_TRACE_RECORD_SIZE]; + +static uint32_t le32(const uint8_t *p) +{ + return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); +} + +/* Event fields as a record carries them. */ +#define REC_TS(r) le32(&(r)[0]) +#define REC_ID(r) ((uint32_t)(r)[4] | ((uint32_t)(r)[5] << 8)) +#define REC_A(r, k) le32(&(r)[8u + (4u * (k))]) + +/* The number of the first event from @from with this id and object, or @end. */ +static uint32_t find(uint32_t from, uint32_t end, uint32_t id, uint32_t object) +{ + uint32_t s; + for (s = from; s != end; s++) { /* bounded by end */ + if (embs_trace_read(s, rec) && (REC_ID(rec) == id) && (REC_A(rec, 1u) == object)) { + return s; + } + } + return end; +} + +EMB_TEST(trace_ring_keeps_events_in_order) +{ + uint32_t start; + uint32_t end; + uint32_t give; + uint32_t take; + uint32_t s; + uint32_t prev = 0u; + uint32_t object = (uint32_t)(uintptr_t)probe.raw; + emb_trace_stats_t st; + EMB_TEST_REQ("OBS-005"); + EMB_ASSERT_OK(emb_trace_start()); + start = embs_trace_next(); + EMB_ASSERT_OK(emb_sem_give(probe)); + EMB_ASSERT_OK(emb_sem_take(probe, EMB_NO_WAIT)); + end = embs_trace_next(); + EMB_ASSERT_TRUE((end - start) >= 2u); + give = find(start, end, EMB_TRACE_SEM_GIVE, object); + take = find(start, end, EMB_TRACE_SEM_TAKE, object); + EMB_ASSERT_TRUE(give != end); + EMB_ASSERT_TRUE(take != end); + EMB_ASSERT_TRUE(give < take); + EMB_ASSERT_TRUE(embs_trace_read(take, rec)); + EMB_ASSERT_EQ(REC_A(rec, 2u), (uint32_t)EMB_OK); /* the take's status */ + /* times grow in the ring's order (the cycle counter, unwrapped over a short span) */ + for (s = start; s != end; s++) { /* bounded by end */ + EMB_ASSERT_TRUE(embs_trace_read(s, rec)); + if (s != start) { + EMB_ASSERT_TRUE((int32_t)(REC_TS(rec) - prev) >= 0); + } + prev = REC_TS(rec); + } + EMB_ASSERT_OK(emb_trace_stats_get(&st)); + EMB_ASSERT_TRUE(st.recorded >= (end - start)); + EMB_ASSERT_STATUS(emb_trace_stats_get(NULL), EMB_EINVAL); +} + +EMB_TEST(trace_ring_overwrites_the_oldest) +{ + uint32_t i; + uint32_t next; + EMB_TEST_REQ("OBS-005"); + EMB_ASSERT_OK(emb_trace_start()); + for (i = 0u; i < (2u * CONFIG_EMB_TRACE_RING_EVENTS); i++) { /* bounded: twice the ring */ + EMB_ASSERT_OK(emb_sem_give(probe)); + } + next = embs_trace_next(); + /* the newest CONFIG_EMB_TRACE_RING_EVENTS are kept, and nothing older */ + EMB_ASSERT_TRUE(embs_trace_read(next - 1u, rec)); + EMB_ASSERT_TRUE(embs_trace_read(next - CONFIG_EMB_TRACE_RING_EVENTS, rec)); + EMB_ASSERT_TRUE(!embs_trace_read(next - CONFIG_EMB_TRACE_RING_EVENTS - 1u, rec)); + EMB_ASSERT_TRUE(!embs_trace_read(next, rec)); /* not yet happened */ + for (i = 0u; i < (2u * CONFIG_EMB_TRACE_RING_EVENTS); i++) { /* bounded: the units given */ + EMB_ASSERT_OK(emb_sem_take(probe, EMB_NO_WAIT)); + } +} + +EMB_TEST(trace_ring_stops_and_dumps) +{ + uint32_t before; + EMB_TEST_REQ("OBS-007"); + EMB_ASSERT_OK(emb_trace_start()); + emb_trace_stop(); + before = embs_trace_next(); + EMB_ASSERT_OK(emb_sem_give(probe)); + EMB_ASSERT_OK(emb_sem_take(probe, EMB_NO_WAIT)); + EMB_ASSERT_EQ(embs_trace_next(), before); /* stopped: nothing recorded */ +#if CONFIG_EMB_CONSOLE_FRAMED + EMB_ASSERT_OK(emb_trace_dump()); +#else + EMB_ASSERT_STATUS(emb_trace_dump(), EMB_ENOTSUP); /* a plain console carries no frames */ +#endif + EMB_ASSERT_OK(emb_trace_start()); +} diff --git a/tools/fault/api-ids.json b/tools/fault/api-ids.json index bd11805f..4cbc6bd1 100644 --- a/tools/fault/api-ids.json +++ b/tools/fault/api-ids.json @@ -1477,6 +1477,36 @@ "name": "emb_console_frame", "header": "console.h", "state": "active" + }, + { + "id": 256, + "name": "emb_log_format_check_", + "header": "log.h", + "state": "active" + }, + { + "id": 257, + "name": "emb_trace_start", + "header": "trace.h", + "state": "active" + }, + { + "id": 258, + "name": "emb_trace_stop", + "header": "trace.h", + "state": "active" + }, + { + "id": 259, + "name": "emb_trace_dump", + "header": "trace.h", + "state": "active" + }, + { + "id": 260, + "name": "emb_trace_stats_get", + "header": "trace.h", + "state": "active" } ] } diff --git a/tools/fault/api-registry.json b/tools/fault/api-registry.json index ac0f2f51..0fb99b22 100644 --- a/tools/fault/api-registry.json +++ b/tools/fault/api-registry.json @@ -1476,6 +1476,36 @@ "name": "emb_console_frame", "header": "console.h", "state": "active" + }, + { + "id": 256, + "name": "emb_log_format_check_", + "header": "log.h", + "state": "active" + }, + { + "id": 257, + "name": "emb_trace_start", + "header": "trace.h", + "state": "active" + }, + { + "id": 258, + "name": "emb_trace_stop", + "header": "trace.h", + "state": "active" + }, + { + "id": 259, + "name": "emb_trace_dump", + "header": "trace.h", + "state": "active" + }, + { + "id": 260, + "name": "emb_trace_stats_get", + "header": "trace.h", + "state": "active" } ] } diff --git a/tools/trace/test_trace.py b/tools/trace/test_trace.py new file mode 100644 index 00000000..a4931c88 --- /dev/null +++ b/tools/trace/test_trace.py @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +"""tools/trace: the trace ring's packets, the counter's wraps, and the CTF and Perfetto outputs +(A128). Babeltrace 2 reads a trace this tool wrote in CI's application job.""" +import json +import shutil +import struct +import sys +import tempfile +import unittest +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +sys.path.insert(0, str(HERE.parent / "transport")) +import frame # noqa: E402 +import trace # noqa: E402 + + +def events_packet(first, events, hz=180_000_000, overwritten=0): + body = b"".join(trace.RECORD.pack(*e) for e in events) + return trace.HEADER.pack(1, trace.KIND_EVENTS, len(events), first, hz, overwritten) + body + + +def names_packet(names): + body = b"".join(bytes([i, len(n)]) + n.encode() for i, n in names) + return trace.HEADER.pack(1, trace.KIND_NAMES, len(names), 0, 180_000_000, 0) + body + + +class Catalogue(unittest.TestCase): + def test_reads_the_enum(self): + cat = trace.catalogue() + self.assertEqual(cat[1][0], "switch") + self.assertIn("from thread index", cat[1][1]) + self.assertEqual(cat[18][0], "sem_take") + + +class Packets(unittest.TestCase): + def test_capture_and_wraps(self): + evs = [(0xFFFF_FF00, 1, 0, 0, 1, 2, 0), (0x0000_0100, 18, 0, 0, 2, 0x2000, 0)] # wraps + data = (b"\x00" + frame.encode(3, b"boot text\n") + b"\x00" + + frame.encode(1, names_packet([(1, "producer"), (2, "consumer")])) + b"\x00" + + frame.encode(1, events_packet(10, evs)) + b"\x00" + + frame.encode(1, events_packet(14, [(0x200, 19, 0, 1, 255, 0x2000, 1)]))) + tr, dec = trace.read_capture(data) + self.assertEqual(len(tr.events), 3) + self.assertEqual(tr.events[1].cycles - tr.events[0].cycles, 0x200) # across the wrap + self.assertEqual(tr.names, {1: "producer", 2: "consumer"}) + self.assertEqual(tr.gaps, 1) # 12 and 13 are missing + self.assertEqual(dec.errors, 0) + + def test_a_bad_packet_is_refused(self): + with self.assertRaises(trace.TraceError): + trace.Trace().packet(trace.HEADER.pack(2, 0, 0, 0, 1, 0)) + with self.assertRaises(trace.TraceError): + trace.Trace().packet(trace.HEADER.pack(1, 0, 2, 0, 1, 0) + b"\x00" * 20) + + +class Outputs(unittest.TestCase): + def setUp(self): + self.d = Path(tempfile.mkdtemp(prefix="trace-")) + self.addCleanup(shutil.rmtree, self.d) + tr = trace.Trace() + tr.packet(names_packet([(1, "a"), (2, "b")])) + tr.packet(events_packet(0, [(100, 1, 0, 0, 1, 2, 0), (280, 10, 0, 1, 15, 0, 0), + (460, 11, 0, 1, 15, 0, 0), (640, 1, 0, 0, 2, 1, 0), + (900, 99, 0, 0, 0, 0, 0)], hz=1_000_000)) + self.tr = tr + self.cat = trace.catalogue() + + def test_ctf_layout(self): + out = trace.ctf(self.tr, self.cat, self.d / "ctf") + meta = (out / "metadata").read_text() + self.assertTrue(meta.startswith("/* CTF 1.8 */")) + self.assertIn("freq = 1000000;", meta) + self.assertIn('name = "switch";', meta) + self.assertIn('name = "event_99";', meta) # an id the catalogue does not name + stream = (out / "stream_0").read_bytes() + magic, _, sid = struct.unpack_from(", declared too.""" + out = Path(out_dir) + out.mkdir(parents=True, exist_ok=True) + cat = dict(cat) + for e in tr.events: + cat.setdefault(e.id, (f"event_{e.id}", "an event this catalogue does not name")) + tid = uuidlib.uuid4() + (out / "metadata").write_text(ctf_metadata(cat, tr.hz or 1, tid), encoding="utf-8") + stream = bytearray() + discarded = 0 + for i in range(0, len(tr.events), per_packet): + chunk = tr.events[i:i + per_packet] + body = bytearray() + for e in chunk: + body += struct.pack(" Date: Fri, 13 Nov 2026 05:05:06 +0100 Subject: [PATCH 12/25] tools: emb, the command-line tool: build, flash, monitor, hil, trace dump BLD-005's facade, from per-board defaults: a build directory knows its board, its image and its console (CMakeCache.txt, the board's hw.json), so flash, monitor, hil and trace dump need only -B. flash uses the board's own probe as run_hil.py does. monitor shows a plain console's text as it comes and decodes a framed one by channel: log records with the image's ELF (and --where for file and line), crash records, the shell's text, trace packets kept with --trace-out. trace dump turns the packets emb_trace_dump() sends into CTF and Perfetto's JSON. On the NUCLEO-F446RE: emb build --framed, emb flash and emb monitor showed examples/logging's records decoded, with their call sites. Signed-off-by: teo1747 --- .github/workflows/ci.yml | 2 + scripts/emb | 10 + tools/emb/emb.py | 438 +++++++++++++++++++++++++++++++++++++++ tools/emb/test_emb.py | 113 ++++++++++ 4 files changed, 563 insertions(+) create mode 100755 scripts/emb create mode 100755 tools/emb/emb.py create mode 100644 tools/emb/test_emb.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54640275..b79be07b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -390,6 +390,8 @@ jobs: run: python3 -I -m unittest discover -s tools/logdec -p 'test_*.py' -v - name: Trace converter's tests (A128) run: python3 -I -m unittest discover -s tools/trace -p 'test_*.py' -v + - name: The emb command-line tool's tests (BLD-005) + run: python3 -I -m unittest discover -s tools/emb -p 'test_*.py' -v - name: EmbSIM runner, its project mode (SIM-002) run: python3 -I -m unittest discover -s tools/embsim -p 'test_*.py' -v - name: UF2 writer (A79) diff --git a/scripts/emb b/scripts/emb new file mode 100755 index 00000000..476050a6 --- /dev/null +++ b/scripts/emb @@ -0,0 +1,10 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +# emb: the command-line tool (BLD-005), tools/emb/emb.py. Put scripts/ on PATH, or call it here. +here=$(cd "$(dirname "$0")" && pwd) +exec "${EMB_PYTHON:-python3}" "$here/../tools/emb/emb.py" "$@" diff --git a/tools/emb/emb.py b/tools/emb/emb.py new file mode 100755 index 00000000..4f351602 --- /dev/null +++ b/tools/emb/emb.py @@ -0,0 +1,438 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +"""emb: build, flash, watch and test an EmbLinkRTOS image (BLD-005, SPEC-015 §10). + + emb build -b nucleo_f446re -S examples/logging # configure and build, per-board defaults + emb build -b nucleo_f446re -S examples/logging --framed --clang + emb flash -B build/logging-nucleo_f446re # the board's own probe (hw.json) + emb monitor -B build/logging-nucleo_f446re # the console: frames decoded + emb hil -B build/nucleo-hil -R test_log # the suite on the board (ctest) + emb trace dump -B build/tracing-nucleo_f446re --ctf out/trace --perfetto out/trace.json + +A build directory knows its board, its image and its console (CMakeCache.txt, the board's +hw.json), so the other commands need only -B. The monitor shows the console's text as it comes, +and on a framed console (A127) decodes each channel: the log's records with the image's ELF +(tools/logdec), the crash record (tools/crashdec), the trace's packets (tools/trace, kept with +--trace-out), the shell's text. Bytes that are not a frame are shown as they are. +""" +import argparse +import os +import select +import shlex +import shutil +import subprocess +import sys +import time +from pathlib import Path + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +for sub in ("transport", "logdec", "crashdec", "trace", "hil"): + sys.path.insert(0, str(HERE.parent / sub)) +import frame as framing # noqa: E402 + +CH_LOG, CH_TRACE, CH_CRASH, CH_SHELL = 0, 1, 2, 3 +CLANG_TOOLCHAIN = {"cortex_m": "arm-none-eabi-clang", "riscv": "riscv-clang", "avr": "avr-clang", + "xtensa": "xtensa-esp32-clang", "native": "native-clang"} + + +class EmbError(Exception): + pass + + +# --------------------------------------------------------------------------- the build tree + +def cache(build): + """The CMake cache of a build directory: {name: value}.""" + path = Path(build) / "CMakeCache.txt" + if not path.is_file(): + raise EmbError(f"{build}: not a configured build directory (no CMakeCache.txt): run emb build") + out = {} + for line in path.read_text(encoding="utf-8", errors="replace").splitlines(): + if line and not line.startswith(("#", "//")) and "=" in line and ":" in line.split("=", 1)[0]: + key, value = line.split("=", 1) + out[key.split(":", 1)[0]] = value + return out + + +def board_dir(name): + """A board of the tree by name: the directory whose board.yaml it is.""" + found = [p.parent for p in (ROOT / "boards").glob("*/*/board.yaml") if p.parent.name == name] + if len(found) != 1: + raise EmbError(f"board {name!r}: {'not found' if not found else 'more than one'} under boards/") + return found[0] + + +def hw_json(build): + """The board's generated hw.json for a build directory.""" + import json + c = cache(build) + for key in ("EMB_BOARD_HW_JSON",): + if c.get(key) and Path(c[key]).is_file(): + return json.loads(Path(c[key]).read_text(encoding="utf-8")) + bdir = Path(c.get("EMB_BOARD_DIR") or board_dir(c.get("EMB_BOARD", ""))) + for cand in (bdir / "hw.json", bdir / "generated" / "hw.json", bdir / "docs" / "hw.json"): + if cand.is_file(): + return json.loads(cand.read_text(encoding="utf-8")) + raise EmbError(f"{build}: no hw.json for board {c.get('EMB_BOARD')}") + + +def image(build, name=None): + """The image a build made: the one named, or the only one at the top of the build tree.""" + b = Path(build) + if name: + p = Path(name) + return p if p.is_file() else b / name + project = cache(build).get("CMAKE_PROJECT_NAME", "") + for cand in (b / f"{project}.elf", b / project): + if project and cand.is_file(): + return cand + elves = sorted(b.glob("*.elf")) + if len(elves) == 1: + return elves[0] + raise EmbError(f"{build}: name the image (found {len(elves)} at the top of the build directory)") + + +def console_port(build=None, given=None): + """The console's serial device: as given, as the build was configured (EMB_HIL_PORT), as + EMB_PORT says, or the only USB serial device there is.""" + if given: + return given + if build: + p = cache(build).get("EMB_HIL_PORT") + if p: + return p + if os.environ.get("EMB_PORT"): + return os.environ["EMB_PORT"] + devs = sorted(str(p) for pat in ("cu.usbmodem*", "cu.usbserial*", "ttyACM*", "ttyUSB*") + for p in Path("/dev").glob(pat)) + if len(devs) == 1: + return devs[0] + raise EmbError(f"which console? found {devs or 'no serial device'}: give --port or set EMB_PORT") + + +# ----------------------------------------------------------------------------- commands + +def build_command(args): + """The cmake invocations for emb build, as lists.""" + src = Path(args.source).resolve() + out = Path(args.build or f"build/{src.name}-{args.board}") + conf = ["cmake", "-S", str(src), "-B", str(out), "-G", "Ninja", f"-DEMB_BOARD={args.board}"] + sets = list(args.set or []) + if args.framed: + sets.append("EMB_CONSOLE_FRAMED=y") + if sets: + conf.append("-DEMB_SET=" + ";".join(sets)) + if args.hil: + conf.append("-DEMB_TEST_EMULATOR=hil") + if args.port: + conf.append(f"-DEMB_HIL_PORT={args.port}") + if args.clang: + import json + hw = json.loads((board_dir(args.board) / "generated" / "hw.json").read_text(encoding="utf-8")) + tc = CLANG_TOOLCHAIN.get(hw["soc"]["arch"]["port"]) + if tc is None: + raise EmbError(f"no Clang toolchain file for {hw['soc']['arch']['port']}") + conf.append(f"-DCMAKE_TOOLCHAIN_FILE={ROOT / 'cmake' / 'toolchains' / (tc + '.cmake')}") + if src != ROOT: + conf.append(f"-DEmbLinkRTOS_DIR={ROOT / 'cmake'}") + try: + import yaml # noqa: F401 the build's configuration step needs PyYAML + conf.append(f"-DPython3_EXECUTABLE={sys.executable}") + except ImportError: + pass + conf += [f"-D{d}" for d in (args.define or [])] + return [conf, ["cmake", "--build", str(out)]], out + + +def run(cmd, dry): + print("$ " + " ".join(shlex.quote(c) for c in cmd), file=sys.stderr) + if dry: + return 0 + return subprocess.run(cmd).returncode + + +def cmd_build(args): + cmds, out = build_command(args) + for c in cmds: + rc = run(c, args.dry_run) + if rc: + return rc + if not args.dry_run: + print(f"emb: built {out}", file=sys.stderr) + return 0 + + +def cmd_flash(args): + import run_hil + hw = hw_json(args.build) + img = image(args.build, args.image) + port = console_port(args.build, args.port) if ("avrdude" in hw["board"].get("debug_probe", {}) or + "esp" in hw["board"].get("debug_probe", {})) else None + if run_hil.uses_picotool(hw) and not args.dry_run: + problem = run_hil.wait_bootsel(args.timeout) + if problem: + raise EmbError(problem) + cmd = run_hil.flash_command(hw, img, args.flash_cmd, port) + return run(cmd, args.dry_run) + + +class Console: + """The console's bytes into what to show: text as it comes, frames when they end. A framed + console precedes each frame with a zero (A127), so bytes after a zero wait for the next zero + and are a frame if they decode; bytes before any zero are a plain console's text.""" + + def __init__(self, max_payload=4096): + self.framing = False + self.buf = bytearray() + self.max = max_payload + 3 + self.frames = self.errors = 0 + + def feed(self, data): + out = [] + for b in data: + if not self.framing: + if b == 0: + if self.buf: + out.append(("text", bytes(self.buf))) + self.buf = bytearray() + self.framing = True + else: + self.buf.append(b) + continue + if b != 0: + self.buf.append(b) + if len(self.buf) > self.max * 2: # no frame is this long: text after all + out.append(("text", bytes(self.buf))) + self.buf = bytearray() + continue + if self.buf: + try: + ch, payload = framing.decode(bytes(self.buf)) + out.append(("frame", ch, payload)) + self.frames += 1 + except framing.FrameError: + if framing._texty(self.buf): + out.append(("text", bytes(self.buf))) + else: + self.errors += 1 + self.buf = bytearray() + if not self.framing and self.buf: # a plain console: show it now + out.append(("text", bytes(self.buf))) + self.buf = bytearray() + return out + + +class Monitor: + """What each channel's payload shows as.""" + + def __init__(self, elf=None, where=False, trace_out=None, write=sys.stdout.write): + self.write = write + self.stream = None + self.trace_out = trace_out + self.trace_packets = 0 + self.note = None + if elf: + import logdec + try: + self.stream = logdec.Stream(logdec.LogDb(elf), where) + except logdec.LogError as e: + self.note = f"emb: no log records decoded: {e}" + + def show(self, item): + if item[0] == "text": + self.write(item[1].decode(errors="replace")) + return + _, ch, payload = item + if ch == CH_SHELL: + self.write(payload.decode(errors="replace")) + elif ch == CH_LOG: + if self.stream is None: + self.write(f"(log records, {len(payload)} bytes: give --elf to decode them)\n") + else: + for line in self.stream.records(payload): + self.write(line + "\n") + elif ch == CH_TRACE: + self.trace_packets += 1 + if self.trace_out is not None: + self.trace_out.write(b"\x00" + framing.encode(CH_TRACE, payload)) + elif ch == CH_CRASH: + import crashdec + try: + self.write(crashdec.text(crashdec.parse(payload)) + "\n") + except Exception as e: # noqa: BLE001 a damaged record is shown, not fatal + self.write(f"(a crash record that does not decode: {e})\n") + else: + self.write(f"(channel {ch}: {payload.hex()})\n") + + +def read_console(port, baud, seconds, until, sink): + """Reads the console until --seconds pass, --until's text is seen, or Ctrl-C.""" + import run_hil + fd = run_hil.open_console(port, baud) + end = time.monotonic() + seconds if seconds else None + seen = b"" + try: + while end is None or time.monotonic() < end: + r, _, _ = select.select([fd], [], [], 0.2) + if not r: + continue + try: + chunk = os.read(fd, 4096) + except BlockingIOError: + continue + sink(chunk) + if until: + seen = (seen + chunk)[-(len(until) + 4096):] + if until.encode() in seen: + return True + except KeyboardInterrupt: + pass + finally: + os.close(fd) + return not until + + +def cmd_monitor(args): + hw = hw_json(args.build) if args.build else None + baud = args.baud or (hw["board"]["console"]["baud"] if hw else 115200) + port = console_port(args.build, args.port) + elf = args.elf or (str(image(args.build)) if args.build else None) + trace_out = open(args.trace_out, "wb") if args.trace_out else None # noqa: SIM115 + mon = Monitor(elf, args.where, trace_out) + if mon.note: + print(mon.note, file=sys.stderr) + con = Console() + log = open(args.log, "wb") if args.log else None # noqa: SIM115 + + def sink(chunk): + if log: + log.write(chunk) + for item in con.feed(chunk): + mon.show(item) + sys.stdout.flush() + + if args.input: + sink(Path(args.input).read_bytes()) + ok = True + else: + print(f"emb: {port} at {baud} baud; Ctrl-C ends", file=sys.stderr) + ok = read_console(port, baud, args.seconds, args.until, sink) + for f in (log, trace_out): + if f: + f.close() + print(f"emb: {con.frames} frames, {con.errors} damaged, {mon.trace_packets} trace packets", file=sys.stderr) + return 0 if ok else 1 + + +def cmd_hil(args): + cmd = ["ctest", "--test-dir", str(args.build), "--output-on-failure"] + if args.regex: + cmd += ["-R", args.regex] + if not args.dry_run: + c = cache(args.build) + if c.get("EMB_TEST_EMULATOR") != "hil": + raise EmbError(f"{args.build} was not configured for the board: emb build --hil --port ...") + return run(cmd, args.dry_run) + + +def cmd_trace_dump(args): + """The trace packets an image sends (emb_trace_dump()) from the console or a capture, written + as CTF and Perfetto's JSON.""" + import trace + if args.input: + data = Path(args.input).read_bytes() + else: + hw = hw_json(args.build) + chunks = [] + read_console(console_port(args.build, args.port), hw["board"]["console"]["baud"], args.seconds, + args.until, chunks.append) + data = b"".join(chunks) + tr, dec = trace.read_capture(data) + if not tr.events: + raise EmbError("no trace packets on channel 1: does the image call emb_trace_dump()?") + cat = trace.catalogue() + if args.ctf: + trace.ctf(tr, cat, args.ctf) + if args.perfetto: + import json + Path(args.perfetto).write_text(json.dumps(trace.perfetto(tr, cat)), encoding="utf-8") + if not (args.ctf or args.perfetto): + sys.stdout.write(trace.text(tr, cat)) + print(f"emb: {len(tr.events)} events, {len(tr.names)} thread names, {tr.gaps} gaps", file=sys.stderr) + return 0 + + +def main(argv=None): + ap = argparse.ArgumentParser(prog="emb", description=__doc__.split("\n")[0], + epilog=__doc__.split("\n\n", 1)[1], formatter_class=argparse.RawDescriptionHelpFormatter) + sub = ap.add_subparsers(dest="command", required=True) + + b = sub.add_parser("build", help="configure and build for a board") + b.add_argument("-b", "--board", required=True) + b.add_argument("-S", "--source", default=".", help="the application, or the RTOS tree for its tests") + b.add_argument("-B", "--build", help="the build directory (default build/-)") + b.add_argument("--clang", action="store_true", help="Clang and LLD instead of the board's GCC") + b.add_argument("--framed", action="store_true", help="the framed console (A127)") + b.add_argument("--hil", action="store_true", help="run the tests on the board (EMB_TEST_EMULATOR=hil)") + b.add_argument("--port", help="the board's console, for --hil") + b.add_argument("--set", action="append", metavar="SYMBOL=VALUE", help="a Kconfig symbol (repeatable)") + b.add_argument("-D", "--define", action="append", metavar="VAR=VALUE", help="a CMake variable") + b.add_argument("-n", "--dry-run", action="store_true", help="print the commands only") + b.set_defaults(func=cmd_build) + + f = sub.add_parser("flash", help="program the image with the board's probe") + f.add_argument("-B", "--build", required=True) + f.add_argument("image", nargs="?", help="default: the build's only image") + f.add_argument("--port", help="the serial port, for boards flashed through it") + f.add_argument("--flash-cmd", help="a command of your own, {image} and {port} replaced") + f.add_argument("--timeout", type=float, default=30.0, help="seconds to wait for BOOTSEL") + f.add_argument("-n", "--dry-run", action="store_true") + f.set_defaults(func=cmd_flash) + + m = sub.add_parser("monitor", help="show the console, frames decoded") + m.add_argument("-B", "--build", help="the build: its image, its board's console") + m.add_argument("--port") + m.add_argument("--baud", type=int) + m.add_argument("--elf", help="the image whose log records to decode (default: the build's)") + m.add_argument("--where", action="store_true", help="each log record's file and line") + m.add_argument("--seconds", type=float, help="stop after this long") + m.add_argument("--until", help="stop once this text is seen") + m.add_argument("--log", help="also keep the raw bytes") + m.add_argument("--trace-out", help="keep the trace packets, for emb trace dump --input") + m.add_argument("--input", help="a capture instead of the port") + m.set_defaults(func=cmd_monitor) + + h = sub.add_parser("hil", help="run a build's tests on the board (ctest)") + h.add_argument("-B", "--build", required=True) + h.add_argument("-R", "--regex", help="the tests whose names match") + h.add_argument("-n", "--dry-run", action="store_true") + h.set_defaults(func=cmd_hil) + + t = sub.add_parser("trace", help="the trace ring") + tsub = t.add_subparsers(dest="trace_command", required=True) + td = tsub.add_parser("dump", help="the packets emb_trace_dump() sends, as CTF or Perfetto JSON") + td.add_argument("-B", "--build") + td.add_argument("--port") + td.add_argument("--input", help="a capture (emb monitor --log or --trace-out) instead of the port") + td.add_argument("--seconds", type=float, default=30.0) + td.add_argument("--until", help="stop once this text is seen") + td.add_argument("--ctf", metavar="DIR") + td.add_argument("--perfetto", metavar="FILE") + td.set_defaults(func=cmd_trace_dump) + + args = ap.parse_args(argv) + try: + return args.func(args) + except EmbError as e: + print(f"emb: {e}", file=sys.stderr) + return 2 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/emb/test_emb.py b/tools/emb/test_emb.py new file mode 100644 index 00000000..3936f158 --- /dev/null +++ b/tools/emb/test_emb.py @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +"""tools/emb: the console's decoding, the build's commands and what a build directory says +(BLD-005, A127).""" +import io +import shutil +import struct +import sys +import tempfile +import unittest +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +sys.path.insert(0, str(HERE.parent / "transport")) +import emb # noqa: E402 +import frame # noqa: E402 + + +class ConsoleDecoding(unittest.TestCase): + def test_a_plain_console_shows_at_once(self): + c = emb.Console() + self.assertEqual(c.feed(b"hello "), [("text", b"hello ")]) + self.assertEqual(c.feed(b"world\n"), [("text", b"world\n")]) + + def test_frames_after_text(self): + c = emb.Console() + out = c.feed(b"ROM boot\n" + b"\x00" + frame.encode(3, b"hi\n") + b"\x00" + frame.encode(0, b"\x08\x00")) + self.assertEqual(out, [("text", b"ROM boot\n"), ("frame", 3, b"hi\n"), ("frame", 0, b"\x08\x00")]) + self.assertEqual(c.frames, 2) + + def test_a_frame_split_across_reads(self): + c = emb.Console() + wire = b"\x00" + frame.encode(3, b"split") + self.assertEqual(c.feed(wire[:4]), []) + self.assertEqual(c.feed(wire[4:]), [("frame", 3, b"split")]) + + def test_damage_is_counted_and_text_kept(self): + c = emb.Console() + bad = bytearray(frame.encode(0, b"\x01\x02\x03")) + bad[1] ^= 0x55 + out = c.feed(b"\x00" + bytes(bad) + b"cut text\x00") + self.assertEqual(out, [("text", b"cut text")]) + self.assertEqual(c.errors, 1) + + +class Monitor(unittest.TestCase): + def test_channels(self): + buf = io.StringIO() + m = emb.Monitor(write=buf.write) + m.show(("frame", 3, b"shell text\n")) + m.show(("frame", 0, b"\x08\x00\x00\x00\x00\x00")) + m.show(("text", b"raw\n")) + m.show(("frame", 1, b"x" * 16)) + self.assertEqual(buf.getvalue(), "shell text\n(log records, 6 bytes: give --elf to decode them)\nraw\n") + self.assertEqual(m.trace_packets, 1) + + +class BuildCommands(unittest.TestCase): + def args(self, **kw): + base = dict(board="nucleo_f446re", source=str(emb.ROOT / "examples" / "logging"), build=None, + clang=False, framed=False, hil=False, port=None, set=None, define=None, dry_run=True) + base.update(kw) + return type("A", (), base)() + + def test_an_application(self): + (conf, build), out = emb.build_command(self.args(framed=True, set=["EMB_TRACE=y"])) + self.assertEqual(out, Path("build/logging-nucleo_f446re")) + self.assertIn("-DEMB_BOARD=nucleo_f446re", conf) + self.assertIn("-DEMB_SET=EMB_TRACE=y;EMB_CONSOLE_FRAMED=y", conf) + self.assertTrue(any(c.startswith("-DEmbLinkRTOS_DIR=") for c in conf)) + self.assertEqual(build, ["cmake", "--build", "build/logging-nucleo_f446re"]) + + def test_clang_and_the_board_suite(self): + (conf, _), _ = emb.build_command(self.args(source=str(emb.ROOT), clang=True, hil=True, + port="/dev/cu.usbmodem1", build="build/x")) + self.assertIn("-DEMB_TEST_EMULATOR=hil", conf) + self.assertIn("-DEMB_HIL_PORT=/dev/cu.usbmodem1", conf) + self.assertTrue(any(c.endswith("arm-none-eabi-clang.cmake") for c in conf)) + self.assertFalse(any(c.startswith("-DEmbLinkRTOS_DIR=") for c in conf)) + + def test_an_unknown_board(self): + with self.assertRaises(emb.EmbError): + emb.build_command(self.args(board="no_such_board", clang=True)) + + +class BuildDirectory(unittest.TestCase): + def setUp(self): + self.d = Path(tempfile.mkdtemp(prefix="emb-")) + self.addCleanup(shutil.rmtree, self.d) + + def test_cache_image_and_port(self): + (self.d / "CMakeCache.txt").write_text( + "# comment\n//help\nCMAKE_PROJECT_NAME:STATIC=logging\nEMB_HIL_PORT:STRING=/dev/cu.x\n" + "EMB_BOARD:STRING=nucleo_f446re\n") + (self.d / "logging.elf").write_bytes(b"\x7fELF") + self.assertEqual(emb.cache(self.d)["EMB_BOARD"], "nucleo_f446re") + self.assertEqual(emb.image(self.d), self.d / "logging.elf") + self.assertEqual(emb.console_port(self.d), "/dev/cu.x") + self.assertEqual(emb.console_port(self.d, "/dev/given"), "/dev/given") + self.assertEqual(emb.hw_json(self.d)["board"]["console"]["baud"], 115200) + + def test_not_a_build(self): + with self.assertRaises(emb.EmbError): + emb.cache(self.d) + + +if __name__ == "__main__": + unittest.main() From f7524317abe83311f28c16dc876e341dbb240466 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:07:40 +0100 Subject: [PATCH 13/25] tools: the NUCLEO relay works both ways, with bench controls The relay passed the other board's TX to the ST-LINK's port only. Now the host's bytes go out of PA9 to the other board too, every byte as it is, each way through a ring of its own so a busy direction never holds up the other: the shell and update channels can reach the board. It also reads the host's stream for frames on channel 15, passed on as well, and drives three bench pins: a reset (PA8, 20 ms low), a power cut (PB5) and a wake-up pulse (PB4). The reset and the power cut are released as inputs so the other board's pull-ups hold its pins. Each command is answered with a channel-15 frame between two of the other board's frames, never cutting one. On the NUCLEO-F446RE: ping and wake answered ok, an unknown command '?'. Signed-off-by: teo1747 --- docs/engineering/hil.md | 9 +- tools/hil/nucleo-uart-relay/relay.c | 355 +++++++++++++++++++++++++--- 2 files changed, 335 insertions(+), 29 deletions(-) diff --git a/docs/engineering/hil.md b/docs/engineering/hil.md index 0fad9c18..3d3fcc59 100644 --- a/docs/engineering/hil.md +++ b/docs/engineering/hil.md @@ -71,12 +71,19 @@ The Pico 2 W's USB port is the boot ROM's loader, not a console. The console is **Or the NUCLEO-F446RE's ST-LINK, through a relay.** Its morpho headers are male, so female-female jumper wires fit, and its ST-LINK has a virtual COM port. The STM32 relays the other board's UART to it in software, because on a stock NUCLEO the header pins named PA2 and PA3 (CN10 pins 35 and 37, Arduino D1 and D0) are not connected to the STM32: solder bridges SB62 and SB63 are open, and the ST-LINK keeps PA2 and PA3 for itself. -`tools/hil/nucleo-uart-relay/build.sh --flash` programs the relay: USART1 receives on PA10, and every byte goes out of USART2 to the ST-LINK's port, at 115200 8N1. The green LED toggles on each byte. Hold the NUCLEO with its USB connector at the top, and use the right-hand double header, CN10, in its inner column, the one nearer the STM32: +`tools/hil/nucleo-uart-relay/build.sh --flash` programs the relay. It works both ways, every byte as it is, at 115200 8N1: what the other board sends on PA10 (USART1 RX) goes out to the ST-LINK's port, and what the host sends to the port goes out of PA9 (USART1 TX) to the other board. Each way has a ring of its own, so a busy direction never holds up the other. The green LED toggles on each byte from the other board. Hold the NUCLEO with its USB connector at the top, and use the right-hand double header, CN10, in its inner column, the one nearer the STM32: | Wire | From | To | |---|---|---| | 1 | Pico 2 W pin 1, GPIO0 (UART0 TX) | CN10 pin 33, PA10: the inner column's 17th pin from the top, the third from the bottom | | 2 | Pico 2 W pin 3, GND | CN10 pin 9: the inner column's 5th pin from the top. The 4th is AVDD, the STM32's 3.3 V: a ground wire there shorts it. | +| 3 | CN10 pin 21, PA9: the inner column's 11th pin from the top | Pico 2 W pin 2, GPIO1 (UART0 RX): the host's way to the board, for the shell and update channels | + +**Bench controls.** The relay also drives three pins for the bench, which later phases wire up: a reset (CN10 pin 23, PA8, to the Pico 2 W's RUN, pin 30), a power cut (CN10 pin 29, PB5, to its 3V3_EN, pin 37) and a wake-up pulse (CN10 pin 27, PB4). The reset and the power cut are released as inputs, so the Pico's own pull-ups hold its pins; the wake pin is driven low between pulses. The host commands them with SPEC-015 §7 frames on channel 15, which the relay reads from the host's stream and still passes on (an image under test leaves channel 15 alone): `reset` (20 ms low), `power off`, `power on`, `power cycle `, `wake ` and `ping`. Each is answered with a channel-15 frame, `ok ` or `? `, sent between two of the other board's frames so it never cuts one: + +```sh +python3 -c "import sys; sys.path.insert(0, 'tools/transport'); import frame; sys.stdout.buffer.write(b'\0' + frame.encode(15, b'reset'))" > /dev/cu.usbmodem31103 +``` The console is then the NUCLEO's port, `/dev/cu.usbmodem*`. A wire one pin off is easy to place. Before the first run, put the other board's TX on PA5 (the 6th pin) for a moment: if the board drives it high, the NUCLEO's green LED lights. diff --git a/tools/hil/nucleo-uart-relay/relay.c b/tools/hil/nucleo-uart-relay/relay.c index f518a1f8..f3ab6b8f 100644 --- a/tools/hil/nucleo-uart-relay/relay.c +++ b/tools/hil/nucleo-uart-relay/relay.c @@ -7,34 +7,67 @@ /** * @file relay.c - * @brief The NUCLEO-F446RE as a 3.3 V USB-UART for another board's console - * (docs/engineering/hil.md). + * @brief The NUCLEO-F446RE as a two-way 3.3 V USB-UART for another board, with bench controls + * (docs/engineering/hil.md, M4.3). * * @details - * USART1 receives on PA10 (CN10 pin 33) and every byte goes out of USART2 (PA2) to the ST-LINK's - * virtual COM port, both at 115200 8N1. The header pins named PA2 and PA3 (CN10 pins 35 and 37, - * Arduino D1 and D0) are not connected to the STM32 on a stock board (SB62 and SB63 open), which is - * why the relay exists. PA10 idles high through a pull-up when nothing drives it; a break (the line - * held low) is not relayed. The green LED (PA5) toggles on each byte. build.sh links it with the - * board's own clock, pin and USART drivers and its regions.ld. + * Both ways at 115200 8N1, every byte as it is: the other board's TX on PA10 (USART1 RX, CN10 pin + * 33) goes out of USART2 (PA2) to the ST-LINK's virtual COM port, and what the host sends to the + * port (USART2 RX, PA3) goes out of PA9 (USART1 TX, CN10 pin 21, Arduino D8) to the other board's + * RX. Each way has a ring of its own and the main loop moves a byte only when its transmitter is + * free, so a busy direction never holds up the other. The header pins named PA2 and PA3 (CN10 + * pins 35 and 37, Arduino D1 and D0) are not connected to the STM32 on a stock board (SB62 and + * SB63 open), which is why the relay exists. PA10 idles high through a pull-up when nothing drives + * it; a break (the line held low) is not relayed. + * + * Bench controls: the relay watches the host's stream for SPEC-015 §7 frames on channel 15 and + * acts on their text, which it also passes on (an image under test leaves channel 15 alone): + * "reset" PA8 (Arduino D7) low for 20 ms: the other board's RUN or NRST + * "power off|on" PB5 (Arduino D4) low, or released: the other board's regulator enable + * "power cycle N" PB5 low for N ms, then released + * "wake N" PB4 (Arduino D5) high for N us: a wake-up pin + * "ping" nothing but the reply + * Each control pin is open drain when released (the other board's pull-up holds it), except + * the wake pin, which is driven. The reply is a channel-15 frame, "ok " or "? ", + * sent toward the host only between two frames of the other board, so it never cuts one. The + * green LED (PA5) toggles on each byte. build.sh links it with the board's own clock, pin and + * USART drivers and its regions.ld. * * @author Junior Deogracias * @date 2026-11-07 (created) */ +#include #include #include #include -#define REG32(a) (*(volatile uint32_t *)(uintptr_t)(a)) -#define USART_SR 0x00u -#define USART_DR 0x04u -#define USART_CR1 0x0Cu -#define SR_RXNE (1u << 5) -#define SR_ORE (1u << 3) -#define SR_FE (1u << 1) -#define GPIOA_PUPDR (EMB_HW_GPIOA_BASE + 0x0Cu) -#define CR1_RE (1u << 2) +#define REG32(a) (*(volatile uint32_t *)(uintptr_t)(a)) + +#define USART_SR 0x00u +#define USART_DR 0x04u +#define USART_CR1 0x0Cu +#define SR_TXE (1u << 7) +#define SR_RXNE (1u << 5) +#define SR_ORE (1u << 3) +#define SR_FE (1u << 1) +#define CR1_RE (1u << 2) +#define CR1_TE (1u << 3) + +#define GPIO_MODER 0x00u +#define GPIO_PUPDR 0x0Cu +#define GPIO_BSRR 0x18u + +#define DEMCR 0xE000EDFCu +#define DWT_CTRL 0xE0001000u +#define DWT_CYCCNT 0xE0001004u +#define CYCLES_PER_MS (EMB_HW_CPU_HZ / 1000u) +#define CYCLES_PER_US (EMB_HW_CPU_HZ / 1000000u) + +#define RING 512u /* a power of two: two frames' worth either way */ +#define CMD_MAX 48u +#define CH_BENCH 15u +#define CRC_POLY 0x1021u extern uint32_t __data_load[], __data_start[], __data_end[], __bss_start[], __bss_end[]; void embn_cm_reset(void); @@ -62,6 +95,7 @@ __attribute__((section(".vectors"), used)) static const vector_t vectors[16] = { static const emb_stm32_pin_t pins[] = { {EMB_STM32_PORT(A), 2u, EMB_STM32_PIN_AF, 7u, 0u, 0u}, /* USART2_TX to the ST-LINK */ {EMB_STM32_PORT(A), 3u, EMB_STM32_PIN_AF, 7u, 0u, 0u}, /* USART2_RX from the ST-LINK */ + {EMB_STM32_PORT(A), 9u, EMB_STM32_PIN_AF, 7u, 0u, 0u}, /* USART1_TX to the other board */ {EMB_STM32_PORT(A), 10u, EMB_STM32_PIN_AF, 7u, 0u, 0u}, /* USART1_RX from the other board */ {EMB_STM32_PORT(A), 5u, EMB_STM32_PIN_OUTPUT, 0u, 0u, 0u}, }; @@ -79,6 +113,242 @@ void embn_cm_reset(void) hang(); } +/* ---- a ring per direction ----------------------------------------------------------- */ + +typedef struct ring { + uint8_t buf[RING]; + uint32_t head; + uint32_t tail; + uint32_t lost; /* bytes dropped when it was full */ +} ring_t; + +static ring_t to_host; /* the other board -> the ST-LINK */ +static ring_t to_board; /* the host -> the other board */ + +static void ring_put(ring_t *r, uint8_t b) +{ + if ((r->head - r->tail) < RING) { + r->buf[r->head & (RING - 1u)] = b; + r->head++; + } else { + r->lost++; + } +} + +static bool ring_get(ring_t *r, uint8_t *b) +{ + if (r->head == r->tail) { + return false; + } + *b = r->buf[r->tail & (RING - 1u)]; + r->tail++; + return true; +} + +/* ---- pins and time ------------------------------------------------------------------ */ + +static uint32_t now(void) +{ + return REG32(DWT_CYCCNT); +} + +/* Output low (or high), or released: an input, so the other board's pull-up holds the line. */ +static void pin_drive(uintptr_t port, unsigned pin, bool high) +{ + REG32(port + GPIO_BSRR) = high ? (1u << pin) : (1u << (pin + 16u)); + REG32(port + GPIO_MODER) = (REG32(port + GPIO_MODER) & ~(3u << (2u * pin))) | (1u << (2u * pin)); +} + +static void pin_release(uintptr_t port, unsigned pin) +{ + REG32(port + GPIO_MODER) &= ~(3u << (2u * pin)); +} + +/* A pin to release later, without stopping the bytes meanwhile. */ +typedef struct pulse { + uintptr_t port; + unsigned pin; + uint32_t until; + bool active; + bool drive_low_after; /* the wake pin is driven, low, between pulses */ +} pulse_t; + +static pulse_t reset_pulse = {EMB_HW_GPIOA_BASE, 8u, 0u, false, false}; +static pulse_t power_pulse = {EMB_HW_GPIOB_BASE, 5u, 0u, false, false}; +static pulse_t wake_pulse = {EMB_HW_GPIOB_BASE, 4u, 0u, false, true}; + +static void pulse_start(pulse_t *p, bool high, uint32_t cycles) +{ + pin_drive(p->port, p->pin, high); + p->until = now() + cycles; + p->active = true; +} + +static void pulse_poll(pulse_t *p) +{ + if (p->active && ((int32_t)(now() - p->until) >= 0)) { + if (p->drive_low_after) { + pin_drive(p->port, p->pin, false); + } else { + pin_release(p->port, p->pin); + } + p->active = false; + } +} + +/* ---- the host's bench commands: frames on channel 15 ----------------------------------- */ + +static uint16_t crc16(uint16_t crc, uint8_t byte) +{ + crc = (uint16_t)(crc ^ (uint16_t)((uint16_t)byte << 8)); + for (unsigned i = 0u; i < 8u; i++) { + crc = ((crc & 0x8000u) != 0u) ? (uint16_t)((uint16_t)(crc << 1) ^ CRC_POLY) : (uint16_t)(crc << 1); + } + return crc; +} + +static uint8_t cmd_raw[CMD_MAX + 8u]; /* the COBS bytes since the last zero */ +static uint32_t cmd_len; +static bool cmd_overrun; + +static char reply[CMD_MAX + 8u]; +static uint32_t reply_len; /* waiting to be sent toward the host */ + +static bool starts(const char *s, uint32_t n, const char *word) +{ + uint32_t i = 0u; + while (word[i] != '\0') { + if ((i >= n) || (s[i] != word[i])) { + return false; + } + i++; + } + return true; +} + +static uint32_t number(const char *s, uint32_t n, uint32_t at) +{ + uint32_t v = 0u; + while ((at < n) && (s[at] >= '0') && (s[at] <= '9')) { + v = (v * 10u) + (uint32_t)(s[at] - '0'); + at++; + } + return v; +} + +static void act(const char *c, uint32_t n) +{ + bool ok = true; + if (starts(c, n, "reset")) { + pulse_start(&reset_pulse, false, 20u * CYCLES_PER_MS); + } else if (starts(c, n, "power off")) { + power_pulse.active = false; + pin_drive(power_pulse.port, power_pulse.pin, false); + } else if (starts(c, n, "power on")) { + power_pulse.active = false; + pin_release(power_pulse.port, power_pulse.pin); + } else if (starts(c, n, "power cycle ")) { + pulse_start(&power_pulse, false, number(c, n, 12u) * CYCLES_PER_MS); + } else if (starts(c, n, "wake ")) { + pulse_start(&wake_pulse, true, number(c, n, 5u) * CYCLES_PER_US); + } else if (!starts(c, n, "ping")) { + ok = false; + } + reply_len = 0u; + reply[reply_len++] = ok ? 'o' : '?'; + if (ok) { + reply[reply_len++] = 'k'; + } + reply[reply_len++] = ' '; + for (uint32_t i = 0u; (i < n) && (reply_len < CMD_MAX); i++) { + reply[reply_len++] = c[i]; + } +} + +/* A zero ended the bytes in cmd_raw: a channel-15 frame with a good CRC is a command. */ +static void cmd_end(void) +{ + uint8_t dec[CMD_MAX + 8u]; + uint32_t n = 0u; + uint32_t i = 0u; + uint16_t crc = 0xFFFFu; + if (cmd_overrun || (cmd_len < 2u)) { + return; + } + while (i < cmd_len) { /* COBS: a code byte, then its run */ + uint32_t code = cmd_raw[i++]; + for (uint32_t k = 1u; (k < code) && (i < cmd_len); k++) { + dec[n++] = cmd_raw[i++]; + } + if ((code < 0xFFu) && (i < cmd_len)) { + dec[n++] = 0u; + } + } + if ((n < 3u) || (dec[0] != CH_BENCH)) { + return; + } + for (i = 0u; i < (n - 2u); i++) { + crc = crc16(crc, dec[i]); + } + if ((dec[n - 2u] != (uint8_t)crc) || (dec[n - 1u] != (uint8_t)(crc >> 8))) { + return; + } + act((const char *)&dec[1], n - 3u); +} + +static void watch_host_byte(uint8_t b) +{ + if (b == 0u) { + cmd_end(); + cmd_len = 0u; + cmd_overrun = false; + } else if (cmd_len < sizeof(cmd_raw)) { + cmd_raw[cmd_len++] = b; + } else { + cmd_overrun = true; /* longer than any command: not one */ + } +} + +/* The reply, framed, toward the host: only between two of the other board's frames (the last + * byte relayed was a zero) or once that way has been quiet for 2 ms. */ +static void reply_send(bool boundary) +{ + uint8_t raw[CMD_MAX + 8u]; + uint32_t n = 0u; + uint16_t crc = 0xFFFFu; + uint32_t code_at; + uint8_t code = 1u; + if ((reply_len == 0u) || !boundary || (to_host.head != to_host.tail)) { + return; + } + raw[n++] = CH_BENCH; + for (uint32_t i = 0u; i < reply_len; i++) { + raw[n++] = (uint8_t)reply[i]; + } + for (uint32_t i = 0u; i < n; i++) { + crc = crc16(crc, raw[i]); + } + raw[n++] = (uint8_t)crc; + raw[n++] = (uint8_t)(crc >> 8); + ring_put(&to_host, 0u); /* a zero first: the decoder starts clean */ + code_at = to_host.head; + ring_put(&to_host, 0u); /* the first code byte, filled below */ + for (uint32_t i = 0u; i < n; i++) { + if (raw[i] == 0u) { + to_host.buf[code_at & (RING - 1u)] = code; + code_at = to_host.head; + ring_put(&to_host, 0u); + code = 1u; + } else { + ring_put(&to_host, raw[i]); + code++; + } + } + to_host.buf[code_at & (RING - 1u)] = code; + ring_put(&to_host, 0u); + reply_len = 0u; +} + static void puts_vcp(const char *s) { while (*s != '\0') { @@ -88,27 +358,56 @@ static void puts_vcp(const char *s) int main(void) { + uint32_t quiet_since; + bool last_zero = true; if (emb_stm32f4_clock_init() == 0) { hang(); } emb_stm32_pins_apply(pins, sizeof(pins) / sizeof(pins[0])); + emb_stm32_clock_enable(EMB_HW_GPIOB_CLKEN_OFFSET, EMB_HW_GPIOB_CLKEN_BIT); emb_stm32_clock_enable(EMB_HW_USART2_CLKEN_OFFSET, EMB_HW_USART2_CLKEN_BIT); emb_stm32_clock_enable(EMB_HW_USART1_CLKEN_OFFSET, EMB_HW_USART1_CLKEN_BIT); emb_stm32_usart_init(EMB_HW_USART2_BASE, EMB_HW_APB1_HZ, 115200u); emb_stm32_usart_init(EMB_HW_USART1_BASE, EMB_HW_APB2_HZ, 115200u); - REG32(GPIOA_PUPDR) = (REG32(GPIOA_PUPDR) & ~(3u << 20)) | - (1u << 20); /* PA10 idles high unwired */ - REG32(EMB_HW_USART1_BASE + USART_CR1) |= CR1_RE; - puts_vcp("\r\n[nucleo uart relay: PA10 -> VCP, 115200]\r\n"); + REG32(EMB_HW_GPIOA_BASE + GPIO_PUPDR) = + (REG32(EMB_HW_GPIOA_BASE + GPIO_PUPDR) & ~(3u << 20)) | (1u << 20); /* PA10 idles high */ + REG32(EMB_HW_USART1_BASE + USART_CR1) |= CR1_RE | CR1_TE; + REG32(EMB_HW_USART2_BASE + USART_CR1) |= CR1_RE | CR1_TE; + REG32(DEMCR) |= 1u << 24; /* TRCENA: the cycle counter times the bench pulses */ + REG32(DWT_CYCCNT) = 0u; + REG32(DWT_CTRL) |= 1u; + pin_drive(wake_pulse.port, wake_pulse.pin, false); /* driven low between wake pulses */ + puts_vcp("\r\n[nucleo uart relay: PA10 <-> VCP <-> PA9, 115200; bench on channel 15]\r\n"); + quiet_since = now(); for (;;) { - uint32_t sr = REG32(EMB_HW_USART1_BASE + USART_SR); - if ((sr & (SR_RXNE | SR_ORE)) != 0u) { - char c = (char)REG32(EMB_HW_USART1_BASE + USART_DR); /* also clears ORE, FE */ - if ((sr & SR_FE) != 0u) { - continue; /* a break: the line held low, nothing sent */ + uint32_t sr1 = REG32(EMB_HW_USART1_BASE + USART_SR); + uint32_t sr2 = REG32(EMB_HW_USART2_BASE + USART_SR); + uint8_t b; + if ((sr1 & (SR_RXNE | SR_ORE)) != 0u) { + b = (uint8_t)REG32(EMB_HW_USART1_BASE + USART_DR); /* also clears ORE, FE */ + if ((sr1 & SR_FE) == 0u) { + ring_put(&to_host, b); + emb_stm32_gpio_toggle(EMB_HW_GPIOA_BASE, 5u); + } + } + if ((sr2 & (SR_RXNE | SR_ORE)) != 0u) { + b = (uint8_t)REG32(EMB_HW_USART2_BASE + USART_DR); + if ((sr2 & SR_FE) == 0u) { + ring_put(&to_board, b); + watch_host_byte(b); } - emb_stm32_usart_putc(EMB_HW_USART2_BASE, c); - emb_stm32_gpio_toggle(EMB_HW_GPIOA_BASE, 5u); } + if (((sr2 & SR_TXE) != 0u) && ring_get(&to_host, &b)) { + REG32(EMB_HW_USART2_BASE + USART_DR) = b; + last_zero = b == 0u; + quiet_since = now(); + } + if (((sr1 & SR_TXE) != 0u) && ring_get(&to_board, &b)) { + REG32(EMB_HW_USART1_BASE + USART_DR) = b; + } + reply_send(last_zero || ((now() - quiet_since) > (2u * CYCLES_PER_MS))); + pulse_poll(&reset_pulse); + pulse_poll(&power_pulse); + pulse_poll(&wake_pulse); } } From 1c1f8d2ab97357093d4d4bd4d5c13547b9e9b577 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:08:24 +0100 Subject: [PATCH 14/25] examples: console_echo, the console both ways The board reads its console's UART through the UART class, a line or what arrived before the line went quiet, and sends it back in capitals with its length. Behind the NUCLEO's relay it checks the host's way to the Pico 2 W (PA9 to GPIO1), which the shell and update channels use. On the NUCLEO-F446RE's own console: 'hello' came back 'echo 6: HELLO'. Signed-off-by: teo1747 --- examples/console_echo/CMakeLists.txt | 15 ++++++ examples/console_echo/main.c | 72 ++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 examples/console_echo/CMakeLists.txt create mode 100644 examples/console_echo/main.c diff --git a/examples/console_echo/CMakeLists.txt b/examples/console_echo/CMakeLists.txt new file mode 100644 index 00000000..e5caa83c --- /dev/null +++ b/examples/console_echo/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +cmake_minimum_required(VERSION 3.20) + +set(EmbLinkRTOS_DIR "${CMAKE_CURRENT_LIST_DIR}/../../cmake" CACHE PATH "The RTOS's cmake/ directory") +find_package(EmbLinkRTOS REQUIRED) + +project(console_echo LANGUAGES C) + +emb_kernel() +emb_add_executable(console_echo main.c) diff --git a/examples/console_echo/main.c b/examples/console_echo/main.c new file mode 100644 index 00000000..6e1dcd4e --- /dev/null +++ b/examples/console_echo/main.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file main.c + * @brief The console both ways: what the host sends comes back (M4.3's two-way relay). + * + * @details + * The board reads its console's UART through the UART class (SPEC-017 §4), a line at a time or + * whatever arrived before the line went quiet, and sends it back in capitals with its length. + * On the Pico 2 W behind the NUCLEO-F446RE's relay this checks the host's way to the board, PA9 + * to GPIO1, which the shell and update channels use. Any board whose console is a UART device + * (EMB_SOC_CONSOLE_DEVICE) runs it. + * + * emb build -b pico2_w -S examples/console_echo + * emb flash -B build/console_echo-pico2_w + * printf 'hello\n' > /dev/cu.usbmodem31103 # and watch: "echo 5: HELLO" + * + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include + +#include +#include + +#ifndef EMB_SOC_CONSOLE_DEVICE +#error "console_echo needs a board whose console is a UART device (EMB_SOC_CONSOLE_DEVICE)" +#endif + +static void echo(void *arg) +{ + static char line[64]; + (void)arg; + emb_board_puts("echo: ready\n"); + for (;;) { + size_t got = 0u; + size_t i; + emb_status_t st = emb_drv_uart_read(EMB_SOC_CONSOLE_DEVICE, line, sizeof(line) - 1u, + EMB_DRV_UART_IDLE, EMB_WAIT_FOREVER, &got); + if (got == 0u) { + continue; + } + for (i = 0u; i < got; i++) { /* bounded by the line */ + if ((line[i] >= 'a') && (line[i] <= 'z')) { + line[i] = (char)(line[i] - 'a' + 'A'); + } + if ((line[i] == '\r') || (line[i] == '\n')) { + line[i] = ' '; + } + } + line[got] = '\0'; + emb_board_puts("echo "); + emb_board_put_u32((uint32_t)got); + emb_board_puts((st == EMB_OK) ? ": " : " (damaged): "); + emb_board_puts(line); + emb_board_puts("\n"); + } +} + +EMB_THREAD_DEFINE(echo_thread, echo, NULL, 3u, 1024u, 0u); + +int main(void) +{ + emb_board_init(); + emb_kernel_init(); + emb_kernel_start(); +} From a5b6b75e13c63a3054b2deb1757d0e837df79404 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:15:30 +0100 Subject: [PATCH 15/25] hil: the framed console's soak, and producers at once in test_log tools/hil/log-soak logs a numbered record every 10 ms, a burst of 100 every second (more than the ring keeps, so records are dropped and counted) and both rings' counters every 5 s, while the trace streams on channel 1. tools/hil/log_soak.py reads it for a while and passes it when no frame is damaged, every record decodes and each numbered record missing is covered by a dropped record after it. A minute on the NUCLEO-F446RE: 5099 frames, none damaged, 6000 numbered records. test_log gains three threads at three priorities and an interrupt logging at once while the test drains the ring: each producer's records arrive whole and in order, and those kept plus those counted dropped are all that were written. It passes natively, under ASan and TSan, and under QEMU on the Cortex-M4 and the Cortex-M0. The trace stream's thread needed . Signed-off-by: teo1747 --- subsys/trace/ring.c | 1 + tests/conformance/test_log.c | 99 +++++++++++++++++ tools/hil/log-soak/CMakeLists.txt | 18 ++++ tools/hil/log-soak/main.c | 87 +++++++++++++++ tools/hil/log_soak.py | 171 ++++++++++++++++++++++++++++++ 5 files changed, 376 insertions(+) create mode 100644 tools/hil/log-soak/CMakeLists.txt create mode 100644 tools/hil/log-soak/main.c create mode 100644 tools/hil/log_soak.py diff --git a/subsys/trace/ring.c b/subsys/trace/ring.c index 6d25d3b3..e44e6d06 100644 --- a/subsys/trace/ring.c +++ b/subsys/trace/ring.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/conformance/test_log.c b/tests/conformance/test_log.c index 4c1fccf3..edae9605 100644 --- a/tests/conformance/test_log.c +++ b/tests/conformance/test_log.c @@ -219,3 +219,102 @@ EMB_TEST(log_flush_sends_what_is_committed) EMB_ASSERT_EQ(after.sent - before.sent, 2u); EMB_ASSERT_EQ(take(), 0u); } + +/* ---- producers at once: threads at three priorities and an interrupt ---------------------- */ + +#define PRODUCERS 3u +#define PER_PRODUCER 300u +#define ISR_RECORDS 50u + +static volatile unsigned producers_done; +static volatile unsigned isr_written; + +static void produce(void *arg) +{ + unsigned id = (unsigned)(uintptr_t)arg; + unsigned i; + for (i = 0u; i < PER_PRODUCER; i++) { /* bounded: the records it writes */ + EMB_LOG_INF(t, "p %u %u", id, i); + if ((i % 16u) == 15u) { + (void)emb_thread_sleep(EMB_MS(1)); /* let the others and the reader in */ + } + } + producers_done = producers_done + 1u; +} + +static void isr_produces(void *arg) +{ + (void)arg; + EMB_LOG_INF(t, "p %u %u", PRODUCERS, isr_written); + isr_written = isr_written + 1u; +} + +EMB_THREAD_DEFINE(producer_a, produce, (void *)(uintptr_t)0u, 2u, 1024u, EMB_THREAD_NO_AUTOSTART); +EMB_THREAD_DEFINE(producer_b, produce, (void *)(uintptr_t)1u, 3u, 1024u, EMB_THREAD_NO_AUTOSTART); +EMB_THREAD_DEFINE(producer_c, produce, (void *)(uintptr_t)2u, 4u, 1024u, EMB_THREAD_NO_AUTOSTART); + +static uint32_t rec_u(size_t at, uint32_t bytes) +{ + uint32_t v = 0u; + uint32_t k; + for (k = 0u; k < bytes; k++) { /* bounded: at most four bytes */ + v |= (uint32_t)rec[at + k] << (8u * k); + } + return v; +} + +EMB_TEST(log_producers_at_once_keep_their_order) +{ + uint32_t idb = embs_log_id_bytes(); + uint32_t ts = CONFIG_EMB_LOG_TIMESTAMP ? 4u : 0u; + uint32_t next[PRODUCERS + 1u] = {0u, 0u, 0u, 0u}; + uint32_t kept = 0u; + uint32_t dropped = 0u; + uint32_t spins = 0u; + bool ended = false; + EMB_TEST_REQ("OBS-003"); + drain(); + emb_test_irq_connect(1u, isr_produces, NULL); + EMB_ASSERT_OK(emb_thread_start(producer_a)); + EMB_ASSERT_OK(emb_thread_start(producer_b)); + EMB_ASSERT_OK(emb_thread_start(producer_c)); + /* The reader runs below the producers and never blocks, so the log thread, at its priority + * or below, cannot take a record from it: it reads whenever the producers sleep, and spins a + * tick when the ring is empty (on native, where time moves only when told, that moves it). */ + for (;;) { /* bounded: the producers end, then the ring empties */ + size_t n; + if ((isr_written < ISR_RECORDS) && ((spins++ % 7u) == 0u)) { + emb_test_irq_raise(1u); + emb_test_irq_settle(); + } + n = take(); + if (n == 0u) { + if ((producers_done < PRODUCERS) || (isr_written < ISR_RECORDS)) { + emb_test_spin_ticks(1u); /* a tick passes: the producers' sleeps end */ + continue; + } + if (ended) { + break; + } + EMB_LOG_INF(t, "end"); /* brings the count of any records dropped last */ + ended = true; + continue; + } + if (rec_u(0u, (idb < 4u) ? idb : 4u) == EMB_LOG_ID_DROPPED) { + dropped += rec_u(idb + ts, 2u); + } else if (n == (idb + ts)) { + /* the end */ + } else { + /* "p ": each producer's records in its own order, none torn */ + uint32_t who = rec_u(idb + ts, 4u); + uint32_t i = rec_u(idb + ts + 4u, 4u); + EMB_ASSERT_EQ(n, idb + ts + 8u); + EMB_ASSERT_TRUE(who <= PRODUCERS); + EMB_ASSERT_TRUE(i >= next[who]); + next[who] = i + 1u; + kept++; + } + } + EMB_ASSERT_EQ(kept + dropped, (PRODUCERS * PER_PRODUCER) + ISR_RECORDS); + EMB_ASSERT_TRUE(kept > 0u); +} diff --git a/tools/hil/log-soak/CMakeLists.txt b/tools/hil/log-soak/CMakeLists.txt new file mode 100644 index 00000000..78a96ca2 --- /dev/null +++ b/tools/hil/log-soak/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +# The framed console's soak (M4.3): logs and the trace's stream together, for tools/hil/log_soak.py. +cmake_minimum_required(VERSION 3.20) + +set(EmbLinkRTOS_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../cmake" CACHE PATH "The RTOS's cmake/ directory") +set(EMB_SET "EMB_CONSOLE_FRAMED=y;EMB_TRACE=y;EMB_TRACE_STREAM=y;EMB_TRACE_STREAM_MS=500" CACHE STRING + "Symbol overrides") +find_package(EmbLinkRTOS REQUIRED) + +project(log_soak LANGUAGES C) + +emb_kernel() +emb_add_executable(log_soak main.c) diff --git a/tools/hil/log-soak/main.c b/tools/hil/log-soak/main.c new file mode 100644 index 00000000..367c1b0c --- /dev/null +++ b/tools/hil/log-soak/main.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2026 Junior Deogracias */ +/* + * This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. + * Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + */ + +/** + * @file main.c + * @brief The framed console's soak: logs and the trace's stream at once, for hours (M4.3). + * + * @details + * A thread logs a numbered record every 10 ms; another logs a burst of 100 every second, more + * than the ring's 1 KiB keeps while the log thread waits for the console, so records are dropped + * and counted; a third logs the log ring's and the trace ring's counters every 5 s. The trace ring + * streams on channel 1 every 500 ms. tools/hil/log_soak.py reads the console and checks that no + * frame is damaged and that every numbered record missing is one a dropped record counted. + * + * @author Junior Deogracias + * @date 2026-11-13 (created) + */ +#include + +#include + +EMB_LOG_MODULE_DEFINE(soak, EMB_LOG_LEVEL_INF); + +static void steady(void *arg) +{ + emb_instant_t next = emb_time_now(); + unsigned seq = 0u; + (void)arg; + for (;;) { + next = emb_instant_add(next, EMB_MS(10)); + (void)emb_thread_sleep_until(next); + EMB_LOG_INF(soak, "seq %u", seq); + seq++; + } +} + +static void bursts(void *arg) +{ + emb_instant_t next = emb_time_now(); + unsigned round = 0u; + (void)arg; + for (;;) { + unsigned i; + next = emb_instant_add(next, EMB_MS(1000)); + (void)emb_thread_sleep_until(next); + for (i = 0u; i < 100u; i++) { + EMB_LOG_DBG(soak, "not compiled at the default level %u", i); + EMB_LOG_WRN(soak, "burst %u %u", round, i); + } + round++; + } +} + +static void counters(void *arg) +{ + emb_instant_t next = emb_time_now(); + (void)arg; + EMB_CHECK(emb_trace_start()); + for (;;) { + emb_log_stats_t ls; + emb_trace_stats_t ts; + next = emb_instant_add(next, EMB_MS(5000)); + (void)emb_thread_sleep_until(next); + (void)emb_log_stats_get(&ls); + (void)emb_trace_stats_get(&ts); + EMB_LOG_INF(soak, "log records %lu dropped %lu sent %lu high %lu", + (unsigned long)ls.records, (unsigned long)ls.dropped, (unsigned long)ls.sent, + (unsigned long)ls.high_water); + EMB_LOG_INF(soak, "trace recorded %lu overwritten %lu sent %lu", (unsigned long)ts.recorded, + (unsigned long)ts.overwritten, (unsigned long)ts.sent); + } +} + +EMB_THREAD_DEFINE(steady_thread, steady, NULL, 5u, 1024u, 0u); +EMB_THREAD_DEFINE(burst_thread, bursts, NULL, 4u, 1024u, 0u); +EMB_THREAD_DEFINE(counter_thread, counters, NULL, 3u, 1024u, 0u); + +int main(void) +{ + emb_board_init(); + emb_kernel_init(); + emb_kernel_start(); +} diff --git a/tools/hil/log_soak.py b/tools/hil/log_soak.py new file mode 100644 index 00000000..d8f2266e --- /dev/null +++ b/tools/hil/log_soak.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2026 Junior Deogracias +# +# This file is part of EmbLinkRTOS, a deterministic real-time kernel for microcontrollers. +# Licensed under the Apache License, Version 2.0; see the LICENSE file at the repository root. + +"""Soak the framed console: read tools/hil/log-soak's console for a while and judge it (M4.3). + + log_soak.py --elf build/log_soak-nucleo_f446re/log_soak.elf --port /dev/cu.usbmodem31103 \\ + --minutes 30 --archive docs/engineering/hil-runs/--log-soak + +Passes when no frame was damaged or too long, every log record decoded, the numbered records +came in order, and each one missing is covered by the dropped records that came after it (A127: +the count stands where the loss was). The trace's packets are counted and their gaps reported. +The run's console and a JSON record of its counters go to --archive. +""" +import argparse +import json +import os +import re +import select +import subprocess +import sys +import time +from pathlib import Path + +HERE = Path(__file__).resolve().parent +for sub in ("transport", "logdec", "trace", "emb"): + sys.path.insert(0, str(HERE.parent / sub)) +sys.path.insert(0, str(HERE)) +import emb # noqa: E402 +import logdec # noqa: E402 +import run_hil # noqa: E402 +import trace # noqa: E402 + +# a line's time is there once the stream's start record was seen, which a late reader misses +SEQ = re.compile(r"(?:^|\] )I soak: seq (\d+)$") +DROPPED = re.compile(r"(?:^|\] )W emb_log: (\d+) records dropped$") +COUNTERS = re.compile(r"(?:^|\] )I soak: (log|trace) (.*)$") + + +class Judge: + def __init__(self, db): + self.stream = logdec.Stream(db) + self.console = emb.Console() + self.trace = trace.Trace() + self.seq_next = None + self.records = self.seq = self.dropped = self.uncovered = 0 + self.pending_drop = 0 # dropped records seen since the last numbered record + self.decode_errors = 0 + self.trace_packets = 0 + self.counters = {} + self.texts = [] + + def feed(self, data): + for item in self.console.feed(data): + if item[0] == "text": + self.texts.append(item[1].decode(errors="replace")) + continue + _, ch, payload = item + if ch == 1: + self.trace_packets += 1 + try: + self.trace.packet(payload) + except trace.TraceError: + self.decode_errors += 1 + continue + if ch != 0: + continue + try: + lines = self.stream.records(payload) + except logdec.LogError: + self.decode_errors += 1 + continue + for line in lines: + self.line(line) + + def line(self, line): + self.records += 1 + m = DROPPED.search(line) + if m: + self.dropped += int(m.group(1)) + self.pending_drop += int(m.group(1)) + return + m = COUNTERS.search(line) + if m: + self.counters[m.group(1)] = m.group(2) + return + m = SEQ.search(line) + if not m: + return + n = int(m.group(1)) + self.seq += 1 + if self.seq_next is not None: + gap = n - self.seq_next + if gap < 0: + self.uncovered += 1 # out of order: no drop explains that + elif gap > self.pending_drop: + self.uncovered += gap - self.pending_drop + self.seq_next = n + 1 + self.pending_drop = 0 + + def record(self): + c = self.console + return {"frames": c.frames, "damaged_frames": c.errors, "log_records": self.records, + "numbered_records": self.seq, "dropped_counted": self.dropped, + "missing_not_counted": self.uncovered, "decode_errors": self.decode_errors, + "trace_packets": self.trace_packets, "trace_events": len(self.trace.events), + "trace_gaps": self.trace.gaps, "target_counters": self.counters} + + def passed(self): + return (self.console.errors == 0 and self.decode_errors == 0 and self.uncovered == 0 + and self.seq > 0 and self.trace_packets > 0) + + +def main(argv=None): + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--elf", required=True) + ap.add_argument("--port", required=True) + ap.add_argument("--baud", type=int, default=115200) + ap.add_argument("--minutes", type=float, default=30.0) + ap.add_argument("--archive", help="keep the console and the record here") + ap.add_argument("--board", default="", help="named in the record") + ap.add_argument("--input", help="judge a capture instead of the port") + args = ap.parse_args(argv) + judge = Judge(logdec.LogDb(args.elf)) + raw = bytearray() + started = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) + t0 = time.monotonic() + if args.input: + raw += Path(args.input).read_bytes() + judge.feed(bytes(raw)) + else: + fd = run_hil.open_console(args.port, args.baud) + end = t0 + args.minutes * 60.0 + last_report = t0 + try: + while time.monotonic() < end: + r, _, _ = select.select([fd], [], [], 0.5) + if r: + try: + chunk = os.read(fd, 4096) + except BlockingIOError: + continue + raw += chunk + judge.feed(chunk) + if time.monotonic() - last_report > 60.0: + last_report = time.monotonic() + rec = judge.record() + print(f"log_soak: {(last_report - t0) / 60:.0f} min: {rec['frames']} frames, " + f"{rec['damaged_frames']} damaged, {rec['numbered_records']} numbered, " + f"{rec['dropped_counted']} dropped, {rec['missing_not_counted']} missing uncounted", + flush=True) + finally: + os.close(fd) + rec = judge.record() + rec.update({"board": args.board, "started": started, "minutes": round((time.monotonic() - t0) / 60.0, 2), + "image": Path(args.elf).name, "outcome": "passed" if judge.passed() else "failed", + "git": run_hil.git_state()}) + if args.archive: + out = Path(args.archive) + out.mkdir(parents=True, exist_ok=True) + (out / "log_soak.bin").write_bytes(bytes(raw)) + (out / "log_soak.json").write_text(json.dumps(rec, indent=1, sort_keys=True) + "\n", encoding="utf-8") + print(json.dumps(rec, indent=1, sort_keys=True)) + return 0 if judge.passed() else 1 + + +if __name__ == "__main__": + sys.exit(main()) From 43c0bee2ef7921ec70f6e40463b53f1ec129463c Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:16:29 +0100 Subject: [PATCH 16/25] docs: logging, the trace and the emb tool, for users docs/user/logging.md: modules and levels, the two backends, the framed console and emb monitor, recording and viewing the trace in Babeltrace 2 and Perfetto, and the emb tool's commands. The change note lists M4.3's additions. Signed-off-by: teo1747 --- changes/feat-transport-frame.md | 13 +++++ docs/user/index.md | 1 + docs/user/logging.md | 92 +++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 docs/user/logging.md diff --git a/changes/feat-transport-frame.md b/changes/feat-transport-frame.md index cfb643f9..b6b0cdbf 100644 --- a/changes/feat-transport-frame.md +++ b/changes/feat-transport-frame.md @@ -6,3 +6,16 @@ ### Changed (the frame's channels and CRC, 2026-11-09) - A113, proposed: channels 0 to 4 are the system's (4 is the update protocol's, as SPEC-019 has it) and 5 to 15 the application's; the CRC is CRC-16/IBM-3740, sent least significant byte first ([amendments](docs/specs/AMENDMENTS-M4.md)). + +### Added (logging, trace, the emb tool and the two-way relay, 2026-11-13) + +- Logging (``, A127): `EMB_LOG_ERR()` to `EMB_LOG_DBG()` with formats the compiler checks, packed in the caller into a ring that never waits and counts what it drops, sent by a log thread. Two backends share the record: plain text formatted on the board, and deferred, formatted on the host by `tools/logdec` from the image's ELF, whose call sites never reach flash. +- The console (``): boards write raw bytes with `emb_board_write()`, `emb_board_puts()` is common, and `CONFIG_EMB_CONSOLE_FRAMED` puts everything on it in frames: text on channel 3, logs on 0, trace on 1. +- The trace ring (`emb_trace_start()`, `emb_trace_dump()`, A128): the kernel's events in RAM as 20-byte records, dumped or streamed on channel 1; `tools/trace` writes CTF 1.8, which Babeltrace 2 reads, and Perfetto's JSON. +- `scripts/emb` (`tools/emb`, BLD-005): `build`, `flash`, `monitor`, `hil` and `trace dump`. +- The NUCLEO relay works both ways and drives a reset, a power cut and a wake pin for the bench, on channel-15 frames. +- Examples: `logging`, `tracing`, `console_echo`; `tools/hil/log-soak` and `log_soak.py`, the framed console's soak. + +### Changed + +- A127 and A128, proposed; logging is not offered on AVR in M4.3. diff --git a/docs/user/index.md b/docs/user/index.md index 992e75f9..cd190771 100644 --- a/docs/user/index.md +++ b/docs/user/index.md @@ -13,6 +13,7 @@ concepts tasks synchronization configuration +logging debugging ``` diff --git a/docs/user/logging.md b/docs/user/logging.md new file mode 100644 index 00000000..aa10007d --- /dev/null +++ b/docs/user/logging.md @@ -0,0 +1,92 @@ +# Logging, tracing and the console + +This page shows how to log from an application, how to see the logs, how to record and view the kernel's trace, and how the `emb` tool fits around them. The design is SPEC-015 as [A127 and A128](../specs/AMENDMENTS-M4.md) make it concrete. + +## Logging + +A module is defined once, in one file, and declared in each other file that logs for it. Each file gives the most detailed level it compiles: + +```c +#include + +EMB_LOG_MODULE_DEFINE(sensor, EMB_LOG_LEVEL_INF); /* in one file */ +/* EMB_LOG_MODULE_DECLARE(sensor, EMB_LOG_LEVEL_DBG); in the others */ + +void read_sensor(unsigned id) +{ + int status = sample(id); + if (status < 0) { + EMB_LOG_ERR(sensor, "read %u failed: %d", id, status); + } + EMB_LOG_DBG(sensor, "raw %x", raw_value(id)); /* compiled out at INF */ + EMB_LOG_HEXDUMP_INF(sensor, frame, len, "rx"); /* bytes, cut at CONFIG_EMB_LOG_HEXDUMP_MAX */ +} +``` + +- A call takes a printf format and at most eight arguments; the compiler checks them against the format as it checks printf's. Strings are copied, up to `CONFIG_EMB_LOG_STR_MAX` bytes. +- A call above its file's level, or above `CONFIG_EMB_LOG_LEVEL_MAX` (information by default), compiles to nothing. `emb_log_level_set(EMB_LOG_MODULE(sensor), EMB_LOG_LEVEL_WRN)` silences a module at run time. +- A call never waits and never formats: it packs its record into a ring in a few microseconds, from a thread or an interrupt. A record that does not fit is dropped and counted, and the next record says how many were lost. +- A log thread at the lowest priority sends the records. On the tiny profile there is no log thread (`CONFIG_EMB_LOG_THREAD`): call `emb_log_flush()` from a thread of your own. A fault handler can call `emb_log_flush()` too, to send what is left. +- Logging costs nothing until an image logs: the ring, the thread and the formatter come with the first call. It is not offered on AVR yet. + +### Two backends + +**Plain text** is the default. The log thread formats each record on the board and prints a line: + +```text +[1.234] E sensor: read 3 failed: -5 +``` + +**Deferred** is the backend when the console is framed (below). The board sends the record as it is, and the host formats it from the image's ELF: the formats and file names never take flash, the image is smaller (3 KB on the logging example), and the console carries about half the bytes. Both print the same lines; the CI checks it on three targets. + +## The framed console + +Built with `CONFIG_EMB_CONSOLE_FRAMED=y`, everything on the console travels in frames (SPEC-015 §7): the board's text on channel 3, log records on 0, trace on 1, crash records on 2. A terminal shows them as noise; `emb monitor` decodes them: + +```sh +scripts/emb build -b nucleo_f446re -S examples/logging --framed +scripts/emb flash -B build/logging-nucleo_f446re +scripts/emb monitor -B build/logging-nucleo_f446re --where +``` + +```text +[0.000] I app: logging on nucleo_f446re (main.c:45) +[0.077] W emb_log: 134 records dropped +``` + +`--where` adds each call's file and line. The monitor refuses a stream from another build of the image: decode with the image's own ELF. Text that is not a frame, such as a boot ROM's message, is shown as it is. + +## The trace + +With `CONFIG_EMB_TRACE=y`, `emb_trace_start()` records the kernel's events (switches, waits, wakes, interrupts, objects) into a RAM ring, the newest overwriting the oldest. `emb_trace_dump()` sends the ring on the framed console, the threads' names first. `CONFIG_EMB_TRACE_STREAM` sends new events every period instead. + +```c +emb_trace_start(); +run_the_part_to_look_at(); +emb_trace_stop(); +emb_trace_dump(); +``` + +```sh +scripts/emb build -b nucleo_f446re -S examples/tracing # sets the trace and the framed console +scripts/emb flash -B build/tracing-nucleo_f446re +scripts/emb trace dump -B build/tracing-nucleo_f446re --until "tracing: done" \ + --ctf build/trace --perfetto build/trace.json +babeltrace2 build/trace # or open it in Trace Compass +``` + +Open `trace.json` in [Perfetto](https://ui.perfetto.dev): a track per thread with its running slices, one for interrupts, and the other events as marks. The times come from the cycle counter: 5.6 ns steps at 180 MHz. + +## The emb tool + +`scripts/emb` (put `scripts/` on your `PATH`) knows a build directory's board, image and console: + +| Command | Does | +|---|---| +| `emb build -b -S [--clang] [--framed] [--set SYM=val]` | configure and build, with the board's toolchain | +| `emb flash -B ` | program the image with the board's probe: OpenOCD, picotool, avrdude or embflash | +| `emb monitor -B [--where] [--until TEXT]` | the console, frames decoded | +| `emb hil -B [-R test]` | the test suite on the board, for a build made with `--hil --port` | +| `emb trace dump -B --ctf DIR --perfetto FILE` | the trace an image dumps, as CTF and Perfetto's JSON | + +`emb build -n` prints the commands without running them. From c8d07630e36a75193c9f10b09bd0916e672ad138 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:25:26 +0100 Subject: [PATCH 17/25] examples: console_echo ends on a line 'exit' So a run can end it: the board's exit, which on the Pico 2 W built for the bench reboots into BOOTSEL for the next image. Signed-off-by: teo1747 --- examples/console_echo/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/console_echo/main.c b/examples/console_echo/main.c index 6e1dcd4e..a01ecd93 100644 --- a/examples/console_echo/main.c +++ b/examples/console_echo/main.c @@ -20,6 +20,8 @@ * emb flash -B build/console_echo-pico2_w * printf 'hello\n' > /dev/cu.usbmodem31103 # and watch: "echo 5: HELLO" * + * A line "exit" ends it. + * * @author Junior Deogracias * @date 2026-11-13 (created) */ @@ -54,6 +56,11 @@ static void echo(void *arg) } } line[got] = '\0'; + if ((got >= 4u) && (line[0] == 'E') && (line[1] == 'X') && (line[2] == 'I') && + (line[3] == 'T')) { + emb_board_puts("echo: done\n"); + emb_board_exit(0); /* built for HIL on the Pico 2 W: back to BOOTSEL */ + } emb_board_puts("echo "); emb_board_put_u32((uint32_t)got); emb_board_puts((st == EMB_OK) ? ": " : " (damaged): "); From 1b58e07ba8f51589ebe35a0fb382fe10b0d08481 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:47:40 +0100 Subject: [PATCH 18/25] hil: the soak's counters off the bursts' tick; the change note's heading The counter thread logged on the same tick as the bursts, when the ring is full of a burst, so its two records were dropped every time (the soak's accounting showed 39 dropped at each fifth second instead of 37). It now logs half a second later. The change note's heading takes its topic and date, as the lint wants. Signed-off-by: teo1747 --- changes/feat-transport-frame.md | 2 +- tools/hil/log-soak/main.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/changes/feat-transport-frame.md b/changes/feat-transport-frame.md index b6b0cdbf..5d2cdd1c 100644 --- a/changes/feat-transport-frame.md +++ b/changes/feat-transport-frame.md @@ -16,6 +16,6 @@ - The NUCLEO relay works both ways and drives a reset, a power cut and a wake pin for the bench, on channel-15 frames. - Examples: `logging`, `tracing`, `console_echo`; `tools/hil/log-soak` and `log_soak.py`, the framed console's soak. -### Changed +### Changed (logging and the trace, 2026-11-13) - A127 and A128, proposed; logging is not offered on AVR in M4.3. diff --git a/tools/hil/log-soak/main.c b/tools/hil/log-soak/main.c index 367c1b0c..978fdcb4 100644 --- a/tools/hil/log-soak/main.c +++ b/tools/hil/log-soak/main.c @@ -57,7 +57,9 @@ static void bursts(void *arg) static void counters(void *arg) { - emb_instant_t next = emb_time_now(); + /* half a second off the bursts' schedule: at the same tick the ring is full of a burst, and + * these two records would be dropped every time */ + emb_instant_t next = emb_instant_add(emb_time_now(), EMB_MS(500)); (void)arg; EMB_CHECK(emb_trace_start()); for (;;) { From b83a95a50cd74f609e66a24291488737cc4d9d01 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 05:54:51 +0100 Subject: [PATCH 19/25] docs: the interrupt-context table lists the log, console, frame and trace calls Regenerated by tools/docs/isr_table.py from the headers' @ctx tags. Signed-off-by: teo1747 --- docs/user/interrupts.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/user/interrupts.md b/docs/user/interrupts.md index 8b9e50e7..692a399f 100644 --- a/docs/user/interrupts.md +++ b/docs/user/interrupts.md @@ -45,12 +45,13 @@ Calling anything else from a handler is misuse: in a checked build it faults wit -133 functions, from the headers' `@ctx` tags. +143 functions, from the headers' `@ctx` tags. | Function | Header | Blocks | |---|---|---| | `emb_check_status()` | `` | no | | `emb_cond_attr_default()` | `` | no | +| `emb_console_frame()` | `` | yes, in a thread outside a critical section: for the console, held by another thread's frame | | `emb_context()` | `` | no | | `emb_device_caps()` | `` | no | | `emb_device_ready()` | `` | no | @@ -115,6 +116,7 @@ Calling anything else from a handler is misuse: in a checked build it faults wit | `emb_frame_decode_byte()` | `` | no | | `emb_frame_decoder_init()` | `` | no | | `emb_frame_encode()` | `` | no | +| `emb_frame_write()` | `` | no | | `emb_in_isr()` | `` | no | | `emb_instant_add()` | `` | no | | `emb_instant_before()` | `` | no | @@ -129,6 +131,11 @@ Calling anything else from a handler is misuse: in a checked build it faults wit | `emb_irq_pend()` | `` | no | | `emb_irq_unlock()` | `` | no | | `emb_isr_stack_info()` | `` | no | +| `emb_log_flush()` | `` | no | +| `emb_log_format_check_()` | `` | no | +| `emb_log_level_set()` | `` | no | +| `emb_log_stats_get()` | `` | no | +| `emb_log_write()` | `` | no | | `emb_msgq_attr_default()` | `` | no | | `emb_msgq_count()` | `` | no | | `emb_msgq_free()` | `` | no | @@ -169,6 +176,9 @@ Calling anything else from a handler is misuse: in a checked build it faults wit | `emb_timer_start_at()` | `` | no | | `emb_timer_start_periodic()` | `` | no | | `emb_timer_stop()` | `` | no | +| `emb_trace_dump()` | `` | yes, in a thread: for the console | +| `emb_trace_stats_get()` | `` | no | +| `emb_trace_stop()` | `` | no | | `emb_version_string()` | `` | no | | `emb_wallclock_adjust()` | `` | no | | `emb_wallclock_get()` | `` | no | From 45e7f51547f828655cb9c0b56dc7a78e1dbac32f Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 06:04:18 +0100 Subject: [PATCH 20/25] tests: test_frame's stream check keeps no second frame buffer The sink compares each byte with what emb_frame_encode() wrote as it comes, instead of copying the frame into a 320-byte buffer of its own, which took the Uno's static data to 1.25 KiB of its 2 KiB and ran the test into its stack under EmbSIM. Signed-off-by: teo1747 --- tests/conformance/test_frame.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/conformance/test_frame.c b/tests/conformance/test_frame.c index cb9b412e..0b3ceffc 100644 --- a/tests/conformance/test_frame.c +++ b/tests/conformance/test_frame.c @@ -232,16 +232,20 @@ EMB_TEST(frame_random_stream_with_damage) EMB_ASSERT_TRUE(dec.errors > 0u); } -/* emb_frame_write()'s sink: collects the frame, and counts the calls. */ -static uint8_t streamed[EMB_FRAME_ENCODED_MAX(300u) + 16u]; +/* emb_frame_write()'s sink: compares each byte with what emb_frame_encode() wrote into wire, as + * it comes, so no second buffer is needed (the Uno has 2 KiB), and counts the calls. */ static size_t streamed_len; static unsigned sink_calls; +static unsigned mismatches; static void collect(void *ctx, const uint8_t *bytes, size_t len) { + size_t i; (void)ctx; - if ((streamed_len + len) <= sizeof(streamed)) { - (void)memcpy(&streamed[streamed_len], bytes, len); + for (i = 0u; i < len; i++) { /* bounded by len */ + if (((streamed_len + i) >= sizeof(wire)) || (wire[streamed_len + i] != bytes[i])) { + mismatches++; + } } streamed_len += len; sink_calls++; @@ -271,9 +275,10 @@ EMB_TEST(frame_write_streams_the_encoders_bytes) n = encode(EMB_FRAME_CHANNEL_SHELL, payload, len); streamed_len = 0u; sink_calls = 0u; + mismatches = 0u; EMB_ASSERT_OK(emb_frame_write(EMB_FRAME_CHANNEL_SHELL, payload, len, collect, NULL)); EMB_ASSERT_EQ(streamed_len, n); - EMB_ASSERT_TRUE(memcmp(streamed, wire, n) == 0); + EMB_ASSERT_EQ(mismatches, 0u); } } /* a run inside the payload goes to the sink in one piece, not byte by byte */ From 34dde4f3d84c0082aa1f0763aed41d6506ba1d06 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 06:18:48 +0100 Subject: [PATCH 21/25] subsys: clang-tidy's findings fixed, and the MISRA findings that were cheap to fix clang-tidy: emb_log_format_check_ loses its trailing underscore (the naming rule); the %f formatter's sign was stored twice; the trace packet's slot index widens before it multiplies. The switches over the arguments' types are wrapped in a NOLINT scope for bugprone-branch- clone: their cases differ in the type va_arg reads, which the check does not compare. MISRA: the two rings' statics and the log's put8 take names of their own (5.9: log_ring, log_stats, rec_put8; trace_ring, trace_stats), which also tells them apart in a debugger; to_digits and the %f formatter no longer modify a parameter (17.8); one conditional is parenthesized (12.1). Signed-off-by: teo1747 --- docs/user/interrupts.md | 2 +- include/emb/api_ids.h | 2 +- include/emb/log.h | 14 ++++----- subsys/logging/log.c | 59 +++++++++++++++++++---------------- subsys/trace/ring.c | 21 +++++++------ tools/fault/api-ids.json | 2 +- tools/fault/api-registry.json | 2 +- 7 files changed, 54 insertions(+), 48 deletions(-) diff --git a/docs/user/interrupts.md b/docs/user/interrupts.md index 692a399f..aca79527 100644 --- a/docs/user/interrupts.md +++ b/docs/user/interrupts.md @@ -132,7 +132,7 @@ Calling anything else from a handler is misuse: in a checked build it faults wit | `emb_irq_unlock()` | `` | no | | `emb_isr_stack_info()` | `` | no | | `emb_log_flush()` | `` | no | -| `emb_log_format_check_()` | `` | no | +| `emb_log_format_check()` | `` | no | | `emb_log_level_set()` | `` | no | | `emb_log_stats_get()` | `` | no | | `emb_log_write()` | `` | no | diff --git a/include/emb/api_ids.h b/include/emb/api_ids.h index 5febecd4..f27d6965 100644 --- a/include/emb/api_ids.h +++ b/include/emb/api_ids.h @@ -250,7 +250,7 @@ #define EMB_API_ID_LOG_FLUSH 0x00FDu #define EMB_API_ID_LOG_STATS_GET 0x00FEu #define EMB_API_ID_CONSOLE_FRAME 0x00FFu -#define EMB_API_ID_LOG_FORMAT_CHECK_ 0x0100u +#define EMB_API_ID_LOG_FORMAT_CHECK 0x0100u #define EMB_API_ID_TRACE_START 0x0101u #define EMB_API_ID_TRACE_STOP 0x0102u #define EMB_API_ID_TRACE_DUMP 0x0103u diff --git a/include/emb/log.h b/include/emb/log.h index a82b53f6..9afc2cad 100644 --- a/include/emb/log.h +++ b/include/emb/log.h @@ -209,7 +209,7 @@ typedef struct emb_log_header { do { \ if (EMB_LOG_ON_(lvl, m)) { \ EMB_LOG_META_(lvl, m, EMB_LOG_FIRST_(__VA_ARGS__), EMB_LOG_SIG_(__VA_ARGS__)); \ - (void)sizeof(emb_log_format_check_(__VA_ARGS__), 0); \ + (void)sizeof(emb_log_format_check(__VA_ARGS__), 0); \ if ((uint8_t)(lvl) <= emb_log_module_##m##_.level) { \ emb_log_write(&emb_log_meta_, \ EMB_LOG_SIG_(__VA_ARGS__) EMB_LOG_REST_(__VA_ARGS__)); \ @@ -228,10 +228,10 @@ typedef struct emb_log_header { } while (0) #else /* logging off: the arguments are still checked against the format, and nothing is emitted */ -#define EMB_LOG_AT_(lvl, m, ...) \ - do { \ - (void)sizeof(emb_log_format_check_(__VA_ARGS__), 0); \ - (void)emb_log_file_level_##m##_; \ +#define EMB_LOG_AT_(lvl, m, ...) \ + do { \ + (void)sizeof(emb_log_format_check(__VA_ARGS__), 0); \ + (void)emb_log_file_level_##m##_; \ } while (0) #define EMB_LOG_HEX_(lvl, m, buf, len, label) \ do { \ @@ -297,7 +297,7 @@ typedef struct emb_log_header { #define EMB_LOG_REST_9(f, a, b, c, d, e, g, h, k) , (a), (b), (c), (d), (e), (g), (h), (k) /** - * emb_log_format_check_() - Never called or defined: how a call's format is checked. + * emb_log_format_check() - Never called or defined: how a call's format is checked. * @format: The call's format. * @...: Its arguments. * @@ -313,7 +313,7 @@ typedef struct emb_log_header { * The log macros name it inside sizeof with the call's format and arguments, so the compiler * checks them as it checks printf's, and nothing is evaluated. */ -void emb_log_format_check_(const char *format, ...) EMB_PRINTF_FORMAT(1, 2); +void emb_log_format_check(const char *format, ...) EMB_PRINTF_FORMAT(1, 2); /** * emb_log_write() - Pack one record into the log ring: what a call site calls. diff --git a/subsys/logging/log.c b/subsys/logging/log.c index cd2c2e62..73e3e203 100644 --- a/subsys/logging/log.c +++ b/subsys/logging/log.c @@ -105,13 +105,13 @@ EMB_STATIC_ASSERT(CONFIG_EMB_LOG_THREAD_PRIORITY < CONFIG_EMB_PRIORITY_COUNT, /* ---- the ring ---------------------------------------------------------------------- */ -static uint8_t ring[RING_SIZE]; +static uint8_t log_ring[RING_SIZE]; /* Lock domain: the critical section (emb_irq_lock), for every variable below. */ static uint32_t ring_head; /* the next byte to reserve */ static uint32_t ring_tail; /* the oldest byte not taken: the free space ends here */ static uint32_t ring_claims; /* moved by each consumer's claim, so a preempted one can tell */ static uint32_t ring_lost; /* records refused since the last one that fitted */ -static emb_log_stats_t ring_stats; +static emb_log_stats_t log_stats; static bool flushing; /* emb_log_flush() is sending: a nested one leaves it to it */ #if CONFIG_EMB_LOG_THREAD static bool log_ready; /* the log thread's semaphore exists */ @@ -120,12 +120,12 @@ static emb_sem_t log_sem; static void ring_set(uint32_t pos, uint8_t b) { - ring[pos & RING_MASK] = b; + log_ring[pos & RING_MASK] = b; } static uint8_t ring_at(uint32_t pos) { - return ring[pos & RING_MASK]; + return log_ring[pos & RING_MASK]; } /* A record's header, its committed bit clear. */ @@ -140,7 +140,7 @@ typedef struct rec_writer { uint32_t pos; } rec_writer_t; -static void put8(rec_writer_t *w, uint8_t b) +static void rec_put8(rec_writer_t *w, uint8_t b) { ring_set(w->pos, b); w->pos++; @@ -150,7 +150,7 @@ static void put_le(rec_writer_t *w, uint64_t v, uint32_t bytes) { uint32_t i; for (i = 0u; i < bytes; i++) { /* bounded: at most eight bytes */ - put8(w, (uint8_t)(v >> (8u * i))); + rec_put8(w, (uint8_t)(v >> (8u * i))); } } @@ -190,15 +190,15 @@ static bool ring_reserve(uint32_t len, uint32_t dropped_len, uint32_t *pos, uint } hdr_write(ring_head + extra, len); ring_head += need; - if ((used + need) > ring_stats.high_water) { - ring_stats.high_water = used + need; + if ((used + need) > log_stats.high_water) { + log_stats.high_water = used + need; } *ts = now_ticks(); } else { if (ring_lost != UINT32_MAX) { ring_lost++; } - ring_stats.dropped++; + log_stats.dropped++; } emb_irq_unlock(key); return ok; @@ -213,7 +213,7 @@ static void ring_commit(uint32_t pos, uint32_t len) EMB_COMPILER_BARRIER(); /* the record's bytes before the bit that publishes them */ ring_set(pos + 1u, (uint8_t)(((len >> 8) & LEN_HI_MASK) | HDR_COMMITTED)); key = emb_irq_lock(); - ring_stats.records++; + log_stats.records++; at_tail = pos == ring_tail; emb_irq_unlock(key); if (at_tail) { @@ -304,6 +304,8 @@ static uint32_t args_size(uint32_t sig, va_list *ap) if ((t == EMB_LOG_T_END) || (t > EMB_LOG_T_HEX)) { break; } + /* NOLINTBEGIN(bugprone-branch-clone): the cases differ in the type va_arg reads, which the + * check does not compare */ switch (t) { case EMB_LOG_T_INT: (void)va_arg(*ap, int); @@ -348,6 +350,7 @@ static uint32_t args_size(uint32_t sig, va_list *ap) break; } } + /* NOLINTEND(bugprone-branch-clone) */ } return size; } @@ -357,7 +360,7 @@ static void put_bytes(rec_writer_t *w, const void *src, uint32_t n) const uint8_t *p = (const uint8_t *)src; uint32_t i; for (i = 0u; i < n; i++) { /* bounded by n */ - put8(w, p[i]); + rec_put8(w, p[i]); } } @@ -369,6 +372,8 @@ static void args_write(rec_writer_t *w, uint32_t sig, va_list *ap) if ((t == EMB_LOG_T_END) || (t > EMB_LOG_T_HEX)) { break; } + /* NOLINTBEGIN(bugprone-branch-clone): the cases differ in the type va_arg reads, which the + * check does not compare */ switch (t) { case EMB_LOG_T_INT: put_le(w, (uint64_t)(int64_t)va_arg(*ap, int), 4u); @@ -396,7 +401,7 @@ static void args_write(rec_writer_t *w, uint32_t sig, va_list *ap) case EMB_LOG_T_STR: { const char *s = va_arg(*ap, const char *); uint32_t n = str_len(s); - put8(w, (uint8_t)n); + rec_put8(w, (uint8_t)n); put_bytes(w, s, n); break; } @@ -413,12 +418,13 @@ static void args_write(rec_writer_t *w, uint32_t sig, va_list *ap) } else { uint32_t i; for (i = 0u; i < n; i++) { /* bounded by HEX_MAX: nothing to dump, zeros */ - put8(w, 0u); + rec_put8(w, 0u); } } break; } } + /* NOLINTEND(bugprone-branch-clone) */ } } @@ -477,7 +483,7 @@ emb_status_t emb_log_stats_get(emb_log_stats_t *out) return EMB_EINVAL; } key = emb_irq_lock(); - *out = ring_stats; + *out = log_stats; emb_irq_unlock(key); return EMB_OK; } @@ -525,7 +531,7 @@ static take_result_t ring_take(uint8_t *buf, uint32_t cap, uint32_t *len) taken = (ring_claims == claim) && (ring_tail == at); if (taken) { ring_tail = at + HDR_BYTES + n; - ring_stats.sent++; + log_stats.sent++; } emb_irq_unlock(key); if (taken) { @@ -579,7 +585,7 @@ static void put_start(void) w.pos = pos + HDR_BYTES; put_head(&w, EMB_LOG_ID_START, ts); for (i = 0u; i < EMB_CRASH_BUILD_ID_SIZE; i++) { /* bounded: 20 bytes */ - put8(&w, EMB_FLASH_READ_U8(&emb_build_id[i])); + rec_put8(&w, EMB_FLASH_READ_U8(&emb_build_id[i])); } put_le(&w, (uint32_t)CONFIG_EMB_TICK_NS, 4u); ring_commit(pos, len); @@ -718,11 +724,12 @@ static uint32_t to_digits(uint64_t v, uint32_t base, bool upper, char *buf) uint32_t n = 0u; uint32_t i; const char *set = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + uint64_t left = v; do { /* bounded: at most 22 digits of a 64-bit value */ - tmp[n] = set[v % base]; + tmp[n] = set[left % base]; n++; - v /= base; - } while (v != 0u); + left /= base; + } while (left != 0u); for (i = 0u; i < n; i++) { /* bounded by n */ buf[i] = tmp[n - 1u - i]; } @@ -758,24 +765,22 @@ static void out_int(out_t *o, const spec_t *sp, int64_t sv, uint64_t uv, char co #if CONFIG_EMB_LOG_FLOAT /* Fixed point for %f (and %e and %g, which print as %f here): up to nine decimals. */ -static void out_double(out_t *o, const spec_t *sp, double d) +static void out_double(out_t *o, const spec_t *sp, double value) { static const uint32_t pow10[10] = {1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 10000000u, 100000000u, 1000000000u}; char digits[40]; uint32_t nd; uint32_t prec = (sp->prec < 0) ? 6u : (((uint32_t)sp->prec > 9u) ? 9u : (uint32_t)sp->prec); - const char *sign = ""; + const char *sign; uint64_t ip; uint64_t fp; - bool neg = d < 0.0; - if (d != d) { /* NaN */ + bool neg = value < 0.0; + double d = neg ? -value : value; + if (value != value) { /* NaN */ out_field(o, sp, "", "nan", 3u); return; } - if (neg) { - d = -d; - } sign = neg ? "-" : (sp->plus ? "+" : (sp->space ? " " : "")); if (d >= 1.8e19) { /* beyond a 64-bit integer part, infinity included */ out_field(o, sp, sign, "inf", 3u); @@ -902,7 +907,7 @@ static void narrow(arg_t *a, uint32_t h, char conv) } a->u &= (h == 2u) ? 0xFFu : 0xFFFFu; if ((conv == 'd') || (conv == 'i')) { - a->s = sign_extend(a->u, h == 2u ? 1u : 2u); + a->s = sign_extend(a->u, (h == 2u) ? 1u : 2u); } else { a->s = (int64_t)a->u; } diff --git a/subsys/trace/ring.c b/subsys/trace/ring.c index e44e6d06..83526e93 100644 --- a/subsys/trace/ring.c +++ b/subsys/trace/ring.c @@ -63,11 +63,11 @@ typedef struct trace_rec { uint32_t a[3]; } trace_rec_t; -static trace_rec_t ring[RING_EVENTS]; +static trace_rec_t trace_ring[RING_EVENTS]; /* Lock domain: the critical section (emb_irq_lock), for every variable below. */ static uint32_t ring_next; /* the next event's number: events [next - size, next) are kept */ static bool recording; -static emb_trace_stats_t ring_stats; +static emb_trace_stats_t trace_stats; static void ring_sink(const emb_trace_event_t *ev, void *ctx) { @@ -76,7 +76,7 @@ static void ring_sink(const emb_trace_event_t *ev, void *ctx) (void)ctx; key = emb_irq_lock(); if (recording) { - r = &ring[ring_next & RING_MASK]; + r = &trace_ring[ring_next & RING_MASK]; r->ts = (uint32_t)emb_arch_cycles(); r->id = ev->id; r->cpu = ev->cpu; @@ -85,7 +85,7 @@ static void ring_sink(const emb_trace_event_t *ev, void *ctx) r->a[1] = (uint32_t)ev->a1; r->a[2] = (uint32_t)ev->a2; ring_next++; - ring_stats.recorded++; + trace_stats.recorded++; } emb_irq_unlock(key); } @@ -113,7 +113,7 @@ emb_status_t emb_trace_stats_get(emb_trace_stats_t *out) return EMB_EINVAL; } key = emb_irq_lock(); - *out = ring_stats; + *out = trace_stats; emb_irq_unlock(key); return EMB_OK; } @@ -131,7 +131,7 @@ bool embs_trace_read(uint32_t seq, uint8_t out[EMB_TRACE_RECORD_SIZE]) emb_irq_key_t key = emb_irq_lock(); bool kept = ((ring_next - seq) - 1u) < RING_EVENTS; /* seq in [next - size, next) */ if (kept) { - const trace_rec_t *r = &ring[seq & RING_MASK]; + const trace_rec_t *r = &trace_ring[seq & RING_MASK]; uint32_t i; uint32_t k; uint32_t w[5]; @@ -186,13 +186,14 @@ static void send_events(uint8_t *packet, uint32_t *from, uint32_t end) uint32_t n = 0u; while ((*from != end) && !embs_trace_read(*from, slot)) { /* bounded by end */ emb_irq_key_t key = emb_irq_lock(); - ring_stats.overwritten++; + trace_stats.overwritten++; emb_irq_unlock(key); (*from)++; } first = *from; while ((n < PACKET_EVENTS) && (*from != end) && - embs_trace_read(*from, &slot[n * EMB_TRACE_RECORD_SIZE])) { /* bounded by a packet */ + embs_trace_read( + *from, &slot[(size_t)n * EMB_TRACE_RECORD_SIZE])) { /* bounded by a packet */ n++; (*from)++; } @@ -202,7 +203,7 @@ static void send_events(uint8_t *packet, uint32_t *from, uint32_t end) (void)emb_console_frame(EMB_FRAME_CHANNEL_TRACE, packet, PACKET_HEADER + (n * EMB_TRACE_RECORD_SIZE)); key = emb_irq_lock(); - ring_stats.sent += n; + trace_stats.sent += n; emb_irq_unlock(key); } } @@ -307,7 +308,7 @@ static void stream_thread(void *arg) end = embs_trace_next(); if ((end - from) > RING_EVENTS) { /* lapped: what was overwritten is lost */ emb_irq_key_t key = emb_irq_lock(); - ring_stats.overwritten += (end - from) - RING_EVENTS; + trace_stats.overwritten += (end - from) - RING_EVENTS; emb_irq_unlock(key); from = end - RING_EVENTS; } diff --git a/tools/fault/api-ids.json b/tools/fault/api-ids.json index 4cbc6bd1..85405173 100644 --- a/tools/fault/api-ids.json +++ b/tools/fault/api-ids.json @@ -1480,7 +1480,7 @@ }, { "id": 256, - "name": "emb_log_format_check_", + "name": "emb_log_format_check", "header": "log.h", "state": "active" }, diff --git a/tools/fault/api-registry.json b/tools/fault/api-registry.json index 0fb99b22..c4f1bd7a 100644 --- a/tools/fault/api-registry.json +++ b/tools/fault/api-registry.json @@ -1479,7 +1479,7 @@ }, { "id": 256, - "name": "emb_log_format_check_", + "name": "emb_log_format_check", "header": "log.h", "state": "active" }, From ef2faaf8817cff9d7314b84f90b5042442009ab1 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 06:26:15 +0100 Subject: [PATCH 22/25] analysis: the MISRA baseline takes M4.3's code Taken from CI's misra-baseline-now at 34dde4f3. The log, trace and console code adds what every kernel file baselines: 8.7 on public functions, 2.5 on macros a header offers, 10.x on status and level comparisons, and 17.1 on , which the variadic log call needs. Each board's emb_board_write() converts its void pointer once (11.5). Lower: the boards' old puts no longer modify their parameter (17.8), and native and exec lost an unused external function each. Signed-off-by: teo1747 --- tools/analysis/misra-baseline.json | 71 +++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/tools/analysis/misra-baseline.json b/tools/analysis/misra-baseline.json index de8746ed..8612ad7b 100644 --- a/tools/analysis/misra-baseline.json +++ b/tools/analysis/misra-baseline.json @@ -99,7 +99,7 @@ "misra-c2012-21.8": 2, "misra-c2012-22.8": 1, "misra-c2012-22.9": 1, - "misra-c2012-8.7": 22, + "misra-c2012-8.7": 20, "misra-c2012-8.9": 1 }, "arch/riscv/include/emb_arch.h": { @@ -164,7 +164,7 @@ }, "boards/native/native/board.c": { "misra-c2012-21.6": 2, - "misra-c2012-8.7": 4 + "misra-c2012-8.7": 3 }, "boards/native/native/include/emb_board.h": { "misra-c2012-2.5": 1 @@ -377,7 +377,7 @@ "misra-config": 5 }, "generated/include/emb/config.h": { - "misra-c2012-2.5": 77 + "misra-c2012-2.5": 97 }, "generated/include/emb/storage.h": { "misra-c2012-19.2": 20, @@ -385,7 +385,7 @@ "misra-c2012-5.6": 16 }, "include/emb/api_ids.h": { - "misra-c2012-2.5": 181 + "misra-c2012-2.5": 195 }, "include/emb/compiler.h": { "misra-c2012-17.8": 3, @@ -402,7 +402,7 @@ "misra-c2012-21.1": 2 }, "include/emb/compiler/gcc.h": { - "misra-c2012-2.5": 5, + "misra-c2012-2.5": 3, "misra-c2012-20.10": 2, "misra-c2012-20.7": 1 }, @@ -479,6 +479,13 @@ "misra-c2012-20.12": 1, "misra-c2012-20.7": 1 }, + "include/emb/log.h": { + "misra-c2012-2.3": 1, + "misra-c2012-2.4": 1, + "misra-c2012-2.5": 54, + "misra-c2012-20.10": 9, + "misra-c2012-20.7": 2 + }, "include/emb/msgq.h": { "misra-c2012-19.2": 1, "misra-c2012-2.5": 3, @@ -532,7 +539,8 @@ "misra-c2012-5.6": 1 }, "include/emb/trace.h": { - "misra-c2012-2.4": 1 + "misra-c2012-2.4": 1, + "misra-c2012-2.5": 3 }, "include/emb/types.h": { "misra-c2012-19.2": 1, @@ -617,7 +625,7 @@ "misra-c2012-12.1": 11, "misra-c2012-2.5": 1, "misra-c2012-8.11": 1, - "misra-c2012-8.7": 14 + "misra-c2012-8.7": 13 }, "kernel/fault/crash.c": { "misra-c2012-10.5": 1, @@ -805,7 +813,7 @@ }, "kernel/trace/trace.c": { "misra-c2012-11.1": 1, - "misra-c2012-8.7": 2 + "misra-c2012-8.7": 1 }, "kernel/wait/wait.c": { "misra-c2012-10.8": 1, @@ -849,8 +857,9 @@ "misra-c2012-10.2": 1, "misra-c2012-10.8": 2, "misra-c2012-11.4": 1, + "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 1, "misra-c2012-8.7": 2 }, @@ -860,8 +869,9 @@ "soc/microchip/atmega/board.c": { "misra-c2012-10.2": 1, "misra-c2012-10.8": 2, + "misra-c2012-11.5": 1, "misra-c2012-12.1": 1, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.7": 4 }, "soc/microchip/atmega/include/emb_board.h": { @@ -871,8 +881,9 @@ "misra-c2012-10.2": 1, "misra-c2012-10.8": 7, "misra-c2012-11.4": 6, + "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 1, "misra-c2012-8.7": 2 }, @@ -883,8 +894,9 @@ "misra-c2012-10.2": 1, "misra-c2012-10.8": 3, "misra-c2012-11.4": 4, + "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 2, "misra-c2012-8.7": 2 }, @@ -894,9 +906,10 @@ "soc/rpi/rp2350/board.c": { "misra-c2012-10.2": 1, "misra-c2012-10.8": 1, + "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, "misra-c2012-12.2": 5, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-2.5": 3, "misra-c2012-8.6": 2, "misra-c2012-8.7": 2 @@ -911,8 +924,9 @@ "soc/st/stm32f4/board.c": { "misra-c2012-10.2": 1, "misra-c2012-10.8": 1, + "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 2, "misra-c2012-8.7": 2 }, @@ -923,8 +937,33 @@ "misra-c2012-20.10": 1, "misra-c2012-8.11": 1 }, - "subsys/transport/frame.c": { + "subsys/console/console.c": { + "misra-c2012-2.5": 1, + "misra-c2012-8.7": 2 + }, + "subsys/logging/log.c": { + "misra-c2012-10.4": 2, + "misra-c2012-10.7": 3, + "misra-c2012-10.8": 4, + "misra-c2012-11.4": 2, "misra-c2012-11.5": 1, - "misra-c2012-8.7": 3 + "misra-c2012-17.1": 30, + "misra-c2012-19.2": 2, + "misra-c2012-2.5": 2, + "misra-c2012-8.7": 9, + "misra-c2012-8.9": 8, + "misra-config": 1 + }, + "subsys/trace/ring.c": { + "misra-c2012-10.4": 1, + "misra-c2012-11.5": 1, + "misra-c2012-2.5": 2, + "misra-c2012-8.7": 4, + "misra-c2012-8.9": 2 + }, + "subsys/transport/frame.c": { + "misra-c2012-10.8": 1, + "misra-c2012-11.5": 2, + "misra-c2012-8.7": 4 } } From 2022c1e28248df6608b1af2c85510c7b5966bb96 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 06:37:45 +0100 Subject: [PATCH 23/25] subsys: the trace sink's record pointer lives in its branch (cppcheck variableScope) Signed-off-by: teo1747 --- subsys/trace/ring.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/trace/ring.c b/subsys/trace/ring.c index 83526e93..30e01366 100644 --- a/subsys/trace/ring.c +++ b/subsys/trace/ring.c @@ -72,11 +72,10 @@ static emb_trace_stats_t trace_stats; static void ring_sink(const emb_trace_event_t *ev, void *ctx) { emb_irq_key_t key; - trace_rec_t *r; (void)ctx; key = emb_irq_lock(); if (recording) { - r = &trace_ring[ring_next & RING_MASK]; + trace_rec_t *r = &trace_ring[ring_next & RING_MASK]; r->ts = (uint32_t)emb_arch_cycles(); r->id = ev->id; r->cpu = ev->cpu; From 33ca78bb29fe33aa1d66b71780a6834c9a6ef89e Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 06:43:02 +0100 Subject: [PATCH 24/25] docs: M4.3 on hardware, the NUCLEO-F446RE and the Pico 2 W The suites at 34dde4f3: 49 of 49 on the NUCLEO-F446RE and 51 of 51 on the Pico 2 W, with GCC and with Clang, test_frame and test_log among them, the producers-at-once case on both. The framed console's soak, 30 minutes on each board: 149,411 and 145,624 frames, none damaged, every numbered record missing counted by a dropped record; a 5-minute soak on the NUCLEO shows the rings' counters. The logging example's backends print the same lines on both boards, the trace example's 256 events decode, and console_echo came back through the relay both ways. The soaks' archives keep the counts, the first 256 KiB of the capture and the whole capture's size and SHA-256. The support matrix follows. Signed-off-by: teo1747 --- docs/engineering/hardware-runs.json | 6 +- .../hil-logging-trace-2026-11-13.md | 54 + .../log_soak.head.bin.gz | Bin 0 -> 91860 bytes .../log_soak.json | 30 + .../log_soak.head.bin.gz | Bin 0 -> 91371 bytes .../log_soak.json | 27 + .../bench_compare.json | 63 + .../bench_compare.log | 7 + .../bench_irq.json | 40 + .../bench_irq.log | 5 + .../bench_switch.json | 39 + .../bench_switch.log | 5 + .../index.json | 942 ++++++++ .../test_cond.json | 107 + .../test_cond.log | 48 + .../test_crash.json | 65 + .../test_crash.log | 19 + .../test_crash_hw.json | 53 + .../test_crash_hw.log | 13 + .../test_crash_reset.json | 53 + .../test_crash_reset.log | 13 + .../test_debug_descriptor.json | 71 + .../test_debug_descriptor.log | 21 + .../test_device.json | 143 ++ .../test_device.log | 71 + .../test_dma.json | 71 + .../test_dma.log | 22 + .../test_entropy.json | 89 + .../test_entropy.log | 34 + .../test_event.json | 113 + .../test_event.log | 52 + .../test_fault.json | 59 + .../test_fault.log | 14 + .../test_first_execution.json | 53 + .../test_first_execution.log | 10 + .../test_flash.json | 83 + .../test_flash.log | 30 + .../test_flash_board.json | 59 + .../test_flash_board.log | 13 + .../test_fpu.json | 59 + .../test_fpu.log | 11 + .../test_frame.json | 101 + .../test_frame.log | 41 + .../test_gpio.json | 77 + .../test_gpio.log | 26 + .../test_i2c.json | 101 + .../test_i2c.log | 42 + .../test_i2c_loop.json | 89 + .../test_i2c_loop.log | 33 + .../test_irq.json | 95 + .../test_irq.log | 40 + .../test_irq_priority.json | 107 + .../test_irq_priority.log | 47 + .../test_isr_stack.json | 65 + .../test_isr_stack.log | 19 + .../test_log.json | 89 + .../test_log.log | 35 + .../test_msgq.json | 119 + .../test_msgq.log | 56 + .../test_mutex.json | 137 ++ .../test_mutex.log | 73 + .../test_notify.json | 107 + .../test_notify.log | 47 + .../test_rtc.json | 77 + .../test_rtc.log | 26 + .../test_rtc_board.json | 71 + .../test_rtc_board.log | 22 + .../test_sched.json | 101 + .../test_sched.log | 42 + .../test_sem.json | 119 + .../test_sem.log | 56 + .../test_smoke.json | 65 + .../test_smoke.log | 17 + .../test_spi.json | 101 + .../test_spi.log | 42 + .../test_spi_loop.json | 95 + .../test_spi_loop.log | 37 + .../test_thread.json | 113 + .../test_thread.log | 52 + .../test_thread_identity.json | 77 + .../test_thread_identity.log | 28 + .../test_thread_join.json | 83 + .../test_thread_join.log | 31 + .../test_time.json | 95 + .../test_time.log | 37 + .../test_timer.json | 89 + .../test_timer.log | 36 + .../test_uart.json | 95 + .../test_uart.log | 38 + .../test_uart_board.json | 77 + .../test_uart_board.log | Bin 0 -> 1165 bytes .../test_uart_loop.json | 83 + .../test_uart_loop.log | 29 + .../test_wallclock.json | 59 + .../test_wallclock.log | 14 + .../test_wdog.json | 59 + .../test_wdog.log | 14 + .../test_wdog_board.json | 53 + .../test_wdog_board.log | 10 + .../test_wdt.json | 59 + .../test_wdt.log | 14 + .../test_wdt_board.json | 59 + .../test_wdt_board.log | 14 + .../test_workq.json | 143 ++ .../test_workq.log | 73 + .../bench_compare.json | 63 + .../bench_compare.log | 7 + .../bench_irq.json | 40 + .../bench_irq.log | 5 + .../bench_switch.json | 39 + .../bench_switch.log | 5 + .../index.json | 942 ++++++++ .../test_cond.json | 107 + .../test_cond.log | 48 + .../test_crash.json | 65 + .../test_crash.log | 19 + .../test_crash_hw.json | 53 + .../test_crash_hw.log | 13 + .../test_crash_reset.json | 53 + .../test_crash_reset.log | 13 + .../test_debug_descriptor.json | 71 + .../test_debug_descriptor.log | 21 + .../test_device.json | 143 ++ .../test_device.log | 71 + .../test_dma.json | 71 + .../test_dma.log | 22 + .../test_entropy.json | 89 + .../test_entropy.log | 34 + .../test_event.json | 113 + .../test_event.log | 52 + .../test_fault.json | 59 + .../test_fault.log | 14 + .../test_first_execution.json | 53 + .../test_first_execution.log | 10 + .../test_flash.json | 83 + .../test_flash.log | 30 + .../test_flash_board.json | 59 + .../test_flash_board.log | 13 + .../test_fpu.json | 59 + .../test_fpu.log | 11 + .../test_frame.json | 101 + .../test_frame.log | 41 + .../test_gpio.json | 77 + .../test_gpio.log | 26 + .../test_i2c.json | 101 + .../test_i2c.log | 42 + .../test_i2c_loop.json | 89 + .../test_i2c_loop.log | 33 + .../test_irq.json | 95 + .../test_irq.log | 40 + .../test_irq_priority.json | 107 + .../test_irq_priority.log | 47 + .../test_isr_stack.json | 65 + .../test_isr_stack.log | 19 + .../test_log.json | 89 + .../test_log.log | 35 + .../test_msgq.json | 119 + .../test_msgq.log | 56 + .../test_mutex.json | 137 ++ .../test_mutex.log | 73 + .../test_notify.json | 107 + .../test_notify.log | 47 + .../test_rtc.json | 77 + .../test_rtc.log | 26 + .../test_rtc_board.json | 71 + .../test_rtc_board.log | 22 + .../test_sched.json | 101 + .../test_sched.log | 42 + .../test_sem.json | 119 + .../test_sem.log | 56 + .../test_smoke.json | 65 + .../test_smoke.log | 17 + .../test_spi.json | 101 + .../test_spi.log | 42 + .../test_spi_loop.json | 95 + .../test_spi_loop.log | 37 + .../test_thread.json | 113 + .../test_thread.log | 52 + .../test_thread_identity.json | 77 + .../test_thread_identity.log | 28 + .../test_thread_join.json | 83 + .../test_thread_join.log | 31 + .../test_time.json | 95 + .../test_time.log | 37 + .../test_timer.json | 89 + .../test_timer.log | 36 + .../test_uart.json | 95 + .../test_uart.log | 38 + .../test_uart_board.json | 77 + .../test_uart_board.log | Bin 0 -> 1165 bytes .../test_uart_loop.json | 83 + .../test_uart_loop.log | 29 + .../test_wallclock.json | 59 + .../test_wallclock.log | 14 + .../test_wdog.json | 59 + .../test_wdog.log | 14 + .../test_wdog_board.json | 53 + .../test_wdog_board.log | 10 + .../test_wdt.json | 59 + .../test_wdt.log | 14 + .../test_wdt_board.json | 59 + .../test_wdt_board.log | 14 + .../test_workq.json | 143 ++ .../test_workq.log | 73 + .../log_soak.head.bin.gz | Bin 0 -> 88943 bytes .../2026-11-13-pico2_w-log-soak/log_soak.json | 30 + .../bench_compare.json | 65 + .../bench_compare.log | 7 + .../bench_irq.json | 42 + .../bench_irq.log | 5 + .../bench_switch.json | 41 + .../bench_switch.log | 5 + .../index.json | 978 ++++++++ .../test_cond.json | 109 + .../test_cond.log | 48 + .../test_crash.json | 67 + .../test_crash.log | 19 + .../test_crash_hw.json | 55 + .../test_crash_hw.log | 13 + .../test_crash_reset.json | 55 + .../test_crash_reset.log | 13 + .../test_debug_descriptor.json | 73 + .../test_debug_descriptor.log | 21 + .../test_device.json | 145 ++ .../test_device.log | 71 + .../test_dma.json | 73 + .../test_dma.log | 22 + .../test_entropy.json | 91 + .../test_entropy.log | 34 + .../test_entropy_board.json | 61 + .../test_entropy_board.log | 2065 +++++++++++++++++ .../test_event.json | 115 + .../test_event.log | 52 + .../test_fault.json | 61 + .../test_fault.log | 14 + .../test_first_execution.json | 55 + .../test_first_execution.log | 10 + .../test_flash.json | 85 + .../test_flash.log | 30 + .../test_flash_board.json | 61 + .../test_flash_board.log | 13 + .../test_fpu.json | 61 + .../test_fpu.log | 11 + .../test_frame.json | 103 + .../test_frame.log | 41 + .../test_gpio.json | 79 + .../test_gpio.log | 26 + .../test_i2c.json | 103 + .../test_i2c.log | 42 + .../test_i2c_loop.json | 91 + .../test_i2c_loop.log | 33 + .../test_irq.json | 97 + .../test_irq.log | 40 + .../test_irq_priority.json | 109 + .../test_irq_priority.log | 47 + .../test_isr_stack.json | 73 + .../test_isr_stack.log | 24 + .../test_log.json | 91 + .../test_log.log | 35 + .../test_msgq.json | 121 + .../test_msgq.log | 56 + .../test_mutex.json | 139 ++ .../test_mutex.log | 73 + .../test_notify.json | 109 + .../test_notify.log | 47 + .../test_rtc.json | 79 + .../test_rtc.log | 26 + .../test_rtc_board.json | 73 + .../test_rtc_board.log | 22 + .../test_sched.json | 103 + .../test_sched.log | 42 + .../test_sem.json | 121 + .../test_sem.log | 56 + .../test_smoke.json | 67 + .../test_smoke.log | 17 + .../test_spi.json | 103 + .../test_spi.log | 42 + .../test_spi_loop.json | 97 + .../test_spi_loop.log | 37 + .../test_stack_limit.json | 55 + .../test_stack_limit.log | 13 + .../test_thread.json | 115 + .../test_thread.log | 52 + .../test_thread_identity.json | 79 + .../test_thread_identity.log | 28 + .../test_thread_join.json | 85 + .../test_thread_join.log | 31 + .../test_time.json | 97 + .../test_time.log | 37 + .../test_timer.json | 91 + .../test_timer.log | 36 + .../test_uart.json | 97 + .../test_uart.log | 38 + .../test_uart_board.json | 73 + .../test_uart_board.log | 23 + .../test_uart_loop.json | 91 + .../test_uart_loop.log | 33 + .../test_wallclock.json | 61 + .../test_wallclock.log | 14 + .../test_wdog.json | 61 + .../test_wdog.log | 14 + .../test_wdog_board.json | 55 + .../test_wdog_board.log | 10 + .../test_wdt.json | 61 + .../test_wdt.log | 14 + .../test_wdt_board.json | 61 + .../test_wdt_board.log | 14 + .../test_workq.json | 145 ++ .../test_workq.log | 73 + .../bench_compare.json | 65 + .../bench_compare.log | 7 + .../bench_irq.json | 42 + .../bench_irq.log | 5 + .../bench_switch.json | 41 + .../bench_switch.log | 5 + .../2026-11-13-pico2_w-logging-gcc/index.json | 978 ++++++++ .../test_cond.json | 109 + .../test_cond.log | 48 + .../test_crash.json | 67 + .../test_crash.log | 19 + .../test_crash_hw.json | 55 + .../test_crash_hw.log | 13 + .../test_crash_reset.json | 55 + .../test_crash_reset.log | 13 + .../test_debug_descriptor.json | 73 + .../test_debug_descriptor.log | 21 + .../test_device.json | 145 ++ .../test_device.log | 71 + .../test_dma.json | 73 + .../test_dma.log | 22 + .../test_entropy.json | 91 + .../test_entropy.log | 34 + .../test_entropy_board.json | 61 + .../test_entropy_board.log | 2065 +++++++++++++++++ .../test_event.json | 115 + .../test_event.log | 52 + .../test_fault.json | 61 + .../test_fault.log | 14 + .../test_first_execution.json | 55 + .../test_first_execution.log | 10 + .../test_flash.json | 85 + .../test_flash.log | 30 + .../test_flash_board.json | 61 + .../test_flash_board.log | 13 + .../test_fpu.json | 61 + .../test_fpu.log | 11 + .../test_frame.json | 103 + .../test_frame.log | 41 + .../test_gpio.json | 79 + .../test_gpio.log | 26 + .../test_i2c.json | 103 + .../test_i2c.log | 42 + .../test_i2c_loop.json | 91 + .../test_i2c_loop.log | 33 + .../test_irq.json | 97 + .../test_irq.log | 40 + .../test_irq_priority.json | 109 + .../test_irq_priority.log | 47 + .../test_isr_stack.json | 73 + .../test_isr_stack.log | 24 + .../test_log.json | 91 + .../test_log.log | 35 + .../test_msgq.json | 121 + .../test_msgq.log | 56 + .../test_mutex.json | 139 ++ .../test_mutex.log | 73 + .../test_notify.json | 109 + .../test_notify.log | 47 + .../test_rtc.json | 79 + .../test_rtc.log | 26 + .../test_rtc_board.json | 73 + .../test_rtc_board.log | 22 + .../test_sched.json | 103 + .../test_sched.log | 42 + .../test_sem.json | 121 + .../test_sem.log | 56 + .../test_smoke.json | 67 + .../test_smoke.log | 17 + .../test_spi.json | 103 + .../test_spi.log | 42 + .../test_spi_loop.json | 97 + .../test_spi_loop.log | 37 + .../test_stack_limit.json | 55 + .../test_stack_limit.log | 13 + .../test_thread.json | 115 + .../test_thread.log | 52 + .../test_thread_identity.json | 79 + .../test_thread_identity.log | 28 + .../test_thread_join.json | 85 + .../test_thread_join.log | 31 + .../test_time.json | 97 + .../test_time.log | 37 + .../test_timer.json | 91 + .../test_timer.log | 36 + .../test_uart.json | 97 + .../test_uart.log | 38 + .../test_uart_board.json | 73 + .../test_uart_board.log | 23 + .../test_uart_loop.json | 91 + .../test_uart_loop.log | 33 + .../test_wallclock.json | 61 + .../test_wallclock.log | 14 + .../test_wdog.json | 61 + .../test_wdog.log | 14 + .../test_wdog_board.json | 55 + .../test_wdog_board.log | 10 + .../test_wdt.json | 61 + .../test_wdt.log | 14 + .../test_wdt_board.json | 61 + .../test_wdt_board.log | 14 + .../test_workq.json | 145 ++ .../test_workq.log | 73 + docs/engineering/index.md | 1 + docs/engineering/support-matrix.md | 4 +- 414 files changed, 30885 insertions(+), 3 deletions(-) create mode 100644 docs/engineering/hil-logging-trace-2026-11-13.md create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak-counters/log_soak.head.bin.gz create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak-counters/log_soak.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak/log_soak.head.bin.gz create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak/log_soak.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/index.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/index.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-log-soak/log_soak.head.bin.gz create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-log-soak/log_soak.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/index.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/index.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.log create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.json create mode 100644 docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.log diff --git a/docs/engineering/hardware-runs.json b/docs/engineering/hardware-runs.json index 3fb1ba83..174fe227 100644 --- a/docs/engineering/hardware-runs.json +++ b/docs/engineering/hardware-runs.json @@ -87,6 +87,10 @@ {"board": "nucleo_f446re", "preset": "cm4-nucleo-hil", "build": "checked (GCC 14.2.1)", "date": "2026-11-12", "configuration": "4648a817b7d5fc56", "passed": 47, "total": 47, "report": "hil-entropy-2026-11-12.md", "archive": "hil-runs/2026-11-12-nucleo_f446re-entropy-gcc"}, {"board": "nucleo_f446re", "preset": "cm4-nucleo-hil", "build": "checked (Clang 23.1.5 with LLD)", "date": "2026-11-12", "configuration": "4648a817b7d5fc56", "passed": 47, "total": 47, "report": "hil-entropy-2026-11-12.md", "archive": "hil-runs/2026-11-12-nucleo_f446re-entropy-clang"}, {"board": "pico2_w", "preset": "cm33-pico2w-hil", "build": "checked (GCC 14.2.1, 150 MHz)", "date": "2026-11-12", "configuration": "1aafec98e5605967", "passed": 49, "total": 49, "report": "hil-entropy-2026-11-12.md", "archive": "hil-runs/2026-11-12-pico2_w-entropy-gcc"}, - {"board": "pico2_w", "preset": "cm33-pico2w-hil", "build": "checked (Clang 23.1.5 with LLD, 150 MHz)", "date": "2026-11-12", "configuration": "1aafec98e5605967", "passed": 49, "total": 49, "report": "hil-entropy-2026-11-12.md", "archive": "hil-runs/2026-11-12-pico2_w-entropy-clang"} + {"board": "pico2_w", "preset": "cm33-pico2w-hil", "build": "checked (Clang 23.1.5 with LLD, 150 MHz)", "date": "2026-11-12", "configuration": "1aafec98e5605967", "passed": 49, "total": 49, "report": "hil-entropy-2026-11-12.md", "archive": "hil-runs/2026-11-12-pico2_w-entropy-clang"}, + {"board": "nucleo_f446re", "preset": "cm4-nucleo-hil", "build": "checked (GCC 14.2.1)", "date": "2026-11-13", "configuration": "aa8dd55373872741", "passed": 49, "total": 49, "report": "hil-logging-trace-2026-11-13.md", "archive": "hil-runs/2026-11-13-nucleo_f446re-logging-gcc"}, + {"board": "nucleo_f446re", "preset": "cm4-nucleo-hil", "build": "checked (Clang 23.1.5 with LLD)", "date": "2026-11-13", "configuration": "aa8dd55373872741", "passed": 49, "total": 49, "report": "hil-logging-trace-2026-11-13.md", "archive": "hil-runs/2026-11-13-nucleo_f446re-logging-clang"}, + {"board": "pico2_w", "preset": "cm33-pico2w-hil", "build": "checked (GCC 14.2.1, 150 MHz)", "date": "2026-11-13", "configuration": "9461e3c42192b75e", "passed": 51, "total": 51, "report": "hil-logging-trace-2026-11-13.md", "archive": "hil-runs/2026-11-13-pico2_w-logging-gcc"}, + {"board": "pico2_w", "preset": "cm33-pico2w-hil", "build": "checked (Clang 23.1.5 with LLD, 150 MHz)", "date": "2026-11-13", "configuration": "9461e3c42192b75e", "passed": 51, "total": 51, "report": "hil-logging-trace-2026-11-13.md", "archive": "hil-runs/2026-11-13-pico2_w-logging-clang"} ] } diff --git a/docs/engineering/hil-logging-trace-2026-11-13.md b/docs/engineering/hil-logging-trace-2026-11-13.md new file mode 100644 index 00000000..afbe3b33 --- /dev/null +++ b/docs/engineering/hil-logging-trace-2026-11-13.md @@ -0,0 +1,54 @@ +# Logging, the trace, the framed console and the two-way relay on hardware: NUCLEO-F446RE and Pico 2 W (2026-11-13) + +M4.3's pieces on both boards: logging with both backends (A127), the trace ring (A128), the framed console, `emb monitor`, and the NUCLEO's relay working both ways. The whole conformance suite ran on each board with GCC and with Clang, and every image passed, `test_frame` and `test_log` among them. Each board then ran the framed console's soak for 30 minutes: no frame was damaged, and every record that did not arrive was one a dropped record counted. + +**Commit:** `34dde4f3` for the suites, from a clean tree (branch `feat/transport-frame`, PR #139). The soaks ran `a5b6b75e` (NUCLEO-F446RE) and `1b58e07b` (Pico 2 W), the examples `9af19156` (NUCLEO-F446RE) and `c8d07630` (Pico 2 W); the subsystems' code is the same in all of them but for `34dde4f3`'s renames and fixes for the static analysis. + +**Bench:** the wires of the UART, SPI and I2C reports, and one more for the relay's way to the Pico 2 W: the NUCLEO's CN10 pin 21 (PA9) to the Pico's pin 2 (GPIO1). The NUCLEO-F446RE's console is its ST-LINK's virtual COM port; the Pico 2 W's is the NUCLEO running `tools/hil/nucleo-uart-relay`, both ways at 115200 baud. The NUCLEO-F446RE runs at 180 MHz, the Pico 2 W at 150 MHz. + +## The suites + +`ctest` ran on `cm4-nucleo-hil` and `cm33-pico2w-hil`, checked, with the UART, SPI and I2C loops as before. Each run's records are under `hil-runs/`: + +| Board | Compiler | Passed | Cases recorded | +|---|---|---|---| +| NUCLEO-F446RE | Arm GNU Toolchain 14.2.Rel1 (GCC 14.2.1) | 49 of 49 | 296 | +| NUCLEO-F446RE | Homebrew Clang 23.1.5 with LLD 23.1.5 | 49 of 49 | 296 | +| Pico 2 W | Arm GNU Toolchain 14.2.Rel1 (GCC 14.2.1) | 51 of 51 | 300 | +| Pico 2 W | Homebrew Clang 23.1.5 with LLD 23.1.5 | 51 of 51 | 300 | + +`test_frame` (9 cases) checks the codec against the host tool's vectors, its decoder's resynchronization and damage, and `emb_frame_write()` streaming exactly the bytes `emb_frame_encode()` writes. `test_log` (7 cases) checks the record's layout, the plain-text formats, the levels, a full ring dropping and counting, an interrupt's record held back by an uncommitted one, and three threads at three priorities with an interrupt logging at once while the test drains the ring: every producer's records came whole and in order, and those kept plus those counted dropped were all that were written (2,828 checks with GCC, 2,855 with Clang, on each board). `test_trace_ring` needs `CONFIG_EMB_TRACE`, which the boards' suites leave off: it runs natively, under ASan and TSan, in CI. + +## The framed console's soak + +`tools/hil/log-soak` logs a numbered record every 10 ms, a burst of 100 every second, more than the 1 KiB ring keeps while the log thread waits for the console, and both rings' counters every 5 s, while the trace streams on channel 1 every 500 ms. `tools/hil/log_soak.py` read each board's console for 30 minutes: + +| | NUCLEO-F446RE | Pico 2 W, through the relay | +|---|---|---| +| Frames | 149,411 | 145,624 | +| Damaged or too long | 0 | 0 | +| Log records decoded | 295,211 | 270,615 | +| Numbered records | 180,011 | 154,761 | +| Dropped, counted in band | 67,320 | 91,749 | +| Missing and not counted | 0 | 0 | +| Trace packets (events) | 23,400 (262,800) | 25,953 (277,999) | + +The trace's stream fills most of the line, so the log thread often waits for the console and the bursts drop records: that is the soak's point, and the accounting held through every one of them. The trace ring overwrites most events between two sends (the Pico 2 W's counters: 6,299,436 recorded, 6,020,401 overwritten, 277,371 sent), and each packet's first event number shows the host what it missed. The records are in `hil-runs/2026-11-13-nucleo_f446re-log-soak` and `hil-runs/2026-11-13-pico2_w-log-soak`, each with the counts, the first 256 KiB of the console as captured, and the whole capture's size and SHA-256 (10 MB a soak is too much for the repository; the captures are kept with the maintainer). + +The NUCLEO's 30 minutes ran the soak before a fix: its counters thread logged on the same tick as the bursts, when the ring was full, so its two records were dropped every time, and counted. They log half a second later since `1b58e07b`; the Pico 2 W's soak shows them, and so does a 5-minute soak on the NUCLEO at `34dde4f3` (`hil-runs/2026-11-13-nucleo_f446re-log-soak-counters`): 24,841 frames, none damaged, 29,988 numbered records, 11,100 dropped and counted, none missing, and the counters every 5 s (the last: 48,547 records committed, 10,915 dropped, 48,546 sent). + +## The examples + +- **Logging** (`examples/logging`), plain and framed on each board: `tools/logdec/backends_agree.py` found the same lines, and each build's burst kept its first records in order and counted the rest. The framed console carried 927 bytes on the NUCLEO-F446RE and 931 on the Pico 2 W, against 1748 and 1742 as plain text, and the framed image is 3 KB smaller: the formats stay in the ELF. +- **`emb`**: `emb build --framed`, `emb flash` and `emb monitor --where` on the NUCLEO-F446RE showed the records decoded with their call sites. +- **Tracing** (`examples/tracing`): 256 events over 16 ms on each board, the threads named, times at the cycle counter's resolution (3.7 µs between the first two events on the NUCLEO-F446RE). `tools/trace/trace.py` wrote the CTF trace and Perfetto's JSON from them. +- **The relay, both ways** (`examples/console_echo` on the Pico 2 W): "hello" and "through the relay" came back in capitals, and the 95 printable characters came back whole, in two lines of the example's 64-byte buffer. The bench commands on channel 15 answered: `ping` and `wake 50` with `ok`, an unknown one with `?`. + +## Found on the way + +- **A metadata at the null pointer.** The deferred backend's section is laid at address 0, so its first call site's metadata had the address 0, and `emb_log_write()` took it for a missing argument and returned. The QEMU AN386 run lost exactly that call's record. The generated linker scripts now leave the section's first 8 bytes empty (`7011cbd0`). +- **The dropped record's length.** Its header was sized for a 4-byte identifier where the record wrote 2: two stale bytes followed it. Found on native, fixed before the first commit. +- **One thread per priority on tiny.** The table scheduler's priorities hold a thread each, so the log thread took the test runner's priority on the micro:bit; there is no log thread on tiny (`9af19156`, A127). +- **AVR.** The plain-text formatter and its stack did not fit the Uno's 2 KiB beside the test framework: logging is not offered on AVR in M4.3. Its call sites are already read from program memory there. +- **`%u` and `uint32_t`.** On Arm and RISC-V newlib `uint32_t` is `unsigned long`: the format check (`EMB_PRINTF_FORMAT`) caught a test passing one to `%u`, which compiled on the Mac's native build. +- **A test buffer the Uno could not afford.** `test_frame`'s streaming case first kept a second frame buffer; under EmbSIM the Uno ran into its stack. The sink now compares each byte as it comes (`45e7f515`). diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak-counters/log_soak.head.bin.gz b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak-counters/log_soak.head.bin.gz new file mode 100644 index 0000000000000000000000000000000000000000..510acb08897f636d2246386ba246cfb0b94ef6b8 GIT binary patch literal 91860 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 z zxx*)bpjUpAbVUDtAdxEk_oA@DBM7J1gvg9|#eU*(T+M1${V^E1Q=5#~ORM*G&MM*A zmfs@A%iIC>HcRm_wl-$`{M)U0+LnN)aEX^(x9~C;s0{v}y7Au&it3O;FG$8s8Wj$) zq~n+cIepxQTiH875!*Luv6N7(a?PZJ=zj)?zjKE$R1M#wZ0RUBUg;tVR`0q4ltUp+%Ua4CH zZwaN(OIlI^S2KRhi^HMhSK@Z z*E#I4p!#>W*HSWJKVODMp!d6D8$?F zq?p8f*JkoEv|%e^(JOz;FpyClVdJVc*!D||R1$?ImcKV)40YmWsK7xU|xzi(bBHS}NwAz@#M?mD?jMd~d&&Y?Nfee$h~!z088Rbl>N>O`0m zJ~Xehedp*CAI=JQw~RCoVF%nJwWpx9(0B2eF6vcd6j}R<3}a+RAYjOAMG7^F!O2Hz zcY%gxz2FhV>>m8vnSbPZ$;C6yb5u7z#|5ZpL4!nR^AIZb#elY|pBFeUZFSU5a^gC1 z!3U=eq$s2c;&cXBxNOg7Ny{@UoWI@Lml7@w7aVz|N*4du7UN;d&4CVXl}pGT%Y_Zyy4rV;xb1sh;!4*rpiYtxq`-FvO8IhzK}bN3059M+r~5GO_SP!t3cX z4eTMfQoyb3P^pHJP}~=Ob$(J)kdWlo}Fzqo=x>&FyH`T@po38j)y4 zAuP?g3nO-8WI6)I>q3P{6U1gI$wrKC5$J$hD2F~(_#jKt{y9ZW0=uV0eRH?R{(CCl zj`P}a78>w5rp}w>jM{@m7%LU3%8Cb=HguXftL8ZN_Hc`_30a#FtixE(@A(t_Ye3en+BvfVcU( zCcM_I<%-+jLd}wVCCXbdt!^))loQm;iFrWOI6rzk-S`R97`2f-rUg8%${T&!P97LG z72Bvx9mRwra!0um79GZ?t>GCaA*dd$264>~>5K+9N^a{UtEPlzJSrs{H2?|CB5>@&y*!cREB z1+Eo!+vhowi;Kb{%c%*4dx0xB;pDRhrJM4oDE6yX7b^$rW{xD{+(Mq^zanv?!M)|d zY1L*&S!d{pRyfJWbth=`p*6wGJ%nTYTW24x?Br~G8^>gO72_0I2$ZM1`(QMqIni(# z@L_1jo*cal8~W={#c`{KP#D|ks`zLS;pLxH@BROIs<-}y#DDH^#w!3u$B&@-JY57* z(BV)0ui=kgV{S!csl!s0t|5|)M5xSAe#mY(&Tm2rF8PL_;@PLf{=lH8*drYcRJgrF z_71KR8(Ij~-yuiGK@dkFaNRZyuGi8%x4yP@Le0aF;ybbEn{1_1X0@x-ezAJ8?J9oep zRci?kO@j;#B7RExhPgs)JzNJEt@=&#fbwcI#4du>y(XE7j(W*ot2n!&yJ7sof2$#x zgtn42X-=?Fd214nPu1BdX2>*MV2R<-w-JD)>TfhMl);@29kw?s2bc4}^1JNWK5pkb zmPNs3m+M3Pdurjyi`Xk#d;&hIv&3KDnOe%fXpKm#R|~0aJWr-!YAOBVykk)~At@=r zSE;wr49X1et^8q{DANGY4;p>)(ig|m`*P+smcyL7U7Ir+A8y_PB_C-9hQ)#Tjt@8am?^zO z41|jB>1DsCONx1Y|FPqR(W-pqha9}jRNfJQ5}lV1dBE}6P$(VGXcQ739z{56AjxaS zjj4@{S*|B2r|75-He60)Dx55!i?s)alevsb#x+>93|`8)>zHUUFhrR{nYJu>F4k!e z>?!fmGnzpM71~EW`t_l%z-vp_K(&}JWZKi{a>hnS{Y6E5)#g>la{-|qB?Ta0- z&P-{pZJaqy;EbeSU)fvo%@(;hCxs$-o&jks#Ge?5B_$%Or3Vm(XQ_wio#BpM55)KF zg`>s~zu+E$CzXeA0H~ByZ&FZ}WWgR(4n>Z)*$M5uF+zK(*D+x28jQNu18XG_J-|0K z_@gT`sHKkZTI?(pZQJgrX*?rr>hRgrAwqbf<#(aA77&~B8=Rki#nwco+4Mn+>IrJ) z&huj?lU<0@URl#^tEX#x=t;$0Mr?ZTML>sudre)vX4T?GW#X?{z-ddwflsczOLiEM7&AJT2BBV$BxmpM0!!Hi_05w^lWP$D2-q!cGDNTedRXg9*LsTB zL%6<{2A|spPvIHXXMKP}{)nsw7aY(8>VVw_z!2uG{2(F<>VRbsDL`v3PqNp~u3NIq z2X%wv{k0{XX5iX4?GYBUR(-^SnR3c>ZqVW^i;@C|iKNKwrbU8KR^(XsT%?Ep3+97Vugm~0iiOoSsU2?ApoL5|8zF|D14N$SW&e#w4ZnP%Gxb~C@vR`c;Nf@)97bj zy8?XwMfs%<%EN}$p}va+E5!ugB1=Z&dT7f-%5zVsBSqmrfyNFre~ zs^Sn?7U~=qgJ{o^tEw40-8zu)xO?O$4dQNZor+X(4LBbQb4$vz9yn@{cy~N>F4Uel zmAZ-B$912yeZNPb%7gUb#nnLjQ2KsY$yIc5(EcBS~( zCvDfL82YRw%-RW)`^?`xJQ5^-H!hsT_DGZBg9?*CN0trqCHlYf3nzw+$bh<|jZ2)p z_#zIHlgk$caz-aOkCQj&kKHd40?&-bZ@WJv;DMvs@Y!nEpZdW84^Th&Kb4=|B>!Wl zm1b7a>Sy!g$av*t$`KP0v*8%k1>S_mE4DP9>^<~;+O^9F~x zJlB8A^==eCCZfS2Y*2htejx1V_2_fZFIn`SI=T6(VZYZtiszpcc?9H z%)s`iEmv#61U7|6?bYsRRku~ror&X_fHbNw$CQzqR2)ZBw91GbWIF_a+47r+RgmoM zrT{^sqrdY6AL@6fATbZMzSX{7b+h zyxnFq;=>pSu9FHC5y9X(DHk|p4128M`U;m4eBUkXp0k4X!5p#(n633SM4Aw`_tQ;a zowlX`)@ixF>~C?H_Flfqw{M2wxXz^T1fBQZ?|^ChP1v|*Z)Q2%#Rt?E#V`~W26MDk>vMvos$`e(9u^h>ESYs-%G z`8ShJvMGY&j`hk@`Wqz~6*pC4v$!mRqyP+C=OA5zL23CR>|vA>!QJ<${gXzV@OuYB%sX?0}zb@0MSUf zWyn=33?Ld?`BM)O32T(gs-qC}hOF;x9If>*(0_8Z=2;8`oX|qqiTIIYg3}S+amUUHeS&qinnS=KV%$>3`bu z5-Ikm#8wc6BOQjwV=^o21IUeMAb%8k!gj-9BM1Ne#_9wxbNO$}>66S{>rUQ~3A8Hh!S1y-6o! zg}pn(4%!@<8buGt$NfmUnwA9=Y$$Fs;{+IzB?KCxxI7#T-R=#rdSTfmDe&(-OHerY zt}r%ZK>hevxA>IHo4fZBE@J3yw+)bw&*Vn52w|J1LBJgml}GTSA5_6|0;82XNDOc# zfkK8rnxux+8_Q@jkaeXV?y|S*3<_jBdcjo}2_5K#xC(Ncv#vkHwmH%q`}IQhhzTOU z_ino>V*GQ_X@r-?1W4kPy`?n^PvSS*^_)DJcZ+? zz|5r@eiUfe*>1~MjrpjR4NT6|zPTb=z~pRN9xIm_;|rGEWx$;*Mrn>W_t*aNGe$`9 z?B2xR0Z8b7l{m|2{CjQdG{tth1x$-Aupkc9vm*TX7ER)?(hF^B+7$W2Kxr3`jHzVe z=NHE{q+ z(A*lqpO%0QO@(2nCt)4ktG$(I(!FdwZvG^2s1WCd{Kjl;I~_JXKgYF0{K4<;?;dDX z#z?bufo|F9;M&LS>d5^7Bp21zr8o0#zL@ZK@`fexp&Rb@iy1>iDPW*rt$P}TYNd2W z*Z4||i#CL`gwc4qc!@PaCsKNZRXS&B*yr{afNP5L8B37;xuLuE$5*nT83`(O$2_we ztg@iSglP5whQop^QL9=`hq&_jz>Zk~LaNY&z`~i#Oa`s0yIe}LHwPl8_!SlR$@V22 zb5Dj(1aW78A1&8RdElS7*FRDQ4WkOld4n^%KVkA|Jj|(xqa!>{oIhTbWaLuZNiSA} zUp@$s2J0{Iag8j3m!%)cN9Xj6T%a#96Mm~3{U4Z{sia{4@yPY226f#Pr(G(4I)49D zFqD=jRw)O8j^AGEyi#@w2c}}s#SnI{v{LsYfN#_jY5y-H*ZG^Amk8us68XLzKk!~T z$&5-eX4I$nYyP+Q-3e+@?CNWBqtaRPvWFsfVVwXdPFruWZ)u%T1;~Ph`_0%T0n}=+HySXbK6snx)?`RpK zhtp8hRpZM=U72@}DG-ayRp)4yE~wObB;nA3&^;^>b(p#pHFtr@7On7Llmeg}kj-ibwjfXEK{NDW=kMN1(!1*FWQ5fid{&TklKw0%EJSn&Mta=aKb zq;KOvOQY-D#xU)mpANFEgChp;`eMu!Gs?v>)_ZWURcS?7SP9}7U#@CyQQ++1sl$&k z5~>~x9xs?+-;JA?46$)anF!B)&ZLei8f2w&cvQ^hEJA(FVR>#74;RU03iGx5Z>`l2X0xe|B6aDzh2_ zs@9#wlwU{0rQTcQhtO?JaMNqUzIzb%Z83eNU2o$j~i)#PEm%&aZQBp7O7Tl^~DOi7b(jLng<1bDJM zZf?vYO2Rv8JFHT{DCO#uAw4~ImmIip>7&O@k($AW7e+2>SCgJ7{10}32};iWdJtci zDF9Qoz4uEe2R{xREh{rbg5Ej6(-Nz`9iIFKTn#uv^7Vr<|E*-EC{z8#2T(NpNlO|0vTzR_NSI$y~8;6*0 zXT2l2x9*>4F2BSX;=1u*;=?5yZDqihU}ZbAYDkJA)!}?jvXRemb_6;UQGzqeW=VpC z&=<7gk=2ZlLxLKs!*hl)-C+%?t<|g~8&d*!T zYa+Sak{jx#y3Sn(AVF;+=IK81Xcs1Yq|$x_?06ioUnTY~BBp`d%*A=RYBqujW~<;r2YK;nuMdRI_KTv@tUy~>^D@qzIp3vh4U`9p=RteHo2j8YVA565H?y_un{4_ zebZ02?^B%$p{>TwnXzw;b9$i#z}yT@)R$L<10F+8tQ+q{U&mUDs@g;}{z-bKd-*ENQwuli_*zQ=9lG+i{{rU&Y^S5P965k&Q1qf^s+6&} z01^5blzJip&s2{NSO96}j6tMV@@&b#$6tMW$MUI*lSL9bJ zxp1dYq^Pa2jr!=h<@zKXU9C%gyQtk5l-D=iWVA+xrEPnLXrsp3jyjTJy#AdSQjGVw z!XSZb?AQ}>$|JO&!T0mC2Zo8tUBU%MI(IY6Bsppi~0sOUzD_T^+1Nc1oOT!o17hxwT(4E=Me=-~v3*@Ck z45`NVt!|48Nk%RrxvJ>?NdxvRjsLQ5y`H0TYU$|y8zSe$4L)TK`SDJADeD1R+zC0y zhNEk{a27ciZG9!+IvP2r0=?9BN#R=(*k=cDH5UG)%phk6KHZ_EBV8Y8;Qo0X<8h}f z04#ZMztNiyTnfACh(P*_oBxCD7T-ElC#634D>L7oje^LTNDGLNL^Sn*qB zSN4=2#c|3nBt6G_mAJK${iN&>AJfPX#btM zOKVakk~+RmT|%4H9mPiFZFz%U1esB^xy=~5)>-Ty2i&vX#wvdC_S^r00T>NGe_l~Y z-GqxrEZ|m=y|8HH)`Cm;b_2%U`;w*2N_g^X4QA}FQW14k!`!`{J;1m-`wjy9Yxm}9 zgT=$q@+|y#UUm?MAIXaR7Vmt6Q_=L+jCfyJ->fz8RyB`-{T6Bj>O!mRc7m$l*|s3) zP^Mi&D1=w?;V)p;@vT&HJ+8nw2|Y z!c*_@RfYtk3Q`{y0pDcKhzPJEDbEd&CgI-8Zt^iVOyu?ivYMuT!uDYvr9YMV$;V*) zaCYqK%;CU3+y1P){X}bvtpD)V)s_Mqiw);LkB?dk0EAMH=%W#|@3obn_^$S^8>SB1 z1^s%!ULY1>##;5s{oAlkOogtEQxJ9Dgc;9@#BGh=c0YUn`kGvy_xZ8*x9&(V!8329 zeoq#OZG_13IF}S-x?hWUe=@5a_?vh%YUaG@kt!VF1xdY4b9m0)2A~1>t1Rz4ge1fK z&?>(?{_f_F*)*)J^AiRL?AkFGGR$7dvF>&>)3JWEe3Q&Oo8vKV=O@D8454DO`bQR6 z^E*+iR#GeP*_~vPML&IK)1T7%UE1F6-^r!Bqa1n-xm!toSH0s$or;h16&}jpTqZ!b zAWxef$lqSRxSReKHp-}XrlYMI`3MMd^lLIDg*sv%xj!w5U*815T}C;@aw=(>8<;ud zPpY6-!XtP$4!WQhak-aQ#4qEf4v;w$uHe0EKw&z^ZP`Ma9RId}?*?@@aks(n1-mq`e(xwW&x8-yYSnb=H6L(D3 zHXKZMcGaqHZpDx4%*J9|40jk1>!M-Zi9eiviGX~Mtn5SLGpXm#T{@Z$+WKgmPtF1N za)%j%ORw z8`~-A$|?EJG9?2)nE_ea`!}_&mj_ov*M!O`3#bmZS&V>ndu0)(inMRKg)C(I+lCQ% zPb40~15-8bxV>M{w35<=>o4+ByFG3ZSgJS~irp|JFe}(zLJ;HHcOYIGl6Y z&nIoS=xpY0fR=mER4894S+DP(bZT-YiVha`uUTh9OqYT3LXAB;yu@Vk{JW*i_nh9` z63b_@g8EzShE|CUc}bBzDZ-|WJs<)2GH&Pmwt4H=OP*P!k_xSAQvsF3>GHREC!4*~ zN-n$4T2egUw$G}`^eeI;{7Y4`gGJ|Cxf0ajc{$6xZeqK|{)y95PL3PTOE4?7lJ>Xe zyr5C0?JTAsDQF&B&a`NQ=svlb<*_6E-OH>PozJVZ%q>YHs91v0(aK-Q%~ExF?Rl$? zvGhVoxK3rh)+6RS-d9Smm1OEfs>(-ra_=&fULHnh9@5rxb!_3P*Y|to-;KMa9q`{6x#!bvSnZdG5#JA#Nz_L7Tqtcnu!Fb5Na&>}!+VZ4&8%Jq?;h(=IXLw8a`$%E9yX?OPp{Qw4!gVN zZ1Mj^VTqDZSQUVXwd43!JMRQE8ZMP5#*$XqW9~l}#bc@b#ej`P?F49(*O4=lpuR8) z)E5HUWTUbbd&1}=IM zxoZh#mkiTJ1&jTpyMmV+%AGF-)1!j>Jh5}X926E^f|10(zdJfT5vez=s{(Q+kn0c(qC(2q-_6Vy`a3H(W_%epkjU3Qf!G=IO{Wuc=wajlQ1T#^;vj zW|cgBLmk5D3Hb)P92oCY`~F=gy5w5mEF)ANJ5ggfB-#bdoJ9g^WfifOOtg6* z)*kmUegfid?Z2EbEvlzQRRC$zy)tT}Btui__Hn-otLAj$L%DeUv{VeOp-nW#SI;?} zLDt&~h6&QMp-(-3SUs;cSV#)>WsWXH7T zuN+d;xbZvBvuq$y`sdq}qK8j*t3%*tT?@E{8iR_tTcjlq8Xok`L-` zGG85IuouyH;S9gvN+IgX2A*g+?MP3yS-Zlv*E(D}&r-q6^}!jDp7wAr0sseo=3-VF z9%|FUfi&YD7hDaI4J{%_|0uu><6g@Rdy6#ENF$xv%{weRtDw zs_#a)(-!Y>@%*yuV6D9zu!8+M!DzbyC_ejem0}~;#Ot}vYt&ox3PW?ZN~kz5Sat0q zG&{*VA98?kyJe?PNo}{7^;^&(ytoNXH+9odRP`1#E^t%?B!TlIF1roZUz@MvVpYT5 z2JS2z;I*!v>0bzISBuC|Q|o-l*s6&*#;U)QG+8$K-zsX6nZ zeV|jIIKavCvu41V>MWuG+OQ@ z|6u*_iFc=8198tXTOhvhu(r?KP(A}Pl&bRGt#LqH%*bzFpJ`#6)gXmc^>()sYCp0N88PZ!oSPr?nqArP{-`#v zK+y8lkvU!}+124zEqH*uT}SVDuf(8OJb(Bhk|%{ul5Q3K;W?m8%5er{I|Yw)GRAqy zjU)zBolO>xwXUp|4ImMjQibuP4LSOm8>gY+Ww|Riy1ZP_pwpmz+nLuIbQ%B)g5fo3 z$`jbQloROW{8?ym{wvG4IMHHo|P7=U97eUA6EC!HdBY!y}PfkF@m$#8|oLwb6 zSW=MIVj%k}>cyyN(Y6H-!8xy9CLPSo)eyyPNmDtvXydUhs_YVqYO80CZ2Ag{o^zjk z#E?wv!uj_!@G_P#*v_%FSSX83us`2tO@dqZ-l4n!Js@_)!Yww`2@JN!CqbZsNErwKcFwg@S zjz7yYsArfG_z!38_xtOIm&a0z0j34nb+0s6R}(o{H_LDSFuv3NP>V`Pp|D2&zDaxazGmIsX=I&fV4_#CkZ@z`=b_n<*i zo91S<$Og^a9-hrspmvLxX4x?^La)xYU&fz)ur6;c{3%p;=QH&8kW+v2OSKvW-)T!2 zPqfg=lb3GHFItAx^BW!wPdAr(K^B0CzYw)lncGNyTR!>AmR9HPmxsCpnu9Rx0P`{;ZEBu^YzDA0&~Ac!11-1C;aO|@4&{pCRE+5U#edo%CN3m z#fxDVtY(w)=Kt|DnuoJerMeqbCw=u(1!$X|H6Bn|5<3Hq*dVHLx8@pTChf<>LsQ$0 z%rmC-VpqiR%@}Vzo1)ir1t#{OI>}uc(+s@PY1{%o42Lv!SYy2PZLSE|f_du-O}>NG z{b;L^1gIV;an%J53aaiqrh@5#gVW-t{{JRLg5nzE-be8`O;sBU=jgeTNTs(Bt>)~< z)wycUL;XxKwE8v*W%`e`Uw0S%gZgBddD|~36(o$mxu~mYX?IuQJgQX%NWaumEeQ-; z%lgc5K)))BFsUH`2~!0^Jw0`QsR5C3ryB!72;N=%u_Uky&-k|ZQ%;Ou%5vyOiEzx2 zPOaprB<5wMPLDC@P_s^%V2pB(8PeO&Tjb&g(tb+JsYbO-f0e_m`*$Nhnt%Kv-VIhG z`aN^tOb$1O*`U9ilP=Unj~W#ZcS87c&7Ru0HXI ztSKJ7eC5dq=o zux^;XT_uLbgTUc|EL&NJN~fyaxeNCJ>qIo3ygppNbL8N({CFh9PS^gF|840V>mmQiT%AXOueu zZHC=2L1&GMgSIZ(06L2trx6}fuJRxg!`#8r!EzwW*@=toW=&vAT@-9eKOA3nlQoa( zEfK4aCN6$rnf`KEjU905RycZ5;29JL7eI^eT2oiGZbEm00P=Ygd)Y1Q6bcTpJ9AP; zTUfzm>Yo$AU6~n2IRs^m!NSd{0Aj|1t9gxkb}fP0^yB%@#%zF~bbhgA-?RB4()vb2 zEM#jy9Z)4AkBQW7YoX{asCaiYx``Qo=%Ll+AB;{WC`UnVx^ZGM4O>G9Q)B$kHYLaU z-@SXW{%SZZxwS%Rr&13{*6Mvm^u$6D79Df>8S{F-hz4ixWzQvVLvzc5ENAbhGV{nl zQxuv49F{Y8z+t%_P2lAl;<)&q#v zr?(?urNI#d1^(#-v{j6+`{C;@sD5rPVM@_i1Iw`1cGOrsW1Mp@_1Muy0vsr6{uNn` zrO1|{Ndz^9^w}@8KinTcz5S`|BwV(a|2J$h`R=Tp_Sxn`tf!;)*6#%QrfH=;yD|Eu zUBme11FogBmKCa|bDvF3?2aR((xm3vXH(V?;V*EyvW6*`^hLudub?=lyCclnq6WTKd2hX_uO zjP4?BueYfbDXJD$t8#JnxcU=Rt{-monMx39mg%Ic@%6k@p$|@jz-5uSd2yJ`KaRAf zrr|CGt#-K+glvz+5S0uEb=9ZzU>QE4lna@=_3^?9M9x+bjNo&s$}iSkru0GfaZsOC z@axV))6R#yQaUEPC8uq`%nqV|v$}7VO&8xH+$Y?~!C(%R3cy{!D*tF2Hd;=JKv@Cts!FBEx>??2t9$h3$f zp|I5d+ikJuD}cgs1w^d3#((OMdR4jYkrt$Uuu@c}lS^uPS^eXOfQ@Bf!VLpT_EM#; zE+|?MEKDp?#z^jb`y*)!7W^q;01~#Z>nL$PPej)UR3RNY8d&8~vm1^UCxP4IL#IC! ztQ1K=!HNMCtVjm~L*SD3Z*NA$>$pTal5Eo&dF9p-t5nIa`~^k%V~beGe%xt=m`s>!<6XYEg?&R4S?I&+*stG(lQ5o3ta zAM!vk?RYDH?-7qxljx14+i2M9!pl{yb96fpT{I1u&t?4U4vwyMVgL(b7Hq#OqVt+V zQ#|PF?RXy2$z7j#2?UEgAXB$#;-#_}w|;VoCbfL3SuXz>Yct@ZXvKt`_?FgZuDpH! z*aGC8YSJQM+rx%CenQxgW8+BJNvGkwW^B8b6&D8DwABpkC4{s;AjjvukIbrzmMV)I zq0GU}Du98t{)-dXm7pVi=BnFMUtZ`AYDcH69c0*?sR?(TDw1GUsBs`dKj4w_*rtjx zG_uK@3Mw>7U?4i3BjQ=ZC+CTr0AR6}b-&Y_RC}DeS8~_?)kb(t_r$Lk0!GHsJW~AH z)qZLlZ*#&q;6OH{-iY8AGePpXZt>AZ2h0WzqgH@z-wJ?#sKRUEVj< zt!ToXC$)trO4{WWIQ<2r^rFXF+v08V-kSXWM$QDSIJv*KTz1eWZNHRP+b3Lnk`Gam zNsNi|*TlwIV`SPyjcxTq4W=fdAWRKXq29KhaW8sYwf_eZnItjT)LcPFdZ!z zEC`Z7bxtFj-Z`mr#eKuo$#oadH(mvG5#Zha;do-pYaSm z4sB<=4l4Ab2!T(@8s!=VMqDSUE5XX!u3yb!0WuK5MGO3m3~*uV)trmRq36pdmK4X~ z=L>FWFG9%U&Wu;UgnqEt7J?_A3j;#h>S3&P$HVSD#7x~FR=PLDO9d7ef0iExZb0^xC!n$BjzYNE`^8feT{Mg(Ig~jsV0uRoUgM^dW=;8 z%Wut{dCh;+8LV=A1ORLTo-CVx+0C(sX&%Xs4o7RZAv8r)K;J^W+FLVSHjXemT6-X zD-;4%;I_8-WD++A6=V%>wVz?Zej%tVo#t=Q$lnHiy1k~ok0E4h0T8FFRmY}aB+i3-7460|b z%2|7}Z5z~h<*uGsAyP!$8&43*(wd#UyH{U_f@S932054kXpO&;isbFAzPU*9J?6QmN zuNhMk956Db=B;X(ay)-FxfTL`*ch#RKLmR)NqlND&H;3<^CqLsglD#Ev~B%$jx2reguW3_oB>bajnz$c!5M*}V3gZ_W{lfBviJozV)R6|N6edRaFy9Pj% zU_!&}fByFk*d+cE>B>0c=wEyb%)lDlw4FYUe6-7FNbh(7+_aIa)`hc2aGyw?fB1cY zp3?fL#}jJ}1!A+jcY}9hQW;)%o#>cqJD2wX;xv8EkJK?OvS69oXTd`0P9w+9em)?b z)M@mnsPV5qg?6n=yz13u&rN!7p`yWd8(ku<6ao7%tPS=ypq3TRqzYTC2sbj-dBY8C zU%RW=pQ~-j^{3V1 zgu+PS+ipPs6W!c9<+L-zmbv||78fO)UvMX(<^6)|C;9o}V$9Z4X+eNzgaP{eLfw@K zjp{D7a)T8}Op`$MKlyes%(^!6RL(`|Eex3^9xRv`!D>zIeVsw2=tKEAFN4ujs|^`J ztZo9a@O4efkf}qQ@aUFL=8vCcKyW_bh)FTFiH6~I%flFC>rQTA1O=<9vQawaNf~VM zt4u_F2`~9%o3k}3SGyP#`iPGRz8q}79Qbm4@5Te~Sl(b>D)mbTvXSk6HjW#8rU%ze zdtHBdgHRzfMNZk!u^>|7#(++F4X44D2WaQumW8DN%q35y4 zUg?Oqx^@PyyU1R~h`4TS>z3ExSI4H}%#~fxb40iT7-3ze2h64uD`ThW#TZIoaKQ`x zn(a4Z^~+-pXT`MseoMve1OE@*Q>fc{qD}T&lc|4$nAXd`+$E#ZE01NU4VFo_u}n$V z-uVk`^YI@aa`XSNjNTXjl1=?6dRr7+tCr7&rda@j-p4&is$o< z9w2YlaXQ{90p7vDER-~3Mo^(g^@kk_mF)HWz8y6 z3WK} z$>2>||MQ>pT`Iw1#zpm4-a&DxT*E-AR78gu0xZud$dBX7jwk+6TGzrsVq_2RtAg|E z20!LnI&~sxLAIjEgi#L~z94e^Mr7jX_<^3Csr92Rmr3=xEN2M8kjJ}Ws{J*+GlWzB zgQ$%x5`zT;Z-*clcuxR+Z%HR(WEs58N6qHZ>&jzO?pCSJWSO=46|mnVbw)Y!Z~+e#@3^ zXHF&MNA#oa99aXV`60---qgXBfS``@K2!#9M%4t5W*U4vBG~`(JImasL(BW8OVyB_R!{@q|NtbLY0kICsf%=Zle~=W{!|3v2i$Jnq=@s}GSAzpJ#`A`j<;-&Q@_I(JH+ z(Tbk7!=K=Hj`g3P$5V7kUl}@K1_YE{-%tx6pk5rEdo|9raO&1u#A}O(zFq*f zRcOlF(5rEeZKl%A{XK&f<;LL61KbSzQ6q0xr;k;p7V(Q+()=yCXBQ4A;RN8riZYB8 z_9;77Ibf)hj>wXx4`n%i<-R$IZ~3=$q5r>?F4&Mu7py_|!t&U^u^fIsdMvq_$S$EK z_9hr5DC3*j((FwrkcL93W& z6ag|Q#S&;=9HRHv-Rb;-+^tcN3^U3$MO1GKGeS4#H~dvgbpE}-)$ zddLzide!R1-tJz*vG#|(#5RNaF-}1o6?+&mNQ2*ge$Tf=8`m8pJK6M^m=7%zz+AI9 z?m1dY$9`+b;)Q&HeX1rhRS|zKklNXm8&&Go-(9-*T5X^^*-~>XVcWG-bEz{VP)pLsz>tk`O6)$*no;OAA z8DpnS@e1aEN>Gg26qzBbe>#=SSbYB}T-Lm%o_Hx!B}a z>o64x=LKun@=8;#u@qGr{mOI5E>B9M2#6XrDU8rALpJEZAfuutjX7RP3Rm{Ti$;u? z^Tae}+bq{F#BbMKZH9RLNa()#oWSfN-CQ04ShP`vO#~pC&%+lX98q5{lNbPrh8iJU z2&bgQ%b#)JyYUpl0E7=N%O$rMZ_tI)yjzezA(LoMs9k%y;~DscKJ;ilo(aEiqvuII zcxTHISScwos0Q&?Fjb-+k+J*>Ep>}z%@BGN#9PK~`illA9K=byigGW2w0Z+0Q}dAZ z`O~2r{%vz>R{yeSsQ%r<)-x&C@bOl47~TU6z1`3ABIlwMeNTs8s6JQyMn?U3e4mo$ zs@MTNT(zZoUj9I;?q?%_-3V`$@(rOWg?pL|Ej%!>y;%F}(oE@zAK!*OBk_G%aj-Cf zJ8tOFRGhs3LH5M2atMoJE*E`4VqHGdAxJ{FrCycxbcIeWI5+Glkrc1rNB>w$4@&C~ z)#ZllAE~?bYQP|**L_fqOUa^a^qRQuFi1DD7y6DaN%TtDeH?cTDRj@OJw&xMg{XN} zL5qkN!j+N&fFsF~-Mzxiie3+j@`1v*A-&(N`^@8A1+8uCuX-MSm|7F^bSjCO?lEui z(87(tO6+Ts%EG4&;EqX(i6n7gNooS7DZ)}XiP_eb>= zUTngovBJws`W99AIL3x)WF$dql@OeHB+I~#5df>uH4c+6Qb zu&eNgR6Rv)=wOjc14i);Tae|`X~&$I2xSmj{SKsHQG*n$A@b3Ol?o@){Z$yvW#yiu?AIZ z#Szx9%2+wbQ3BF3cHbUoqj`_S!J-Pg{oq}Y++wJ2&g!>xAk+ILbZh9T(Dsd?r`M`M z-k|flL-kMERBDs&i_iZ*_{KaRk`0%46o4fHnWLS>i$0yjoduaK*KBOh1rft|4pI2^`vH(eI<0B6BLCCbJZ zdb`rYdOp`2j{q{C-=O8_#@-8TSq!D6U8t8fcuYsUfQljj;nr5qP%T-w_3^OjL2_$n zn?`-0HRA@=yA|K!fL7jCuUWu4*X0eXmOrdH|M5cnYG@$EN12`Phg%e46sO4ll5P23 zChN1n%Ju`;0{2JS9ugz~*%X>N_kt6UO|q4vKiZb#POV|T@HCodqG0^JpL>>KrBHW$ zV$ej7`sfAr5$xCF2%;DmiP?-=3u)At872Q)^u|ZccPz`}0`VXM>)(cjj5~hgJ@?6U z@5JoCZN6w;8km`OZacY9;U1{&je#xY7)y`~70Ta#)a1P*RAej|r|WK}2_Bfs#6x8|axwTx^*=2_OAZ&J9(6I0?6X%@bg-b#6vddJFEfi<$Uh)L2tAono-leJl z?b6VrG=Q~6|7^O0tY^VRmN=tB+j_ApJ%8a?Uof}3pB;;lkL6UKf&kWz+s^MDo}5RB z3*eUWsN2&U_FfP*e}_E4#m-^!?fsiwmEKg}X0(Kl9>w}-eXP+bxONkaxERkLoqHjc z>Cb#m!n^O`A{Z)m!;*j#;r3;32Mh(mTL||&fVQ0#g};e$oApm3r7Xm4Bm+5NaFS`P zE$|ToQB||?hZzz>(80jxUtmXD8i9rDePde-OZoi z=7l!Zv2}6?SL%2Q8*M~ij}>3isw~j`dwM|JHng$ijeP@f?ntec|Ge!of4j;kB-q`` zu?En}7dHj=?V@=Vp5;wY^9Bl)Np-4#5m#bXU|%PC@+B#6!iCqokKul$_?pbdXRzX( z)cO)@7KUhs2)a*o-0ht(^Mb3C4H?}rs$JV zfVOC4u^x=kOxc7rroG{`kbUmh%HD>6zwKu8;U_-j=xzY4*-R1vG9KCZJZm@TZVm8F zvTmow&*HuC<)NH@H)hy3hS2jPcn+{K8$|ZwQFvm8I0erAiAp(bn9KTKh{Y*=P~^Kx zzO)Qo%&&|u*ENBO^?P0NelT-&9_<|zizxw#leD!jWpfsRHc>D`4F~T`x8c!%o6btT zlwH`d-6=m@kwynQ^{Sty9J9uXOlURd@X8j7dK_v3Dw!2f$w5oAg*E>yXL>w&5mbeA zsqSsm*+!{miDF3NP7v?krSVI%rSR&NPzJk31SdcZ=P(h=!amD`=OR3-gF$-V6bzfK zKaX{1dNEt$@@xL&B@uC|%RHFjN~)elThG03AaPPQ7jzH5V!B13?OdP929?9IB0QMr z{98-2MH`S)X27ig*U&ZC`d>tJ;vS3V_s!!DmXXsd+0q=q0F1bO_Z#1u(Q~584c2?O zsI}ocT-tEQa9WUby~eeqoVQgXtqxxQ(>KIFn6r17*U2K!`Vg8@AFKa*C30^oIzf4o zl`CY&RKse~7tPPj+J|}z69_T+av7voDqnWH6=H&p-soL_x};ph5#XKPdqQe?>UTCf z9*HUVATqIxkq#1f$)TwFODZqjBj5{aNu{D@s-?gq;I1K{l2sE(kyC3-sy*f|r#G#e z>SYn)#ago|xSc}1HPQHn=CIxn9p$w@BoKSm5MBv<0X|U8n~>_h_y%5BWwPdMRe2|L zh46W%3*^VyDk{DD^8#r41x&KCKkLYQpe6SBmM`pa3(^&;Ox#K9SRTe(@ z=K|3uH!yV&U^4gHDTkZj_IOHFwjppmw>3NjfHC~e!C&!;`c&}}u*`H&ssI-OdT48X z>Ua<-x!N7nw%8_qh}ichQZ9l=HO{?=xQM;FP_Nr7lW*Vp@t{cy(Mk^n-|+4TE+WrY z{vq@>V4Dc5gv>vY1vjux$F#_sK39P5SR8#(4muO20v5c6R4w!FiBP;7{+}yk36_`5 zF7e1Ww^iz`?j@`p^$V9s(9tvma_k~Ws1+*(I8-jCg-H>j#2Wf?uA=dV5_KrDqIaRq zzl}Q#ln$b(Pf-=dL6NIb)@8u{3qOA#-J-w41LqoZ$a$M~1MBd~BcN)mC+~fx=01zO z>jyn?n7bkM+RfXHNljgaXpa4#zurtq2U6gC@JWNoq zk>PkH$uBbI`!$s#Szt=Cqou8PlqU?Ww>nC}rWHKiSRyPk8rM7Kz8G`$_SHAq9ozbD zovPTuxtq&*37jz`%z(mtlXs&5JeQ6yF(_+cKp{f_6R1Uxlnrdx+&L|RXYzYtgo_j8 z=K@svEM4D-@VsK<3MyWpy`+4rhRtsC&4l07wBwS#Ddzo|A|J+hvil{e?cE~CcY{+C zRKze6A@6{-(6FEQiPYaZ0v!k}2u5p0IhtAyx!bd4M_G!}MT zmsS2e!OLrYO414fg6JBh26rHjuz#Wlr3tv>@&qWX%x8Xa#Dy7+-v}8&Is}c1ii>Mk zHtKGe@yo`{nmW+MK)+0c@jmr$y3xr|_{nnZe&uUjktd(9${;^Wt|A1S2ZS+O(ZCEJ zG7FOFa8`tXA(OUHH{83T@f&(jm><*}TZ66?pFBo^r|t-WJ*oN8uETF-ywP+$Hft)y zf%8Ku>37X%evPN!K*!*&yY+C=sJtgw@}7>%6!0Hx=1xp^dJ@1{yE>(&Y1I{Nv%35* z(aekxwFDMQxmRINrg!B@9f~v_t1*AqQ4M|JP%IEY56bQet|S8NwYyh&L2&J0jh7rg z>Gr~xJiJR*nH!ZRT(35?(+33o-!A`HkqP=sE%*K<=(D`DQ;%v>ixeX6f4(!wEd0~M zK~i`g$19gxhJFjdOF*HTO1#=R z{;2MqAbM1!Y3uvrt033Mv+Kt7!5$`JAka5&#xq8QIBn#b)(Wm_ zoy~z*NWAPkI-=$!W`uz-!=wk8X8&m7ACGt3glC=U7+wRoY0?7N+7NVi1`k%GmHQF6 zv83v+ES6tevhL{(g7D|tIyFS&M34CfhMhrE>(ta+)^#fPYrbM>cLpsmtGPgXaq^SB zoz)g5i(nGKl}a`uv4bu^vgq`2*I?^Y2J)mweW!S_YOEw4l>VsPx3GWT=Ob$ zDp4LxkTvi`uQE@I83iK;^-J>J%(Chw0oTz z`olfq2MW^*Gc=fnc(>c{gLT)ydyL?kvFvx?!g5gnF02#G(rms{j_qe&$YDczHU8R@ z^}ihL&1(K=OZX9tt;0$|zb{Mzu*-H!vmlwH>Z8XVgZSjy)R&&4*TJJ>qP!T=dh&JL zPjTm-MnXDPrhm}-74yLR1G_$#R9D6y+k1SlxnWE(OT-wu`8th$D*ofnX&&&ROKFFJ)~7wb5A<1*qtHY_-Y&s2Ks%srk`*y z#YX5){ysv{?4iK6jhuL|lGp&*iw4`ap*);gm_+zB5yO(e1uR3T4{8|`A)MCz^iE~K zjp6z|$olTuj98id8{f*!spjl!LW&>O+uwO2Nty*U?e2u}7vyvM1rlw0V-AR;+^hc) zjoAiUDJy>9DI)M-uEjPa1`Wto^zyHI9u77QSl*TfE8aT<{`q%a3W+o6$)YaOoPsqT zScg1f*9yA^ZjP~{dgKNuD&*kCL>F|w4~kv5DyInITZiK4ao?C#lVo+aH3$Dp0y|xX zl=bZo)kfDXwX4(hw%B7DuWi|PD$@83gmK}FeLPeUK|*%vg0TWMdeOO;;xUP3aNvm=MAn-U9h=uCl@Hk0#a2fskN`r1?HSFnex#>nm!_~9( z&-@h^%3J3=R>3==)IeGFGZ8%e zPrZ|Zl_(RVt6i2=Y*^huA~Gxkne`r-@}0#QFy}`Pym=%S1B z_Loj2X>D#Ihp|(ou%*<^Q(zx>ojbl2Oz`tQ<-|ohWF@D@7YTPZ7ivumZ!sJd*La&$ zJP3yL40^XfhDG7`z8f@Lk?fMhZ#>cHgY>cOA|>C`L{@?Dygrm!m;kkjXtv+`HOgge zAsQiBP%)0sj(gRo2a_~YF{#epX`D)Zx*H@4jmm5_JeYmF{n*845u$YQ{Kkb-XIg-^ zOy}s<{s!iva=gDN;GRK&=-q3mA!;!Y)x6v96$yz_-3^lAh@5RrI+%ST-gf`(=I$|? z?s1Th!jO0MG;)rK79L%wcLQemOY7NA<9NfS#iK|#rrZ}+`nkCc+|fAnA2j> zGlVSlf`W8`F&V(8DW$B6cfAN}i$83>eclH5Gh)!9#NkhRd?BDc?>e*r$aH*r(^XROJ7)%tHfqTnd%0AH*p5H5)O~Gg|c>B%Pw5MBD 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 F{V#gv_RRnQ literal 0 HcmV?d00001 diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak/log_soak.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak/log_soak.json new file mode 100644 index 00000000..65882c1e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-log-soak/log_soak.json @@ -0,0 +1,27 @@ +{ + "board": "nucleo_f446re", + "capture": { + "bytes": 9928976, + "sample": "log_soak.head.bin.gz: the first 262144 bytes, gzip", + "sha256": "882a977b96461cea8c4e98979b6eeda2825d74f2a781a44eee4cea7022755ac0" + }, + "damaged_frames": 0, + "decode_errors": 0, + "dropped_counted": 67320, + "frames": 149411, + "git": { + "commit": "a5b6b75e13c63a3054b2deb1757d0e837df79404", + "dirty": false + }, + "image": "log_soak.elf", + "log_records": 295211, + "minutes": 30.0, + "missing_not_counted": 0, + "numbered_records": 180011, + "outcome": "passed", + "started": "2026-11-13T04:15:44Z", + "target_counters": {}, + "trace_events": 262800, + "trace_gaps": 23399, + "trace_packets": 23400 +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.json new file mode 100644 index 00000000..7158b178 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.json @@ -0,0 +1,63 @@ +{ + "baud": 115200, + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 92027, + "unit_hz": 180000000, + "units": 18405437 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 87267, + "unit_hz": 180000000, + "units": 17453546 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 19904, + "unit_hz": 180000000, + "units": 1990469 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 189013, + "unit_hz": 180000000, + "units": 9450680 + } + ], + "board": "nucleo_f446re", + "cases": [], + "ended": "2026-11-13T05:29:05Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/benchmarks/bench_compare.elf verify reset exit" + ], + "flashed_sha256": { + "bench_compare.elf": "21588c95a3631d4ab1450ccfaa09421cd3ba3fa044bd1fa67d93d5aa0d12645c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_compare.elf", + "image_sha256": "21588c95a3631d4ab1450ccfaa09421cd3ba3fa044bd1fa67d93d5aa0d12645c", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:29:03Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.log new file mode 100644 index 00000000..a6d46f85 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_compare.log @@ -0,0 +1,7 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image bench_compare.elf sha256 21588c95a3631d4ab1450ccfaa09421cd3ba3fa044bd1fa67d93d5aa0d12645c +bench_compare: EmbLinkRTOS 0.2.0 +BENCH v1 name=notify_handover units=18405437 ops=20000 per_op_x100=92027 unit_hz=180000000 os=emblink +BENCH v1 name=sem_handover units=17453546 ops=20000 per_op_x100=87267 unit_hz=180000000 os=emblink +BENCH v1 name=sem_give_take units=1990469 ops=10000 per_op_x100=19904 unit_hz=180000000 os=emblink +BENCH v1 name=isr_wake units=9450680 ops=5000 per_op_x100=189013 unit_hz=180000000 os=emblink +BENCH_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.json new file mode 100644 index 00000000..61d675b3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.json @@ -0,0 +1,40 @@ +{ + "baud": 115200, + "bench": [ + { + "avg_x100": 15503, + "checked": 1, + "max": 194, + "min": 155, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 180000000 + } + ], + "board": "nucleo_f446re", + "cases": [], + "ended": "2026-11-13T05:29:03Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/benchmarks/bench_irq.elf verify reset exit" + ], + "flashed_sha256": { + "bench_irq.elf": "65e245b01ab714cbaab63d4b6e0c901d8f6ca2952c167fcb425ec5df0a1f0d71" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_irq.elf", + "image_sha256": "65e245b01ab714cbaab63d4b6e0c901d8f6ca2952c167fcb425ec5df0a1f0d71", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:29:01Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.log new file mode 100644 index 00000000..4f9ba54e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_irq.log @@ -0,0 +1,5 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image bench_irq.elf sha256 65e245b01ab714cbaab63d4b6e0c901d8f6ca2952c167fcb425ec5df0a1f0d71 +bench irq pend to handler: min 155 max 194 avg x100 15503 cycle-units over 1000 runs +BENCH v1 name=irq_pend_to_handler min=155 max=194 avg_x100=15503 ops=1000 unit_hz=180000000 checked=1 +meta: board nucleo_f446re, compiler clang, profile base, checked 1, cycle unit hz 180000000 +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.json new file mode 100644 index 00000000..c111e75d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.json @@ -0,0 +1,39 @@ +{ + "baud": 115200, + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 88920, + "unit_hz": 180000000, + "units": 17784139 + } + ], + "board": "nucleo_f446re", + "cases": [], + "ended": "2026-11-13T05:29:01Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/benchmarks/bench_switch.elf verify reset exit" + ], + "flashed_sha256": { + "bench_switch.elf": "2cdde1511d82dce25a8fd42f39777ffd9be7f3cca5611e699fcd00eb2bf07683" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_switch.elf", + "image_sha256": "2cdde1511d82dce25a8fd42f39777ffd9be7f3cca5611e699fcd00eb2bf07683", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:59Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.log new file mode 100644 index 00000000..71d3127b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/bench_switch.log @@ -0,0 +1,5 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image bench_switch.elf sha256 2cdde1511d82dce25a8fd42f39777ffd9be7f3cca5611e699fcd00eb2bf07683 +bench notify round trip (2 switches): total 17784139 cycle-units over 20000 ops; per op x100 = 88920 +BENCH v1 name=notify_handover units=17784139 ops=20000 per_op_x100=88920 unit_hz=180000000 checked=1 +meta: board nucleo_f446re, compiler clang, profile base, checked 1, cycle unit hz 180000000 +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/index.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/index.json new file mode 100644 index 00000000..87708dd4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/index.json @@ -0,0 +1,942 @@ +{ + "board": "nucleo_f446re", + "build": "checked (Clang 23.1.5 with LLD)", + "configuration": "aa8dd55373872741", + "date": "2026-11-13", + "format": "emb-hil-archive v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "images": [ + { + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 92027, + "unit_hz": 180000000, + "units": 18405437 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 87267, + "unit_hz": 180000000, + "units": 17453546 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 19904, + "unit_hz": 180000000, + "units": 1990469 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 189013, + "unit_hz": 180000000, + "units": 9450680 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_compare.elf": "21588c95a3631d4ab1450ccfaa09421cd3ba3fa044bd1fa67d93d5aa0d12645c" + }, + "image": "bench_compare.elf", + "image_sha256": "21588c95a3631d4ab1450ccfaa09421cd3ba3fa044bd1fa67d93d5aa0d12645c", + "isr_stack": null, + "log": "bench_compare.log", + "outcome": "passed", + "started": "2026-11-13T05:29:03Z" + }, + { + "bench": [ + { + "avg_x100": 15503, + "checked": 1, + "max": 194, + "min": 155, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 180000000 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_irq.elf": "65e245b01ab714cbaab63d4b6e0c901d8f6ca2952c167fcb425ec5df0a1f0d71" + }, + "image": "bench_irq.elf", + "image_sha256": "65e245b01ab714cbaab63d4b6e0c901d8f6ca2952c167fcb425ec5df0a1f0d71", + "isr_stack": null, + "log": "bench_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:29:01Z" + }, + { + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 88920, + "unit_hz": 180000000, + "units": 17784139 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_switch.elf": "2cdde1511d82dce25a8fd42f39777ffd9be7f3cca5611e699fcd00eb2bf07683" + }, + "image": "bench_switch.elf", + "image_sha256": "2cdde1511d82dce25a8fd42f39777ffd9be7f3cca5611e699fcd00eb2bf07683", + "isr_stack": null, + "log": "bench_switch.log", + "outcome": "passed", + "started": "2026-11-13T05:28:59Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_cond.elf": "4f82039d779c11a887c9d43a9289d34c1f7cc7e6d5040b184569707339f852d8" + }, + "image": "test_cond.elf", + "image_sha256": "4f82039d779c11a887c9d43a9289d34c1f7cc7e6d5040b184569707339f852d8", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_cond.log", + "outcome": "passed", + "started": "2026-11-13T05:27:40Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_crash.elf": "9e2e6866e98597ebcca6a31a953783d1a9fd206bfa36d052addd6364e322b47e" + }, + "image": "test_crash.elf", + "image_sha256": "9e2e6866e98597ebcca6a31a953783d1a9fd206bfa36d052addd6364e322b47e", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_crash.log", + "outcome": "passed", + "started": "2026-11-13T05:28:50Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_hw.elf": "57dac087b0ce3f804ad074f9e5e2742a4ced55b1755cd83b466008f803f26d4d" + }, + "image": "test_crash_hw.elf", + "image_sha256": "57dac087b0ce3f804ad074f9e5e2742a4ced55b1755cd83b466008f803f26d4d", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_crash_hw.log", + "outcome": "passed", + "started": "2026-11-13T05:28:54Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_reset.elf": "9a2d3ed9d38680bcd86c3b3441407529c18f9c736d1d8f2dd269c6f0632d6b78" + }, + "image": "test_crash_reset.elf", + "image_sha256": "9a2d3ed9d38680bcd86c3b3441407529c18f9c736d1d8f2dd269c6f0632d6b78", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_crash_reset.log", + "outcome": "passed", + "started": "2026-11-13T05:28:52Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_debug_descriptor.elf": "6b6fac9f745de06e3ce4b058a26570e19752e730e70133f908980771299e5333" + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "6b6fac9f745de06e3ce4b058a26570e19752e730e70133f908980771299e5333", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_debug_descriptor.log", + "outcome": "passed", + "started": "2026-11-13T05:28:55Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_device.elf": "e362f5f6e6baf215b80cc501560f8581031987383b4c434c15659cf4949eb0c0" + }, + "image": "test_device.elf", + "image_sha256": "e362f5f6e6baf215b80cc501560f8581031987383b4c434c15659cf4949eb0c0", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "log": "test_device.log", + "outcome": "passed", + "started": "2026-11-13T05:27:54Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_dma.elf": "3134c0fe5771e553fff3d411077867a645ae1d0bc56a8a87aeec7ee24741bb71" + }, + "image": "test_dma.elf", + "image_sha256": "3134c0fe5771e553fff3d411077867a645ae1d0bc56a8a87aeec7ee24741bb71", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_dma.log", + "outcome": "passed", + "started": "2026-11-13T05:28:05Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_entropy.elf": "1cafa29dec461c82dc23eb4e32afad4bd764befc2885c95ea865453ccc6484ab" + }, + "image": "test_entropy.elf", + "image_sha256": "1cafa29dec461c82dc23eb4e32afad4bd764befc2885c95ea865453ccc6484ab", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_entropy.log", + "outcome": "passed", + "started": "2026-11-13T05:28:07Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_event.elf": "9ccc4975b129e36712b4ff8a7648c9ce3d83e88623ddaf457477a7d5852a3e21" + }, + "image": "test_event.elf", + "image_sha256": "9ccc4975b129e36712b4ff8a7648c9ce3d83e88623ddaf457477a7d5852a3e21", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_event.log", + "outcome": "passed", + "started": "2026-11-13T05:27:38Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_fault.elf": "62203d0b369d67ce9d8e5e248122c57a42451620741e63fe52925ad32e92d7ec" + }, + "image": "test_fault.elf", + "image_sha256": "62203d0b369d67ce9d8e5e248122c57a42451620741e63fe52925ad32e92d7ec", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_fault.log", + "outcome": "passed", + "started": "2026-11-13T05:27:10Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_first_execution.elf": "f72bdf269b9ae3821cd7161493e61151f3a1f70cecad060e1b6114079890ef50" + }, + "image": "test_first_execution.elf", + "image_sha256": "f72bdf269b9ae3821cd7161493e61151f3a1f70cecad060e1b6114079890ef50", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_first_execution.log", + "outcome": "passed", + "started": "2026-11-13T05:28:48Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_flash.elf": "6113cc4bbd335a4df871789ea0aa079191b7317d6f6637c25e295ae2c104ae9a" + }, + "image": "test_flash.elf", + "image_sha256": "6113cc4bbd335a4df871789ea0aa079191b7317d6f6637c25e295ae2c104ae9a", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_flash.log", + "outcome": "passed", + "started": "2026-11-13T05:28:16Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_flash_board.elf": "821ae2f877a0ca65f20f671c3b3f98d0d9c193cdb0b15be1b57aebec4b90a0cb" + }, + "image": "test_flash_board.elf", + "image_sha256": "821ae2f877a0ca65f20f671c3b3f98d0d9c193cdb0b15be1b57aebec4b90a0cb", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_flash_board.log", + "outcome": "passed", + "started": "2026-11-13T05:28:19Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_fpu.elf": "11cfcd98716f2e291e8d6db9e2f4ed74fa7748a375019148ae17ab58bb92a903" + }, + "image": "test_fpu.elf", + "image_sha256": "11cfcd98716f2e291e8d6db9e2f4ed74fa7748a375019148ae17ab58bb92a903", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_fpu.log", + "outcome": "passed", + "started": "2026-11-13T05:28:58Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_frame.elf": "5b147777f902c4e96556bced1d0a3e0f0fb310a0c7fce023bfd254aaab762f8f" + }, + "image": "test_frame.elf", + "image_sha256": "5b147777f902c4e96556bced1d0a3e0f0fb310a0c7fce023bfd254aaab762f8f", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_frame.log", + "outcome": "passed", + "started": "2026-11-13T05:27:50Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 10, + "flashed_sha256": { + "test_gpio.elf": "022583011f1d5877bae3ac74312a3e1e32939f6ce51b8e7f10bd6693de855a23" + }, + "image": "test_gpio.elf", + "image_sha256": "022583011f1d5877bae3ac74312a3e1e32939f6ce51b8e7f10bd6693de855a23", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_gpio.log", + "outcome": "passed", + "started": "2026-11-13T05:28:03Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 12, + "flashed_sha256": { + "test_i2c.elf": "240ffced9fa4377fbf45410375ade338c63d1e1e438cc3cabbb987bc4c0dc66d" + }, + "image": "test_i2c.elf", + "image_sha256": "240ffced9fa4377fbf45410375ade338c63d1e1e438cc3cabbb987bc4c0dc66d", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_i2c.log", + "outcome": "passed", + "started": "2026-11-13T05:28:39Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_i2c_loop.elf": "aa4f92f691353bb07b4fbd191d020c40cca23346e5b5bfb8522810975b9f6971" + }, + "image": "test_i2c_loop.elf", + "image_sha256": "aa4f92f691353bb07b4fbd191d020c40cca23346e5b5bfb8522810975b9f6971", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_i2c_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:28:41Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_irq.elf": "f5ba898d04878a395264c2640fe75ab31071c34c80a9ee59082b3e486e2e1cde" + }, + "image": "test_irq.elf", + "image_sha256": "f5ba898d04878a395264c2640fe75ab31071c34c80a9ee59082b3e486e2e1cde", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:27:14Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_irq_priority.elf": "abd91eeabdde757b29ff71f8faa4e39927a950497699d06604fb840a02fe305c" + }, + "image": "test_irq_priority.elf", + "image_sha256": "abd91eeabdde757b29ff71f8faa4e39927a950497699d06604fb840a02fe305c", + "isr_stack": { + "size": 2048, + "used": 276 + }, + "log": "test_irq_priority.log", + "outcome": "passed", + "started": "2026-11-13T05:27:16Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_isr_stack.elf": "f5aea1246f440db90329eb06ac0235eb82a9ea67989a9465d1c3e6f232741560" + }, + "image": "test_isr_stack.elf", + "image_sha256": "f5aea1246f440db90329eb06ac0235eb82a9ea67989a9465d1c3e6f232741560", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_isr_stack.log", + "outcome": "passed", + "started": "2026-11-13T05:27:18Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_log.elf": "8c906d2d50afdf39fc55ed36b04e4fe942ec0ede15235335c0867ee95b00e5b9" + }, + "image": "test_log.elf", + "image_sha256": "8c906d2d50afdf39fc55ed36b04e4fe942ec0ede15235335c0867ee95b00e5b9", + "isr_stack": { + "size": 2048, + "used": 204 + }, + "log": "test_log.log", + "outcome": "passed", + "started": "2026-11-13T05:27:52Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_msgq.elf": "4a96ca644bc33c584a084797ab45442e937c24642e928ae498f816c939a1b1e5" + }, + "image": "test_msgq.elf", + "image_sha256": "4a96ca644bc33c584a084797ab45442e937c24642e928ae498f816c939a1b1e5", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_msgq.log", + "outcome": "passed", + "started": "2026-11-13T05:27:42Z" + }, + { + "bench": [], + "cases": 15, + "cases_passed": 15, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_mutex.elf": "8d21a5be0b45a0fdb2c7d6022e36e822cf5dc9636e6df6b30d8814cb0bd2dedb" + }, + "image": "test_mutex.elf", + "image_sha256": "8d21a5be0b45a0fdb2c7d6022e36e822cf5dc9636e6df6b30d8814cb0bd2dedb", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_mutex.log", + "outcome": "passed", + "started": "2026-11-13T05:27:35Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_notify.elf": "8e196bb9e6b9982c21f470a684f916649f597a9ccaf14317675a23f4421fd9d8" + }, + "image": "test_notify.elf", + "image_sha256": "8e196bb9e6b9982c21f470a684f916649f597a9ccaf14317675a23f4421fd9d8", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_notify.log", + "outcome": "passed", + "started": "2026-11-13T05:27:31Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_rtc.elf": "b89382516ea92142bb3f9b68da8d7e8117c962309f7db319d0e2a3942a52d4d4" + }, + "image": "test_rtc.elf", + "image_sha256": "b89382516ea92142bb3f9b68da8d7e8117c962309f7db319d0e2a3942a52d4d4", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_rtc.log", + "outcome": "passed", + "started": "2026-11-13T05:28:09Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_rtc_board.elf": "4e0bafeca974de1d68bc97c663a84eddadd4cd086e4f2a4925d9eea42e80bad6" + }, + "image": "test_rtc_board.elf", + "image_sha256": "4e0bafeca974de1d68bc97c663a84eddadd4cd086e4f2a4925d9eea42e80bad6", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_rtc_board.log", + "outcome": "passed", + "started": "2026-11-13T05:28:11Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_sched.elf": "9361736815227f4c669a45ce18b47c07a29804b093fb89be9827c3e5740582a9" + }, + "image": "test_sched.elf", + "image_sha256": "9361736815227f4c669a45ce18b47c07a29804b093fb89be9827c3e5740582a9", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_sched.log", + "outcome": "passed", + "started": "2026-11-13T05:27:12Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_sem.elf": "0c9102288ce058a29bf044aec23b8ec1139ad6bc76a153f5686f059f8804c000" + }, + "image": "test_sem.elf", + "image_sha256": "0c9102288ce058a29bf044aec23b8ec1139ad6bc76a153f5686f059f8804c000", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_sem.log", + "outcome": "passed", + "started": "2026-11-13T05:27:33Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_smoke.elf": "6b4317cc982acd490058ab897089cdefc50961773405303c4ec07514225c7a61" + }, + "image": "test_smoke.elf", + "image_sha256": "6b4317cc982acd490058ab897089cdefc50961773405303c4ec07514225c7a61", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_smoke.log", + "outcome": "passed", + "started": "2026-11-13T05:27:08Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_spi.elf": "94e535c1e194e459a68161a207bda8b5820fc764352fc2ccf90986e07eacbb3c" + }, + "image": "test_spi.elf", + "image_sha256": "94e535c1e194e459a68161a207bda8b5820fc764352fc2ccf90986e07eacbb3c", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_spi.log", + "outcome": "passed", + "started": "2026-11-13T05:28:43Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_spi_loop.elf": "2db90115dcead0d1ff441217e626bd476277fa77347b9f58b9f03c0d55ab4953" + }, + "image": "test_spi_loop.elf", + "image_sha256": "2db90115dcead0d1ff441217e626bd476277fa77347b9f58b9f03c0d55ab4953", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_spi_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:28:46Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_thread.elf": "e40c69531ab3f3ffd0ff166d9c3cd5e38afc2a58fada51b67b72242b4e9b57be" + }, + "image": "test_thread.elf", + "image_sha256": "e40c69531ab3f3ffd0ff166d9c3cd5e38afc2a58fada51b67b72242b4e9b57be", + "isr_stack": { + "size": 2048, + "used": 180 + }, + "log": "test_thread.log", + "outcome": "passed", + "started": "2026-11-13T05:27:20Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_thread_identity.elf": "a77eb1b7c148fbb89a714da427f5600d823840e5cb95bb5b16128e6ba563db92" + }, + "image": "test_thread_identity.elf", + "image_sha256": "a77eb1b7c148fbb89a714da427f5600d823840e5cb95bb5b16128e6ba563db92", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_thread_identity.log", + "outcome": "passed", + "started": "2026-11-13T05:27:25Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_thread_join.elf": "cc2dd007187fc00caeb1dc8559e02f9541a9c020adfe6281afe40cfadca4e8bc" + }, + "image": "test_thread_join.elf", + "image_sha256": "cc2dd007187fc00caeb1dc8559e02f9541a9c020adfe6281afe40cfadca4e8bc", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_thread_join.log", + "outcome": "passed", + "started": "2026-11-13T05:27:23Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_time.elf": "cd0a3f2480c19f4650d3566a541e960c0b84f6f3bb25064fa0251a883a72415b" + }, + "image": "test_time.elf", + "image_sha256": "cd0a3f2480c19f4650d3566a541e960c0b84f6f3bb25064fa0251a883a72415b", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_time.log", + "outcome": "passed", + "started": "2026-11-13T05:27:27Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_timer.elf": "e8df5611513d366ec3f24eb84d06a508b2fe71de5bb102d02266f39d7e5a13ce" + }, + "image": "test_timer.elf", + "image_sha256": "e8df5611513d366ec3f24eb84d06a508b2fe71de5bb102d02266f39d7e5a13ce", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_timer.log", + "outcome": "passed", + "started": "2026-11-13T05:27:47Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_uart.elf": "dac55b7683e7ed28339c7b1d672a35abeea79a88e364a2b1e3eb90535356d8d5" + }, + "image": "test_uart.elf", + "image_sha256": "dac55b7683e7ed28339c7b1d672a35abeea79a88e364a2b1e3eb90535356d8d5", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_uart.log", + "outcome": "passed", + "started": "2026-11-13T05:27:57Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_board.elf": "998f974d2c2f4f9b092cf829afa1718b3b027ece65c8970d8817dfc6de7fa75a" + }, + "image": "test_uart_board.elf", + "image_sha256": "998f974d2c2f4f9b092cf829afa1718b3b027ece65c8970d8817dfc6de7fa75a", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_uart_board.log", + "outcome": "passed", + "started": "2026-11-13T05:27:59Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_loop.elf": "64e293a9e75ccd39a25dad79d97883ce97763365ff3c8b4c983273dbc8e04081" + }, + "image": "test_uart_loop.elf", + "image_sha256": "64e293a9e75ccd39a25dad79d97883ce97763365ff3c8b4c983273dbc8e04081", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_uart_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:28:01Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wallclock.elf": "2211c6a7f7dc50a8f1c83fc92a7c7e47e4bd68a72b4094c636a638164f13f41b" + }, + "image": "test_wallclock.elf", + "image_sha256": "2211c6a7f7dc50a8f1c83fc92a7c7e47e4bd68a72b4094c636a638164f13f41b", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_wallclock.log", + "outcome": "passed", + "started": "2026-11-13T05:27:29Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_wdog.elf": "c18067062465b924d306e8d465aee9383e03176d31eb6c21269b128742601ec3" + }, + "image": "test_wdog.elf", + "image_sha256": "c18067062465b924d306e8d465aee9383e03176d31eb6c21269b128742601ec3", + "isr_stack": { + "size": 2048, + "used": 280 + }, + "log": "test_wdog.log", + "outcome": "passed", + "started": "2026-11-13T05:28:31Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdog_board.elf": "0e9ee9372b1fbf3773a49833d62f45b9f6489acb647e5bed0e907a5d146742cd" + }, + "image": "test_wdog_board.elf", + "image_sha256": "0e9ee9372b1fbf3773a49833d62f45b9f6489acb647e5bed0e907a5d146742cd", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_wdog_board.log", + "outcome": "passed", + "started": "2026-11-13T05:28:36Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_wdt.elf": "a8538756991daafbef39b7c8fad59eeda0dcbcd8d3b633c0cac92a38082e8fe3" + }, + "image": "test_wdt.elf", + "image_sha256": "a8538756991daafbef39b7c8fad59eeda0dcbcd8d3b633c0cac92a38082e8fe3", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_wdt.log", + "outcome": "passed", + "started": "2026-11-13T05:28:29Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdt_board.elf": "161de1088c78d19e48cd141b620d0be508692b4013890d7e27775f0399ed986f" + }, + "image": "test_wdt_board.elf", + "image_sha256": "161de1088c78d19e48cd141b620d0be508692b4013890d7e27775f0399ed986f", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "log": "test_wdt_board.log", + "outcome": "passed", + "started": "2026-11-13T05:28:33Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 6, + "flashed_sha256": { + "test_workq.elf": "90bfe9c70b255409b4de7d9e0625fdbc087e67f4371f459082a378fb24c9c975" + }, + "image": "test_workq.elf", + "image_sha256": "90bfe9c70b255409b4de7d9e0625fdbc087e67f4371f459082a378fb24c9c975", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "log": "test_workq.log", + "outcome": "passed", + "started": "2026-11-13T05:27:45Z" + } + ], + "isr_stack_max_used": 280, + "passed": 49, + "preset": "cm4-nucleo-hil", + "total": 49 +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.json new file mode 100644 index 00000000..6258be1b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.json @@ -0,0 +1,107 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 17, + "name": "cond_signal_wakes_one_waiter_which_owns_the_mutex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "cond_broadcast_wakes_all_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "cond_signal_is_not_stored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_relock_after_timeout_waits_for_the_mutex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "cond_cancel_returns_with_the_mutex_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "cond_destroy_aborts_waiters_which_relock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "cond_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_wait_requires_single_ownership", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "cond_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "cond_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:42Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_cond" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_cond.elf verify reset exit" + ], + "flashed_sha256": { + "test_cond.elf": "4f82039d779c11a887c9d43a9289d34c1f7cc7e6d5040b184569707339f852d8" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_cond.elf", + "image_sha256": "4f82039d779c11a887c9d43a9289d34c1f7cc7e6d5040b184569707339f852d8", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:40Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.log new file mode 100644 index 00000000..b4fc42da --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_cond.log @@ -0,0 +1,48 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_cond.elf sha256 4f82039d779c11a887c9d43a9289d34c1f7cc7e6d5040b184569707339f852d8 +EVIDENCE v1 suite=test_cond config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST cond_signal_wakes_one_waiter_which_owns_the_mutex + -> ok + req KRN-SYNC-030 KRN-WAIT-001 +CASE cond_signal_wakes_one_waiter_which_owns_the_mutex outcome=passed asserts=17 skips=0 +TEST cond_broadcast_wakes_all_in_priority_order + -> ok + req KRN-SYNC-030 KRN-WAIT-013 +CASE cond_broadcast_wakes_all_in_priority_order outcome=passed asserts=18 skips=0 +TEST cond_signal_is_not_stored + -> ok + req KRN-SYNC-030 +CASE cond_signal_is_not_stored outcome=passed asserts=13 skips=0 +TEST cond_relock_after_timeout_waits_for_the_mutex + -> ok + req KRN-SYNC-030 +CASE cond_relock_after_timeout_waits_for_the_mutex outcome=passed asserts=12 skips=0 +TEST cond_cancel_returns_with_the_mutex_owned + -> ok + req KRN-SYNC-030 KRN-WAIT-017 +CASE cond_cancel_returns_with_the_mutex_owned outcome=passed asserts=10 skips=0 +TEST cond_destroy_aborts_waiters_which_relock + -> ok + req KRN-OBJ-001 KRN-SYNC-030 +CASE cond_destroy_aborts_waiters_which_relock outcome=passed asserts=9 skips=0 +TEST cond_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE cond_destroy_with_waiters_is_misuse outcome=passed asserts=11 skips=0 +TEST cond_wait_requires_single_ownership + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-030 API-013 +CASE cond_wait_requires_single_ownership outcome=passed asserts=12 skips=0 +TEST cond_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE cond_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST cond_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE cond_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=176 +10 tests, 0 failed, 0 skipped, 28 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.json new file mode 100644 index 00000000..0b046c27 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 38, + "name": "crash_record_round_trip", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "crash_record_corruption_is_ignored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "crash_record_get_refuses_null", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:52Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_crash" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_crash.elf verify reset exit" + ], + "flashed_sha256": { + "test_crash.elf": "9e2e6866e98597ebcca6a31a953783d1a9fd206bfa36d052addd6364e322b47e" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash.elf", + "image_sha256": "9e2e6866e98597ebcca6a31a953783d1a9fd206bfa36d052addd6364e322b47e", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:50Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.log new file mode 100644 index 00000000..9c76268d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash.log @@ -0,0 +1,19 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash.elf sha256 9e2e6866e98597ebcca6a31a953783d1a9fd206bfa36d052addd6364e322b47e +EVIDENCE v1 suite=test_crash config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_round_trip +EMB_CRASH 454d424301005c0031a17542e2fdeafa9f7ef26ffb06ce2b0916ec85302e322e300000000a0000000000000001000000050202012900000003000000341200007856000000000000bc7a000000000000000000000000000047e1acd4 + -> ok + req OBS-016 API-017 +CASE crash_record_round_trip outcome=passed asserts=38 skips=0 +TEST crash_record_corruption_is_ignored + -> ok + req OBS-016 +CASE crash_record_corruption_is_ignored outcome=passed asserts=6 skips=0 +TEST crash_record_get_refuses_null + fault checks that reset the board: 1 + -> ok + req OBS-016 API-015 +CASE crash_record_get_refuses_null outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=176 +3 tests, 0 failed, 0 skipped, 14 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.json new file mode 100644 index 00000000..817e7c7e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 9, + "name": "crash_record_keeps_a_hardware_fault", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:55Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_crash_hw" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_crash_hw.elf verify reset exit" + ], + "flashed_sha256": { + "test_crash_hw.elf": "57dac087b0ce3f804ad074f9e5e2742a4ced55b1755cd83b466008f803f26d4d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_hw.elf", + "image_sha256": "57dac087b0ce3f804ad074f9e5e2742a4ced55b1755cd83b466008f803f26d4d", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:54Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.log new file mode 100644 index 00000000..c8a27dab --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_hw.log @@ -0,0 +1,13 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_hw.elf sha256 57dac087b0ce3f804ad074f9e5e2742a4ced55b1755cd83b466008f803f26d4d +EVIDENCE v1 suite=test_crash_hw config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_keeps_a_hardware_fault +crash_record_keeps_a_hardware_fault: first boot, trapping +EVIDENCE v1 suite=test_crash_hw config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_keeps_a_hardware_fault +EMB_CRASH 454d424301008c0031a17542e2fdeafa9f7ef26ffb06ce2b0916ec85302e322e300000001100000000000000020000000a000600000000000000000000000100e2030008e3030008d0210020000000000000000004080000000001000000000034ed00e038ed00e0e503000818080020e88201000000008020120020e3030008e203000800000061fe09ddfd + -> ok + req OBS-016 KRN-IRQ-030 +CASE crash_record_keeps_a_hardware_fault outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=176 +1 tests, 0 failed, 0 skipped, 49 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.json new file mode 100644 index 00000000..20d99de9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "crash_record_survives_reset", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:54Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_crash_reset" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_crash_reset.elf verify reset exit" + ], + "flashed_sha256": { + "test_crash_reset.elf": "9a2d3ed9d38680bcd86c3b3441407529c18f9c736d1d8f2dd269c6f0632d6b78" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_reset.elf", + "image_sha256": "9a2d3ed9d38680bcd86c3b3441407529c18f9c736d1d8f2dd269c6f0632d6b78", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:52Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.log new file mode 100644 index 00000000..0aac2ecd --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_crash_reset.log @@ -0,0 +1,13 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_reset.elf sha256 9a2d3ed9d38680bcd86c3b3441407529c18f9c736d1d8f2dd269c6f0632d6b78 +EVIDENCE v1 suite=test_crash_reset config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_survives_reset +crash_record_survives_reset: first boot, faulting +EVIDENCE v1 suite=test_crash_reset config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_survives_reset +EMB_CRASH 454d424301005c0031a17542e2fdeafa9f7ef26ffb06ce2b0916ec85302e322e300000000f00000000000000020000000b00ed5e000000000000000000000000ed03000800000000000000000000000000000000000000005dd4b845 + -> ok + req OBS-016 KRN-IRQ-030 ARCH-AVR-008 +CASE crash_record_survives_reset outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=176 +1 tests, 0 failed, 0 skipped, 40 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.json new file mode 100644 index 00000000..6f09f404 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.json @@ -0,0 +1,71 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 12, + "name": "debug_descriptor_header", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "debug_descriptor_finds_the_running_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "debug_descriptor_isr_stack", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 82, + "name": "debug_descriptor_reads_thread_states", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:58Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_debug_descriptor" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_debug_descriptor.elf verify reset exit" + ], + "flashed_sha256": { + "test_debug_descriptor.elf": "6b6fac9f745de06e3ce4b058a26570e19752e730e70133f908980771299e5333" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "6b6fac9f745de06e3ce4b058a26570e19752e730e70133f908980771299e5333", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:55Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.log new file mode 100644 index 00000000..45172e73 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_debug_descriptor.log @@ -0,0 +1,21 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_debug_descriptor.elf sha256 6b6fac9f745de06e3ce4b058a26570e19752e730e70133f908980771299e5333 +EVIDENCE v1 suite=test_debug_descriptor config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST debug_descriptor_header + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_header outcome=passed asserts=12 skips=0 +TEST debug_descriptor_finds_the_running_thread + -> ok + req OBS-008 +CASE debug_descriptor_finds_the_running_thread outcome=passed asserts=7 skips=0 +TEST debug_descriptor_isr_stack + -> ok + req PORT-012 +CASE debug_descriptor_isr_stack outcome=passed asserts=2 skips=0 +TEST debug_descriptor_reads_thread_states + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_reads_thread_states outcome=passed asserts=82 skips=0 +ISR_STACK size=2048 used=176 +4 tests, 0 failed, 0 skipped, 62 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.json new file mode 100644 index 00000000..87faba7a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.json @@ -0,0 +1,143 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 10, + "name": "device_init_reaches_ready_or_failed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "device_on_a_failed_dependency_fails_without_its_driver", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "device_list_initializes_past_a_failure", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "device_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "drv_submit_refused_unless_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "drv_request_completes_from_the_interrupt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "drv_completion_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_queue_is_first_in_first_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_lanes_run_independently", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_cancel_queued_and_running_requests_complete_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_wait_returns_the_result_or_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 38, + "name": "device_board_devices_ready_in_dependency_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 23, + "name": "device_optional_operations", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "drv_setters_ignore_a_missing_request", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "device_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 47, + "name": "drv_status_codes_are_named_in_their_ranges", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:57Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_device" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_device.elf verify reset exit" + ], + "flashed_sha256": { + "test_device.elf": "e362f5f6e6baf215b80cc501560f8581031987383b4c434c15659cf4949eb0c0" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_device.elf", + "image_sha256": "e362f5f6e6baf215b80cc501560f8581031987383b4c434c15659cf4949eb0c0", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:54Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.log new file mode 100644 index 00000000..0dc37f4e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_device.log @@ -0,0 +1,71 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_device.elf sha256 e362f5f6e6baf215b80cc501560f8581031987383b4c434c15659cf4949eb0c0 +EVIDENCE v1 suite=test_device config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST device_init_reaches_ready_or_failed + -> ok + req DRV-002 DRV-003 +CASE device_init_reaches_ready_or_failed outcome=passed asserts=10 skips=0 +TEST device_on_a_failed_dependency_fails_without_its_driver + -> ok + req DRV-003 +CASE device_on_a_failed_dependency_fails_without_its_driver outcome=passed asserts=5 skips=0 +TEST device_list_initializes_past_a_failure + -> ok + req DRV-001 DRV-003 +CASE device_list_initializes_past_a_failure outcome=passed asserts=4 skips=0 +TEST device_suspend_and_resume + -> ok + req DRV-002 PWR-002 +CASE device_suspend_and_resume outcome=passed asserts=10 skips=0 +TEST drv_submit_refused_unless_ready + -> ok + req DRV-003 +CASE drv_submit_refused_unless_ready outcome=passed asserts=2 skips=0 +TEST drv_request_completes_from_the_interrupt + -> ok + req DRV-004 DRV-005 +CASE drv_request_completes_from_the_interrupt outcome=passed asserts=6 skips=0 +TEST drv_completion_targets + -> ok + req DRV-005 +CASE drv_completion_targets outcome=passed asserts=13 skips=0 +TEST drv_queue_is_first_in_first_out + -> ok + req DRV-004 +CASE drv_queue_is_first_in_first_out outcome=passed asserts=8 skips=0 +TEST drv_lanes_run_independently + fault checks that reset the board: 1 + -> ok + req DRV-004 DRV-006 +CASE drv_lanes_run_independently outcome=passed asserts=15 skips=0 +TEST drv_cancel_queued_and_running_requests_complete_once + -> ok + req DRV-006 +CASE drv_cancel_queued_and_running_requests_complete_once outcome=passed asserts=15 skips=0 +TEST drv_wait_returns_the_result_or_times_out + -> ok + req DRV-004 DRV-006 +CASE drv_wait_returns_the_result_or_times_out outcome=passed asserts=8 skips=0 +TEST device_board_devices_ready_in_dependency_order + -> ok + req DRV-001 DRV-002 +CASE device_board_devices_ready_in_dependency_order outcome=passed asserts=38 skips=0 +TEST device_optional_operations + -> ok + req DRV-002 DRV-006 PWR-002 +CASE device_optional_operations outcome=passed asserts=23 skips=0 +TEST drv_setters_ignore_a_missing_request + -> ok + req DRV-005 +CASE drv_setters_ignore_a_missing_request outcome=passed asserts=3 skips=0 +TEST device_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-002 DRV-004 +CASE device_misuse_faults outcome=passed asserts=11 skips=0 +TEST drv_status_codes_are_named_in_their_ranges + -> ok + req DRV-008 +CASE drv_status_codes_are_named_in_their_ranges outcome=passed asserts=47 skips=0 +ISR_STACK size=2048 used=228 +16 tests, 0 failed, 0 skipped, 26 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.json new file mode 100644 index 00000000..068a06d2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.json @@ -0,0 +1,71 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 10, + "name": "dma_job_starts_and_ends", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dma_stop_gives_what_moved", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "dma_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dma_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:07Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_dma" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_dma.elf verify reset exit" + ], + "flashed_sha256": { + "test_dma.elf": "3134c0fe5771e553fff3d411077867a645ae1d0bc56a8a87aeec7ee24741bb71" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_dma.elf", + "image_sha256": "3134c0fe5771e553fff3d411077867a645ae1d0bc56a8a87aeec7ee24741bb71", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:05Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.log new file mode 100644 index 00000000..660bbdc9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_dma.log @@ -0,0 +1,22 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_dma.elf sha256 3134c0fe5771e553fff3d411077867a645ae1d0bc56a8a87aeec7ee24741bb71 +EVIDENCE v1 suite=test_dma config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST dma_job_starts_and_ends + -> ok + req DRV-004 +CASE dma_job_starts_and_ends outcome=passed asserts=10 skips=0 +TEST dma_stop_gives_what_moved + -> ok + req DRV-006 +CASE dma_stop_gives_what_moved outcome=passed asserts=7 skips=0 +TEST dma_refusals + -> ok + req DRV-004 +CASE dma_refusals outcome=passed asserts=5 skips=0 +TEST dma_misuse_faults + fault checks that reset the board: 8 + -> ok + req DRV-004 +CASE dma_misuse_faults outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=176 +4 tests, 0 failed, 0 skipped, 12 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.json new file mode 100644 index 00000000..3aa11abb --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "entropy_conditioning_is_sha256", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "entropy_read_conditions_twice_the_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 54, + "name": "entropy_read_raw_assembles_blocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "entropy_health_failure_delivers_none_of_its_block", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "entropy_timeout_keeps_what_was_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "entropy_board_source_or_its_absence", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "entropy_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:09Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_entropy" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_entropy.elf verify reset exit" + ], + "flashed_sha256": { + "test_entropy.elf": "1cafa29dec461c82dc23eb4e32afad4bd764befc2885c95ea865453ccc6484ab" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_entropy.elf", + "image_sha256": "1cafa29dec461c82dc23eb4e32afad4bd764befc2885c95ea865453ccc6484ab", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:07Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.log new file mode 100644 index 00000000..83b95512 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_entropy.log @@ -0,0 +1,34 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_entropy.elf sha256 1cafa29dec461c82dc23eb4e32afad4bd764befc2885c95ea865453ccc6484ab +EVIDENCE v1 suite=test_entropy config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST entropy_conditioning_is_sha256 + -> ok + req DRV-001 +CASE entropy_conditioning_is_sha256 outcome=passed asserts=3 skips=0 +TEST entropy_read_conditions_twice_the_bytes + -> ok + req DRV-001 +CASE entropy_read_conditions_twice_the_bytes outcome=passed asserts=6 skips=0 +TEST entropy_read_raw_assembles_blocks + -> ok + req DRV-001 +CASE entropy_read_raw_assembles_blocks outcome=passed asserts=54 skips=0 +TEST entropy_health_failure_delivers_none_of_its_block + -> ok + req DRV-001 +CASE entropy_health_failure_delivers_none_of_its_block outcome=passed asserts=7 skips=0 +TEST entropy_timeout_keeps_what_was_read + -> ok + req DRV-001 +CASE entropy_timeout_keeps_what_was_read outcome=passed asserts=4 skips=0 +TEST entropy_board_source_or_its_absence + -> ok + req SEC-012 +CASE entropy_board_source_or_its_absence outcome=passed asserts=1 skips=0 +TEST entropy_misuse_faults + fault checks that reset the board: 4 + -> ok + req DRV-001 +CASE entropy_misuse_faults outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=176 +7 tests, 0 failed, 0 skipped, 12 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.json new file mode 100644 index 00000000..b09a5c1b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.json @@ -0,0 +1,113 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 15, + "name": "event_any_all_and_clear", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_overlapping_clear_serves_waiters_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_set_wakes_every_satisfied_waiter_in_one_pass", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "event_set_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "event_wait_times_out_cancels_and_ignores_clear", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "event_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_wait_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "event_binding_fires_after_direct_waiters", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "event_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:40Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_event" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_event.elf verify reset exit" + ], + "flashed_sha256": { + "test_event.elf": "9ccc4975b129e36712b4ff8a7648c9ce3d83e88623ddaf457477a7d5852a3e21" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_event.elf", + "image_sha256": "9ccc4975b129e36712b4ff8a7648c9ce3d83e88623ddaf457477a7d5852a3e21", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:38Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.log new file mode 100644 index 00000000..4eb6048e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_event.log @@ -0,0 +1,52 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_event.elf sha256 9ccc4975b129e36712b4ff8a7648c9ce3d83e88623ddaf457477a7d5852a3e21 +EVIDENCE v1 suite=test_event config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST event_any_all_and_clear + -> ok + req KRN-SYNC-029 +CASE event_any_all_and_clear outcome=passed asserts=15 skips=0 +TEST event_overlapping_clear_serves_waiters_in_order + -> ok + req KRN-SYNC-029 KRN-WAIT-001 +CASE event_overlapping_clear_serves_waiters_in_order outcome=passed asserts=11 skips=0 +TEST event_set_wakes_every_satisfied_waiter_in_one_pass + -> ok + req KRN-SYNC-029 KRN-WAIT-013 +CASE event_set_wakes_every_satisfied_waiter_in_one_pass outcome=passed asserts=11 skips=0 +TEST event_set_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-029 KRN-SYNC-027 +CASE event_set_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST event_wait_times_out_cancels_and_ignores_clear + -> ok + req KRN-SYNC-029 KRN-WAIT-004 KRN-WAIT-017 +CASE event_wait_times_out_cancels_and_ignores_clear outcome=passed asserts=12 skips=0 +TEST event_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE event_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST event_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE event_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST event_wait_validates_arguments + fault checks that reset the board: 3 + -> ok + req KRN-SYNC-029 API-015 +CASE event_wait_validates_arguments outcome=passed asserts=5 skips=0 +TEST event_binding_fires_after_direct_waiters + -> ok + req KRN-SYNC-035 KRN-NOTIF-004 KRN-NOTIF-005 KRN-NOTIF-013 +CASE event_binding_fires_after_direct_waiters outcome=passed asserts=15 skips=0 +TEST event_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE event_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST event_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE event_define_constructs_in_init_table outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=176 +11 tests, 0 failed, 0 skipped, 28 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.json new file mode 100644 index 00000000..1ec0ad8d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "fault_successful_check_preserves_status", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "fault_status_policy_is_preserved", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:12Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_fault" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_fault.elf verify reset exit" + ], + "flashed_sha256": { + "test_fault.elf": "62203d0b369d67ce9d8e5e248122c57a42451620741e63fe52925ad32e92d7ec" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fault.elf", + "image_sha256": "62203d0b369d67ce9d8e5e248122c57a42451620741e63fe52925ad32e92d7ec", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:10Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.log new file mode 100644 index 00000000..2a66a4f4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fault.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_fault.elf sha256 62203d0b369d67ce9d8e5e248122c57a42451620741e63fe52925ad32e92d7ec +EVIDENCE v1 suite=test_fault config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST fault_successful_check_preserves_status + -> ok + req API-015 API-017 +CASE fault_successful_check_preserves_status outcome=passed asserts=3 skips=0 +TEST fault_status_policy_is_preserved + fault checks that reset the board: 2 + -> ok + req API-015 +CASE fault_status_policy_is_preserved outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=176 +2 tests, 0 failed, 0 skipped, 13 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.json new file mode 100644 index 00000000..afeb56c5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 80614, + "name": "first_execution_sequence_repeats_reliably", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:50Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_first_execution" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_first_execution.elf verify reset exit" + ], + "flashed_sha256": { + "test_first_execution.elf": "f72bdf269b9ae3821cd7161493e61151f3a1f70cecad060e1b6114079890ef50" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_first_execution.elf", + "image_sha256": "f72bdf269b9ae3821cd7161493e61151f3a1f70cecad060e1b6114079890ef50", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:48Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.log new file mode 100644 index 00000000..2e878849 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_first_execution.log @@ -0,0 +1,10 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_first_execution.elf sha256 f72bdf269b9ae3821cd7161493e61151f3a1f70cecad060e1b6114079890ef50 +EVIDENCE v1 suite=test_first_execution config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST first_execution_sequence_repeats_reliably + ticks seen 401, elapsed 401, timer start +0, late 0 + -> ok + req KRN-SCH-001 KRN-SCH-004 KRN-IRQ-010 KRN-TIM-010 KRN-NOTIF-003 +CASE first_execution_sequence_repeats_reliably outcome=passed asserts=80614 skips=0 +ISR_STACK size=2048 used=176 +1 tests, 0 failed, 0 skipped, 434 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.json new file mode 100644 index 00000000..78e78ba5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.json @@ -0,0 +1,83 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 10, + "name": "flash_geometry_and_sectors", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_program_read_erase", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "flash_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_area_stays_inside", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "flash_power_loss_tears_an_operation", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "flash_polled_calls", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:19Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_flash" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_flash.elf verify reset exit" + ], + "flashed_sha256": { + "test_flash.elf": "6113cc4bbd335a4df871789ea0aa079191b7317d6f6637c25e295ae2c104ae9a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash.elf", + "image_sha256": "6113cc4bbd335a4df871789ea0aa079191b7317d6f6637c25e295ae2c104ae9a", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:16Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.log new file mode 100644 index 00000000..afda5b16 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash.log @@ -0,0 +1,30 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash.elf sha256 6113cc4bbd335a4df871789ea0aa079191b7317d6f6637c25e295ae2c104ae9a +EVIDENCE v1 suite=test_flash config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST flash_geometry_and_sectors + -> ok + req DRV-001 +CASE flash_geometry_and_sectors outcome=passed asserts=10 skips=0 +TEST flash_program_read_erase + -> ok + req DRV-001 DRV-003 +CASE flash_program_read_erase outcome=passed asserts=10 skips=0 +TEST flash_refusals + fault checks that reset the board: 4 + -> ok + req DRV-001 DRV-003 +CASE flash_refusals outcome=passed asserts=14 skips=0 +TEST flash_area_stays_inside + -> ok + req DRV-001 +CASE flash_area_stays_inside outcome=passed asserts=10 skips=0 +TEST flash_power_loss_tears_an_operation + -> ok + req DRV-001 +CASE flash_power_loss_tears_an_operation outcome=passed asserts=15 skips=0 +TEST flash_polled_calls + -> ok + req DRV-007 +CASE flash_polled_calls outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=176 +6 tests, 0 failed, 0 skipped, 44 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.json new file mode 100644 index 00000000..f644a66a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 516, + "name": "flash_board_erase_keeps_the_clock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4616, + "name": "flash_board_program_and_read_back", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:29Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_flash_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_flash_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_flash_board.elf": "821ae2f877a0ca65f20f671c3b3f98d0d9c193cdb0b15be1b57aebec4b90a0cb" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash_board.elf", + "image_sha256": "821ae2f877a0ca65f20f671c3b3f98d0d9c193cdb0b15be1b57aebec4b90a0cb", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:19Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.log new file mode 100644 index 00000000..b0b6714a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_flash_board.log @@ -0,0 +1,13 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash_board.elf sha256 821ae2f877a0ca65f20f671c3b3f98d0d9c193cdb0b15be1b57aebec4b90a0cb +EVIDENCE v1 suite=test_flash_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST flash_board_erase_keeps_the_clock + erase of 128 KiB: 895 ms by the cycles, 895 ms by the clock -> ok + req DRV-001 DRV-003 +CASE flash_board_erase_keeps_the_clock outcome=passed asserts=516 skips=0 +TEST flash_board_program_and_read_back + -> ok + req DRV-001 DRV-003 +CASE flash_board_program_and_read_back outcome=passed asserts=4616 skips=0 +ISR_STACK size=2048 used=176 +2 tests, 0 failed, 0 skipped, 8195 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.json new file mode 100644 index 00000000..bff25c6a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "fpu_callee_saved_registers_survive_a_switch", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "fpu_state_survives_preemption", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:59Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_fpu" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_fpu.elf verify reset exit" + ], + "flashed_sha256": { + "test_fpu.elf": "11cfcd98716f2e291e8d6db9e2f4ed74fa7748a375019148ae17ab58bb92a903" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fpu.elf", + "image_sha256": "11cfcd98716f2e291e8d6db9e2f4ed74fa7748a375019148ae17ab58bb92a903", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:58Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.log new file mode 100644 index 00000000..ebdb7522 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_fpu.log @@ -0,0 +1,11 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_fpu.elf sha256 11cfcd98716f2e291e8d6db9e2f4ed74fa7748a375019148ae17ab58bb92a903 +EVIDENCE v1 suite=test_fpu config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST fpu_callee_saved_registers_survive_a_switch + -> ok +CASE fpu_callee_saved_registers_survive_a_switch outcome=passed asserts=6 skips=0 +TEST fpu_state_survives_preemption + -> ok +CASE fpu_state_survives_preemption outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +2 tests, 0 failed, 0 skipped, 41 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.json new file mode 100644 index 00000000..b34c911e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 9, + "name": "frame_encoding_matches_the_host_tool", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 39, + "name": "frame_runs_at_the_cobs_boundary", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "frame_round_trip_through_the_decoder", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "frame_decoder_resynchronizes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "frame_decoder_drops_an_overrun", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "frame_misuse_is_refused", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 383, + "name": "frame_random_stream_with_damage", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 122, + "name": "frame_write_streams_the_encoders_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "frame_write_misuse_is_refused", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:52Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_frame" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_frame.elf verify reset exit" + ], + "flashed_sha256": { + "test_frame.elf": "5b147777f902c4e96556bced1d0a3e0f0fb310a0c7fce023bfd254aaab762f8f" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_frame.elf", + "image_sha256": "5b147777f902c4e96556bced1d0a3e0f0fb310a0c7fce023bfd254aaab762f8f", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:50Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.log new file mode 100644 index 00000000..e9e342d3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_frame.log @@ -0,0 +1,41 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_frame.elf sha256 5b147777f902c4e96556bced1d0a3e0f0fb310a0c7fce023bfd254aaab762f8f +EVIDENCE v1 suite=test_frame config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST frame_encoding_matches_the_host_tool + -> ok + req OBS-019 +CASE frame_encoding_matches_the_host_tool outcome=passed asserts=9 skips=0 +TEST frame_runs_at_the_cobs_boundary + -> ok + req OBS-019 +CASE frame_runs_at_the_cobs_boundary outcome=passed asserts=39 skips=0 +TEST frame_round_trip_through_the_decoder + -> ok + req OBS-019 +CASE frame_round_trip_through_the_decoder outcome=passed asserts=12 skips=0 +TEST frame_decoder_resynchronizes + -> ok + req OBS-019 +CASE frame_decoder_resynchronizes outcome=passed asserts=17 skips=0 +TEST frame_decoder_drops_an_overrun + -> ok + req OBS-019 +CASE frame_decoder_drops_an_overrun outcome=passed asserts=6 skips=0 +TEST frame_misuse_is_refused + -> ok + req OBS-019 +CASE frame_misuse_is_refused outcome=passed asserts=8 skips=0 +TEST frame_random_stream_with_damage + -> ok + req OBS-019 +CASE frame_random_stream_with_damage outcome=passed asserts=383 skips=0 +TEST frame_write_streams_the_encoders_bytes + -> ok + req OBS-019 +CASE frame_write_streams_the_encoders_bytes outcome=passed asserts=122 skips=0 +TEST frame_write_misuse_is_refused + -> ok + req OBS-019 +CASE frame_write_misuse_is_refused outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=176 +9 tests, 0 failed, 0 skipped, 129 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.json new file mode 100644 index 00000000..deba14bb --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 9, + "name": "gpio_output_drives_and_reads_back", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "gpio_input_reads_its_pull", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "gpio_named_line_follows_its_sense", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "gpio_driver_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "gpio_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:05Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_gpio" + }, + "exit": 0, + "fault_checks_by_reset": 10, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_gpio.elf verify reset exit" + ], + "flashed_sha256": { + "test_gpio.elf": "022583011f1d5877bae3ac74312a3e1e32939f6ce51b8e7f10bd6693de855a23" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_gpio.elf", + "image_sha256": "022583011f1d5877bae3ac74312a3e1e32939f6ce51b8e7f10bd6693de855a23", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:03Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.log new file mode 100644 index 00000000..bc0aafe3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_gpio.log @@ -0,0 +1,26 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_gpio.elf sha256 022583011f1d5877bae3ac74312a3e1e32939f6ce51b8e7f10bd6693de855a23 +EVIDENCE v1 suite=test_gpio config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST gpio_output_drives_and_reads_back + -> ok + req DRV-004 +CASE gpio_output_drives_and_reads_back outcome=passed asserts=9 skips=0 +TEST gpio_input_reads_its_pull + -> ok + req DRV-004 +CASE gpio_input_reads_its_pull outcome=passed asserts=6 skips=0 +TEST gpio_named_line_follows_its_sense + -> ok + req DRV-004 +CASE gpio_named_line_follows_its_sense outcome=passed asserts=13 skips=0 +TEST gpio_driver_refusals + -> ok + req DRV-004 +CASE gpio_driver_refusals outcome=passed asserts=3 skips=0 +TEST gpio_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-004 +CASE gpio_misuse_faults outcome=passed asserts=11 skips=0 +ISR_STACK size=2048 used=176 +5 tests, 0 failed, 0 skipped, 12 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.json new file mode 100644 index 00000000..549694a0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "i2c_write_then_read_a_register", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_segments_count_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "i2c_errors_and_timeout", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "i2c_target_answers_its_address", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "i2c_controller_and_target_at_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "i2c_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_held_bus_keeps_one_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_recover_clocks_a_stuck_bus_free", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_recover_waits_for_a_held_bus", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:41Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_i2c" + }, + "exit": 0, + "fault_checks_by_reset": 12, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_i2c.elf verify reset exit" + ], + "flashed_sha256": { + "test_i2c.elf": "240ffced9fa4377fbf45410375ade338c63d1e1e438cc3cabbb987bc4c0dc66d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c.elf", + "image_sha256": "240ffced9fa4377fbf45410375ade338c63d1e1e438cc3cabbb987bc4c0dc66d", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:39Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.log new file mode 100644 index 00000000..d7a8ffd7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c.log @@ -0,0 +1,42 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c.elf sha256 240ffced9fa4377fbf45410375ade338c63d1e1e438cc3cabbb987bc4c0dc66d +EVIDENCE v1 suite=test_i2c config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST i2c_write_then_read_a_register + -> ok + req DRV-004 DRV-005 +CASE i2c_write_then_read_a_register outcome=passed asserts=7 skips=0 +TEST i2c_segments_count_bytes + -> ok + req DRV-005 +CASE i2c_segments_count_bytes outcome=passed asserts=6 skips=0 +TEST i2c_errors_and_timeout + -> ok + req DRV-006 +CASE i2c_errors_and_timeout outcome=passed asserts=7 skips=0 +TEST i2c_target_answers_its_address + -> ok + req DRV-004 DRV-005 +CASE i2c_target_answers_its_address outcome=passed asserts=10 skips=0 +TEST i2c_controller_and_target_at_once + -> ok + req DRV-004 +CASE i2c_controller_and_target_at_once outcome=passed asserts=9 skips=0 +TEST i2c_misuse_faults + fault checks that reset the board: 12 + -> ok + req DRV-004 +CASE i2c_misuse_faults outcome=passed asserts=13 skips=0 +TEST i2c_held_bus_keeps_one_target + -> ok + req DRV-004 +CASE i2c_held_bus_keeps_one_target outcome=passed asserts=11 skips=0 +TEST i2c_recover_clocks_a_stuck_bus_free + -> ok + req DRV-006 +CASE i2c_recover_clocks_a_stuck_bus_free outcome=passed asserts=11 skips=0 +TEST i2c_recover_waits_for_a_held_bus + -> ok + req DRV-006 +CASE i2c_recover_waits_for_a_held_bus outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +9 tests, 0 failed, 0 skipped, 47 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.json new file mode 100644 index 00000000..3e83d7ad --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 8, + "name": "i2c_loop_write_to_the_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 32, + "name": "i2c_loop_register_reads_of_every_length", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_nobody_answers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_target_drops_beyond_its_buffer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "i2c_loop_fast_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "i2c_loop_listen_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 88, + "name": "i2c_loop_recovers_a_stuck_target", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:43Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_i2c_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_i2c_loop.elf verify reset exit" + ], + "flashed_sha256": { + "test_i2c_loop.elf": "aa4f92f691353bb07b4fbd191d020c40cca23346e5b5bfb8522810975b9f6971" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c_loop.elf", + "image_sha256": "aa4f92f691353bb07b4fbd191d020c40cca23346e5b5bfb8522810975b9f6971", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:41Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.log new file mode 100644 index 00000000..64fa1b9f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_i2c_loop.log @@ -0,0 +1,33 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c_loop.elf sha256 aa4f92f691353bb07b4fbd191d020c40cca23346e5b5bfb8522810975b9f6971 +EVIDENCE v1 suite=test_i2c_loop config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST i2c_loop_write_to_the_target + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_write_to_the_target outcome=passed asserts=8 skips=0 +TEST i2c_loop_register_reads_of_every_length + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_register_reads_of_every_length outcome=passed asserts=32 skips=0 +TEST i2c_loop_nobody_answers + -> ok + req DRV-006 +CASE i2c_loop_nobody_answers outcome=passed asserts=6 skips=0 +TEST i2c_loop_target_drops_beyond_its_buffer + -> ok + req DRV-006 +CASE i2c_loop_target_drops_beyond_its_buffer outcome=passed asserts=6 skips=0 +TEST i2c_loop_fast_mode + -> ok + req DRV-004 +CASE i2c_loop_fast_mode outcome=passed asserts=5 skips=0 +TEST i2c_loop_listen_times_out + -> ok + req DRV-006 +CASE i2c_loop_listen_times_out outcome=passed asserts=2 skips=0 +TEST i2c_loop_recovers_a_stuck_target + -> ok + req DRV-006 +CASE i2c_loop_recovers_a_stuck_target outcome=passed asserts=88 skips=0 +ISR_STACK size=2048 used=176 +7 tests, 0 failed, 0 skipped, 183 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.json new file mode 100644 index 00000000..e486a10e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "irq_lock_is_nestable_and_lifo", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "irq_isr_wake_switches_at_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_delivery_is_deferred_while_masked", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_scheduler_lock_defers_the_switch_not_the_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "irq_disabled_source_stays_pending", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_blocking_call_from_isr_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_connect_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_unlock_without_lock_is_misuse", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:16Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_irq" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_irq.elf verify reset exit" + ], + "flashed_sha256": { + "test_irq.elf": "f5ba898d04878a395264c2640fe75ab31071c34c80a9ee59082b3e486e2e1cde" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq.elf", + "image_sha256": "f5ba898d04878a395264c2640fe75ab31071c34c80a9ee59082b3e486e2e1cde", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:14Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.log new file mode 100644 index 00000000..a41ea540 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq.log @@ -0,0 +1,40 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq.elf sha256 f5ba898d04878a395264c2640fe75ab31071c34c80a9ee59082b3e486e2e1cde +EVIDENCE v1 suite=test_irq config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST irq_lock_is_nestable_and_lifo + -> ok + req KRN-IRQ-001 KRN-IRQ-002 +CASE irq_lock_is_nestable_and_lifo outcome=passed asserts=5 skips=0 +TEST irq_isr_wake_switches_at_outermost_exit + -> ok + req KRN-IRQ-010 KRN-IRQ-012 KRN-IRQ-013 KRN-SCH-021 +CASE irq_isr_wake_switches_at_outermost_exit outcome=passed asserts=7 skips=0 +TEST irq_delivery_is_deferred_while_masked + -> ok + req KRN-IRQ-001 KRN-IRQ-033 +CASE irq_delivery_is_deferred_while_masked outcome=passed asserts=4 skips=0 +TEST irq_scheduler_lock_defers_the_switch_not_the_handler + -> ok + req KRN-SCH-016 KRN-SCH-018 KRN-SCH-019 +CASE irq_scheduler_lock_defers_the_switch_not_the_handler outcome=passed asserts=4 skips=0 +TEST irq_disabled_source_stays_pending + -> ok + req KRN-IRQ-020 +CASE irq_disabled_source_stays_pending outcome=passed asserts=5 skips=0 +TEST irq_blocking_call_from_isr_is_misuse + fault checks that reset the board: 1 + -> ok + req API-013 KRN-IRQ-014 +CASE irq_blocking_call_from_isr_is_misuse outcome=passed asserts=1 skips=0 +TEST irq_connect_validates_arguments + fault checks that reset the board: 2 + -> ok + req KRN-IRQ-021 +CASE irq_connect_validates_arguments outcome=passed asserts=2 skips=0 +TEST irq_unlock_without_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-IRQ-002 +CASE irq_unlock_without_lock_is_misuse outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=176 +8 tests, 0 failed, 0 skipped, 14 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.json new file mode 100644 index 00000000..63bf8966 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.json @@ -0,0 +1,107 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 2, + "name": "irq_priority_accepts_advertised_endpoints", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_rejects_out_of_range_level", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_priority_rejects_unknown_number", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_port_rejects_invalid_inputs", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 37, + "name": "irq_priority_encodings_and_invalid_write_guard", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "irq_priority_higher_generic_level_wins_pending_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_higher_generic_level_preempts_lower", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 25, + "name": "irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_equal_levels_do_not_preempt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "irq_priority_highest_kernel_level_is_masked", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:18Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_irq_priority" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_irq_priority.elf verify reset exit" + ], + "flashed_sha256": { + "test_irq_priority.elf": "abd91eeabdde757b29ff71f8faa4e39927a950497699d06604fb840a02fe305c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq_priority.elf", + "image_sha256": "abd91eeabdde757b29ff71f8faa4e39927a950497699d06604fb840a02fe305c", + "isr_stack": { + "size": 2048, + "used": 276 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:16Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.log new file mode 100644 index 00000000..312217af --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_irq_priority.log @@ -0,0 +1,47 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq_priority.elf sha256 abd91eeabdde757b29ff71f8faa4e39927a950497699d06604fb840a02fe305c +EVIDENCE v1 suite=test_irq_priority config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST irq_priority_accepts_advertised_endpoints + -> ok + req KRN-IRQ-028 KRN-IRQ-029 +CASE irq_priority_accepts_advertised_endpoints outcome=passed asserts=2 skips=0 +TEST irq_priority_rejects_out_of_range_level + fault checks that reset the board: 2 + -> ok + req API-015 KRN-IRQ-028 +CASE irq_priority_rejects_out_of_range_level outcome=passed asserts=2 skips=0 +TEST irq_priority_rejects_unknown_number + fault checks that reset the board: 1 + -> ok + req API-015 KRN-IRQ-029 +CASE irq_priority_rejects_unknown_number outcome=passed asserts=1 skips=0 +TEST irq_priority_port_rejects_invalid_inputs + -> ok + req KRN-IRQ-028 +CASE irq_priority_port_rejects_invalid_inputs outcome=passed asserts=2 skips=0 +TEST irq_priority_encodings_and_invalid_write_guard + -> ok + req KRN-IRQ-028 KRN-IRQ-031 +CASE irq_priority_encodings_and_invalid_write_guard outcome=passed asserts=37 skips=0 +TEST irq_priority_higher_generic_level_wins_pending_order + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_wins_pending_order outcome=passed asserts=18 skips=0 +TEST irq_priority_higher_generic_level_preempts_lower + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_preempts_lower outcome=passed asserts=16 skips=0 +TEST irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback + -> ok + req KRN-WQ-007 KRN-TIM-025 KRN-IRQ-012 +CASE irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback outcome=passed asserts=25 skips=0 +TEST irq_priority_equal_levels_do_not_preempt + -> ok + req KRN-IRQ-028 +CASE irq_priority_equal_levels_do_not_preempt outcome=passed asserts=16 skips=0 +TEST irq_priority_highest_kernel_level_is_masked + -> ok + req KRN-IRQ-018 KRN-IRQ-028 +CASE irq_priority_highest_kernel_level_is_masked outcome=passed asserts=17 skips=0 +ISR_STACK size=2048 used=276 +10 tests, 0 failed, 0 skipped, 129 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.json new file mode 100644 index 00000000..4a687add --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "isr_stack_info_reports_size_and_use", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "isr_stack_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "thread_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:20Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_isr_stack" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_isr_stack.elf verify reset exit" + ], + "flashed_sha256": { + "test_isr_stack.elf": "f5aea1246f440db90329eb06ac0235eb82a9ea67989a9465d1c3e6f232741560" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_isr_stack.elf", + "image_sha256": "f5aea1246f440db90329eb06ac0235eb82a9ea67989a9465d1c3e6f232741560", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:18Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.log new file mode 100644 index 00000000..86dfbbc8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_isr_stack.log @@ -0,0 +1,19 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_isr_stack.elf sha256 f5aea1246f440db90329eb06ac0235eb82a9ea67989a9465d1c3e6f232741560 +EVIDENCE v1 suite=test_isr_stack config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST isr_stack_info_reports_size_and_use + -> ok + req PORT-016 KRN-MEM-009 +CASE isr_stack_info_reports_size_and_use outcome=passed asserts=6 skips=0 +TEST isr_stack_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req PORT-016 KRN-MEM-010 +CASE isr_stack_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +TEST thread_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req KRN-MEM-010 PORT-016 +CASE thread_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=176 +3 tests, 0 failed, 0 skipped, 16 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.json new file mode 100644 index 00000000..d60277fc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "log_record_layout", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "log_text_formats", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "log_levels_compile_and_run_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 84, + "name": "log_overflow_drops_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "log_isr_record_waits_for_the_one_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "log_flush_sends_what_is_committed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2855, + "name": "log_producers_at_once_keep_their_order", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:54Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_log" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_log.elf verify reset exit" + ], + "flashed_sha256": { + "test_log.elf": "8c906d2d50afdf39fc55ed36b04e4fe942ec0ede15235335c0867ee95b00e5b9" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_log.elf", + "image_sha256": "8c906d2d50afdf39fc55ed36b04e4fe942ec0ede15235335c0867ee95b00e5b9", + "isr_stack": { + "size": 2048, + "used": 204 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:52Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.log new file mode 100644 index 00000000..354a1880 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_log.log @@ -0,0 +1,35 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_log.elf sha256 8c906d2d50afdf39fc55ed36b04e4fe942ec0ede15235335c0867ee95b00e5b9 +EVIDENCE v1 suite=test_log config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST log_record_layout + -> ok + req OBS-013 +CASE log_record_layout outcome=passed asserts=3 skips=0 +TEST log_text_formats + -> ok + req OBS-013 +CASE log_text_formats outcome=passed asserts=11 skips=0 +TEST log_levels_compile_and_run_time + -> ok + req OBS-002 +CASE log_levels_compile_and_run_time outcome=passed asserts=9 skips=0 +TEST log_overflow_drops_and_counts + -> ok + req OBS-003 +CASE log_overflow_drops_and_counts outcome=passed asserts=84 skips=0 +TEST log_isr_record_waits_for_the_one_before_it + -> ok + req OBS-003 +CASE log_isr_record_waits_for_the_one_before_it outcome=passed asserts=6 skips=0 +TEST log_flush_sends_what_is_committed +[0.064] I t: flushed 1 +[0.064] I t: flushed 2 + -> ok + req OBS-003 +CASE log_flush_sends_what_is_committed outcome=passed asserts=4 skips=0 +TEST log_producers_at_once_keep_their_order + -> ok + req OBS-003 +CASE log_producers_at_once_keep_their_order outcome=passed asserts=2855 skips=0 +ISR_STACK size=2048 used=204 +7 tests, 0 failed, 0 skipped, 110 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.json new file mode 100644 index 00000000..a18f7045 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.json @@ -0,0 +1,119 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 25, + "name": "msgq_fifo_order_counts_and_peek", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "msgq_send_front_is_received_first_and_never_waits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_waiting_receivers_get_items_directly_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "msgq_receive_refills_the_freed_slot_from_a_waiting_sender", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_waits_time_out_and_cancel_without_storing", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "msgq_isr_send_and_receive_never_wait", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_destroy_aborts_receivers_and_senders", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "msgq_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "msgq_init_validates_the_ring", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_binding_fires_on_empty_to_nonempty_only", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "msgq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "msgq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:45Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_msgq" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_msgq.elf verify reset exit" + ], + "flashed_sha256": { + "test_msgq.elf": "4a96ca644bc33c584a084797ab45442e937c24642e928ae498f816c939a1b1e5" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_msgq.elf", + "image_sha256": "4a96ca644bc33c584a084797ab45442e937c24642e928ae498f816c939a1b1e5", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:42Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.log new file mode 100644 index 00000000..1e26bf34 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_msgq.log @@ -0,0 +1,56 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_msgq.elf sha256 4a96ca644bc33c584a084797ab45442e937c24642e928ae498f816c939a1b1e5 +EVIDENCE v1 suite=test_msgq config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST msgq_fifo_order_counts_and_peek + -> ok + req KRN-IPC-010 KRN-IPC-019 +CASE msgq_fifo_order_counts_and_peek outcome=passed asserts=25 skips=0 +TEST msgq_send_front_is_received_first_and_never_waits + -> ok + req KRN-IPC-012 +CASE msgq_send_front_is_received_first_and_never_waits outcome=passed asserts=9 skips=0 +TEST msgq_waiting_receivers_get_items_directly_in_priority_order + -> ok + req KRN-IPC-010 KRN-IPC-005 KRN-WAIT-001 +CASE msgq_waiting_receivers_get_items_directly_in_priority_order outcome=passed asserts=11 skips=0 +TEST msgq_receive_refills_the_freed_slot_from_a_waiting_sender + -> ok + req KRN-IPC-010 KRN-IPC-011 +CASE msgq_receive_refills_the_freed_slot_from_a_waiting_sender outcome=passed asserts=12 skips=0 +TEST msgq_waits_time_out_and_cancel_without_storing + -> ok + req KRN-IPC-010 KRN-WAIT-004 KRN-WAIT-017 +CASE msgq_waits_time_out_and_cancel_without_storing outcome=passed asserts=15 skips=0 +TEST msgq_isr_send_and_receive_never_wait + -> ok + req KRN-IPC-003 KRN-IPC-010 KRN-IRQ-010 +CASE msgq_isr_send_and_receive_never_wait outcome=passed asserts=13 skips=0 +TEST msgq_destroy_aborts_receivers_and_senders + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE msgq_destroy_aborts_receivers_and_senders outcome=passed asserts=11 skips=0 +TEST msgq_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE msgq_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST msgq_init_validates_the_ring + fault checks that reset the board: 6 + -> ok + req KRN-IPC-011 KRN-IPC-019 API-015 +CASE msgq_init_validates_the_ring outcome=passed asserts=6 skips=0 +TEST msgq_binding_fires_on_empty_to_nonempty_only + -> ok + req KRN-IPC-018 KRN-NOTIF-004 KRN-NOTIF-013 +CASE msgq_binding_fires_on_empty_to_nonempty_only outcome=passed asserts=15 skips=0 +TEST msgq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE msgq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST msgq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE msgq_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +12 tests, 0 failed, 0 skipped, 28 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.json new file mode 100644 index 00000000..8c6a3202 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.json @@ -0,0 +1,137 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 8, + "name": "mutex_lock_unlock_and_ownership", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "mutex_recursive_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "mutex_contended_lock_inherits_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "mutex_timeout_removes_the_contribution", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 28, + "name": "mutex_inheritance_propagates_along_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_deadlock_is_detected_on_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "mutex_ceiling_raises_the_owner", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_ceiling_violation_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_ceiling_violation_when_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_owner_death_policy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "mutex_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "mutex_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "mutex_waiter_priority_change_reorders_and_propagates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "mutex_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:38Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_mutex" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_mutex.elf verify reset exit" + ], + "flashed_sha256": { + "test_mutex.elf": "8d21a5be0b45a0fdb2c7d6022e36e822cf5dc9636e6df6b30d8814cb0bd2dedb" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_mutex.elf", + "image_sha256": "8d21a5be0b45a0fdb2c7d6022e36e822cf5dc9636e6df6b30d8814cb0bd2dedb", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:35Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 15 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.log new file mode 100644 index 00000000..a8964a29 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_mutex.log @@ -0,0 +1,73 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_mutex.elf sha256 8d21a5be0b45a0fdb2c7d6022e36e822cf5dc9636e6df6b30d8814cb0bd2dedb +EVIDENCE v1 suite=test_mutex config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST mutex_lock_unlock_and_ownership + fault checks that reset the board: 2 + -> ok + req KRN-SYNC-001 KRN-SYNC-008 +CASE mutex_lock_unlock_and_ownership outcome=passed asserts=8 skips=0 +TEST mutex_recursive_counts + -> ok + req KRN-SYNC-004 +CASE mutex_recursive_counts outcome=passed asserts=8 skips=0 +TEST mutex_contended_lock_inherits_and_hands_off + -> ok + req KRN-SYNC-003 KRN-SYNC-009 KRN-SYNC-010 KRN-WAIT-012 +CASE mutex_contended_lock_inherits_and_hands_off outcome=passed asserts=16 skips=0 +TEST mutex_timeout_removes_the_contribution + -> ok + req KRN-SYNC-014 KRN-WAIT-013 +CASE mutex_timeout_removes_the_contribution outcome=passed asserts=14 skips=0 +TEST mutex_inheritance_propagates_along_the_chain + -> ok + req KRN-SYNC-009 KRN-SYNC-010 KRN-SYNC-016 +CASE mutex_inheritance_propagates_along_the_chain outcome=passed asserts=28 skips=0 +TEST mutex_deadlock_is_detected_on_the_chain + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-015 +CASE mutex_deadlock_is_detected_on_the_chain outcome=passed asserts=5 skips=0 +TEST mutex_ceiling_raises_the_owner + -> ok + req KRN-SYNC-005 KRN-SYNC-006 +CASE mutex_ceiling_raises_the_owner outcome=passed asserts=7 skips=0 +TEST mutex_ceiling_violation_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_is_misuse outcome=passed asserts=3 skips=0 +TEST mutex_ceiling_violation_when_owned + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_when_owned outcome=passed asserts=5 skips=0 +TEST mutex_owner_death_policy + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-011 +CASE mutex_owner_death_policy outcome=passed asserts=3 skips=0 +TEST mutex_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 +CASE mutex_destroy_rules outcome=passed asserts=15 skips=0 +TEST mutex_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE mutex_storage_reuse_requires_destroy outcome=passed asserts=12 skips=0 +TEST mutex_waiter_priority_change_reorders_and_propagates + -> ok + req KRN-WAIT-003 KRN-SYNC-018 +CASE mutex_waiter_priority_change_reorders_and_propagates outcome=passed asserts=20 skips=0 +TEST mutex_init_validates_arguments + fault checks that reset the board: 3 + -> ok + req API-015 +CASE mutex_init_validates_arguments outcome=passed asserts=3 skips=0 +TEST mutex_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE mutex_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=176 +15 tests, 0 failed, 0 skipped, 26 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.json new file mode 100644 index 00000000..ad5ad001 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.json @@ -0,0 +1,107 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "notify_bits_are_level_sensitive", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "notify_any_and_all_modes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wake_from_thread_hands_off_bits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "notify_wake_from_isr", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wait_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "notify_rejects_kernel_bits_and_terminated_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "notify_semaphore_binding_signals_ready_transition", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "notify_unbind_stops_signals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "notify_bound_target_cannot_be_destroyed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "notify_bind_refuses_a_terminated_target", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:33Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_notify" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_notify.elf verify reset exit" + ], + "flashed_sha256": { + "test_notify.elf": "8e196bb9e6b9982c21f470a684f916649f597a9ccaf14317675a23f4421fd9d8" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_notify.elf", + "image_sha256": "8e196bb9e6b9982c21f470a684f916649f597a9ccaf14317675a23f4421fd9d8", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:31Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.log new file mode 100644 index 00000000..1f8d0086 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_notify.log @@ -0,0 +1,47 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_notify.elf sha256 8e196bb9e6b9982c21f470a684f916649f597a9ccaf14317675a23f4421fd9d8 +EVIDENCE v1 suite=test_notify config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST notify_bits_are_level_sensitive + -> ok + req KRN-NOTIF-001 KRN-NOTIF-002 +CASE notify_bits_are_level_sensitive outcome=passed asserts=7 skips=0 +TEST notify_any_and_all_modes + -> ok + req KRN-NOTIF-001 +CASE notify_any_and_all_modes outcome=passed asserts=12 skips=0 +TEST notify_wake_from_thread_hands_off_bits + -> ok + req KRN-NOTIF-003 KRN-WAIT-012 +CASE notify_wake_from_thread_hands_off_bits outcome=passed asserts=5 skips=0 +TEST notify_wake_from_isr + -> ok + req KRN-NOTIF-002 KRN-IRQ-010 +CASE notify_wake_from_isr outcome=passed asserts=3 skips=0 +TEST notify_wait_times_out + -> ok + req KRN-NOTIF-001 KRN-WAIT-004 +CASE notify_wait_times_out outcome=passed asserts=5 skips=0 +TEST notify_rejects_kernel_bits_and_terminated_targets + fault checks that reset the board: 3 + -> ok + req KRN-NOTIF-002 KRN-NOTIF-006 +CASE notify_rejects_kernel_bits_and_terminated_targets outcome=passed asserts=6 skips=0 +TEST notify_semaphore_binding_signals_ready_transition + -> ok + req KRN-NOTIF-004 KRN-NOTIF-005 +CASE notify_semaphore_binding_signals_ready_transition outcome=passed asserts=10 skips=0 +TEST notify_unbind_stops_signals + -> ok + req KRN-NOTIF-009 KRN-NOTIF-013 +CASE notify_unbind_stops_signals outcome=passed asserts=14 skips=0 +TEST notify_bound_target_cannot_be_destroyed + fault checks that reset the board: 1 + -> ok + req KRN-NOTIF-014 KRN-NOTIF-009 +CASE notify_bound_target_cannot_be_destroyed outcome=passed asserts=11 skips=0 +TEST notify_bind_refuses_a_terminated_target + -> ok + req KRN-NOTIF-014 +CASE notify_bind_refuses_a_terminated_target outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +10 tests, 0 failed, 0 skipped, 29 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.json new file mode 100644 index 00000000..bac24355 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "rtc_get_set_and_not_set", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_once_and_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_canceled_and_set_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "rtc_backup_and_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "rtc_seeds_the_wall_clock", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:11Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_rtc" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_rtc.elf verify reset exit" + ], + "flashed_sha256": { + "test_rtc.elf": "b89382516ea92142bb3f9b68da8d7e8117c962309f7db319d0e2a3942a52d4d4" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc.elf", + "image_sha256": "b89382516ea92142bb3f9b68da8d7e8117c962309f7db319d0e2a3942a52d4d4", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:09Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.log new file mode 100644 index 00000000..064f707c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc.log @@ -0,0 +1,26 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc.elf sha256 b89382516ea92142bb3f9b68da8d7e8117c962309f7db319d0e2a3942a52d4d4 +EVIDENCE v1 suite=test_rtc config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST rtc_get_set_and_not_set + -> ok + req DRV-001 +CASE rtc_get_set_and_not_set outcome=passed asserts=7 skips=0 +TEST rtc_alarm_once_and_again + -> ok + req DRV-001 +CASE rtc_alarm_once_and_again outcome=passed asserts=10 skips=0 +TEST rtc_alarm_canceled_and_set_disarms + -> ok + req DRV-001 +CASE rtc_alarm_canceled_and_set_disarms outcome=passed asserts=10 skips=0 +TEST rtc_backup_and_misuse + fault checks that reset the board: 3 + -> ok + req DRV-001 +CASE rtc_backup_and_misuse outcome=passed asserts=8 skips=0 +TEST rtc_seeds_the_wall_clock + -> ok + req KRN-TIM-031 +CASE rtc_seeds_the_wall_clock outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=176 +5 tests, 0 failed, 0 skipped, 23 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.json new file mode 100644 index 00000000..af5a443f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.json @@ -0,0 +1,71 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 9, + "name": "rtc_board_set_read_and_keep_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 42, + "name": "rtc_board_alarm_on_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "rtc_board_backup_registers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "rtc_board_keeps_its_time_across_a_reset", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:16Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_rtc_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_rtc_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_rtc_board.elf": "4e0bafeca974de1d68bc97c663a84eddadd4cd086e4f2a4925d9eea42e80bad6" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc_board.elf", + "image_sha256": "4e0bafeca974de1d68bc97c663a84eddadd4cd086e4f2a4925d9eea42e80bad6", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:11Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.log new file mode 100644 index 00000000..4ec1fd65 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_rtc_board.log @@ -0,0 +1,22 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc_board.elf sha256 4e0bafeca974de1d68bc97c663a84eddadd4cd086e4f2a4925d9eea42e80bad6 +EVIDENCE v1 suite=test_rtc_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST rtc_board_set_read_and_keep_time + set and get took 25 ms; the RTC read 23 ms past the time set over 2005 ms of the kernel's clock the RTC moved 2003 ms -> ok + req DRV-001 +CASE rtc_board_set_read_and_keep_time outcome=passed asserts=9 skips=0 +TEST rtc_board_alarm_on_time + an alarm 300 ms ahead fired after 299 ms -> ok + req DRV-001 +CASE rtc_board_alarm_on_time outcome=passed asserts=42 skips=0 +TEST rtc_board_backup_registers + -> ok + req DRV-001 +CASE rtc_board_backup_registers outcome=passed asserts=4 skips=0 +TEST rtc_board_keeps_its_time_across_a_reset + after the reset the RTC read 27 ms past the time set fault checks that reset the board: 1 + -> ok + req DRV-001 KRN-TIM-031 +CASE rtc_board_keeps_its_time_across_a_reset outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=176 +4 tests, 0 failed, 0 skipped, 20 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.json new file mode 100644 index 00000000..bb35f2f2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "sched_higher_priority_runs_first", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_lock_defers_preemption_until_unlock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "sched_yield_never_to_lower_priority", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sched_fifo_within_level_and_yield_rotates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "sched_preempted_thread_goes_ahead_of_its_peers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "sched_blocking_under_scheduler_lock_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sched_idle_runs_when_nothing_is_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_thread_self_and_priorities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sched_raising_a_ready_thread_above_the_caller_preempts", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:14Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_sched" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_sched.elf verify reset exit" + ], + "flashed_sha256": { + "test_sched.elf": "9361736815227f4c669a45ce18b47c07a29804b093fb89be9827c3e5740582a9" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sched.elf", + "image_sha256": "9361736815227f4c669a45ce18b47c07a29804b093fb89be9827c3e5740582a9", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:12Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.log new file mode 100644 index 00000000..fd7b2dbe --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sched.log @@ -0,0 +1,42 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_sched.elf sha256 9361736815227f4c669a45ce18b47c07a29804b093fb89be9827c3e5740582a9 +EVIDENCE v1 suite=test_sched config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST sched_higher_priority_runs_first + -> ok + req KRN-SCH-001 KRN-SCH-002 +CASE sched_higher_priority_runs_first outcome=passed asserts=3 skips=0 +TEST sched_lock_defers_preemption_until_unlock + -> ok + req KRN-SCH-016 KRN-SCH-017 KRN-SCH-018 +CASE sched_lock_defers_preemption_until_unlock outcome=passed asserts=4 skips=0 +TEST sched_yield_never_to_lower_priority + -> ok + req KRN-SCH-008 +CASE sched_yield_never_to_lower_priority outcome=passed asserts=3 skips=0 +TEST sched_fifo_within_level_and_yield_rotates + -> ok + req KRN-SCH-003 KRN-SCH-008 +CASE sched_fifo_within_level_and_yield_rotates outcome=passed asserts=5 skips=0 +TEST sched_preempted_thread_goes_ahead_of_its_peers + -> ok + req KRN-SCH-041 KRN-IRQ-013 +CASE sched_preempted_thread_goes_ahead_of_its_peers outcome=passed asserts=8 skips=0 +TEST sched_blocking_under_scheduler_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SCH-019 API-013 +CASE sched_blocking_under_scheduler_lock_is_misuse outcome=passed asserts=1 skips=0 +TEST sched_idle_runs_when_nothing_is_ready + -> ok + req KRN-SCH-043 SIM-005 +CASE sched_idle_runs_when_nothing_is_ready outcome=passed asserts=2 skips=0 +TEST sched_thread_self_and_priorities + -> ok + req KRN-THR-002 KRN-SCH-009 +CASE sched_thread_self_and_priorities outcome=passed asserts=4 skips=0 +TEST sched_raising_a_ready_thread_above_the_caller_preempts + -> ok + req KRN-THR-022 KRN-SYNC-032 +CASE sched_raising_a_ready_thread_above_the_caller_preempts outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +9 tests, 0 failed, 0 skipped, 61 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.json new file mode 100644 index 00000000..d5262679 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.json @@ -0,0 +1,119 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 8, + "name": "sem_counts_and_nowait", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_give_hands_off_to_highest_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_fifo_option_orders_by_arrival", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_take_times_out_and_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sem_give_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_max_overflow_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sem_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sem_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "sem_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sem_blocking_take_from_prekernel_or_isr_rejected", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sem_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:35Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_sem" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_sem.elf verify reset exit" + ], + "flashed_sha256": { + "test_sem.elf": "0c9102288ce058a29bf044aec23b8ec1139ad6bc76a153f5686f059f8804c000" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sem.elf", + "image_sha256": "0c9102288ce058a29bf044aec23b8ec1139ad6bc76a153f5686f059f8804c000", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:33Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.log new file mode 100644 index 00000000..6d958148 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_sem.log @@ -0,0 +1,56 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_sem.elf sha256 0c9102288ce058a29bf044aec23b8ec1139ad6bc76a153f5686f059f8804c000 +EVIDENCE v1 suite=test_sem config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST sem_counts_and_nowait + -> ok + req KRN-SYNC-020 KRN-SYNC-021 +CASE sem_counts_and_nowait outcome=passed asserts=8 skips=0 +TEST sem_give_hands_off_to_highest_waiter + -> ok + req KRN-WAIT-001 KRN-WAIT-012 KRN-SYNC-022 +CASE sem_give_hands_off_to_highest_waiter outcome=passed asserts=13 skips=0 +TEST sem_fifo_option_orders_by_arrival + -> ok + req KRN-WAIT-002 +CASE sem_fifo_option_orders_by_arrival outcome=passed asserts=9 skips=0 +TEST sem_take_times_out_and_disarms + -> ok + req KRN-WAIT-004 KRN-WAIT-013 +CASE sem_take_times_out_and_disarms outcome=passed asserts=9 skips=0 +TEST sem_give_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-022 KRN-IRQ-010 KRN-IRQ-033 +CASE sem_give_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST sem_max_overflow_and_saturate + -> ok + req KRN-SYNC-020 +CASE sem_max_overflow_and_saturate outcome=passed asserts=13 skips=0 +TEST sem_init_validates_arguments + fault checks that reset the board: 2 + -> ok + req API-015 +CASE sem_init_validates_arguments outcome=passed asserts=2 skips=0 +TEST sem_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE sem_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST sem_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE sem_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST sem_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE sem_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST sem_blocking_take_from_prekernel_or_isr_rejected + -> ok + req API-012 API-013 +CASE sem_blocking_take_from_prekernel_or_isr_rejected outcome=passed asserts=4 skips=0 +TEST sem_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE sem_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +12 tests, 0 failed, 0 skipped, 43 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.json new file mode 100644 index 00000000..b2ae2aa6 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "smoke_thread_runs_and_exits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "smoke_sleep_advances_virtual_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "smoke_libc_errno_from_a_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:10Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_smoke" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_smoke.elf verify reset exit" + ], + "flashed_sha256": { + "test_smoke.elf": "6b4317cc982acd490058ab897089cdefc50961773405303c4ec07514225c7a61" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_smoke.elf", + "image_sha256": "6b4317cc982acd490058ab897089cdefc50961773405303c4ec07514225c7a61", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:08Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.log new file mode 100644 index 00000000..9c08432d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_smoke.log @@ -0,0 +1,17 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_smoke.elf sha256 6b4317cc982acd490058ab897089cdefc50961773405303c4ec07514225c7a61 +EVIDENCE v1 suite=test_smoke config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST smoke_thread_runs_and_exits + -> ok + req KRN-THR-001 KRN-THR-005 KRN-THR-017 +CASE smoke_thread_runs_and_exits outcome=passed asserts=5 skips=0 +TEST smoke_sleep_advances_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 +CASE smoke_sleep_advances_virtual_time outcome=passed asserts=2 skips=0 +TEST smoke_libc_errno_from_a_thread + -> ok + req PORT-015 +CASE smoke_libc_errno_from_a_thread outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=176 +3 tests, 0 failed, 0 skipped, 57 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.json new file mode 100644 index 00000000..4f1173e3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "spi_transfer_loops_back", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_without_buffers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_transfers_run_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_unsupported_and_stopped", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "spi_chip_select_around_each_transfer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "spi_held_bus_keeps_the_chip_select", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_held_bus_refuses_another_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "spi_other_threads_wait_for_a_held_bus", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:46Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_spi" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_spi.elf verify reset exit" + ], + "flashed_sha256": { + "test_spi.elf": "94e535c1e194e459a68161a207bda8b5820fc764352fc2ccf90986e07eacbb3c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi.elf", + "image_sha256": "94e535c1e194e459a68161a207bda8b5820fc764352fc2ccf90986e07eacbb3c", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:43Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.log new file mode 100644 index 00000000..1d03b102 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi.log @@ -0,0 +1,42 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi.elf sha256 94e535c1e194e459a68161a207bda8b5820fc764352fc2ccf90986e07eacbb3c +EVIDENCE v1 suite=test_spi config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST spi_transfer_loops_back + -> ok + req DRV-004 DRV-005 +CASE spi_transfer_loops_back outcome=passed asserts=6 skips=0 +TEST spi_without_buffers + -> ok + req DRV-005 +CASE spi_without_buffers outcome=passed asserts=7 skips=0 +TEST spi_transfers_run_in_order + -> ok + req DRV-004 +CASE spi_transfers_run_in_order outcome=passed asserts=10 skips=0 +TEST spi_unsupported_and_stopped + -> ok + req DRV-006 +CASE spi_unsupported_and_stopped outcome=passed asserts=7 skips=0 +TEST spi_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE spi_misuse_faults outcome=passed asserts=7 skips=0 +TEST spi_chip_select_around_each_transfer + -> ok + req DRV-004 +CASE spi_chip_select_around_each_transfer outcome=passed asserts=11 skips=0 +TEST spi_held_bus_keeps_the_chip_select + -> ok + req DRV-004 +CASE spi_held_bus_keeps_the_chip_select outcome=passed asserts=15 skips=0 +TEST spi_held_bus_refuses_another_target + -> ok + req DRV-004 +CASE spi_held_bus_refuses_another_target outcome=passed asserts=10 skips=0 +TEST spi_other_threads_wait_for_a_held_bus + -> ok + req DRV-004 +CASE spi_other_threads_wait_for_a_held_bus outcome=passed asserts=16 skips=0 +ISR_STACK size=2048 used=176 +9 tests, 0 failed, 0 skipped, 75 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.json new file mode 100644 index 00000000..247c3052 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 4, + "name": "spi_loop_frames_come_back_intact", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "spi_loop_every_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_slow_and_fast_clocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_refuses_a_clock_too_slow", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "spi_loop_timeout_stops_after_whole_frames", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "spi_loop_no_transmit_buffer_sends_ones", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 21, + "name": "spi_loop_chip_select_at_the_pin", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "spi_loop_runs_by_dma", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:48Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_spi_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_spi_loop.elf verify reset exit" + ], + "flashed_sha256": { + "test_spi_loop.elf": "2db90115dcead0d1ff441217e626bd476277fa77347b9f58b9f03c0d55ab4953" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi_loop.elf", + "image_sha256": "2db90115dcead0d1ff441217e626bd476277fa77347b9f58b9f03c0d55ab4953", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:46Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.log new file mode 100644 index 00000000..c7487496 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_spi_loop.log @@ -0,0 +1,37 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi_loop.elf sha256 2db90115dcead0d1ff441217e626bd476277fa77347b9f58b9f03c0d55ab4953 +EVIDENCE v1 suite=test_spi_loop config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST spi_loop_frames_come_back_intact + -> ok + req DRV-004 DRV-005 +CASE spi_loop_frames_come_back_intact outcome=passed asserts=4 skips=0 +TEST spi_loop_every_mode + -> ok + req DRV-004 +CASE spi_loop_every_mode outcome=passed asserts=8 skips=0 +TEST spi_loop_slow_and_fast_clocks + -> ok + req DRV-004 +CASE spi_loop_slow_and_fast_clocks outcome=passed asserts=4 skips=0 +TEST spi_loop_refuses_a_clock_too_slow + -> ok + req DRV-006 +CASE spi_loop_refuses_a_clock_too_slow outcome=passed asserts=4 skips=0 +TEST spi_loop_timeout_stops_after_whole_frames + -> ok + req DRV-006 +CASE spi_loop_timeout_stops_after_whole_frames outcome=passed asserts=5 skips=0 +TEST spi_loop_no_transmit_buffer_sends_ones + -> ok + req DRV-005 +CASE spi_loop_no_transmit_buffer_sends_ones outcome=passed asserts=17 skips=0 +TEST spi_loop_chip_select_at_the_pin + -> ok + req DRV-004 +CASE spi_loop_chip_select_at_the_pin outcome=passed asserts=21 skips=0 +TEST spi_loop_runs_by_dma + -> ok + req DRV-004 DRV-006 +CASE spi_loop_runs_by_dma outcome=passed asserts=14 skips=0 +ISR_STACK size=2048 used=176 +8 tests, 0 failed, 0 skipped, 211 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.json new file mode 100644 index 00000000..25399ff3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.json @@ -0,0 +1,113 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "thread_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_start_twice_is_estate_and_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "thread_suspend_resume_are_idempotent_overlays", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_wake_while_suspended_is_applied_at_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_cancel_wakes_a_sleeping_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_cancel_pending_delivered_at_next_point", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_cancel_point_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_priority_change_requeues_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_state_reports_lifecycle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_define_registers_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "thread_stack_info_reports_size", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:22Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_thread" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_thread.elf verify reset exit" + ], + "flashed_sha256": { + "test_thread.elf": "e40c69531ab3f3ffd0ff166d9c3cd5e38afc2a58fada51b67b72242b4e9b57be" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread.elf", + "image_sha256": "e40c69531ab3f3ffd0ff166d9c3cd5e38afc2a58fada51b67b72242b4e9b57be", + "isr_stack": { + "size": 2048, + "used": 180 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:20Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.log new file mode 100644 index 00000000..8f789552 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread.log @@ -0,0 +1,52 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread.elf sha256 e40c69531ab3f3ffd0ff166d9c3cd5e38afc2a58fada51b67b72242b4e9b57be +EVIDENCE v1 suite=test_thread config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST thread_init_validates_arguments + fault checks that reset the board: 6 + -> ok + req KRN-THR-001 API-015 +CASE thread_init_validates_arguments outcome=passed asserts=6 skips=0 +TEST thread_start_twice_is_estate_and_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-THR-016 KRN-THR-022 KRN-OBJ-001 +CASE thread_start_twice_is_estate_and_destroy_rules outcome=passed asserts=13 skips=0 +TEST thread_suspend_resume_are_idempotent_overlays + -> ok + req KRN-THR-010 KRN-THR-019 +CASE thread_suspend_resume_are_idempotent_overlays outcome=passed asserts=18 skips=0 +TEST thread_wake_while_suspended_is_applied_at_resume + -> ok + req KRN-WAIT-016 KRN-THR-010 +CASE thread_wake_while_suspended_is_applied_at_resume outcome=passed asserts=12 skips=0 +TEST thread_cancel_wakes_a_sleeping_thread + -> ok + req KRN-THR-011 KRN-WAIT-017 +CASE thread_cancel_wakes_a_sleeping_thread outcome=passed asserts=6 skips=0 +TEST thread_cancel_pending_delivered_at_next_point + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_pending_delivered_at_next_point outcome=passed asserts=11 skips=0 +TEST thread_cancel_point_and_counts + fault checks that reset the board: 1 + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_point_and_counts outcome=passed asserts=5 skips=0 +TEST thread_priority_change_requeues_waiter + -> ok + req KRN-WAIT-003 KRN-SCH-009 KRN-SYNC-018 +CASE thread_priority_change_requeues_waiter outcome=passed asserts=13 skips=0 +TEST thread_state_reports_lifecycle + -> ok + req KRN-THR-021 +CASE thread_state_reports_lifecycle outcome=passed asserts=11 skips=0 +TEST thread_define_registers_in_init_table + -> ok + req KRN-THR-015 API-017 +CASE thread_define_registers_in_init_table outcome=passed asserts=5 skips=0 +TEST thread_stack_info_reports_size + -> ok + req KRN-MEM-009 +CASE thread_stack_info_reports_size outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=180 +11 tests, 0 failed, 0 skipped, 66 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.json new file mode 100644 index 00000000..4277c534 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 15, + "name": "thread_identity_survives_priority_and_termination", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1200, + "name": "thread_identity_repeated_construction_does_not_alias_live_object", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_identity_survives_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "thread_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "idle_context_is_not_an_application_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:27Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_thread_identity" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_thread_identity.elf verify reset exit" + ], + "flashed_sha256": { + "test_thread_identity.elf": "a77eb1b7c148fbb89a714da427f5600d823840e5cb95bb5b16128e6ba563db92" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_identity.elf", + "image_sha256": "a77eb1b7c148fbb89a714da427f5600d823840e5cb95bb5b16128e6ba563db92", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:25Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.log new file mode 100644 index 00000000..311f784a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_identity.log @@ -0,0 +1,28 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_identity.elf sha256 a77eb1b7c148fbb89a714da427f5600d823840e5cb95bb5b16128e6ba563db92 +EVIDENCE v1 suite=test_thread_identity config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST thread_identity_survives_priority_and_termination + fault checks that reset the board: 1 + -> ok + req KRN-THR-025 +CASE thread_identity_survives_priority_and_termination outcome=passed asserts=15 skips=0 +TEST thread_identity_repeated_construction_does_not_alias_live_object + -> ok + req KRN-THR-025 +CASE thread_identity_repeated_construction_does_not_alias_live_object outcome=passed asserts=1200 skips=0 +TEST thread_identity_survives_suspend_and_resume + -> ok + req KRN-THR-025 +CASE thread_identity_survives_suspend_and_resume outcome=passed asserts=12 skips=0 +TEST thread_storage_reuse_requires_destroy + fault checks that reset the board: 2 + -> ok + req KRN-THR-015 KRN-THR-023 +CASE thread_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST idle_context_is_not_an_application_thread + fault checks that reset the board: 2 + -> ok + req KRN-THR-025 KRN-THR-026 +CASE idle_context_is_not_an_application_thread outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +5 tests, 0 failed, 0 skipped, 16 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.json new file mode 100644 index 00000000..1b74b8dd --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.json @@ -0,0 +1,83 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 4, + "name": "thread_join_after_exit_returns_code", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_join_before_exit_blocks_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_timeout_then_success", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "thread_second_joiner_is_ebusy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_self_and_detached_are_errors", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_detach_after_exit_makes_reusable", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:25Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_thread_join" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_thread_join.elf verify reset exit" + ], + "flashed_sha256": { + "test_thread_join.elf": "cc2dd007187fc00caeb1dc8559e02f9541a9c020adfe6281afe40cfadca4e8bc" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_join.elf", + "image_sha256": "cc2dd007187fc00caeb1dc8559e02f9541a9c020adfe6281afe40cfadca4e8bc", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:23Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.log new file mode 100644 index 00000000..dfc9f4de --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_thread_join.log @@ -0,0 +1,31 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_join.elf sha256 cc2dd007187fc00caeb1dc8559e02f9541a9c020adfe6281afe40cfadca4e8bc +EVIDENCE v1 suite=test_thread_join config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST thread_join_after_exit_returns_code + -> ok + req KRN-THR-004 KRN-THR-006 KRN-THR-017 +CASE thread_join_after_exit_returns_code outcome=passed asserts=4 skips=0 +TEST thread_join_before_exit_blocks_and_hands_off + -> ok + req KRN-THR-017 KRN-WAIT-012 +CASE thread_join_before_exit_blocks_and_hands_off outcome=passed asserts=6 skips=0 +TEST thread_join_timeout_then_success + -> ok + req KRN-THR-017 KRN-WAIT-004 +CASE thread_join_timeout_then_success outcome=passed asserts=5 skips=0 +TEST thread_second_joiner_is_ebusy + -> ok + req KRN-THR-018 +CASE thread_second_joiner_is_ebusy outcome=passed asserts=10 skips=0 +TEST thread_join_self_and_detached_are_errors + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 +CASE thread_join_self_and_detached_are_errors outcome=passed asserts=5 skips=0 +TEST thread_detach_after_exit_makes_reusable + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 KRN-THR-022 +CASE thread_detach_after_exit_makes_reusable outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=176 +6 tests, 0 failed, 0 skipped, 15 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.json new file mode 100644 index 00000000..032b0638 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 4, + "name": "time_sleep_is_exact_in_virtual_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "time_sleep_until_does_not_drift", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "time_zero_sleep_and_past_deadline_yield", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "time_timeouts_expire_in_deadline_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "time_conversions_round_up_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_at_least_adds_one_tick", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_instant_helpers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 40, + "name": "time_now_is_monotonic_across_sleeps", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:29Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_time" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_time.elf verify reset exit" + ], + "flashed_sha256": { + "test_time.elf": "cd0a3f2480c19f4650d3566a541e960c0b84f6f3bb25064fa0251a883a72415b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_time.elf", + "image_sha256": "cd0a3f2480c19f4650d3566a541e960c0b84f6f3bb25064fa0251a883a72415b", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:27Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.log new file mode 100644 index 00000000..32665681 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_time.log @@ -0,0 +1,37 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_time.elf sha256 cd0a3f2480c19f4650d3566a541e960c0b84f6f3bb25064fa0251a883a72415b +EVIDENCE v1 suite=test_time config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST time_sleep_is_exact_in_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 API-023 +CASE time_sleep_is_exact_in_virtual_time outcome=passed asserts=4 skips=0 +TEST time_sleep_until_does_not_drift + -> ok + req KRN-TIM-011 +CASE time_sleep_until_does_not_drift outcome=passed asserts=20 skips=0 +TEST time_zero_sleep_and_past_deadline_yield + -> ok + req KRN-TIM-010 API-024 +CASE time_zero_sleep_and_past_deadline_yield outcome=passed asserts=3 skips=0 +TEST time_timeouts_expire_in_deadline_order + -> ok + req KRN-TIM-020 KRN-TIM-021 +CASE time_timeouts_expire_in_deadline_order outcome=passed asserts=14 skips=0 +TEST time_conversions_round_up_and_saturate + -> ok + req API-021 API-022 +CASE time_conversions_round_up_and_saturate outcome=passed asserts=12 skips=0 +TEST time_at_least_adds_one_tick + -> ok + req KRN-TIM-024 +CASE time_at_least_adds_one_tick outcome=passed asserts=6 skips=0 +TEST time_instant_helpers + -> ok + req API-021 +CASE time_instant_helpers outcome=passed asserts=6 skips=0 +TEST time_now_is_monotonic_across_sleeps + -> ok + req KRN-TIM-001 +CASE time_now_is_monotonic_across_sleeps outcome=passed asserts=40 skips=0 +ISR_STACK size=2048 used=176 +8 tests, 0 failed, 0 skipped, 195 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.json new file mode 100644 index 00000000..47f69a0d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 22, + "name": "timer_isr_context_one_shot_and_periodic_without_drift", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 22, + "name": "timer_restart_remaining_and_stop_states", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "timer_callback_runs_on_its_work_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_stop_sync_waits_for_a_running_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_expiries_during_a_long_callback_are_overruns", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "timer_init_needs_a_queue_or_isr_context", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "timer_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:50Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_timer" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_timer.elf verify reset exit" + ], + "flashed_sha256": { + "test_timer.elf": "e8df5611513d366ec3f24eb84d06a508b2fe71de5bb102d02266f39d7e5a13ce" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_timer.elf", + "image_sha256": "e8df5611513d366ec3f24eb84d06a508b2fe71de5bb102d02266f39d7e5a13ce", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:47Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.log new file mode 100644 index 00000000..74320db9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_timer.log @@ -0,0 +1,36 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_timer.elf sha256 e8df5611513d366ec3f24eb84d06a508b2fe71de5bb102d02266f39d7e5a13ce +EVIDENCE v1 suite=test_timer config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST timer_isr_context_one_shot_and_periodic_without_drift + -> ok + req KRN-TIM-025 KRN-TIM-005 KRN-TIM-014 KRN-TIM-015 +CASE timer_isr_context_one_shot_and_periodic_without_drift outcome=passed asserts=22 skips=0 +TEST timer_restart_remaining_and_stop_states + fault checks that reset the board: 2 + -> ok + req KRN-TIM-025 KRN-TIM-028 +CASE timer_restart_remaining_and_stop_states outcome=passed asserts=22 skips=0 +TEST timer_callback_runs_on_its_work_queue + fault checks that reset the board: 1 + -> ok + req KRN-TIM-013 KRN-TIM-005 KRN-TIM-026 +CASE timer_callback_runs_on_its_work_queue outcome=passed asserts=11 skips=0 +TEST timer_stop_sync_waits_for_a_running_callback + -> ok + req KRN-TIM-028 KRN-WAIT-012 +CASE timer_stop_sync_waits_for_a_running_callback outcome=passed asserts=13 skips=0 +TEST timer_expiries_during_a_long_callback_are_overruns + -> ok + req KRN-TIM-027 +CASE timer_expiries_during_a_long_callback_are_overruns outcome=passed asserts=13 skips=0 +TEST timer_init_needs_a_queue_or_isr_context + fault checks that reset the board: 2 + -> ok + req KRN-TIM-013 API-015 +CASE timer_init_needs_a_queue_or_isr_context outcome=passed asserts=3 skips=0 +TEST timer_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE timer_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=176 +7 tests, 0 failed, 0 skipped, 29 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.json new file mode 100644 index 00000000..48b957e7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 8, + "name": "uart_read_and_write_run_at_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_ring_keeps_bytes_no_read_waits_for", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "uart_idle_ends_a_read_early", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "uart_overrun_and_damaged_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_read_times_out_with_what_it_got", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_polled_calls_and_capabilities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_break_runs_after_the_writes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:59Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_uart" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_uart.elf verify reset exit" + ], + "flashed_sha256": { + "test_uart.elf": "dac55b7683e7ed28339c7b1d672a35abeea79a88e364a2b1e3eb90535356d8d5" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart.elf", + "image_sha256": "dac55b7683e7ed28339c7b1d672a35abeea79a88e364a2b1e3eb90535356d8d5", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:57Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.log new file mode 100644 index 00000000..dc9024fb --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart.log @@ -0,0 +1,38 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart.elf sha256 dac55b7683e7ed28339c7b1d672a35abeea79a88e364a2b1e3eb90535356d8d5 +EVIDENCE v1 suite=test_uart config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST uart_read_and_write_run_at_once + -> ok + req DRV-004 DRV-005 +CASE uart_read_and_write_run_at_once outcome=passed asserts=8 skips=0 +TEST uart_ring_keeps_bytes_no_read_waits_for + -> ok + req DRV-005 +CASE uart_ring_keeps_bytes_no_read_waits_for outcome=passed asserts=8 skips=0 +TEST uart_idle_ends_a_read_early + -> ok + req DRV-005 +CASE uart_idle_ends_a_read_early outcome=passed asserts=10 skips=0 +TEST uart_overrun_and_damaged_bytes + -> ok + req DRV-005 DRV-008 +CASE uart_overrun_and_damaged_bytes outcome=passed asserts=11 skips=0 +TEST uart_read_times_out_with_what_it_got + -> ok + req DRV-006 +CASE uart_read_times_out_with_what_it_got outcome=passed asserts=6 skips=0 +TEST uart_polled_calls_and_capabilities + -> ok + req DRV-007 +CASE uart_polled_calls_and_capabilities outcome=passed asserts=8 skips=0 +TEST uart_break_runs_after_the_writes + -> ok + req DRV-004 +CASE uart_break_runs_after_the_writes outcome=passed asserts=5 skips=0 +TEST uart_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE uart_misuse_faults outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=176 +8 tests, 0 failed, 0 skipped, 12 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_board.json new file mode 100644 index 00000000..150ffbfb --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_board.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "uart_console_writes_by_request", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "uart_console_read_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "uart_console_break_or_not_supported", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "uart_console_polled_write", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_console_writes_by_dma", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:01Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_uart_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_uart_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_uart_board.elf": "998f974d2c2f4f9b092cf829afa1718b3b027ece65c8970d8817dfc6de7fa75a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_board.elf", + "image_sha256": "998f974d2c2f4f9b092cf829afa1718b3b027ece65c8970d8817dfc6de7fa75a", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:59Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_board.log new file mode 100644 index 0000000000000000000000000000000000000000..0bca6744910cea9a4b619f938c649cf9be762d65 GIT binary patch literal 1165 zcmbVL%Wm5+5bRlBvA16Q5M@0BsDNv$Ku{zH+sKum$fYe<7FCjRk$!zC%W#rHZh>Az zVpqE}vz$Ft^#hcOX#q{gYgAN*VXSciMse8go)*D37uXaNXtgR4REv$`0;X~(n;T1S zl`}5)?nk99%mtq3yqk5VJSl;v1tI#PkUSQcNR~v*D_$Pg z#q+9wGXc|87V|&QfU8DU`<$^0~=IlxjJFqGGkCc|JByy5tw7un%o}|ppgk` ztCJJqsz*7*BiJ9y?g0mX0WMvOBUPF<%2Ly{y_-;c8f6fUFc`1D$HbZ9?g&~{*C>Xk zyglC#9A0shQ!>KoeW(9n^5!OSVh)u-T{UiRoMEnp8wi=+M(d~L1j5u^odajH*(l4g z$$db%NAt}ykJ}C1?v|_XV5(o32foAXoV{|A#9nk+YBK>JBy(HjcHO^>y6vxo5U>?L Q8n1ZzO8f1h#q-+x4Q{WBBLDyZ literal 0 HcmV?d00001 diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.json new file mode 100644 index 00000000..19d40a3e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.json @@ -0,0 +1,83 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "uart_loop_echo_full_duplex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_ring_keeps_what_arrives", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_loop_idle_line_ends_a_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_loop_a_kilobyte_intact", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_break_arrives_as_a_framing_error", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_overrun_is_reported", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:03Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_uart_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_uart_loop.elf verify reset exit" + ], + "flashed_sha256": { + "test_uart_loop.elf": "64e293a9e75ccd39a25dad79d97883ce97763365ff3c8b4c983273dbc8e04081" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_loop.elf", + "image_sha256": "64e293a9e75ccd39a25dad79d97883ce97763365ff3c8b4c983273dbc8e04081", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:01Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.log new file mode 100644 index 00000000..2240297c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_uart_loop.log @@ -0,0 +1,29 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart_loop.elf sha256 64e293a9e75ccd39a25dad79d97883ce97763365ff3c8b4c983273dbc8e04081 +EVIDENCE v1 suite=test_uart_loop config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST uart_loop_echo_full_duplex + -> ok + req DRV-004 DRV-005 +CASE uart_loop_echo_full_duplex outcome=passed asserts=7 skips=0 +TEST uart_loop_ring_keeps_what_arrives + -> ok + req DRV-005 +CASE uart_loop_ring_keeps_what_arrives outcome=passed asserts=4 skips=0 +TEST uart_loop_idle_line_ends_a_read + -> ok + req DRV-005 +CASE uart_loop_idle_line_ends_a_read outcome=passed asserts=5 skips=0 +TEST uart_loop_a_kilobyte_intact + -> ok + req DRV-004 DRV-005 +CASE uart_loop_a_kilobyte_intact outcome=passed asserts=6 skips=0 +TEST uart_loop_break_arrives_as_a_framing_error + -> ok + req DRV-004 DRV-008 +CASE uart_loop_break_arrives_as_a_framing_error outcome=passed asserts=4 skips=0 +TEST uart_loop_overrun_is_reported + -> ok + req DRV-005 DRV-008 +CASE uart_loop_overrun_is_reported outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=176 +6 tests, 0 failed, 0 skipped, 211 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.json new file mode 100644 index 00000000..adda5829 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 8, + "name": "wallclock_set_and_get", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "wallclock_adjust_moves_no_deadline", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:31Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wallclock" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_wallclock.elf verify reset exit" + ], + "flashed_sha256": { + "test_wallclock.elf": "2211c6a7f7dc50a8f1c83fc92a7c7e47e4bd68a72b4094c636a638164f13f41b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wallclock.elf", + "image_sha256": "2211c6a7f7dc50a8f1c83fc92a7c7e47e4bd68a72b4094c636a638164f13f41b", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:29Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.log new file mode 100644 index 00000000..aba4f4a3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wallclock.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wallclock.elf sha256 2211c6a7f7dc50a8f1c83fc92a7c7e47e4bd68a72b4094c636a638164f13f41b +EVIDENCE v1 suite=test_wallclock config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wallclock_set_and_get + fault checks that reset the board: 1 + -> ok + req KRN-TIM-031 +CASE wallclock_set_and_get outcome=passed asserts=8 skips=0 +TEST wallclock_adjust_moves_no_deadline + -> ok + req KRN-TIM-031 +CASE wallclock_adjust_moves_no_deadline outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=176 +2 tests, 0 failed, 0 skipped, 94 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.json new file mode 100644 index 00000000..e3bed7dc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 13, + "name": "wdog_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 122, + "name": "wdog_feeds_until_a_party_misses", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:33Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdog" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_wdog.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdog.elf": "c18067062465b924d306e8d465aee9383e03176d31eb6c21269b128742601ec3" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog.elf", + "image_sha256": "c18067062465b924d306e8d465aee9383e03176d31eb6c21269b128742601ec3", + "isr_stack": { + "size": 2048, + "used": 280 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:31Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.log new file mode 100644 index 00000000..6c44a859 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog.elf sha256 c18067062465b924d306e8d465aee9383e03176d31eb6c21269b128742601ec3 +EVIDENCE v1 suite=test_wdog config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdog_refusals + fault checks that reset the board: 4 + -> ok + req FLT-004 +CASE wdog_refusals outcome=passed asserts=13 skips=0 +TEST wdog_feeds_until_a_party_misses + -> ok + req FLT-004 +CASE wdog_feeds_until_a_party_misses outcome=passed asserts=122 skips=0 +ISR_STACK size=2048 used=280 +2 tests, 0 failed, 0 skipped, 472 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.json new file mode 100644 index 00000000..22cd63be --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 10, + "name": "wdog_board_hung_thread_resets_the_board", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:39Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdog_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_wdog_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdog_board.elf": "0e9ee9372b1fbf3773a49833d62f45b9f6489acb647e5bed0e907a5d146742cd" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog_board.elf", + "image_sha256": "0e9ee9372b1fbf3773a49833d62f45b9f6489acb647e5bed0e907a5d146742cd", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:36Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.log new file mode 100644 index 00000000..0fbc0be5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdog_board.log @@ -0,0 +1,10 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog_board.elf sha256 0e9ee9372b1fbf3773a49833d62f45b9f6489acb647e5bed0e907a5d146742cd +EVIDENCE v1 suite=test_wdog_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdog_board_hung_thread_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdog_board_hung_thread_resets_the_board outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=176 +1 tests, 0 failed, 0 skipped, 14 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.json new file mode 100644 index 00000000..f475bdcc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 13, + "name": "wdt_start_feed_and_cause", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "wdt_not_ready_and_misuse", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:31Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdt" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_wdt.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdt.elf": "a8538756991daafbef39b7c8fad59eeda0dcbcd8d3b633c0cac92a38082e8fe3" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt.elf", + "image_sha256": "a8538756991daafbef39b7c8fad59eeda0dcbcd8d3b633c0cac92a38082e8fe3", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:29Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.log new file mode 100644 index 00000000..f515dc18 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt.elf sha256 a8538756991daafbef39b7c8fad59eeda0dcbcd8d3b633c0cac92a38082e8fe3 +EVIDENCE v1 suite=test_wdt config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdt_start_feed_and_cause + -> ok + req FLT-004 +CASE wdt_start_feed_and_cause outcome=passed asserts=13 skips=0 +TEST wdt_not_ready_and_misuse + fault checks that reset the board: 3 + -> ok + req FLT-004 +CASE wdt_not_ready_and_misuse outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=176 +2 tests, 0 failed, 0 skipped, 13 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.json new file mode 100644 index 00000000..59a544e2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "wdt_board_refuses_what_it_cannot_count", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "wdt_board_starved_resets_the_board", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:28:36Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdt_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_wdt_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdt_board.elf": "161de1088c78d19e48cd141b620d0be508692b4013890d7e27775f0399ed986f" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt_board.elf", + "image_sha256": "161de1088c78d19e48cd141b620d0be508692b4013890d7e27775f0399ed986f", + "isr_stack": { + "size": 2048, + "used": 176 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:28:33Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.log new file mode 100644 index 00000000..a387729a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_wdt_board.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt_board.elf sha256 161de1088c78d19e48cd141b620d0be508692b4013890d7e27775f0399ed986f +EVIDENCE v1 suite=test_wdt_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdt_board_refuses_what_it_cannot_count + -> ok + req FLT-004 +CASE wdt_board_refuses_what_it_cannot_count outcome=passed asserts=3 skips=0 +TEST wdt_board_starved_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdt_board_starved_resets_the_board outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=176 +2 tests, 0 failed, 0 skipped, 14 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.json new file mode 100644 index 00000000..817b4de7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.json @@ -0,0 +1,143 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 9, + "name": "workq_runs_items_in_fifo_order_on_its_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_resubmit_while_running_runs_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "workq_item_belongs_to_one_queue_at_a_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "workq_cancel_reports_pending_running_and_idle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "workq_flush_waits_for_items_queued_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_submit_from_isr_runs_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_thread_is_a_kernel_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_destroy_refuses_a_busy_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_system_queue_runs_items", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_runs_after_its_delay_and_schedule_is_idempotent", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_reschedule_replaces_the_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "dwork_rescheduled_during_its_expiry_keeps_the_new_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 19, + "name": "dwork_cancel_reports_pending_for_a_delay_and_a_queued_item", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dwork_cancel_sync_waits_for_a_running_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "workq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:47Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_workq" + }, + "exit": 0, + "fault_checks_by_reset": 6, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-clang/tests/conformance/test_workq.elf verify reset exit" + ], + "flashed_sha256": { + "test_workq.elf": "90bfe9c70b255409b4de7d9e0625fdbc087e67f4371f459082a378fb24c9c975" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_workq.elf", + "image_sha256": "90bfe9c70b255409b4de7d9e0625fdbc087e67f4371f459082a378fb24c9c975", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:45Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.log new file mode 100644 index 00000000..9afbe41e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-clang/test_workq.log @@ -0,0 +1,73 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_workq.elf sha256 90bfe9c70b255409b4de7d9e0625fdbc087e67f4371f459082a378fb24c9c975 +EVIDENCE v1 suite=test_workq config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST workq_runs_items_in_fifo_order_on_its_thread + -> ok + req KRN-WQ-001 KRN-WQ-002 KRN-WQ-005 KRN-WQ-009 +CASE workq_runs_items_in_fifo_order_on_its_thread outcome=passed asserts=9 skips=0 +TEST workq_resubmit_while_running_runs_again + -> ok + req KRN-WQ-005 +CASE workq_resubmit_while_running_runs_again outcome=passed asserts=5 skips=0 +TEST workq_item_belongs_to_one_queue_at_a_time + -> ok + req KRN-WQ-005 +CASE workq_item_belongs_to_one_queue_at_a_time outcome=passed asserts=12 skips=0 +TEST workq_cancel_reports_pending_running_and_idle + -> ok + req KRN-WQ-004 KRN-WQ-006 +CASE workq_cancel_reports_pending_running_and_idle outcome=passed asserts=17 skips=0 +TEST workq_flush_waits_for_items_queued_before_it + -> ok + req KRN-WQ-006 KRN-WAIT-012 +CASE workq_flush_waits_for_items_queued_before_it outcome=passed asserts=9 skips=0 +TEST workq_submit_from_isr_runs_at_exit + -> ok + req KRN-WQ-001 KRN-IRQ-010 +CASE workq_submit_from_isr_runs_at_exit outcome=passed asserts=5 skips=0 +TEST workq_thread_is_a_kernel_thread + fault checks that reset the board: 2 + -> ok + req KRN-WQ-009 KRN-WQ-010 +CASE workq_thread_is_a_kernel_thread outcome=passed asserts=8 skips=0 +TEST workq_destroy_refuses_a_busy_queue + fault checks that reset the board: 2 + -> ok + req KRN-OBJ-001 KRN-WQ-010 API-013 +CASE workq_destroy_refuses_a_busy_queue outcome=passed asserts=8 skips=0 +TEST workq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE workq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST workq_system_queue_runs_items + -> ok + req KRN-WQ-008 +CASE workq_system_queue_runs_items outcome=passed asserts=3 skips=0 +TEST dwork_runs_after_its_delay_and_schedule_is_idempotent + -> ok + req KRN-WQ-003 KRN-WQ-007 +CASE dwork_runs_after_its_delay_and_schedule_is_idempotent outcome=passed asserts=7 skips=0 +TEST dwork_reschedule_replaces_the_delay + -> ok + req KRN-WQ-007 +CASE dwork_reschedule_replaces_the_delay outcome=passed asserts=7 skips=0 +TEST dwork_rescheduled_during_its_expiry_keeps_the_new_delay + -> ok + req KRN-WQ-007 KRN-TIM-024 +CASE dwork_rescheduled_during_its_expiry_keeps_the_new_delay outcome=passed asserts=9 skips=0 +TEST dwork_cancel_reports_pending_for_a_delay_and_a_queued_item + fault checks that reset the board: 1 + -> ok + req KRN-WQ-007 KRN-WQ-004 +CASE dwork_cancel_reports_pending_for_a_delay_and_a_queued_item outcome=passed asserts=19 skips=0 +TEST dwork_cancel_sync_waits_for_a_running_handler + -> ok + req KRN-WQ-007 KRN-WQ-006 +CASE dwork_cancel_sync_waits_for_a_running_handler outcome=passed asserts=10 skips=0 +TEST workq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE workq_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=228 +16 tests, 0 failed, 0 skipped, 53 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.json new file mode 100644 index 00000000..f6a72da5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.json @@ -0,0 +1,63 @@ +{ + "baud": 115200, + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 101439, + "unit_hz": 180000000, + "units": 20287984 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 93230, + "unit_hz": 180000000, + "units": 18646118 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 20949, + "unit_hz": 180000000, + "units": 2094981 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 209553, + "unit_hz": 180000000, + "units": 10477652 + } + ], + "board": "nucleo_f446re", + "cases": [], + "ended": "2026-11-13T05:27:08Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/benchmarks/bench_compare.elf verify reset exit" + ], + "flashed_sha256": { + "bench_compare.elf": "841e509f9ad815e6c868469414ccd484943267dd95fd0e1dcd903a6eb8e964b4" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_compare.elf", + "image_sha256": "841e509f9ad815e6c868469414ccd484943267dd95fd0e1dcd903a6eb8e964b4", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:06Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.log new file mode 100644 index 00000000..a561e8bd --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_compare.log @@ -0,0 +1,7 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image bench_compare.elf sha256 841e509f9ad815e6c868469414ccd484943267dd95fd0e1dcd903a6eb8e964b4 +bench_compare: EmbLinkRTOS 0.2.0 +BENCH v1 name=notify_handover units=20287984 ops=20000 per_op_x100=101439 unit_hz=180000000 os=emblink +BENCH v1 name=sem_handover units=18646118 ops=20000 per_op_x100=93230 unit_hz=180000000 os=emblink +BENCH v1 name=sem_give_take units=2094981 ops=10000 per_op_x100=20949 unit_hz=180000000 os=emblink +BENCH v1 name=isr_wake units=10477652 ops=5000 per_op_x100=209553 unit_hz=180000000 os=emblink +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.json new file mode 100644 index 00000000..4d7bad97 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.json @@ -0,0 +1,40 @@ +{ + "baud": 115200, + "bench": [ + { + "avg_x100": 17447, + "checked": 1, + "max": 601, + "min": 174, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 180000000 + } + ], + "board": "nucleo_f446re", + "cases": [], + "ended": "2026-11-13T05:27:06Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/benchmarks/bench_irq.elf verify reset exit" + ], + "flashed_sha256": { + "bench_irq.elf": "93e1a4617f7b8085537c7fbeb0958d786206c9d23f7dd918ac002baf4d1d039c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_irq.elf", + "image_sha256": "93e1a4617f7b8085537c7fbeb0958d786206c9d23f7dd918ac002baf4d1d039c", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:04Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.log new file mode 100644 index 00000000..5d307ae4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_irq.log @@ -0,0 +1,5 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image bench_irq.elf sha256 93e1a4617f7b8085537c7fbeb0958d786206c9d23f7dd918ac002baf4d1d039c +bench irq pend to handler: min 174 max 601 avg x100 17447 cycle-units over 1000 runs +BENCH v1 name=irq_pend_to_handler min=174 max=601 avg_x100=17447 ops=1000 unit_hz=180000000 checked=1 +meta: board nucleo_f446re, compiler gcc, profile base, checked 1, cycle unit hz 180000000 +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.json new file mode 100644 index 00000000..d7c47cca --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.json @@ -0,0 +1,39 @@ +{ + "baud": 115200, + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 98430, + "unit_hz": 180000000, + "units": 19686183 + } + ], + "board": "nucleo_f446re", + "cases": [], + "ended": "2026-11-13T05:27:04Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/benchmarks/bench_switch.elf verify reset exit" + ], + "flashed_sha256": { + "bench_switch.elf": "667999d069507853b3b659f55bcbc2909fdbc2488aafb077565700076b46d420" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_switch.elf", + "image_sha256": "667999d069507853b3b659f55bcbc2909fdbc2488aafb077565700076b46d420", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:03Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.log new file mode 100644 index 00000000..88215599 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/bench_switch.log @@ -0,0 +1,5 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image bench_switch.elf sha256 667999d069507853b3b659f55bcbc2909fdbc2488aafb077565700076b46d420 +bench notify round trip (2 switches): total 19686183 cycle-units over 20000 ops; per op x100 = 98430 +BENCH v1 name=notify_handover units=19686183 ops=20000 per_op_x100=98430 unit_hz=180000000 checked=1 +meta: board nucleo_f446re, compiler gcc, profile base, checked 1, cycle unit hz 180000000 +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/index.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/index.json new file mode 100644 index 00000000..7163547d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/index.json @@ -0,0 +1,942 @@ +{ + "board": "nucleo_f446re", + "build": "checked (GCC 14.2.1)", + "configuration": "aa8dd55373872741", + "date": "2026-11-13", + "format": "emb-hil-archive v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "images": [ + { + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 101439, + "unit_hz": 180000000, + "units": 20287984 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 93230, + "unit_hz": 180000000, + "units": 18646118 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 20949, + "unit_hz": 180000000, + "units": 2094981 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 209553, + "unit_hz": 180000000, + "units": 10477652 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_compare.elf": "841e509f9ad815e6c868469414ccd484943267dd95fd0e1dcd903a6eb8e964b4" + }, + "image": "bench_compare.elf", + "image_sha256": "841e509f9ad815e6c868469414ccd484943267dd95fd0e1dcd903a6eb8e964b4", + "isr_stack": null, + "log": "bench_compare.log", + "outcome": "passed", + "started": "2026-11-13T05:27:06Z" + }, + { + "bench": [ + { + "avg_x100": 17447, + "checked": 1, + "max": 601, + "min": 174, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 180000000 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_irq.elf": "93e1a4617f7b8085537c7fbeb0958d786206c9d23f7dd918ac002baf4d1d039c" + }, + "image": "bench_irq.elf", + "image_sha256": "93e1a4617f7b8085537c7fbeb0958d786206c9d23f7dd918ac002baf4d1d039c", + "isr_stack": null, + "log": "bench_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:27:04Z" + }, + { + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 98430, + "unit_hz": 180000000, + "units": 19686183 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_switch.elf": "667999d069507853b3b659f55bcbc2909fdbc2488aafb077565700076b46d420" + }, + "image": "bench_switch.elf", + "image_sha256": "667999d069507853b3b659f55bcbc2909fdbc2488aafb077565700076b46d420", + "isr_stack": null, + "log": "bench_switch.log", + "outcome": "passed", + "started": "2026-11-13T05:27:03Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_cond.elf": "41c51b7dfd92ca3723feaf83f4f01e8e93483c4285861c4e91d6144ee34af4d0" + }, + "image": "test_cond.elf", + "image_sha256": "41c51b7dfd92ca3723feaf83f4f01e8e93483c4285861c4e91d6144ee34af4d0", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_cond.log", + "outcome": "passed", + "started": "2026-11-13T05:25:48Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_crash.elf": "cfa5eaf0f5eb57667d4c63c858fc7a668032690b5353a888b1b66815a334eb12" + }, + "image": "test_crash.elf", + "image_sha256": "cfa5eaf0f5eb57667d4c63c858fc7a668032690b5353a888b1b66815a334eb12", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_crash.log", + "outcome": "passed", + "started": "2026-11-13T05:26:54Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_hw.elf": "1b2248b94a1a9fee43337fbd631a52e507fcfc8f73dac046db96b09a165b903d" + }, + "image": "test_crash_hw.elf", + "image_sha256": "1b2248b94a1a9fee43337fbd631a52e507fcfc8f73dac046db96b09a165b903d", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_crash_hw.log", + "outcome": "passed", + "started": "2026-11-13T05:26:57Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_reset.elf": "2b1cf897d420b06d76e8072c3576ad1ee535d8783c913a46e0efcbccd8508d78" + }, + "image": "test_crash_reset.elf", + "image_sha256": "2b1cf897d420b06d76e8072c3576ad1ee535d8783c913a46e0efcbccd8508d78", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_crash_reset.log", + "outcome": "passed", + "started": "2026-11-13T05:26:55Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_debug_descriptor.elf": "01a3864b5d7a8f2aea13ef0dc01240a1646a89a15a6be0d1c10a99e3216ebd7c" + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "01a3864b5d7a8f2aea13ef0dc01240a1646a89a15a6be0d1c10a99e3216ebd7c", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_debug_descriptor.log", + "outcome": "passed", + "started": "2026-11-13T05:26:59Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_device.elf": "d73ec6be61b3d28808d32cb412d25f80396e1f940e34bdd6dc8a845b2e86c7d6" + }, + "image": "test_device.elf", + "image_sha256": "d73ec6be61b3d28808d32cb412d25f80396e1f940e34bdd6dc8a845b2e86c7d6", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_device.log", + "outcome": "passed", + "started": "2026-11-13T05:26:02Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_dma.elf": "40e30b045163ebb96b759445f956685b6f6f3c921b7385575e73f8fae9dafdf9" + }, + "image": "test_dma.elf", + "image_sha256": "40e30b045163ebb96b759445f956685b6f6f3c921b7385575e73f8fae9dafdf9", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_dma.log", + "outcome": "passed", + "started": "2026-11-13T05:26:12Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_entropy.elf": "3a2bdeabc26bab22a6a7cf9d0561d01cbea27908c634593c6464d761c8ec4c87" + }, + "image": "test_entropy.elf", + "image_sha256": "3a2bdeabc26bab22a6a7cf9d0561d01cbea27908c634593c6464d761c8ec4c87", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_entropy.log", + "outcome": "passed", + "started": "2026-11-13T05:26:13Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_event.elf": "3c29b6ce688949fe75b0da2bc1624b184ad623ecf1e74bad62da2a0ae849efa3" + }, + "image": "test_event.elf", + "image_sha256": "3c29b6ce688949fe75b0da2bc1624b184ad623ecf1e74bad62da2a0ae849efa3", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_event.log", + "outcome": "passed", + "started": "2026-11-13T05:25:46Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_fault.elf": "15b176dfd92447ceb933a3c0f989191645d6cfa0d201abc6ab3e36a013e4893b" + }, + "image": "test_fault.elf", + "image_sha256": "15b176dfd92447ceb933a3c0f989191645d6cfa0d201abc6ab3e36a013e4893b", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_fault.log", + "outcome": "passed", + "started": "2026-11-13T05:25:20Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_first_execution.elf": "02515a8c8f5254e4ed43be4b14527b16f83a85591d14f7d631517bd49286298c" + }, + "image": "test_first_execution.elf", + "image_sha256": "02515a8c8f5254e4ed43be4b14527b16f83a85591d14f7d631517bd49286298c", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_first_execution.log", + "outcome": "passed", + "started": "2026-11-13T05:26:52Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_flash.elf": "8e2d171d7a29292d1101323fef70b0b3a6a1a80df86e9934ea0bdac16ab3c417" + }, + "image": "test_flash.elf", + "image_sha256": "8e2d171d7a29292d1101323fef70b0b3a6a1a80df86e9934ea0bdac16ab3c417", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_flash.log", + "outcome": "passed", + "started": "2026-11-13T05:26:22Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_flash_board.elf": "dad37ba8da2fe2f4259e4d1b91f1065f443f833ee3b18c1ef4c4c10d1b3f6414" + }, + "image": "test_flash_board.elf", + "image_sha256": "dad37ba8da2fe2f4259e4d1b91f1065f443f833ee3b18c1ef4c4c10d1b3f6414", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_flash_board.log", + "outcome": "passed", + "started": "2026-11-13T05:26:24Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_fpu.elf": "b6e422c3a1bec9c45df6a3efa2562b1e40d4e522adee47fa0ba28a57a9ac628a" + }, + "image": "test_fpu.elf", + "image_sha256": "b6e422c3a1bec9c45df6a3efa2562b1e40d4e522adee47fa0ba28a57a9ac628a", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_fpu.log", + "outcome": "passed", + "started": "2026-11-13T05:27:01Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_frame.elf": "6324d3d08e4faac8281827d2606a3d8487482b1fb6888cc6ed8d70463dcf9208" + }, + "image": "test_frame.elf", + "image_sha256": "6324d3d08e4faac8281827d2606a3d8487482b1fb6888cc6ed8d70463dcf9208", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_frame.log", + "outcome": "passed", + "started": "2026-11-13T05:25:57Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 10, + "flashed_sha256": { + "test_gpio.elf": "0f429a63e5a5e50b8156c3c229482103db06eeaf0313f8c34f69bd1bc2b99eb9" + }, + "image": "test_gpio.elf", + "image_sha256": "0f429a63e5a5e50b8156c3c229482103db06eeaf0313f8c34f69bd1bc2b99eb9", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_gpio.log", + "outcome": "passed", + "started": "2026-11-13T05:26:10Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 12, + "flashed_sha256": { + "test_i2c.elf": "0bfcd3ab407f01254b23c735975dbc0683432a0fb6f6e70caa6159d489edf71a" + }, + "image": "test_i2c.elf", + "image_sha256": "0bfcd3ab407f01254b23c735975dbc0683432a0fb6f6e70caa6159d489edf71a", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_i2c.log", + "outcome": "passed", + "started": "2026-11-13T05:26:42Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_i2c_loop.elf": "0a2fb114e8ec51f9439ebd5d1820490c2af5e6e023b5e2431474d41c93b4b7af" + }, + "image": "test_i2c_loop.elf", + "image_sha256": "0a2fb114e8ec51f9439ebd5d1820490c2af5e6e023b5e2431474d41c93b4b7af", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_i2c_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:26:45Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_irq.elf": "baed947899ca702e11ef282a59d6c8f73b2fb75d21c7c6b8077de57b98237eb3" + }, + "image": "test_irq.elf", + "image_sha256": "baed947899ca702e11ef282a59d6c8f73b2fb75d21c7c6b8077de57b98237eb3", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:25:23Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_irq_priority.elf": "90e3535e5575bb962b0f49b8add1cbfca76fe1806c68709f3dbe431c896f926e" + }, + "image": "test_irq_priority.elf", + "image_sha256": "90e3535e5575bb962b0f49b8add1cbfca76fe1806c68709f3dbe431c896f926e", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_irq_priority.log", + "outcome": "passed", + "started": "2026-11-13T05:25:25Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_isr_stack.elf": "d4c9b480c882bd6c4f00fa8e4ea25797e9a6a4dd4a009b12d5cc63c8e5f669e6" + }, + "image": "test_isr_stack.elf", + "image_sha256": "d4c9b480c882bd6c4f00fa8e4ea25797e9a6a4dd4a009b12d5cc63c8e5f669e6", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_isr_stack.log", + "outcome": "passed", + "started": "2026-11-13T05:25:27Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_log.elf": "6e3543f75cc8f66e9dba13ebbd15ac02170a44371a5383d5d804d2665e501717" + }, + "image": "test_log.elf", + "image_sha256": "6e3543f75cc8f66e9dba13ebbd15ac02170a44371a5383d5d804d2665e501717", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_log.log", + "outcome": "passed", + "started": "2026-11-13T05:25:59Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_msgq.elf": "3ff8db0959995742655238df58aac352b8b413c7ea446aaec594d75699641957" + }, + "image": "test_msgq.elf", + "image_sha256": "3ff8db0959995742655238df58aac352b8b413c7ea446aaec594d75699641957", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_msgq.log", + "outcome": "passed", + "started": "2026-11-13T05:25:50Z" + }, + { + "bench": [], + "cases": 15, + "cases_passed": 15, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_mutex.elf": "5d970aaf301ecbf58ceb9838ac5d12eea4e9328dee2d787b1e8be0a8622b4196" + }, + "image": "test_mutex.elf", + "image_sha256": "5d970aaf301ecbf58ceb9838ac5d12eea4e9328dee2d787b1e8be0a8622b4196", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_mutex.log", + "outcome": "passed", + "started": "2026-11-13T05:25:43Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_notify.elf": "f5aa93929573df3b18aed241103041c7839bfc8bcb61a1daa982c4e41e2f5283" + }, + "image": "test_notify.elf", + "image_sha256": "f5aa93929573df3b18aed241103041c7839bfc8bcb61a1daa982c4e41e2f5283", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_notify.log", + "outcome": "passed", + "started": "2026-11-13T05:25:39Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_rtc.elf": "f51c6c414a0284555a8a881f309f4c0770f69bac1f4d4f8a7dff55808eb1f4d7" + }, + "image": "test_rtc.elf", + "image_sha256": "f51c6c414a0284555a8a881f309f4c0770f69bac1f4d4f8a7dff55808eb1f4d7", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_rtc.log", + "outcome": "passed", + "started": "2026-11-13T05:26:15Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_rtc_board.elf": "5822c0beeed56a216cdbe52ac0b2dc78fc0b34dd8f62d218933a58c90ddbe603" + }, + "image": "test_rtc_board.elf", + "image_sha256": "5822c0beeed56a216cdbe52ac0b2dc78fc0b34dd8f62d218933a58c90ddbe603", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_rtc_board.log", + "outcome": "passed", + "started": "2026-11-13T05:26:17Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_sched.elf": "0871f0b6c578bd017837b3a8af16e787b9dfb62c981b18369b11f6fbf4fdfe10" + }, + "image": "test_sched.elf", + "image_sha256": "0871f0b6c578bd017837b3a8af16e787b9dfb62c981b18369b11f6fbf4fdfe10", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_sched.log", + "outcome": "passed", + "started": "2026-11-13T05:25:21Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_sem.elf": "34037f4d59bbbd8db4b2eb9cfb53c12d881b647f1511bb8ebdac0e60d3525128" + }, + "image": "test_sem.elf", + "image_sha256": "34037f4d59bbbd8db4b2eb9cfb53c12d881b647f1511bb8ebdac0e60d3525128", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_sem.log", + "outcome": "passed", + "started": "2026-11-13T05:25:41Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_smoke.elf": "905cdc4c52441e7479e51e598c3f5859dee562fd91e0af14bd5e5dbef3d8c79e" + }, + "image": "test_smoke.elf", + "image_sha256": "905cdc4c52441e7479e51e598c3f5859dee562fd91e0af14bd5e5dbef3d8c79e", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_smoke.log", + "outcome": "passed", + "started": "2026-11-13T05:25:18Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_spi.elf": "6f1b537820ad2474b8885e2478be2a5c9363ad99aa7395c0122204a8d9891959" + }, + "image": "test_spi.elf", + "image_sha256": "6f1b537820ad2474b8885e2478be2a5c9363ad99aa7395c0122204a8d9891959", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_spi.log", + "outcome": "passed", + "started": "2026-11-13T05:26:47Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_spi_loop.elf": "448d8b1570c80b605f3ee6b016ba7958725c90fb8a1d9889fe8ac7407ca1288b" + }, + "image": "test_spi_loop.elf", + "image_sha256": "448d8b1570c80b605f3ee6b016ba7958725c90fb8a1d9889fe8ac7407ca1288b", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_spi_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:26:49Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_thread.elf": "14ed1d72b9f7c88e9ede79348452586c03b5e3121163889180adccf6674b6e09" + }, + "image": "test_thread.elf", + "image_sha256": "14ed1d72b9f7c88e9ede79348452586c03b5e3121163889180adccf6674b6e09", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_thread.log", + "outcome": "passed", + "started": "2026-11-13T05:25:29Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_thread_identity.elf": "cadc6605cb7fd8f6b7dc223707787f921b9813841fce4a652ff2b0c5a40ca64a" + }, + "image": "test_thread_identity.elf", + "image_sha256": "cadc6605cb7fd8f6b7dc223707787f921b9813841fce4a652ff2b0c5a40ca64a", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_thread_identity.log", + "outcome": "passed", + "started": "2026-11-13T05:25:33Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_thread_join.elf": "f65124c909d95a7428f450fb5cd1cbad3b704310f5cd326460bba1364e42d9ca" + }, + "image": "test_thread_join.elf", + "image_sha256": "f65124c909d95a7428f450fb5cd1cbad3b704310f5cd326460bba1364e42d9ca", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_thread_join.log", + "outcome": "passed", + "started": "2026-11-13T05:25:31Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_time.elf": "8056268c5b641343ca02a09cf24903a46598305884ee6ff58d36df90f0a25239" + }, + "image": "test_time.elf", + "image_sha256": "8056268c5b641343ca02a09cf24903a46598305884ee6ff58d36df90f0a25239", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_time.log", + "outcome": "passed", + "started": "2026-11-13T05:25:35Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_timer.elf": "7924a4c2e1f381178144fa7507572fbf4d6024363d7c069f004a7150695da560" + }, + "image": "test_timer.elf", + "image_sha256": "7924a4c2e1f381178144fa7507572fbf4d6024363d7c069f004a7150695da560", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_timer.log", + "outcome": "passed", + "started": "2026-11-13T05:25:55Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_uart.elf": "afbdded14f9115ae91ec578229f7d4f3600b7ab61283145569ef05555a5e3936" + }, + "image": "test_uart.elf", + "image_sha256": "afbdded14f9115ae91ec578229f7d4f3600b7ab61283145569ef05555a5e3936", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_uart.log", + "outcome": "passed", + "started": "2026-11-13T05:26:04Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_board.elf": "1c876b1c018cd82d438334607f261cc41cdd217f6ce93d4c451be94040bea7a7" + }, + "image": "test_uart_board.elf", + "image_sha256": "1c876b1c018cd82d438334607f261cc41cdd217f6ce93d4c451be94040bea7a7", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_uart_board.log", + "outcome": "passed", + "started": "2026-11-13T05:26:06Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_loop.elf": "e1c065c0cf6f133e5bece1351cab690578a640cf136e7f4833ec99626e66af86" + }, + "image": "test_uart_loop.elf", + "image_sha256": "e1c065c0cf6f133e5bece1351cab690578a640cf136e7f4833ec99626e66af86", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_uart_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:26:08Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wallclock.elf": "49472c5284ca0516d3b5b6da38a8242fb0cce504c56cbe1c1af0e17c92452e26" + }, + "image": "test_wallclock.elf", + "image_sha256": "49472c5284ca0516d3b5b6da38a8242fb0cce504c56cbe1c1af0e17c92452e26", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_wallclock.log", + "outcome": "passed", + "started": "2026-11-13T05:25:37Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_wdog.elf": "aaa4416ba7ce0046a050b536ba129052ab749f52a3a2f0d0a573db23dc0afa25" + }, + "image": "test_wdog.elf", + "image_sha256": "aaa4416ba7ce0046a050b536ba129052ab749f52a3a2f0d0a573db23dc0afa25", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_wdog.log", + "outcome": "passed", + "started": "2026-11-13T05:26:35Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdog_board.elf": "010c0fd4ee6c5304a53ebdf4688d7cd2bf1ae074caa6ce719d850671005ee6ae" + }, + "image": "test_wdog_board.elf", + "image_sha256": "010c0fd4ee6c5304a53ebdf4688d7cd2bf1ae074caa6ce719d850671005ee6ae", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_wdog_board.log", + "outcome": "passed", + "started": "2026-11-13T05:26:40Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_wdt.elf": "b4a4a11eae5f9fb4c464f9f87aa0f0a1a732a2f277cc22ed0773805253fb5cf5" + }, + "image": "test_wdt.elf", + "image_sha256": "b4a4a11eae5f9fb4c464f9f87aa0f0a1a732a2f277cc22ed0773805253fb5cf5", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_wdt.log", + "outcome": "passed", + "started": "2026-11-13T05:26:34Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdt_board.elf": "cc2f53c3a26f1e79f54a7449dbea9697c1f365e34b153ff033bb20a37af74e96" + }, + "image": "test_wdt_board.elf", + "image_sha256": "cc2f53c3a26f1e79f54a7449dbea9697c1f365e34b153ff033bb20a37af74e96", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_wdt_board.log", + "outcome": "passed", + "started": "2026-11-13T05:26:38Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 6, + "flashed_sha256": { + "test_workq.elf": "4e245964d19f330fd470991208b91156b344975540f308eb7ae6ebc08f9137db" + }, + "image": "test_workq.elf", + "image_sha256": "4e245964d19f330fd470991208b91156b344975540f308eb7ae6ebc08f9137db", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "log": "test_workq.log", + "outcome": "passed", + "started": "2026-11-13T05:25:53Z" + } + ], + "isr_stack_max_used": 264, + "passed": 49, + "preset": "cm4-nucleo-hil", + "total": 49 +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.json new file mode 100644 index 00000000..7ea8b52f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.json @@ -0,0 +1,107 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 2, + "name": "cond_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "cond_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_wait_requires_single_ownership", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "cond_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "cond_destroy_aborts_waiters_which_relock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "cond_cancel_returns_with_the_mutex_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_relock_after_timeout_waits_for_the_mutex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "cond_signal_is_not_stored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "cond_broadcast_wakes_all_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "cond_signal_wakes_one_waiter_which_owns_the_mutex", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:50Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_cond" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_cond.elf verify reset exit" + ], + "flashed_sha256": { + "test_cond.elf": "41c51b7dfd92ca3723feaf83f4f01e8e93483c4285861c4e91d6144ee34af4d0" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_cond.elf", + "image_sha256": "41c51b7dfd92ca3723feaf83f4f01e8e93483c4285861c4e91d6144ee34af4d0", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:48Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.log new file mode 100644 index 00000000..9ae5a15f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_cond.log @@ -0,0 +1,48 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_cond.elf sha256 41c51b7dfd92ca3723feaf83f4f01e8e93483c4285861c4e91d6144ee34af4d0 +EVIDENCE v1 suite=test_cond config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST cond_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE cond_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +TEST cond_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE cond_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST cond_wait_requires_single_ownership + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-030 API-013 +CASE cond_wait_requires_single_ownership outcome=passed asserts=12 skips=0 +TEST cond_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE cond_destroy_with_waiters_is_misuse outcome=passed asserts=11 skips=0 +TEST cond_destroy_aborts_waiters_which_relock + -> ok + req KRN-OBJ-001 KRN-SYNC-030 +CASE cond_destroy_aborts_waiters_which_relock outcome=passed asserts=9 skips=0 +TEST cond_cancel_returns_with_the_mutex_owned + -> ok + req KRN-SYNC-030 KRN-WAIT-017 +CASE cond_cancel_returns_with_the_mutex_owned outcome=passed asserts=10 skips=0 +TEST cond_relock_after_timeout_waits_for_the_mutex + -> ok + req KRN-SYNC-030 +CASE cond_relock_after_timeout_waits_for_the_mutex outcome=passed asserts=12 skips=0 +TEST cond_signal_is_not_stored + -> ok + req KRN-SYNC-030 +CASE cond_signal_is_not_stored outcome=passed asserts=13 skips=0 +TEST cond_broadcast_wakes_all_in_priority_order + -> ok + req KRN-SYNC-030 KRN-WAIT-013 +CASE cond_broadcast_wakes_all_in_priority_order outcome=passed asserts=18 skips=0 +TEST cond_signal_wakes_one_waiter_which_owns_the_mutex + -> ok + req KRN-SYNC-030 KRN-WAIT-001 +CASE cond_signal_wakes_one_waiter_which_owns_the_mutex outcome=passed asserts=17 skips=0 +ISR_STACK size=2048 used=264 +10 tests, 0 failed, 0 skipped, 114 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.json new file mode 100644 index 00000000..1423cfc4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 1, + "name": "crash_record_get_refuses_null", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "crash_record_corruption_is_ignored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 38, + "name": "crash_record_round_trip", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:55Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_crash" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_crash.elf verify reset exit" + ], + "flashed_sha256": { + "test_crash.elf": "cfa5eaf0f5eb57667d4c63c858fc7a668032690b5353a888b1b66815a334eb12" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash.elf", + "image_sha256": "cfa5eaf0f5eb57667d4c63c858fc7a668032690b5353a888b1b66815a334eb12", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:54Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.log new file mode 100644 index 00000000..b6c55166 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash.log @@ -0,0 +1,19 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash.elf sha256 cfa5eaf0f5eb57667d4c63c858fc7a668032690b5353a888b1b66815a334eb12 +EVIDENCE v1 suite=test_crash config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_get_refuses_null + fault checks that reset the board: 1 + -> ok + req OBS-016 API-015 +CASE crash_record_get_refuses_null outcome=passed asserts=1 skips=0 +TEST crash_record_corruption_is_ignored + -> ok + req OBS-016 +CASE crash_record_corruption_is_ignored outcome=passed asserts=6 skips=0 +TEST crash_record_round_trip +EMB_CRASH 454d424301005c00b4e808273baf1d72d570e2a9ea527629838e7799302e322e300000001a0000000000000001000000050202012900000003000000341200007856000000000000bc7a00000000000000000000000000004eacd846 + -> ok + req OBS-016 API-017 +CASE crash_record_round_trip outcome=passed asserts=38 skips=0 +ISR_STACK size=2048 used=264 +3 tests, 0 failed, 0 skipped, 53 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.json new file mode 100644 index 00000000..ab6aac46 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 9, + "name": "crash_record_keeps_a_hardware_fault", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:59Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_crash_hw" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_crash_hw.elf verify reset exit" + ], + "flashed_sha256": { + "test_crash_hw.elf": "1b2248b94a1a9fee43337fbd631a52e507fcfc8f73dac046db96b09a165b903d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_hw.elf", + "image_sha256": "1b2248b94a1a9fee43337fbd631a52e507fcfc8f73dac046db96b09a165b903d", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:57Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.log new file mode 100644 index 00000000..ac40bb2d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_hw.log @@ -0,0 +1,13 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_hw.elf sha256 1b2248b94a1a9fee43337fbd631a52e507fcfc8f73dac046db96b09a165b903d +EVIDENCE v1 suite=test_crash_hw config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_keeps_a_hardware_fault +crash_record_keeps_a_hardware_fault: first boot, trapping +EVIDENCE v1 suite=test_crash_hw config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_keeps_a_hardware_fault +EMB_CRASH 454d424301008c00b4e808273baf1d72d570e2a9ea527629838e7799302e322e300000001100000000000000020000000a0006000000000000000000000001002a0200082b020008e0190020000000000000000004080000000001000000000034ed00e038ed00e09d0300080a0000000000008018080020000000002b0200082a0200080000006189df291d + -> ok + req OBS-016 KRN-IRQ-030 +CASE crash_record_keeps_a_hardware_fault outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=264 +1 tests, 0 failed, 0 skipped, 49 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.json new file mode 100644 index 00000000..1940f9a4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "crash_record_survives_reset", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:57Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_crash_reset" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_crash_reset.elf verify reset exit" + ], + "flashed_sha256": { + "test_crash_reset.elf": "2b1cf897d420b06d76e8072c3576ad1ee535d8783c913a46e0efcbccd8508d78" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_reset.elf", + "image_sha256": "2b1cf897d420b06d76e8072c3576ad1ee535d8783c913a46e0efcbccd8508d78", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:55Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.log new file mode 100644 index 00000000..eeb5e367 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_crash_reset.log @@ -0,0 +1,13 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_reset.elf sha256 2b1cf897d420b06d76e8072c3576ad1ee535d8783c913a46e0efcbccd8508d78 +EVIDENCE v1 suite=test_crash_reset config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_survives_reset +crash_record_survives_reset: first boot, faulting +EVIDENCE v1 suite=test_crash_reset config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST crash_record_survives_reset +EMB_CRASH 454d424301005c00b4e808273baf1d72d570e2a9ea527629838e7799302e322e300000000f00000000000000020000000b00ed5e000000000000000000000000430200080000000000000000000000000000000000000000ebc99ab7 + -> ok + req OBS-016 KRN-IRQ-030 ARCH-AVR-008 +CASE crash_record_survives_reset outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=264 +1 tests, 0 failed, 0 skipped, 40 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.json new file mode 100644 index 00000000..594152e7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.json @@ -0,0 +1,71 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 82, + "name": "debug_descriptor_reads_thread_states", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "debug_descriptor_isr_stack", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "debug_descriptor_finds_the_running_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "debug_descriptor_header", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:01Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_debug_descriptor" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_debug_descriptor.elf verify reset exit" + ], + "flashed_sha256": { + "test_debug_descriptor.elf": "01a3864b5d7a8f2aea13ef0dc01240a1646a89a15a6be0d1c10a99e3216ebd7c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "01a3864b5d7a8f2aea13ef0dc01240a1646a89a15a6be0d1c10a99e3216ebd7c", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:59Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.log new file mode 100644 index 00000000..1166c5ea --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_debug_descriptor.log @@ -0,0 +1,21 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_debug_descriptor.elf sha256 01a3864b5d7a8f2aea13ef0dc01240a1646a89a15a6be0d1c10a99e3216ebd7c +EVIDENCE v1 suite=test_debug_descriptor config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST debug_descriptor_reads_thread_states + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_reads_thread_states outcome=passed asserts=82 skips=0 +TEST debug_descriptor_isr_stack + -> ok + req PORT-012 +CASE debug_descriptor_isr_stack outcome=passed asserts=2 skips=0 +TEST debug_descriptor_finds_the_running_thread + -> ok + req OBS-008 +CASE debug_descriptor_finds_the_running_thread outcome=passed asserts=7 skips=0 +TEST debug_descriptor_header + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_header outcome=passed asserts=12 skips=0 +ISR_STACK size=2048 used=264 +4 tests, 0 failed, 0 skipped, 63 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.json new file mode 100644 index 00000000..bdf56816 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.json @@ -0,0 +1,143 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 47, + "name": "drv_status_codes_are_named_in_their_ranges", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "device_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "drv_setters_ignore_a_missing_request", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 23, + "name": "device_optional_operations", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 38, + "name": "device_board_devices_ready_in_dependency_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_wait_returns_the_result_or_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_cancel_queued_and_running_requests_complete_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_lanes_run_independently", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_queue_is_first_in_first_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "drv_completion_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "drv_request_completes_from_the_interrupt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "drv_submit_refused_unless_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "device_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "device_list_initializes_past_a_failure", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "device_on_a_failed_dependency_fails_without_its_driver", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "device_init_reaches_ready_or_failed", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:04Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_device" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_device.elf verify reset exit" + ], + "flashed_sha256": { + "test_device.elf": "d73ec6be61b3d28808d32cb412d25f80396e1f940e34bdd6dc8a845b2e86c7d6" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_device.elf", + "image_sha256": "d73ec6be61b3d28808d32cb412d25f80396e1f940e34bdd6dc8a845b2e86c7d6", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:02Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.log new file mode 100644 index 00000000..e858e2d0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_device.log @@ -0,0 +1,71 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_device.elf sha256 d73ec6be61b3d28808d32cb412d25f80396e1f940e34bdd6dc8a845b2e86c7d6 +EVIDENCE v1 suite=test_device config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST drv_status_codes_are_named_in_their_ranges + -> ok + req DRV-008 +CASE drv_status_codes_are_named_in_their_ranges outcome=passed asserts=47 skips=0 +TEST device_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-002 DRV-004 +CASE device_misuse_faults outcome=passed asserts=11 skips=0 +TEST drv_setters_ignore_a_missing_request + -> ok + req DRV-005 +CASE drv_setters_ignore_a_missing_request outcome=passed asserts=3 skips=0 +TEST device_optional_operations + -> ok + req DRV-002 DRV-006 PWR-002 +CASE device_optional_operations outcome=passed asserts=23 skips=0 +TEST device_board_devices_ready_in_dependency_order + -> ok + req DRV-001 DRV-002 +CASE device_board_devices_ready_in_dependency_order outcome=passed asserts=38 skips=0 +TEST drv_wait_returns_the_result_or_times_out + -> ok + req DRV-004 DRV-006 +CASE drv_wait_returns_the_result_or_times_out outcome=passed asserts=8 skips=0 +TEST drv_cancel_queued_and_running_requests_complete_once + -> ok + req DRV-006 +CASE drv_cancel_queued_and_running_requests_complete_once outcome=passed asserts=15 skips=0 +TEST drv_lanes_run_independently + fault checks that reset the board: 1 + -> ok + req DRV-004 DRV-006 +CASE drv_lanes_run_independently outcome=passed asserts=15 skips=0 +TEST drv_queue_is_first_in_first_out + -> ok + req DRV-004 +CASE drv_queue_is_first_in_first_out outcome=passed asserts=8 skips=0 +TEST drv_completion_targets + -> ok + req DRV-005 +CASE drv_completion_targets outcome=passed asserts=13 skips=0 +TEST drv_request_completes_from_the_interrupt + -> ok + req DRV-004 DRV-005 +CASE drv_request_completes_from_the_interrupt outcome=passed asserts=6 skips=0 +TEST drv_submit_refused_unless_ready + -> ok + req DRV-003 +CASE drv_submit_refused_unless_ready outcome=passed asserts=2 skips=0 +TEST device_suspend_and_resume + -> ok + req DRV-002 PWR-002 +CASE device_suspend_and_resume outcome=passed asserts=10 skips=0 +TEST device_list_initializes_past_a_failure + -> ok + req DRV-001 DRV-003 +CASE device_list_initializes_past_a_failure outcome=passed asserts=4 skips=0 +TEST device_on_a_failed_dependency_fails_without_its_driver + -> ok + req DRV-003 +CASE device_on_a_failed_dependency_fails_without_its_driver outcome=passed asserts=5 skips=0 +TEST device_init_reaches_ready_or_failed + -> ok + req DRV-002 DRV-003 +CASE device_init_reaches_ready_or_failed outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=264 +16 tests, 0 failed, 0 skipped, 111 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.json new file mode 100644 index 00000000..1ce1ff06 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.json @@ -0,0 +1,71 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 10, + "name": "dma_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "dma_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dma_stop_gives_what_moved", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dma_job_starts_and_ends", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:13Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_dma" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_dma.elf verify reset exit" + ], + "flashed_sha256": { + "test_dma.elf": "40e30b045163ebb96b759445f956685b6f6f3c921b7385575e73f8fae9dafdf9" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_dma.elf", + "image_sha256": "40e30b045163ebb96b759445f956685b6f6f3c921b7385575e73f8fae9dafdf9", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:12Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.log new file mode 100644 index 00000000..98fbd33c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_dma.log @@ -0,0 +1,22 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_dma.elf sha256 40e30b045163ebb96b759445f956685b6f6f3c921b7385575e73f8fae9dafdf9 +EVIDENCE v1 suite=test_dma config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST dma_misuse_faults + fault checks that reset the board: 8 + -> ok + req DRV-004 +CASE dma_misuse_faults outcome=passed asserts=10 skips=0 +TEST dma_refusals + -> ok + req DRV-004 +CASE dma_refusals outcome=passed asserts=5 skips=0 +TEST dma_stop_gives_what_moved + -> ok + req DRV-006 +CASE dma_stop_gives_what_moved outcome=passed asserts=7 skips=0 +TEST dma_job_starts_and_ends + -> ok + req DRV-004 +CASE dma_job_starts_and_ends outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=264 +4 tests, 0 failed, 0 skipped, 40 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.json new file mode 100644 index 00000000..013207c3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "entropy_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "entropy_board_source_or_its_absence", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "entropy_timeout_keeps_what_was_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "entropy_health_failure_delivers_none_of_its_block", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 54, + "name": "entropy_read_raw_assembles_blocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "entropy_read_conditions_twice_the_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "entropy_conditioning_is_sha256", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:15Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_entropy" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_entropy.elf verify reset exit" + ], + "flashed_sha256": { + "test_entropy.elf": "3a2bdeabc26bab22a6a7cf9d0561d01cbea27908c634593c6464d761c8ec4c87" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_entropy.elf", + "image_sha256": "3a2bdeabc26bab22a6a7cf9d0561d01cbea27908c634593c6464d761c8ec4c87", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:13Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.log new file mode 100644 index 00000000..fa48614f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_entropy.log @@ -0,0 +1,34 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_entropy.elf sha256 3a2bdeabc26bab22a6a7cf9d0561d01cbea27908c634593c6464d761c8ec4c87 +EVIDENCE v1 suite=test_entropy config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST entropy_misuse_faults + fault checks that reset the board: 4 + -> ok + req DRV-001 +CASE entropy_misuse_faults outcome=passed asserts=5 skips=0 +TEST entropy_board_source_or_its_absence + -> ok + req SEC-012 +CASE entropy_board_source_or_its_absence outcome=passed asserts=1 skips=0 +TEST entropy_timeout_keeps_what_was_read + -> ok + req DRV-001 +CASE entropy_timeout_keeps_what_was_read outcome=passed asserts=4 skips=0 +TEST entropy_health_failure_delivers_none_of_its_block + -> ok + req DRV-001 +CASE entropy_health_failure_delivers_none_of_its_block outcome=passed asserts=7 skips=0 +TEST entropy_read_raw_assembles_blocks + -> ok + req DRV-001 +CASE entropy_read_raw_assembles_blocks outcome=passed asserts=54 skips=0 +TEST entropy_read_conditions_twice_the_bytes + -> ok + req DRV-001 +CASE entropy_read_conditions_twice_the_bytes outcome=passed asserts=5 skips=0 +TEST entropy_conditioning_is_sha256 + -> ok + req DRV-001 +CASE entropy_conditioning_is_sha256 outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=264 +7 tests, 0 failed, 0 skipped, 95 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.json new file mode 100644 index 00000000..bf0cd02e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.json @@ -0,0 +1,113 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 1, + "name": "event_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "event_binding_fires_after_direct_waiters", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_wait_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "event_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "event_wait_times_out_cancels_and_ignores_clear", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "event_set_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_set_wakes_every_satisfied_waiter_in_one_pass", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_overlapping_clear_serves_waiters_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "event_any_all_and_clear", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:48Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_event" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_event.elf verify reset exit" + ], + "flashed_sha256": { + "test_event.elf": "3c29b6ce688949fe75b0da2bc1624b184ad623ecf1e74bad62da2a0ae849efa3" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_event.elf", + "image_sha256": "3c29b6ce688949fe75b0da2bc1624b184ad623ecf1e74bad62da2a0ae849efa3", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:46Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.log new file mode 100644 index 00000000..f402db8c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_event.log @@ -0,0 +1,52 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_event.elf sha256 3c29b6ce688949fe75b0da2bc1624b184ad623ecf1e74bad62da2a0ae849efa3 +EVIDENCE v1 suite=test_event config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST event_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE event_define_constructs_in_init_table outcome=passed asserts=1 skips=0 +TEST event_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE event_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST event_binding_fires_after_direct_waiters + -> ok + req KRN-SYNC-035 KRN-NOTIF-004 KRN-NOTIF-005 KRN-NOTIF-013 +CASE event_binding_fires_after_direct_waiters outcome=passed asserts=15 skips=0 +TEST event_wait_validates_arguments + fault checks that reset the board: 3 + -> ok + req KRN-SYNC-029 API-015 +CASE event_wait_validates_arguments outcome=passed asserts=5 skips=0 +TEST event_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE event_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST event_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE event_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST event_wait_times_out_cancels_and_ignores_clear + -> ok + req KRN-SYNC-029 KRN-WAIT-004 KRN-WAIT-017 +CASE event_wait_times_out_cancels_and_ignores_clear outcome=passed asserts=12 skips=0 +TEST event_set_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-029 KRN-SYNC-027 +CASE event_set_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST event_set_wakes_every_satisfied_waiter_in_one_pass + -> ok + req KRN-SYNC-029 KRN-WAIT-013 +CASE event_set_wakes_every_satisfied_waiter_in_one_pass outcome=passed asserts=11 skips=0 +TEST event_overlapping_clear_serves_waiters_in_order + -> ok + req KRN-SYNC-029 KRN-WAIT-001 +CASE event_overlapping_clear_serves_waiters_in_order outcome=passed asserts=11 skips=0 +TEST event_any_all_and_clear + -> ok + req KRN-SYNC-029 +CASE event_any_all_and_clear outcome=passed asserts=15 skips=0 +ISR_STACK size=2048 used=264 +11 tests, 0 failed, 0 skipped, 120 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.json new file mode 100644 index 00000000..d951cdc5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 2, + "name": "fault_status_policy_is_preserved", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "fault_successful_check_preserves_status", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:21Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_fault" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_fault.elf verify reset exit" + ], + "flashed_sha256": { + "test_fault.elf": "15b176dfd92447ceb933a3c0f989191645d6cfa0d201abc6ab3e36a013e4893b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fault.elf", + "image_sha256": "15b176dfd92447ceb933a3c0f989191645d6cfa0d201abc6ab3e36a013e4893b", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:20Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.log new file mode 100644 index 00000000..6f1c320d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fault.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_fault.elf sha256 15b176dfd92447ceb933a3c0f989191645d6cfa0d201abc6ab3e36a013e4893b +EVIDENCE v1 suite=test_fault config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST fault_status_policy_is_preserved + fault checks that reset the board: 2 + -> ok + req API-015 +CASE fault_status_policy_is_preserved outcome=passed asserts=2 skips=0 +TEST fault_successful_check_preserves_status + -> ok + req API-015 API-017 +CASE fault_successful_check_preserves_status outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=264 +2 tests, 0 failed, 0 skipped, 27 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.json new file mode 100644 index 00000000..f783277e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 80614, + "name": "first_execution_sequence_repeats_reliably", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:53Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_first_execution" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_first_execution.elf verify reset exit" + ], + "flashed_sha256": { + "test_first_execution.elf": "02515a8c8f5254e4ed43be4b14527b16f83a85591d14f7d631517bd49286298c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_first_execution.elf", + "image_sha256": "02515a8c8f5254e4ed43be4b14527b16f83a85591d14f7d631517bd49286298c", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:52Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.log new file mode 100644 index 00000000..621b7025 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_first_execution.log @@ -0,0 +1,10 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_first_execution.elf sha256 02515a8c8f5254e4ed43be4b14527b16f83a85591d14f7d631517bd49286298c +EVIDENCE v1 suite=test_first_execution config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST first_execution_sequence_repeats_reliably + ticks seen 401, elapsed 401, timer start +0, late 0 + -> ok + req KRN-SCH-001 KRN-SCH-004 KRN-IRQ-010 KRN-TIM-010 KRN-NOTIF-003 +CASE first_execution_sequence_repeats_reliably outcome=passed asserts=80614 skips=0 +ISR_STACK size=2048 used=264 +1 tests, 0 failed, 0 skipped, 434 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.json new file mode 100644 index 00000000..b8c18ebf --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.json @@ -0,0 +1,83 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "flash_polled_calls", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "flash_power_loss_tears_an_operation", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_area_stays_inside", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "flash_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_program_read_erase", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "flash_geometry_and_sectors", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:24Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_flash" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_flash.elf verify reset exit" + ], + "flashed_sha256": { + "test_flash.elf": "8e2d171d7a29292d1101323fef70b0b3a6a1a80df86e9934ea0bdac16ab3c417" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash.elf", + "image_sha256": "8e2d171d7a29292d1101323fef70b0b3a6a1a80df86e9934ea0bdac16ab3c417", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:22Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.log new file mode 100644 index 00000000..0fe52daa --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash.log @@ -0,0 +1,30 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash.elf sha256 8e2d171d7a29292d1101323fef70b0b3a6a1a80df86e9934ea0bdac16ab3c417 +EVIDENCE v1 suite=test_flash config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST flash_polled_calls + -> ok + req DRV-007 +CASE flash_polled_calls outcome=passed asserts=6 skips=0 +TEST flash_power_loss_tears_an_operation + -> ok + req DRV-001 +CASE flash_power_loss_tears_an_operation outcome=passed asserts=15 skips=0 +TEST flash_area_stays_inside + -> ok + req DRV-001 +CASE flash_area_stays_inside outcome=passed asserts=10 skips=0 +TEST flash_refusals + fault checks that reset the board: 4 + -> ok + req DRV-001 DRV-003 +CASE flash_refusals outcome=passed asserts=14 skips=0 +TEST flash_program_read_erase + -> ok + req DRV-001 DRV-003 +CASE flash_program_read_erase outcome=passed asserts=10 skips=0 +TEST flash_geometry_and_sectors + -> ok + req DRV-001 +CASE flash_geometry_and_sectors outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=264 +6 tests, 0 failed, 0 skipped, 35 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.json new file mode 100644 index 00000000..76e6e8df --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 4616, + "name": "flash_board_program_and_read_back", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 516, + "name": "flash_board_erase_keeps_the_clock", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:34Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_flash_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_flash_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_flash_board.elf": "dad37ba8da2fe2f4259e4d1b91f1065f443f833ee3b18c1ef4c4c10d1b3f6414" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash_board.elf", + "image_sha256": "dad37ba8da2fe2f4259e4d1b91f1065f443f833ee3b18c1ef4c4c10d1b3f6414", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:24Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.log new file mode 100644 index 00000000..f4551319 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_flash_board.log @@ -0,0 +1,13 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash_board.elf sha256 dad37ba8da2fe2f4259e4d1b91f1065f443f833ee3b18c1ef4c4c10d1b3f6414 +EVIDENCE v1 suite=test_flash_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST flash_board_program_and_read_back + -> ok + req DRV-001 DRV-003 +CASE flash_board_program_and_read_back outcome=passed asserts=4616 skips=0 +TEST flash_board_erase_keeps_the_clock + erase of 128 KiB: 898 ms by the cycles, 899 ms by the clock -> ok + req DRV-001 DRV-003 +CASE flash_board_erase_keeps_the_clock outcome=passed asserts=516 skips=0 +ISR_STACK size=2048 used=264 +2 tests, 0 failed, 0 skipped, 8240 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.json new file mode 100644 index 00000000..0e56d249 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "fpu_state_survives_preemption", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "fpu_callee_saved_registers_survive_a_switch", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:27:03Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_fpu" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_fpu.elf verify reset exit" + ], + "flashed_sha256": { + "test_fpu.elf": "b6e422c3a1bec9c45df6a3efa2562b1e40d4e522adee47fa0ba28a57a9ac628a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fpu.elf", + "image_sha256": "b6e422c3a1bec9c45df6a3efa2562b1e40d4e522adee47fa0ba28a57a9ac628a", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:27:01Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.log new file mode 100644 index 00000000..2a81ceb3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_fpu.log @@ -0,0 +1,11 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_fpu.elf sha256 b6e422c3a1bec9c45df6a3efa2562b1e40d4e522adee47fa0ba28a57a9ac628a +EVIDENCE v1 suite=test_fpu config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST fpu_state_survives_preemption + -> ok +CASE fpu_state_survives_preemption outcome=passed asserts=6 skips=0 +TEST fpu_callee_saved_registers_survive_a_switch + -> ok +CASE fpu_callee_saved_registers_survive_a_switch outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=264 +2 tests, 0 failed, 0 skipped, 41 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.json new file mode 100644 index 00000000..1fe481d8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "frame_write_misuse_is_refused", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 122, + "name": "frame_write_streams_the_encoders_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 383, + "name": "frame_random_stream_with_damage", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "frame_misuse_is_refused", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "frame_decoder_drops_an_overrun", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "frame_decoder_resynchronizes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "frame_round_trip_through_the_decoder", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 39, + "name": "frame_runs_at_the_cobs_boundary", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "frame_encoding_matches_the_host_tool", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:59Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_frame" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_frame.elf verify reset exit" + ], + "flashed_sha256": { + "test_frame.elf": "6324d3d08e4faac8281827d2606a3d8487482b1fb6888cc6ed8d70463dcf9208" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_frame.elf", + "image_sha256": "6324d3d08e4faac8281827d2606a3d8487482b1fb6888cc6ed8d70463dcf9208", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:57Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.log new file mode 100644 index 00000000..7263483d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_frame.log @@ -0,0 +1,41 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_frame.elf sha256 6324d3d08e4faac8281827d2606a3d8487482b1fb6888cc6ed8d70463dcf9208 +EVIDENCE v1 suite=test_frame config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST frame_write_misuse_is_refused + -> ok + req OBS-019 +CASE frame_write_misuse_is_refused outcome=passed asserts=5 skips=0 +TEST frame_write_streams_the_encoders_bytes + -> ok + req OBS-019 +CASE frame_write_streams_the_encoders_bytes outcome=passed asserts=122 skips=0 +TEST frame_random_stream_with_damage + -> ok + req OBS-019 +CASE frame_random_stream_with_damage outcome=passed asserts=383 skips=0 +TEST frame_misuse_is_refused + -> ok + req OBS-019 +CASE frame_misuse_is_refused outcome=passed asserts=8 skips=0 +TEST frame_decoder_drops_an_overrun + -> ok + req OBS-019 +CASE frame_decoder_drops_an_overrun outcome=passed asserts=6 skips=0 +TEST frame_decoder_resynchronizes + -> ok + req OBS-019 +CASE frame_decoder_resynchronizes outcome=passed asserts=17 skips=0 +TEST frame_round_trip_through_the_decoder + -> ok + req OBS-019 +CASE frame_round_trip_through_the_decoder outcome=passed asserts=12 skips=0 +TEST frame_runs_at_the_cobs_boundary + -> ok + req OBS-019 +CASE frame_runs_at_the_cobs_boundary outcome=passed asserts=39 skips=0 +TEST frame_encoding_matches_the_host_tool + -> ok + req OBS-019 +CASE frame_encoding_matches_the_host_tool outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=264 +9 tests, 0 failed, 0 skipped, 133 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.json new file mode 100644 index 00000000..15ecc754 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 11, + "name": "gpio_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "gpio_driver_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "gpio_named_line_follows_its_sense", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "gpio_input_reads_its_pull", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "gpio_output_drives_and_reads_back", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:11Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_gpio" + }, + "exit": 0, + "fault_checks_by_reset": 10, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_gpio.elf verify reset exit" + ], + "flashed_sha256": { + "test_gpio.elf": "0f429a63e5a5e50b8156c3c229482103db06eeaf0313f8c34f69bd1bc2b99eb9" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_gpio.elf", + "image_sha256": "0f429a63e5a5e50b8156c3c229482103db06eeaf0313f8c34f69bd1bc2b99eb9", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:10Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.log new file mode 100644 index 00000000..d9b8243b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_gpio.log @@ -0,0 +1,26 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_gpio.elf sha256 0f429a63e5a5e50b8156c3c229482103db06eeaf0313f8c34f69bd1bc2b99eb9 +EVIDENCE v1 suite=test_gpio config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST gpio_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-004 +CASE gpio_misuse_faults outcome=passed asserts=11 skips=0 +TEST gpio_driver_refusals + -> ok + req DRV-004 +CASE gpio_driver_refusals outcome=passed asserts=3 skips=0 +TEST gpio_named_line_follows_its_sense + -> ok + req DRV-004 +CASE gpio_named_line_follows_its_sense outcome=passed asserts=13 skips=0 +TEST gpio_input_reads_its_pull + -> ok + req DRV-004 +CASE gpio_input_reads_its_pull outcome=passed asserts=6 skips=0 +TEST gpio_output_drives_and_reads_back + -> ok + req DRV-004 +CASE gpio_output_drives_and_reads_back outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=264 +5 tests, 0 failed, 0 skipped, 55 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.json new file mode 100644 index 00000000..3a3666e2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "i2c_recover_waits_for_a_held_bus", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_recover_clocks_a_stuck_bus_free", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_held_bus_keeps_one_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "i2c_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "i2c_controller_and_target_at_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "i2c_target_answers_its_address", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "i2c_errors_and_timeout", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_segments_count_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "i2c_write_then_read_a_register", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:45Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_i2c" + }, + "exit": 0, + "fault_checks_by_reset": 12, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_i2c.elf verify reset exit" + ], + "flashed_sha256": { + "test_i2c.elf": "0bfcd3ab407f01254b23c735975dbc0683432a0fb6f6e70caa6159d489edf71a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c.elf", + "image_sha256": "0bfcd3ab407f01254b23c735975dbc0683432a0fb6f6e70caa6159d489edf71a", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:42Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.log new file mode 100644 index 00000000..955d4653 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c.log @@ -0,0 +1,42 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c.elf sha256 0bfcd3ab407f01254b23c735975dbc0683432a0fb6f6e70caa6159d489edf71a +EVIDENCE v1 suite=test_i2c config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST i2c_recover_waits_for_a_held_bus + -> ok + req DRV-006 +CASE i2c_recover_waits_for_a_held_bus outcome=passed asserts=5 skips=0 +TEST i2c_recover_clocks_a_stuck_bus_free + -> ok + req DRV-006 +CASE i2c_recover_clocks_a_stuck_bus_free outcome=passed asserts=11 skips=0 +TEST i2c_held_bus_keeps_one_target + -> ok + req DRV-004 +CASE i2c_held_bus_keeps_one_target outcome=passed asserts=11 skips=0 +TEST i2c_misuse_faults + fault checks that reset the board: 12 + -> ok + req DRV-004 +CASE i2c_misuse_faults outcome=passed asserts=13 skips=0 +TEST i2c_controller_and_target_at_once + -> ok + req DRV-004 +CASE i2c_controller_and_target_at_once outcome=passed asserts=9 skips=0 +TEST i2c_target_answers_its_address + -> ok + req DRV-004 DRV-005 +CASE i2c_target_answers_its_address outcome=passed asserts=10 skips=0 +TEST i2c_errors_and_timeout + -> ok + req DRV-006 +CASE i2c_errors_and_timeout outcome=passed asserts=7 skips=0 +TEST i2c_segments_count_bytes + -> ok + req DRV-005 +CASE i2c_segments_count_bytes outcome=passed asserts=6 skips=0 +TEST i2c_write_then_read_a_register + -> ok + req DRV-004 DRV-005 +CASE i2c_write_then_read_a_register outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=264 +9 tests, 0 failed, 0 skipped, 76 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.json new file mode 100644 index 00000000..5c49344c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 88, + "name": "i2c_loop_recovers_a_stuck_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "i2c_loop_listen_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "i2c_loop_fast_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_target_drops_beyond_its_buffer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_nobody_answers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 32, + "name": "i2c_loop_register_reads_of_every_length", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "i2c_loop_write_to_the_target", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:47Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_i2c_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_i2c_loop.elf verify reset exit" + ], + "flashed_sha256": { + "test_i2c_loop.elf": "0a2fb114e8ec51f9439ebd5d1820490c2af5e6e023b5e2431474d41c93b4b7af" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c_loop.elf", + "image_sha256": "0a2fb114e8ec51f9439ebd5d1820490c2af5e6e023b5e2431474d41c93b4b7af", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:45Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.log new file mode 100644 index 00000000..320ef638 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_i2c_loop.log @@ -0,0 +1,33 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c_loop.elf sha256 0a2fb114e8ec51f9439ebd5d1820490c2af5e6e023b5e2431474d41c93b4b7af +EVIDENCE v1 suite=test_i2c_loop config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST i2c_loop_recovers_a_stuck_target + -> ok + req DRV-006 +CASE i2c_loop_recovers_a_stuck_target outcome=passed asserts=88 skips=0 +TEST i2c_loop_listen_times_out + -> ok + req DRV-006 +CASE i2c_loop_listen_times_out outcome=passed asserts=2 skips=0 +TEST i2c_loop_fast_mode + -> ok + req DRV-004 +CASE i2c_loop_fast_mode outcome=passed asserts=5 skips=0 +TEST i2c_loop_target_drops_beyond_its_buffer + -> ok + req DRV-006 +CASE i2c_loop_target_drops_beyond_its_buffer outcome=passed asserts=6 skips=0 +TEST i2c_loop_nobody_answers + -> ok + req DRV-006 +CASE i2c_loop_nobody_answers outcome=passed asserts=6 skips=0 +TEST i2c_loop_register_reads_of_every_length + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_register_reads_of_every_length outcome=passed asserts=32 skips=0 +TEST i2c_loop_write_to_the_target + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_write_to_the_target outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=264 +7 tests, 0 failed, 0 skipped, 182 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.json new file mode 100644 index 00000000..f7e885fa --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 1, + "name": "irq_unlock_without_lock_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_connect_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_blocking_call_from_isr_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "irq_disabled_source_stays_pending", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_scheduler_lock_defers_the_switch_not_the_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_delivery_is_deferred_while_masked", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "irq_isr_wake_switches_at_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "irq_lock_is_nestable_and_lifo", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:25Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_irq" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_irq.elf verify reset exit" + ], + "flashed_sha256": { + "test_irq.elf": "baed947899ca702e11ef282a59d6c8f73b2fb75d21c7c6b8077de57b98237eb3" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq.elf", + "image_sha256": "baed947899ca702e11ef282a59d6c8f73b2fb75d21c7c6b8077de57b98237eb3", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:23Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.log new file mode 100644 index 00000000..6cd20b47 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq.log @@ -0,0 +1,40 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq.elf sha256 baed947899ca702e11ef282a59d6c8f73b2fb75d21c7c6b8077de57b98237eb3 +EVIDENCE v1 suite=test_irq config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST irq_unlock_without_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-IRQ-002 +CASE irq_unlock_without_lock_is_misuse outcome=passed asserts=1 skips=0 +TEST irq_connect_validates_arguments + fault checks that reset the board: 2 + -> ok + req KRN-IRQ-021 +CASE irq_connect_validates_arguments outcome=passed asserts=2 skips=0 +TEST irq_blocking_call_from_isr_is_misuse + fault checks that reset the board: 1 + -> ok + req API-013 KRN-IRQ-014 +CASE irq_blocking_call_from_isr_is_misuse outcome=passed asserts=1 skips=0 +TEST irq_disabled_source_stays_pending + -> ok + req KRN-IRQ-020 +CASE irq_disabled_source_stays_pending outcome=passed asserts=5 skips=0 +TEST irq_scheduler_lock_defers_the_switch_not_the_handler + -> ok + req KRN-SCH-016 KRN-SCH-018 KRN-SCH-019 +CASE irq_scheduler_lock_defers_the_switch_not_the_handler outcome=passed asserts=4 skips=0 +TEST irq_delivery_is_deferred_while_masked + -> ok + req KRN-IRQ-001 KRN-IRQ-033 +CASE irq_delivery_is_deferred_while_masked outcome=passed asserts=4 skips=0 +TEST irq_isr_wake_switches_at_outermost_exit + -> ok + req KRN-IRQ-010 KRN-IRQ-012 KRN-IRQ-013 KRN-SCH-021 +CASE irq_isr_wake_switches_at_outermost_exit outcome=passed asserts=7 skips=0 +TEST irq_lock_is_nestable_and_lifo + -> ok + req KRN-IRQ-001 KRN-IRQ-002 +CASE irq_lock_is_nestable_and_lifo outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=264 +8 tests, 0 failed, 0 skipped, 86 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.json new file mode 100644 index 00000000..37a675ad --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.json @@ -0,0 +1,107 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 17, + "name": "irq_priority_highest_kernel_level_is_masked", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_equal_levels_do_not_preempt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 25, + "name": "irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_higher_generic_level_preempts_lower", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "irq_priority_higher_generic_level_wins_pending_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 37, + "name": "irq_priority_encodings_and_invalid_write_guard", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_port_rejects_invalid_inputs", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_priority_rejects_unknown_number", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_rejects_out_of_range_level", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_accepts_advertised_endpoints", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:27Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_irq_priority" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_irq_priority.elf verify reset exit" + ], + "flashed_sha256": { + "test_irq_priority.elf": "90e3535e5575bb962b0f49b8add1cbfca76fe1806c68709f3dbe431c896f926e" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq_priority.elf", + "image_sha256": "90e3535e5575bb962b0f49b8add1cbfca76fe1806c68709f3dbe431c896f926e", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:25Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.log new file mode 100644 index 00000000..5008bd71 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_irq_priority.log @@ -0,0 +1,47 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq_priority.elf sha256 90e3535e5575bb962b0f49b8add1cbfca76fe1806c68709f3dbe431c896f926e +EVIDENCE v1 suite=test_irq_priority config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST irq_priority_highest_kernel_level_is_masked + -> ok + req KRN-IRQ-018 KRN-IRQ-028 +CASE irq_priority_highest_kernel_level_is_masked outcome=passed asserts=17 skips=0 +TEST irq_priority_equal_levels_do_not_preempt + -> ok + req KRN-IRQ-028 +CASE irq_priority_equal_levels_do_not_preempt outcome=passed asserts=16 skips=0 +TEST irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback + -> ok + req KRN-WQ-007 KRN-TIM-025 KRN-IRQ-012 +CASE irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback outcome=passed asserts=25 skips=0 +TEST irq_priority_higher_generic_level_preempts_lower + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_preempts_lower outcome=passed asserts=16 skips=0 +TEST irq_priority_higher_generic_level_wins_pending_order + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_wins_pending_order outcome=passed asserts=18 skips=0 +TEST irq_priority_encodings_and_invalid_write_guard + -> ok + req KRN-IRQ-028 KRN-IRQ-031 +CASE irq_priority_encodings_and_invalid_write_guard outcome=passed asserts=37 skips=0 +TEST irq_priority_port_rejects_invalid_inputs + -> ok + req KRN-IRQ-028 +CASE irq_priority_port_rejects_invalid_inputs outcome=passed asserts=2 skips=0 +TEST irq_priority_rejects_unknown_number + fault checks that reset the board: 1 + -> ok + req API-015 KRN-IRQ-029 +CASE irq_priority_rejects_unknown_number outcome=passed asserts=1 skips=0 +TEST irq_priority_rejects_out_of_range_level + fault checks that reset the board: 2 + -> ok + req API-015 KRN-IRQ-028 +CASE irq_priority_rejects_out_of_range_level outcome=passed asserts=2 skips=0 +TEST irq_priority_accepts_advertised_endpoints + -> ok + req KRN-IRQ-028 KRN-IRQ-029 +CASE irq_priority_accepts_advertised_endpoints outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=264 +10 tests, 0 failed, 0 skipped, 29 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.json new file mode 100644 index 00000000..47d45ffc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 1, + "name": "thread_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "isr_stack_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "isr_stack_info_reports_size_and_use", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:29Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_isr_stack" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_isr_stack.elf verify reset exit" + ], + "flashed_sha256": { + "test_isr_stack.elf": "d4c9b480c882bd6c4f00fa8e4ea25797e9a6a4dd4a009b12d5cc63c8e5f669e6" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_isr_stack.elf", + "image_sha256": "d4c9b480c882bd6c4f00fa8e4ea25797e9a6a4dd4a009b12d5cc63c8e5f669e6", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:27Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.log new file mode 100644 index 00000000..6f21351c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_isr_stack.log @@ -0,0 +1,19 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_isr_stack.elf sha256 d4c9b480c882bd6c4f00fa8e4ea25797e9a6a4dd4a009b12d5cc63c8e5f669e6 +EVIDENCE v1 suite=test_isr_stack config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST thread_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req KRN-MEM-010 PORT-016 +CASE thread_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +TEST isr_stack_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req PORT-016 KRN-MEM-010 +CASE isr_stack_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +TEST isr_stack_info_reports_size_and_use + -> ok + req PORT-016 KRN-MEM-009 +CASE isr_stack_info_reports_size_and_use outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=264 +3 tests, 0 failed, 0 skipped, 29 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.json new file mode 100644 index 00000000..afa49f71 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 2828, + "name": "log_producers_at_once_keep_their_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "log_flush_sends_what_is_committed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "log_isr_record_waits_for_the_one_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 84, + "name": "log_overflow_drops_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "log_levels_compile_and_run_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "log_text_formats", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "log_record_layout", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:02Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_log" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_log.elf verify reset exit" + ], + "flashed_sha256": { + "test_log.elf": "6e3543f75cc8f66e9dba13ebbd15ac02170a44371a5383d5d804d2665e501717" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_log.elf", + "image_sha256": "6e3543f75cc8f66e9dba13ebbd15ac02170a44371a5383d5d804d2665e501717", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:59Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.log new file mode 100644 index 00000000..4bfb1dd3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_log.log @@ -0,0 +1,35 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_log.elf sha256 6e3543f75cc8f66e9dba13ebbd15ac02170a44371a5383d5d804d2665e501717 +EVIDENCE v1 suite=test_log config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST log_producers_at_once_keep_their_order + -> ok + req OBS-003 +CASE log_producers_at_once_keep_their_order outcome=passed asserts=2828 skips=0 +TEST log_flush_sends_what_is_committed +[0.042] I t: flushed 1 +[0.042] I t: flushed 2 + -> ok + req OBS-003 +CASE log_flush_sends_what_is_committed outcome=passed asserts=4 skips=0 +TEST log_isr_record_waits_for_the_one_before_it + -> ok + req OBS-003 +CASE log_isr_record_waits_for_the_one_before_it outcome=passed asserts=6 skips=0 +TEST log_overflow_drops_and_counts + -> ok + req OBS-003 +CASE log_overflow_drops_and_counts outcome=passed asserts=84 skips=0 +TEST log_levels_compile_and_run_time + -> ok + req OBS-002 +CASE log_levels_compile_and_run_time outcome=passed asserts=9 skips=0 +TEST log_text_formats + -> ok + req OBS-013 +CASE log_text_formats outcome=passed asserts=11 skips=0 +TEST log_record_layout + -> ok + req OBS-013 +CASE log_record_layout outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=264 +7 tests, 0 failed, 0 skipped, 110 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.json new file mode 100644 index 00000000..d657cee2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.json @@ -0,0 +1,119 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "msgq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "msgq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_binding_fires_on_empty_to_nonempty_only", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "msgq_init_validates_the_ring", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "msgq_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_destroy_aborts_receivers_and_senders", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "msgq_isr_send_and_receive_never_wait", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_waits_time_out_and_cancel_without_storing", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "msgq_receive_refills_the_freed_slot_from_a_waiting_sender", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_waiting_receivers_get_items_directly_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "msgq_send_front_is_received_first_and_never_waits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 25, + "name": "msgq_fifo_order_counts_and_peek", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:52Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_msgq" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_msgq.elf verify reset exit" + ], + "flashed_sha256": { + "test_msgq.elf": "3ff8db0959995742655238df58aac352b8b413c7ea446aaec594d75699641957" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_msgq.elf", + "image_sha256": "3ff8db0959995742655238df58aac352b8b413c7ea446aaec594d75699641957", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:50Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.log new file mode 100644 index 00000000..28507ae0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_msgq.log @@ -0,0 +1,56 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_msgq.elf sha256 3ff8db0959995742655238df58aac352b8b413c7ea446aaec594d75699641957 +EVIDENCE v1 suite=test_msgq config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST msgq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE msgq_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +TEST msgq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE msgq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST msgq_binding_fires_on_empty_to_nonempty_only + -> ok + req KRN-IPC-018 KRN-NOTIF-004 KRN-NOTIF-013 +CASE msgq_binding_fires_on_empty_to_nonempty_only outcome=passed asserts=15 skips=0 +TEST msgq_init_validates_the_ring + fault checks that reset the board: 6 + -> ok + req KRN-IPC-011 KRN-IPC-019 API-015 +CASE msgq_init_validates_the_ring outcome=passed asserts=6 skips=0 +TEST msgq_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE msgq_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST msgq_destroy_aborts_receivers_and_senders + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE msgq_destroy_aborts_receivers_and_senders outcome=passed asserts=11 skips=0 +TEST msgq_isr_send_and_receive_never_wait + -> ok + req KRN-IPC-003 KRN-IPC-010 KRN-IRQ-010 +CASE msgq_isr_send_and_receive_never_wait outcome=passed asserts=13 skips=0 +TEST msgq_waits_time_out_and_cancel_without_storing + -> ok + req KRN-IPC-010 KRN-WAIT-004 KRN-WAIT-017 +CASE msgq_waits_time_out_and_cancel_without_storing outcome=passed asserts=15 skips=0 +TEST msgq_receive_refills_the_freed_slot_from_a_waiting_sender + -> ok + req KRN-IPC-010 KRN-IPC-011 +CASE msgq_receive_refills_the_freed_slot_from_a_waiting_sender outcome=passed asserts=12 skips=0 +TEST msgq_waiting_receivers_get_items_directly_in_priority_order + -> ok + req KRN-IPC-010 KRN-IPC-005 KRN-WAIT-001 +CASE msgq_waiting_receivers_get_items_directly_in_priority_order outcome=passed asserts=11 skips=0 +TEST msgq_send_front_is_received_first_and_never_waits + -> ok + req KRN-IPC-012 +CASE msgq_send_front_is_received_first_and_never_waits outcome=passed asserts=9 skips=0 +TEST msgq_fifo_order_counts_and_peek + -> ok + req KRN-IPC-010 KRN-IPC-019 +CASE msgq_fifo_order_counts_and_peek outcome=passed asserts=25 skips=0 +ISR_STACK size=2048 used=264 +12 tests, 0 failed, 0 skipped, 133 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.json new file mode 100644 index 00000000..7bd792ce --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.json @@ -0,0 +1,137 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 4, + "name": "mutex_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "mutex_waiter_priority_change_reorders_and_propagates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "mutex_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "mutex_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_owner_death_policy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_ceiling_violation_when_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_ceiling_violation_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "mutex_ceiling_raises_the_owner", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_deadlock_is_detected_on_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 28, + "name": "mutex_inheritance_propagates_along_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "mutex_timeout_removes_the_contribution", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "mutex_contended_lock_inherits_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "mutex_recursive_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "mutex_lock_unlock_and_ownership", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:46Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_mutex" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_mutex.elf verify reset exit" + ], + "flashed_sha256": { + "test_mutex.elf": "5d970aaf301ecbf58ceb9838ac5d12eea4e9328dee2d787b1e8be0a8622b4196" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_mutex.elf", + "image_sha256": "5d970aaf301ecbf58ceb9838ac5d12eea4e9328dee2d787b1e8be0a8622b4196", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:43Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 15 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.log new file mode 100644 index 00000000..31fff2c5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_mutex.log @@ -0,0 +1,73 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_mutex.elf sha256 5d970aaf301ecbf58ceb9838ac5d12eea4e9328dee2d787b1e8be0a8622b4196 +EVIDENCE v1 suite=test_mutex config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST mutex_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE mutex_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +TEST mutex_init_validates_arguments + fault checks that reset the board: 3 + -> ok + req API-015 +CASE mutex_init_validates_arguments outcome=passed asserts=3 skips=0 +TEST mutex_waiter_priority_change_reorders_and_propagates + -> ok + req KRN-WAIT-003 KRN-SYNC-018 +CASE mutex_waiter_priority_change_reorders_and_propagates outcome=passed asserts=20 skips=0 +TEST mutex_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE mutex_storage_reuse_requires_destroy outcome=passed asserts=12 skips=0 +TEST mutex_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 +CASE mutex_destroy_rules outcome=passed asserts=15 skips=0 +TEST mutex_owner_death_policy + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-011 +CASE mutex_owner_death_policy outcome=passed asserts=3 skips=0 +TEST mutex_ceiling_violation_when_owned + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_when_owned outcome=passed asserts=5 skips=0 +TEST mutex_ceiling_violation_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_is_misuse outcome=passed asserts=3 skips=0 +TEST mutex_ceiling_raises_the_owner + -> ok + req KRN-SYNC-005 KRN-SYNC-006 +CASE mutex_ceiling_raises_the_owner outcome=passed asserts=7 skips=0 +TEST mutex_deadlock_is_detected_on_the_chain + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-015 +CASE mutex_deadlock_is_detected_on_the_chain outcome=passed asserts=5 skips=0 +TEST mutex_inheritance_propagates_along_the_chain + -> ok + req KRN-SYNC-009 KRN-SYNC-010 KRN-SYNC-016 +CASE mutex_inheritance_propagates_along_the_chain outcome=passed asserts=28 skips=0 +TEST mutex_timeout_removes_the_contribution + -> ok + req KRN-SYNC-014 KRN-WAIT-013 +CASE mutex_timeout_removes_the_contribution outcome=passed asserts=14 skips=0 +TEST mutex_contended_lock_inherits_and_hands_off + -> ok + req KRN-SYNC-003 KRN-SYNC-009 KRN-SYNC-010 KRN-WAIT-012 +CASE mutex_contended_lock_inherits_and_hands_off outcome=passed asserts=16 skips=0 +TEST mutex_recursive_counts + -> ok + req KRN-SYNC-004 +CASE mutex_recursive_counts outcome=passed asserts=8 skips=0 +TEST mutex_lock_unlock_and_ownership + fault checks that reset the board: 2 + -> ok + req KRN-SYNC-001 KRN-SYNC-008 +CASE mutex_lock_unlock_and_ownership outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=264 +15 tests, 0 failed, 0 skipped, 15 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.json new file mode 100644 index 00000000..412e7920 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.json @@ -0,0 +1,107 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "notify_bind_refuses_a_terminated_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "notify_bound_target_cannot_be_destroyed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "notify_unbind_stops_signals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "notify_semaphore_binding_signals_ready_transition", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "notify_rejects_kernel_bits_and_terminated_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wait_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "notify_wake_from_isr", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wake_from_thread_hands_off_bits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "notify_any_and_all_modes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "notify_bits_are_level_sensitive", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:41Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_notify" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_notify.elf verify reset exit" + ], + "flashed_sha256": { + "test_notify.elf": "f5aa93929573df3b18aed241103041c7839bfc8bcb61a1daa982c4e41e2f5283" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_notify.elf", + "image_sha256": "f5aa93929573df3b18aed241103041c7839bfc8bcb61a1daa982c4e41e2f5283", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:39Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.log new file mode 100644 index 00000000..6d3380e4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_notify.log @@ -0,0 +1,47 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_notify.elf sha256 f5aa93929573df3b18aed241103041c7839bfc8bcb61a1daa982c4e41e2f5283 +EVIDENCE v1 suite=test_notify config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST notify_bind_refuses_a_terminated_target + -> ok + req KRN-NOTIF-014 +CASE notify_bind_refuses_a_terminated_target outcome=passed asserts=6 skips=0 +TEST notify_bound_target_cannot_be_destroyed + fault checks that reset the board: 1 + -> ok + req KRN-NOTIF-014 KRN-NOTIF-009 +CASE notify_bound_target_cannot_be_destroyed outcome=passed asserts=11 skips=0 +TEST notify_unbind_stops_signals + -> ok + req KRN-NOTIF-009 KRN-NOTIF-013 +CASE notify_unbind_stops_signals outcome=passed asserts=14 skips=0 +TEST notify_semaphore_binding_signals_ready_transition + -> ok + req KRN-NOTIF-004 KRN-NOTIF-005 +CASE notify_semaphore_binding_signals_ready_transition outcome=passed asserts=10 skips=0 +TEST notify_rejects_kernel_bits_and_terminated_targets + fault checks that reset the board: 3 + -> ok + req KRN-NOTIF-002 KRN-NOTIF-006 +CASE notify_rejects_kernel_bits_and_terminated_targets outcome=passed asserts=6 skips=0 +TEST notify_wait_times_out + -> ok + req KRN-NOTIF-001 KRN-WAIT-004 +CASE notify_wait_times_out outcome=passed asserts=5 skips=0 +TEST notify_wake_from_isr + -> ok + req KRN-NOTIF-002 KRN-IRQ-010 +CASE notify_wake_from_isr outcome=passed asserts=3 skips=0 +TEST notify_wake_from_thread_hands_off_bits + -> ok + req KRN-NOTIF-003 KRN-WAIT-012 +CASE notify_wake_from_thread_hands_off_bits outcome=passed asserts=5 skips=0 +TEST notify_any_and_all_modes + -> ok + req KRN-NOTIF-001 +CASE notify_any_and_all_modes outcome=passed asserts=12 skips=0 +TEST notify_bits_are_level_sensitive + -> ok + req KRN-NOTIF-001 KRN-NOTIF-002 +CASE notify_bits_are_level_sensitive outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=264 +10 tests, 0 failed, 0 skipped, 81 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.json new file mode 100644 index 00000000..91013456 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "rtc_seeds_the_wall_clock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "rtc_backup_and_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_canceled_and_set_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_once_and_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "rtc_get_set_and_not_set", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:17Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_rtc" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_rtc.elf verify reset exit" + ], + "flashed_sha256": { + "test_rtc.elf": "f51c6c414a0284555a8a881f309f4c0770f69bac1f4d4f8a7dff55808eb1f4d7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc.elf", + "image_sha256": "f51c6c414a0284555a8a881f309f4c0770f69bac1f4d4f8a7dff55808eb1f4d7", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:15Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.log new file mode 100644 index 00000000..e7e7d035 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc.log @@ -0,0 +1,26 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc.elf sha256 f51c6c414a0284555a8a881f309f4c0770f69bac1f4d4f8a7dff55808eb1f4d7 +EVIDENCE v1 suite=test_rtc config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST rtc_seeds_the_wall_clock + -> ok + req KRN-TIM-031 +CASE rtc_seeds_the_wall_clock outcome=passed asserts=3 skips=0 +TEST rtc_backup_and_misuse + fault checks that reset the board: 3 + -> ok + req DRV-001 +CASE rtc_backup_and_misuse outcome=passed asserts=8 skips=0 +TEST rtc_alarm_canceled_and_set_disarms + -> ok + req DRV-001 +CASE rtc_alarm_canceled_and_set_disarms outcome=passed asserts=10 skips=0 +TEST rtc_alarm_once_and_again + -> ok + req DRV-001 +CASE rtc_alarm_once_and_again outcome=passed asserts=10 skips=0 +TEST rtc_get_set_and_not_set + -> ok + req DRV-001 +CASE rtc_get_set_and_not_set outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=264 +5 tests, 0 failed, 0 skipped, 44 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.json new file mode 100644 index 00000000..f0a95af0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.json @@ -0,0 +1,71 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "rtc_board_keeps_its_time_across_a_reset", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "rtc_board_backup_registers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 42, + "name": "rtc_board_alarm_on_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "rtc_board_set_read_and_keep_time", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:22Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_rtc_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_rtc_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_rtc_board.elf": "5822c0beeed56a216cdbe52ac0b2dc78fc0b34dd8f62d218933a58c90ddbe603" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc_board.elf", + "image_sha256": "5822c0beeed56a216cdbe52ac0b2dc78fc0b34dd8f62d218933a58c90ddbe603", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:17Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.log new file mode 100644 index 00000000..be314392 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_rtc_board.log @@ -0,0 +1,22 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc_board.elf sha256 5822c0beeed56a216cdbe52ac0b2dc78fc0b34dd8f62d218933a58c90ddbe603 +EVIDENCE v1 suite=test_rtc_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST rtc_board_keeps_its_time_across_a_reset + after the reset the RTC read 27 ms past the time set fault checks that reset the board: 1 + -> ok + req DRV-001 KRN-TIM-031 +CASE rtc_board_keeps_its_time_across_a_reset outcome=passed asserts=7 skips=0 +TEST rtc_board_backup_registers + -> ok + req DRV-001 +CASE rtc_board_backup_registers outcome=passed asserts=4 skips=0 +TEST rtc_board_alarm_on_time + an alarm 300 ms ahead fired after 297 ms -> ok + req DRV-001 +CASE rtc_board_alarm_on_time outcome=passed asserts=42 skips=0 +TEST rtc_board_set_read_and_keep_time + set and get took 25 ms; the RTC read 23 ms past the time set over 2005 ms of the kernel's clock the RTC moved 2003 ms -> ok + req DRV-001 +CASE rtc_board_set_read_and_keep_time outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=264 +4 tests, 0 failed, 0 skipped, 2788 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.json new file mode 100644 index 00000000..2197540e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "sched_raising_a_ready_thread_above_the_caller_preempts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_thread_self_and_priorities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sched_idle_runs_when_nothing_is_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "sched_blocking_under_scheduler_lock_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "sched_preempted_thread_goes_ahead_of_its_peers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sched_fifo_within_level_and_yield_rotates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "sched_yield_never_to_lower_priority", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_lock_defers_preemption_until_unlock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "sched_higher_priority_runs_first", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:23Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_sched" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_sched.elf verify reset exit" + ], + "flashed_sha256": { + "test_sched.elf": "0871f0b6c578bd017837b3a8af16e787b9dfb62c981b18369b11f6fbf4fdfe10" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sched.elf", + "image_sha256": "0871f0b6c578bd017837b3a8af16e787b9dfb62c981b18369b11f6fbf4fdfe10", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:21Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.log new file mode 100644 index 00000000..cfc63e51 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sched.log @@ -0,0 +1,42 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_sched.elf sha256 0871f0b6c578bd017837b3a8af16e787b9dfb62c981b18369b11f6fbf4fdfe10 +EVIDENCE v1 suite=test_sched config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST sched_raising_a_ready_thread_above_the_caller_preempts + -> ok + req KRN-THR-022 KRN-SYNC-032 +CASE sched_raising_a_ready_thread_above_the_caller_preempts outcome=passed asserts=6 skips=0 +TEST sched_thread_self_and_priorities + -> ok + req KRN-THR-002 KRN-SCH-009 +CASE sched_thread_self_and_priorities outcome=passed asserts=4 skips=0 +TEST sched_idle_runs_when_nothing_is_ready + -> ok + req KRN-SCH-043 SIM-005 +CASE sched_idle_runs_when_nothing_is_ready outcome=passed asserts=2 skips=0 +TEST sched_blocking_under_scheduler_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SCH-019 API-013 +CASE sched_blocking_under_scheduler_lock_is_misuse outcome=passed asserts=1 skips=0 +TEST sched_preempted_thread_goes_ahead_of_its_peers + -> ok + req KRN-SCH-041 KRN-IRQ-013 +CASE sched_preempted_thread_goes_ahead_of_its_peers outcome=passed asserts=8 skips=0 +TEST sched_fifo_within_level_and_yield_rotates + -> ok + req KRN-SCH-003 KRN-SCH-008 +CASE sched_fifo_within_level_and_yield_rotates outcome=passed asserts=5 skips=0 +TEST sched_yield_never_to_lower_priority + -> ok + req KRN-SCH-008 +CASE sched_yield_never_to_lower_priority outcome=passed asserts=3 skips=0 +TEST sched_lock_defers_preemption_until_unlock + -> ok + req KRN-SCH-016 KRN-SCH-017 KRN-SCH-018 +CASE sched_lock_defers_preemption_until_unlock outcome=passed asserts=4 skips=0 +TEST sched_higher_priority_runs_first + -> ok + req KRN-SCH-001 KRN-SCH-002 +CASE sched_higher_priority_runs_first outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=264 +9 tests, 0 failed, 0 skipped, 86 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.json new file mode 100644 index 00000000..22de5e82 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.json @@ -0,0 +1,119 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "sem_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sem_blocking_take_from_prekernel_or_isr_rejected", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "sem_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sem_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sem_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_max_overflow_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sem_give_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_take_times_out_and_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_fifo_option_orders_by_arrival", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_give_hands_off_to_highest_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "sem_counts_and_nowait", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:43Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_sem" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_sem.elf verify reset exit" + ], + "flashed_sha256": { + "test_sem.elf": "34037f4d59bbbd8db4b2eb9cfb53c12d881b647f1511bb8ebdac0e60d3525128" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sem.elf", + "image_sha256": "34037f4d59bbbd8db4b2eb9cfb53c12d881b647f1511bb8ebdac0e60d3525128", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:41Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.log new file mode 100644 index 00000000..765b16ba --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_sem.log @@ -0,0 +1,56 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_sem.elf sha256 34037f4d59bbbd8db4b2eb9cfb53c12d881b647f1511bb8ebdac0e60d3525128 +EVIDENCE v1 suite=test_sem config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST sem_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE sem_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +TEST sem_blocking_take_from_prekernel_or_isr_rejected + -> ok + req API-012 API-013 +CASE sem_blocking_take_from_prekernel_or_isr_rejected outcome=passed asserts=4 skips=0 +TEST sem_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE sem_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST sem_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE sem_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST sem_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE sem_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST sem_init_validates_arguments + fault checks that reset the board: 2 + -> ok + req API-015 +CASE sem_init_validates_arguments outcome=passed asserts=2 skips=0 +TEST sem_max_overflow_and_saturate + -> ok + req KRN-SYNC-020 +CASE sem_max_overflow_and_saturate outcome=passed asserts=13 skips=0 +TEST sem_give_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-022 KRN-IRQ-010 KRN-IRQ-033 +CASE sem_give_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST sem_take_times_out_and_disarms + -> ok + req KRN-WAIT-004 KRN-WAIT-013 +CASE sem_take_times_out_and_disarms outcome=passed asserts=9 skips=0 +TEST sem_fifo_option_orders_by_arrival + -> ok + req KRN-WAIT-002 +CASE sem_fifo_option_orders_by_arrival outcome=passed asserts=9 skips=0 +TEST sem_give_hands_off_to_highest_waiter + -> ok + req KRN-WAIT-001 KRN-WAIT-012 KRN-SYNC-022 +CASE sem_give_hands_off_to_highest_waiter outcome=passed asserts=13 skips=0 +TEST sem_counts_and_nowait + -> ok + req KRN-SYNC-020 KRN-SYNC-021 +CASE sem_counts_and_nowait outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=264 +12 tests, 0 failed, 0 skipped, 108 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.json new file mode 100644 index 00000000..1bcad515 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "smoke_libc_errno_from_a_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "smoke_sleep_advances_virtual_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "smoke_thread_runs_and_exits", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:19Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_smoke" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_smoke.elf verify reset exit" + ], + "flashed_sha256": { + "test_smoke.elf": "905cdc4c52441e7479e51e598c3f5859dee562fd91e0af14bd5e5dbef3d8c79e" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_smoke.elf", + "image_sha256": "905cdc4c52441e7479e51e598c3f5859dee562fd91e0af14bd5e5dbef3d8c79e", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:18Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.log new file mode 100644 index 00000000..604301d7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_smoke.log @@ -0,0 +1,17 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_smoke.elf sha256 905cdc4c52441e7479e51e598c3f5859dee562fd91e0af14bd5e5dbef3d8c79e +EVIDENCE v1 suite=test_smoke config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST smoke_libc_errno_from_a_thread + -> ok + req PORT-015 +CASE smoke_libc_errno_from_a_thread outcome=passed asserts=3 skips=0 +TEST smoke_sleep_advances_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 +CASE smoke_sleep_advances_virtual_time outcome=passed asserts=2 skips=0 +TEST smoke_thread_runs_and_exits + -> ok + req KRN-THR-001 KRN-THR-005 KRN-THR-017 +CASE smoke_thread_runs_and_exits outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=264 +3 tests, 0 failed, 0 skipped, 56 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.json new file mode 100644 index 00000000..083270ce --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.json @@ -0,0 +1,101 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 15, + "name": "spi_other_threads_wait_for_a_held_bus", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_held_bus_refuses_another_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "spi_held_bus_keeps_the_chip_select", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "spi_chip_select_around_each_transfer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_unsupported_and_stopped", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_transfers_run_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_without_buffers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_transfer_loops_back", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:49Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_spi" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_spi.elf verify reset exit" + ], + "flashed_sha256": { + "test_spi.elf": "6f1b537820ad2474b8885e2478be2a5c9363ad99aa7395c0122204a8d9891959" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi.elf", + "image_sha256": "6f1b537820ad2474b8885e2478be2a5c9363ad99aa7395c0122204a8d9891959", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:47Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.log new file mode 100644 index 00000000..0eb41c08 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi.log @@ -0,0 +1,42 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi.elf sha256 6f1b537820ad2474b8885e2478be2a5c9363ad99aa7395c0122204a8d9891959 +EVIDENCE v1 suite=test_spi config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST spi_other_threads_wait_for_a_held_bus + -> ok + req DRV-004 +CASE spi_other_threads_wait_for_a_held_bus outcome=passed asserts=15 skips=0 +TEST spi_held_bus_refuses_another_target + -> ok + req DRV-004 +CASE spi_held_bus_refuses_another_target outcome=passed asserts=10 skips=0 +TEST spi_held_bus_keeps_the_chip_select + -> ok + req DRV-004 +CASE spi_held_bus_keeps_the_chip_select outcome=passed asserts=15 skips=0 +TEST spi_chip_select_around_each_transfer + -> ok + req DRV-004 +CASE spi_chip_select_around_each_transfer outcome=passed asserts=11 skips=0 +TEST spi_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE spi_misuse_faults outcome=passed asserts=7 skips=0 +TEST spi_unsupported_and_stopped + -> ok + req DRV-006 +CASE spi_unsupported_and_stopped outcome=passed asserts=7 skips=0 +TEST spi_transfers_run_in_order + -> ok + req DRV-004 +CASE spi_transfers_run_in_order outcome=passed asserts=10 skips=0 +TEST spi_without_buffers + -> ok + req DRV-005 +CASE spi_without_buffers outcome=passed asserts=7 skips=0 +TEST spi_transfer_loops_back + -> ok + req DRV-004 DRV-005 +CASE spi_transfer_loops_back outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=264 +9 tests, 0 failed, 0 skipped, 62 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.json new file mode 100644 index 00000000..28de4af1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 14, + "name": "spi_loop_runs_by_dma", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 21, + "name": "spi_loop_chip_select_at_the_pin", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "spi_loop_no_transmit_buffer_sends_ones", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "spi_loop_timeout_stops_after_whole_frames", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_refuses_a_clock_too_slow", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_slow_and_fast_clocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "spi_loop_every_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_frames_come_back_intact", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:51Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_spi_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_spi_loop.elf verify reset exit" + ], + "flashed_sha256": { + "test_spi_loop.elf": "448d8b1570c80b605f3ee6b016ba7958725c90fb8a1d9889fe8ac7407ca1288b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi_loop.elf", + "image_sha256": "448d8b1570c80b605f3ee6b016ba7958725c90fb8a1d9889fe8ac7407ca1288b", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:49Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.log new file mode 100644 index 00000000..084f47c1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_spi_loop.log @@ -0,0 +1,37 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi_loop.elf sha256 448d8b1570c80b605f3ee6b016ba7958725c90fb8a1d9889fe8ac7407ca1288b +EVIDENCE v1 suite=test_spi_loop config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST spi_loop_runs_by_dma + -> ok + req DRV-004 DRV-006 +CASE spi_loop_runs_by_dma outcome=passed asserts=14 skips=0 +TEST spi_loop_chip_select_at_the_pin + -> ok + req DRV-004 +CASE spi_loop_chip_select_at_the_pin outcome=passed asserts=21 skips=0 +TEST spi_loop_no_transmit_buffer_sends_ones + -> ok + req DRV-005 +CASE spi_loop_no_transmit_buffer_sends_ones outcome=passed asserts=17 skips=0 +TEST spi_loop_timeout_stops_after_whole_frames + -> ok + req DRV-006 +CASE spi_loop_timeout_stops_after_whole_frames outcome=passed asserts=5 skips=0 +TEST spi_loop_refuses_a_clock_too_slow + -> ok + req DRV-006 +CASE spi_loop_refuses_a_clock_too_slow outcome=passed asserts=4 skips=0 +TEST spi_loop_slow_and_fast_clocks + -> ok + req DRV-004 +CASE spi_loop_slow_and_fast_clocks outcome=passed asserts=4 skips=0 +TEST spi_loop_every_mode + -> ok + req DRV-004 +CASE spi_loop_every_mode outcome=passed asserts=8 skips=0 +TEST spi_loop_frames_come_back_intact + -> ok + req DRV-004 DRV-005 +CASE spi_loop_frames_come_back_intact outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=264 +8 tests, 0 failed, 0 skipped, 212 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.json new file mode 100644 index 00000000..0e3af2e9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.json @@ -0,0 +1,113 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 2, + "name": "thread_stack_info_reports_size", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_define_registers_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_state_reports_lifecycle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_priority_change_requeues_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_cancel_point_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_cancel_pending_delivered_at_next_point", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_cancel_wakes_a_sleeping_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_wake_while_suspended_is_applied_at_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "thread_suspend_resume_are_idempotent_overlays", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_start_twice_is_estate_and_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_init_validates_arguments", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:31Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_thread" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_thread.elf verify reset exit" + ], + "flashed_sha256": { + "test_thread.elf": "14ed1d72b9f7c88e9ede79348452586c03b5e3121163889180adccf6674b6e09" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread.elf", + "image_sha256": "14ed1d72b9f7c88e9ede79348452586c03b5e3121163889180adccf6674b6e09", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:29Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.log new file mode 100644 index 00000000..1e4a4145 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread.log @@ -0,0 +1,52 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread.elf sha256 14ed1d72b9f7c88e9ede79348452586c03b5e3121163889180adccf6674b6e09 +EVIDENCE v1 suite=test_thread config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST thread_stack_info_reports_size + -> ok + req KRN-MEM-009 +CASE thread_stack_info_reports_size outcome=passed asserts=2 skips=0 +TEST thread_define_registers_in_init_table + -> ok + req KRN-THR-015 API-017 +CASE thread_define_registers_in_init_table outcome=passed asserts=5 skips=0 +TEST thread_state_reports_lifecycle + -> ok + req KRN-THR-021 +CASE thread_state_reports_lifecycle outcome=passed asserts=11 skips=0 +TEST thread_priority_change_requeues_waiter + -> ok + req KRN-WAIT-003 KRN-SCH-009 KRN-SYNC-018 +CASE thread_priority_change_requeues_waiter outcome=passed asserts=13 skips=0 +TEST thread_cancel_point_and_counts + fault checks that reset the board: 1 + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_point_and_counts outcome=passed asserts=5 skips=0 +TEST thread_cancel_pending_delivered_at_next_point + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_pending_delivered_at_next_point outcome=passed asserts=11 skips=0 +TEST thread_cancel_wakes_a_sleeping_thread + -> ok + req KRN-THR-011 KRN-WAIT-017 +CASE thread_cancel_wakes_a_sleeping_thread outcome=passed asserts=6 skips=0 +TEST thread_wake_while_suspended_is_applied_at_resume + -> ok + req KRN-WAIT-016 KRN-THR-010 +CASE thread_wake_while_suspended_is_applied_at_resume outcome=passed asserts=12 skips=0 +TEST thread_suspend_resume_are_idempotent_overlays + -> ok + req KRN-THR-010 KRN-THR-019 +CASE thread_suspend_resume_are_idempotent_overlays outcome=passed asserts=18 skips=0 +TEST thread_start_twice_is_estate_and_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-THR-016 KRN-THR-022 KRN-OBJ-001 +CASE thread_start_twice_is_estate_and_destroy_rules outcome=passed asserts=13 skips=0 +TEST thread_init_validates_arguments + fault checks that reset the board: 6 + -> ok + req KRN-THR-001 API-015 +CASE thread_init_validates_arguments outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=264 +11 tests, 0 failed, 0 skipped, 14 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.json new file mode 100644 index 00000000..4aeed202 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "idle_context_is_not_an_application_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "thread_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_identity_survives_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1200, + "name": "thread_identity_repeated_construction_does_not_alias_live_object", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "thread_identity_survives_priority_and_termination", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:35Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_thread_identity" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_thread_identity.elf verify reset exit" + ], + "flashed_sha256": { + "test_thread_identity.elf": "cadc6605cb7fd8f6b7dc223707787f921b9813841fce4a652ff2b0c5a40ca64a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_identity.elf", + "image_sha256": "cadc6605cb7fd8f6b7dc223707787f921b9813841fce4a652ff2b0c5a40ca64a", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:33Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.log new file mode 100644 index 00000000..007358c0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_identity.log @@ -0,0 +1,28 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_identity.elf sha256 cadc6605cb7fd8f6b7dc223707787f921b9813841fce4a652ff2b0c5a40ca64a +EVIDENCE v1 suite=test_thread_identity config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST idle_context_is_not_an_application_thread + fault checks that reset the board: 2 + -> ok + req KRN-THR-025 KRN-THR-026 +CASE idle_context_is_not_an_application_thread outcome=passed asserts=6 skips=0 +TEST thread_storage_reuse_requires_destroy + fault checks that reset the board: 2 + -> ok + req KRN-THR-015 KRN-THR-023 +CASE thread_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST thread_identity_survives_suspend_and_resume + -> ok + req KRN-THR-025 +CASE thread_identity_survives_suspend_and_resume outcome=passed asserts=12 skips=0 +TEST thread_identity_repeated_construction_does_not_alias_live_object + -> ok + req KRN-THR-025 +CASE thread_identity_repeated_construction_does_not_alias_live_object outcome=passed asserts=1200 skips=0 +TEST thread_identity_survives_priority_and_termination + fault checks that reset the board: 1 + -> ok + req KRN-THR-025 +CASE thread_identity_survives_priority_and_termination outcome=passed asserts=15 skips=0 +ISR_STACK size=2048 used=264 +5 tests, 0 failed, 0 skipped, 15 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.json new file mode 100644 index 00000000..a2a0e4ef --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.json @@ -0,0 +1,83 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "thread_detach_after_exit_makes_reusable", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_self_and_detached_are_errors", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "thread_second_joiner_is_ebusy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_timeout_then_success", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_join_before_exit_blocks_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "thread_join_after_exit_returns_code", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:33Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_thread_join" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_thread_join.elf verify reset exit" + ], + "flashed_sha256": { + "test_thread_join.elf": "f65124c909d95a7428f450fb5cd1cbad3b704310f5cd326460bba1364e42d9ca" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_join.elf", + "image_sha256": "f65124c909d95a7428f450fb5cd1cbad3b704310f5cd326460bba1364e42d9ca", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:31Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.log new file mode 100644 index 00000000..85ccaa6d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_thread_join.log @@ -0,0 +1,31 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_join.elf sha256 f65124c909d95a7428f450fb5cd1cbad3b704310f5cd326460bba1364e42d9ca +EVIDENCE v1 suite=test_thread_join config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST thread_detach_after_exit_makes_reusable + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 KRN-THR-022 +CASE thread_detach_after_exit_makes_reusable outcome=passed asserts=5 skips=0 +TEST thread_join_self_and_detached_are_errors + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 +CASE thread_join_self_and_detached_are_errors outcome=passed asserts=5 skips=0 +TEST thread_second_joiner_is_ebusy + -> ok + req KRN-THR-018 +CASE thread_second_joiner_is_ebusy outcome=passed asserts=10 skips=0 +TEST thread_join_timeout_then_success + -> ok + req KRN-THR-017 KRN-WAIT-004 +CASE thread_join_timeout_then_success outcome=passed asserts=5 skips=0 +TEST thread_join_before_exit_blocks_and_hands_off + -> ok + req KRN-THR-017 KRN-WAIT-012 +CASE thread_join_before_exit_blocks_and_hands_off outcome=passed asserts=6 skips=0 +TEST thread_join_after_exit_returns_code + -> ok + req KRN-THR-004 KRN-THR-006 KRN-THR-017 +CASE thread_join_after_exit_returns_code outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=264 +6 tests, 0 failed, 0 skipped, 106 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.json new file mode 100644 index 00000000..41302d09 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 40, + "name": "time_now_is_monotonic_across_sleeps", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_instant_helpers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_at_least_adds_one_tick", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "time_conversions_round_up_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "time_timeouts_expire_in_deadline_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "time_zero_sleep_and_past_deadline_yield", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "time_sleep_until_does_not_drift", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "time_sleep_is_exact_in_virtual_time", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:37Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_time" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_time.elf verify reset exit" + ], + "flashed_sha256": { + "test_time.elf": "8056268c5b641343ca02a09cf24903a46598305884ee6ff58d36df90f0a25239" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_time.elf", + "image_sha256": "8056268c5b641343ca02a09cf24903a46598305884ee6ff58d36df90f0a25239", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:35Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.log new file mode 100644 index 00000000..5e9ccd6f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_time.log @@ -0,0 +1,37 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_time.elf sha256 8056268c5b641343ca02a09cf24903a46598305884ee6ff58d36df90f0a25239 +EVIDENCE v1 suite=test_time config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST time_now_is_monotonic_across_sleeps + -> ok + req KRN-TIM-001 +CASE time_now_is_monotonic_across_sleeps outcome=passed asserts=40 skips=0 +TEST time_instant_helpers + -> ok + req API-021 +CASE time_instant_helpers outcome=passed asserts=6 skips=0 +TEST time_at_least_adds_one_tick + -> ok + req KRN-TIM-024 +CASE time_at_least_adds_one_tick outcome=passed asserts=6 skips=0 +TEST time_conversions_round_up_and_saturate + -> ok + req API-021 API-022 +CASE time_conversions_round_up_and_saturate outcome=passed asserts=12 skips=0 +TEST time_timeouts_expire_in_deadline_order + -> ok + req KRN-TIM-020 KRN-TIM-021 +CASE time_timeouts_expire_in_deadline_order outcome=passed asserts=14 skips=0 +TEST time_zero_sleep_and_past_deadline_yield + -> ok + req KRN-TIM-010 API-024 +CASE time_zero_sleep_and_past_deadline_yield outcome=passed asserts=3 skips=0 +TEST time_sleep_until_does_not_drift + -> ok + req KRN-TIM-011 +CASE time_sleep_until_does_not_drift outcome=passed asserts=20 skips=0 +TEST time_sleep_is_exact_in_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 API-023 +CASE time_sleep_is_exact_in_virtual_time outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=264 +8 tests, 0 failed, 0 skipped, 195 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.json new file mode 100644 index 00000000..f204b4ee --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.json @@ -0,0 +1,89 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 4, + "name": "timer_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "timer_init_needs_a_queue_or_isr_context", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_expiries_during_a_long_callback_are_overruns", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_stop_sync_waits_for_a_running_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "timer_callback_runs_on_its_work_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 22, + "name": "timer_restart_remaining_and_stop_states", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 22, + "name": "timer_isr_context_one_shot_and_periodic_without_drift", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:57Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_timer" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_timer.elf verify reset exit" + ], + "flashed_sha256": { + "test_timer.elf": "7924a4c2e1f381178144fa7507572fbf4d6024363d7c069f004a7150695da560" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_timer.elf", + "image_sha256": "7924a4c2e1f381178144fa7507572fbf4d6024363d7c069f004a7150695da560", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:55Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.log new file mode 100644 index 00000000..a11d0584 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_timer.log @@ -0,0 +1,36 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_timer.elf sha256 7924a4c2e1f381178144fa7507572fbf4d6024363d7c069f004a7150695da560 +EVIDENCE v1 suite=test_timer config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST timer_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE timer_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +TEST timer_init_needs_a_queue_or_isr_context + fault checks that reset the board: 2 + -> ok + req KRN-TIM-013 API-015 +CASE timer_init_needs_a_queue_or_isr_context outcome=passed asserts=3 skips=0 +TEST timer_expiries_during_a_long_callback_are_overruns + -> ok + req KRN-TIM-027 +CASE timer_expiries_during_a_long_callback_are_overruns outcome=passed asserts=13 skips=0 +TEST timer_stop_sync_waits_for_a_running_callback + -> ok + req KRN-TIM-028 KRN-WAIT-012 +CASE timer_stop_sync_waits_for_a_running_callback outcome=passed asserts=13 skips=0 +TEST timer_callback_runs_on_its_work_queue + fault checks that reset the board: 1 + -> ok + req KRN-TIM-013 KRN-TIM-005 KRN-TIM-026 +CASE timer_callback_runs_on_its_work_queue outcome=passed asserts=11 skips=0 +TEST timer_restart_remaining_and_stop_states + fault checks that reset the board: 2 + -> ok + req KRN-TIM-025 KRN-TIM-028 +CASE timer_restart_remaining_and_stop_states outcome=passed asserts=22 skips=0 +TEST timer_isr_context_one_shot_and_periodic_without_drift + -> ok + req KRN-TIM-025 KRN-TIM-005 KRN-TIM-014 KRN-TIM-015 +CASE timer_isr_context_one_shot_and_periodic_without_drift outcome=passed asserts=22 skips=0 +ISR_STACK size=2048 used=264 +7 tests, 0 failed, 0 skipped, 65 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.json new file mode 100644 index 00000000..3db24d04 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.json @@ -0,0 +1,95 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 6, + "name": "uart_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_break_runs_after_the_writes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_polled_calls_and_capabilities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_read_times_out_with_what_it_got", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "uart_overrun_and_damaged_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "uart_idle_ends_a_read_early", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_ring_keeps_bytes_no_read_waits_for", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_read_and_write_run_at_once", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:06Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_uart" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_uart.elf verify reset exit" + ], + "flashed_sha256": { + "test_uart.elf": "afbdded14f9115ae91ec578229f7d4f3600b7ab61283145569ef05555a5e3936" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart.elf", + "image_sha256": "afbdded14f9115ae91ec578229f7d4f3600b7ab61283145569ef05555a5e3936", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:04Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.log new file mode 100644 index 00000000..8ee764f2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart.log @@ -0,0 +1,38 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart.elf sha256 afbdded14f9115ae91ec578229f7d4f3600b7ab61283145569ef05555a5e3936 +EVIDENCE v1 suite=test_uart config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST uart_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE uart_misuse_faults outcome=passed asserts=6 skips=0 +TEST uart_break_runs_after_the_writes + -> ok + req DRV-004 +CASE uart_break_runs_after_the_writes outcome=passed asserts=5 skips=0 +TEST uart_polled_calls_and_capabilities + -> ok + req DRV-007 +CASE uart_polled_calls_and_capabilities outcome=passed asserts=8 skips=0 +TEST uart_read_times_out_with_what_it_got + -> ok + req DRV-006 +CASE uart_read_times_out_with_what_it_got outcome=passed asserts=6 skips=0 +TEST uart_overrun_and_damaged_bytes + -> ok + req DRV-005 DRV-008 +CASE uart_overrun_and_damaged_bytes outcome=passed asserts=11 skips=0 +TEST uart_idle_ends_a_read_early + -> ok + req DRV-005 +CASE uart_idle_ends_a_read_early outcome=passed asserts=10 skips=0 +TEST uart_ring_keeps_bytes_no_read_waits_for + -> ok + req DRV-005 +CASE uart_ring_keeps_bytes_no_read_waits_for outcome=passed asserts=8 skips=0 +TEST uart_read_and_write_run_at_once + -> ok + req DRV-004 DRV-005 +CASE uart_read_and_write_run_at_once outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=264 +8 tests, 0 failed, 0 skipped, 103 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_board.json new file mode 100644 index 00000000..bcfd7da7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_board.json @@ -0,0 +1,77 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 5, + "name": "uart_console_writes_by_dma", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "uart_console_polled_write", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "uart_console_break_or_not_supported", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "uart_console_read_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_console_writes_by_request", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:08Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_uart_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_uart_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_uart_board.elf": "1c876b1c018cd82d438334607f261cc41cdd217f6ce93d4c451be94040bea7a7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_board.elf", + "image_sha256": "1c876b1c018cd82d438334607f261cc41cdd217f6ce93d4c451be94040bea7a7", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:06Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_board.log new file mode 100644 index 0000000000000000000000000000000000000000..06c7871297806df5d683a2fcad17427a7d79e225 GIT binary patch literal 1165 zcmbW0O>f&U42F01ui$N$G?i@mqXj%5OFW<$+CvibD##Mu7_lu+k~?(2esWx--RAVL zi!Df^_`KxHL*3j$sfAI{4YEPaE5;Io3$R+kZhs$z-~7h5SU_)diJ*Jzv{Z0aO<~v8 z@pI%-R!{z-HV&>8K3~gWIoPt*3fqWM5`l0)X&e#)r5Mx#>Q+1~+Sz=Rx zJ%}()fXXaQN-7D>q{>3YqAZG7LeeTssFaLKr9zrkiNu>oG09?D;teB=lqgb>2F2su zrg&Hv@JzuDwZr_cY#?=4)laz)nNo2arBRlKDWjv_s%|hZg~ds0eik~G2;>3f5miou zeX-laNq~RM>IV5w<5O8)zHrrw06;)fcV6kihfP;tx&q}3Z0=VJV3}X~nB{Wm?_YfZ zee{2WKVY+cyds1J>(#FKAPeZhN!?=J3u{rq_%+VvG1z0>+nmf`_PS|MO|-!%;MS8) zn-kwGN;-q`{-sMKz5^FYN`vCawc(w1+z$O{B2=Gd^UsxHKK_45Jc#11ZhiZFMP~t$ znF9P7b}4cAK?&YGFe79e%zk{uRVIC6i;K3U&4-*!|r=hkBAW#WEMSj-FNqRpnDW%|Q Rd9*=s|CNu^!;6Pa@Eh=SiB|vs literal 0 HcmV?d00001 diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.json new file mode 100644 index 00000000..ff438af2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.json @@ -0,0 +1,83 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 4, + "name": "uart_loop_overrun_is_reported", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_break_arrives_as_a_framing_error", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_loop_a_kilobyte_intact", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_loop_idle_line_ends_a_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_ring_keeps_what_arrives", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "uart_loop_echo_full_duplex", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:10Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_uart_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_uart_loop.elf verify reset exit" + ], + "flashed_sha256": { + "test_uart_loop.elf": "e1c065c0cf6f133e5bece1351cab690578a640cf136e7f4833ec99626e66af86" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_loop.elf", + "image_sha256": "e1c065c0cf6f133e5bece1351cab690578a640cf136e7f4833ec99626e66af86", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:08Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.log new file mode 100644 index 00000000..54f1b184 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_uart_loop.log @@ -0,0 +1,29 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart_loop.elf sha256 e1c065c0cf6f133e5bece1351cab690578a640cf136e7f4833ec99626e66af86 +EVIDENCE v1 suite=test_uart_loop config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST uart_loop_overrun_is_reported + -> ok + req DRV-005 DRV-008 +CASE uart_loop_overrun_is_reported outcome=passed asserts=4 skips=0 +TEST uart_loop_break_arrives_as_a_framing_error + -> ok + req DRV-004 DRV-008 +CASE uart_loop_break_arrives_as_a_framing_error outcome=passed asserts=4 skips=0 +TEST uart_loop_a_kilobyte_intact + -> ok + req DRV-004 DRV-005 +CASE uart_loop_a_kilobyte_intact outcome=passed asserts=6 skips=0 +TEST uart_loop_idle_line_ends_a_read + -> ok + req DRV-005 +CASE uart_loop_idle_line_ends_a_read outcome=passed asserts=5 skips=0 +TEST uart_loop_ring_keeps_what_arrives + -> ok + req DRV-005 +CASE uart_loop_ring_keeps_what_arrives outcome=passed asserts=4 skips=0 +TEST uart_loop_echo_full_duplex + -> ok + req DRV-004 DRV-005 +CASE uart_loop_echo_full_duplex outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=264 +6 tests, 0 failed, 0 skipped, 212 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.json new file mode 100644 index 00000000..92d036d9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 9, + "name": "wallclock_adjust_moves_no_deadline", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "wallclock_set_and_get", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:39Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wallclock" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_wallclock.elf verify reset exit" + ], + "flashed_sha256": { + "test_wallclock.elf": "49472c5284ca0516d3b5b6da38a8242fb0cce504c56cbe1c1af0e17c92452e26" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wallclock.elf", + "image_sha256": "49472c5284ca0516d3b5b6da38a8242fb0cce504c56cbe1c1af0e17c92452e26", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:37Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.log new file mode 100644 index 00000000..2e557746 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wallclock.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wallclock.elf sha256 49472c5284ca0516d3b5b6da38a8242fb0cce504c56cbe1c1af0e17c92452e26 +EVIDENCE v1 suite=test_wallclock config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wallclock_adjust_moves_no_deadline + -> ok + req KRN-TIM-031 +CASE wallclock_adjust_moves_no_deadline outcome=passed asserts=9 skips=0 +TEST wallclock_set_and_get + fault checks that reset the board: 1 + -> ok + req KRN-TIM-031 +CASE wallclock_set_and_get outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=264 +2 tests, 0 failed, 0 skipped, 63 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.json new file mode 100644 index 00000000..41502ff9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 123, + "name": "wdog_feeds_until_a_party_misses", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "wdog_refusals", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:37Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdog" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_wdog.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdog.elf": "aaa4416ba7ce0046a050b536ba129052ab749f52a3a2f0d0a573db23dc0afa25" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog.elf", + "image_sha256": "aaa4416ba7ce0046a050b536ba129052ab749f52a3a2f0d0a573db23dc0afa25", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:35Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.log new file mode 100644 index 00000000..176c50d6 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog.elf sha256 aaa4416ba7ce0046a050b536ba129052ab749f52a3a2f0d0a573db23dc0afa25 +EVIDENCE v1 suite=test_wdog config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdog_feeds_until_a_party_misses + -> ok + req FLT-004 +CASE wdog_feeds_until_a_party_misses outcome=passed asserts=123 skips=0 +TEST wdog_refusals + fault checks that reset the board: 4 + -> ok + req FLT-004 +CASE wdog_refusals outcome=passed asserts=13 skips=0 +ISR_STACK size=2048 used=264 +2 tests, 0 failed, 0 skipped, 12 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.json new file mode 100644 index 00000000..b98817f0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.json @@ -0,0 +1,53 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 10, + "name": "wdog_board_hung_thread_resets_the_board", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:42Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdog_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_wdog_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdog_board.elf": "010c0fd4ee6c5304a53ebdf4688d7cd2bf1ae074caa6ce719d850671005ee6ae" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog_board.elf", + "image_sha256": "010c0fd4ee6c5304a53ebdf4688d7cd2bf1ae074caa6ce719d850671005ee6ae", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:40Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.log new file mode 100644 index 00000000..4b7792c2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdog_board.log @@ -0,0 +1,10 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog_board.elf sha256 010c0fd4ee6c5304a53ebdf4688d7cd2bf1ae074caa6ce719d850671005ee6ae +EVIDENCE v1 suite=test_wdog_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdog_board_hung_thread_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdog_board_hung_thread_resets_the_board outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=264 +1 tests, 0 failed, 0 skipped, 14 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.json new file mode 100644 index 00000000..24968272 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 7, + "name": "wdt_not_ready_and_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "wdt_start_feed_and_cause", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:35Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdt" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_wdt.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdt.elf": "b4a4a11eae5f9fb4c464f9f87aa0f0a1a732a2f277cc22ed0773805253fb5cf5" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt.elf", + "image_sha256": "b4a4a11eae5f9fb4c464f9f87aa0f0a1a732a2f277cc22ed0773805253fb5cf5", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:34Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.log new file mode 100644 index 00000000..8299f9f3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt.elf sha256 b4a4a11eae5f9fb4c464f9f87aa0f0a1a732a2f277cc22ed0773805253fb5cf5 +EVIDENCE v1 suite=test_wdt config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdt_not_ready_and_misuse + fault checks that reset the board: 3 + -> ok + req FLT-004 +CASE wdt_not_ready_and_misuse outcome=passed asserts=7 skips=0 +TEST wdt_start_feed_and_cause + -> ok + req FLT-004 +CASE wdt_start_feed_and_cause outcome=passed asserts=13 skips=0 +ISR_STACK size=2048 used=264 +2 tests, 0 failed, 0 skipped, 23 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.json new file mode 100644 index 00000000..41079384 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.json @@ -0,0 +1,59 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 3, + "name": "wdt_board_starved_resets_the_board", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "wdt_board_refuses_what_it_cannot_count", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:26:40Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_wdt_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_wdt_board.elf verify reset exit" + ], + "flashed_sha256": { + "test_wdt_board.elf": "cc2f53c3a26f1e79f54a7449dbea9697c1f365e34b153ff033bb20a37af74e96" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt_board.elf", + "image_sha256": "cc2f53c3a26f1e79f54a7449dbea9697c1f365e34b153ff033bb20a37af74e96", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:26:38Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.log new file mode 100644 index 00000000..6c218d4d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_wdt_board.log @@ -0,0 +1,14 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt_board.elf sha256 cc2f53c3a26f1e79f54a7449dbea9697c1f365e34b153ff033bb20a37af74e96 +EVIDENCE v1 suite=test_wdt_board config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST wdt_board_starved_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdt_board_starved_resets_the_board outcome=passed asserts=3 skips=0 +TEST wdt_board_refuses_what_it_cannot_count + -> ok + req FLT-004 +CASE wdt_board_refuses_what_it_cannot_count outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=264 +2 tests, 0 failed, 0 skipped, 26 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.json b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.json new file mode 100644 index 00000000..5948d29e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.json @@ -0,0 +1,143 @@ +{ + "baud": 115200, + "bench": [], + "board": "nucleo_f446re", + "cases": [ + { + "asserts": 2, + "name": "workq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dwork_cancel_sync_waits_for_a_running_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 19, + "name": "dwork_cancel_reports_pending_for_a_delay_and_a_queued_item", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "dwork_rescheduled_during_its_expiry_keeps_the_new_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_reschedule_replaces_the_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_runs_after_its_delay_and_schedule_is_idempotent", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_system_queue_runs_items", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_destroy_refuses_a_busy_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_thread_is_a_kernel_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_submit_from_isr_runs_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "workq_flush_waits_for_items_queued_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "workq_cancel_reports_pending_running_and_idle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "workq_item_belongs_to_one_queue_at_a_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_resubmit_while_running_runs_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "workq_runs_items_in_fifo_order_on_its_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:25:55Z", + "evidence": { + "board": "nucleo_f446re", + "checked": "1", + "config": "aa8dd55373872741", + "profile": "base", + "suite": "test_workq" + }, + "exit": 0, + "fault_checks_by_reset": 6, + "flash_command": [ + "openocd", + "-f", + "board/st_nucleo_f4.cfg", + "-c", + "program /Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/nucleo-gcc/tests/conformance/test_workq.elf verify reset exit" + ], + "flashed_sha256": { + "test_workq.elf": "4e245964d19f330fd470991208b91156b344975540f308eb7ae6ebc08f9137db" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_workq.elf", + "image_sha256": "4e245964d19f330fd470991208b91156b344975540f308eb7ae6ebc08f9137db", + "isr_stack": { + "size": 2048, + "used": 264 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "STM32F446RE", + "started": "2026-11-13T05:25:53Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.log b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.log new file mode 100644 index 00000000..e4cf2e0f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-nucleo_f446re-logging-gcc/test_workq.log @@ -0,0 +1,73 @@ +hil: board nucleo_f446re, soc STM32F446RE, probe openocd -f board/st_nucleo_f4.cfg, port /dev/cu.usbmodem31103 at 115200 baud, image test_workq.elf sha256 4e245964d19f330fd470991208b91156b344975540f308eb7ae6ebc08f9137db +EVIDENCE v1 suite=test_workq config=aa8dd55373872741 profile=base board=nucleo_f446re checked=1 +TEST workq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE workq_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +TEST dwork_cancel_sync_waits_for_a_running_handler + -> ok + req KRN-WQ-007 KRN-WQ-006 +CASE dwork_cancel_sync_waits_for_a_running_handler outcome=passed asserts=10 skips=0 +TEST dwork_cancel_reports_pending_for_a_delay_and_a_queued_item + fault checks that reset the board: 1 + -> ok + req KRN-WQ-007 KRN-WQ-004 +CASE dwork_cancel_reports_pending_for_a_delay_and_a_queued_item outcome=passed asserts=19 skips=0 +TEST dwork_rescheduled_during_its_expiry_keeps_the_new_delay + -> ok + req KRN-WQ-007 KRN-TIM-024 +CASE dwork_rescheduled_during_its_expiry_keeps_the_new_delay outcome=passed asserts=9 skips=0 +TEST dwork_reschedule_replaces_the_delay + -> ok + req KRN-WQ-007 +CASE dwork_reschedule_replaces_the_delay outcome=passed asserts=7 skips=0 +TEST dwork_runs_after_its_delay_and_schedule_is_idempotent + -> ok + req KRN-WQ-003 KRN-WQ-007 +CASE dwork_runs_after_its_delay_and_schedule_is_idempotent outcome=passed asserts=7 skips=0 +TEST workq_system_queue_runs_items + -> ok + req KRN-WQ-008 +CASE workq_system_queue_runs_items outcome=passed asserts=3 skips=0 +TEST workq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE workq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST workq_destroy_refuses_a_busy_queue + fault checks that reset the board: 2 + -> ok + req KRN-OBJ-001 KRN-WQ-010 API-013 +CASE workq_destroy_refuses_a_busy_queue outcome=passed asserts=8 skips=0 +TEST workq_thread_is_a_kernel_thread + fault checks that reset the board: 2 + -> ok + req KRN-WQ-009 KRN-WQ-010 +CASE workq_thread_is_a_kernel_thread outcome=passed asserts=8 skips=0 +TEST workq_submit_from_isr_runs_at_exit + -> ok + req KRN-WQ-001 KRN-IRQ-010 +CASE workq_submit_from_isr_runs_at_exit outcome=passed asserts=5 skips=0 +TEST workq_flush_waits_for_items_queued_before_it + -> ok + req KRN-WQ-006 KRN-WAIT-012 +CASE workq_flush_waits_for_items_queued_before_it outcome=passed asserts=9 skips=0 +TEST workq_cancel_reports_pending_running_and_idle + -> ok + req KRN-WQ-004 KRN-WQ-006 +CASE workq_cancel_reports_pending_running_and_idle outcome=passed asserts=17 skips=0 +TEST workq_item_belongs_to_one_queue_at_a_time + -> ok + req KRN-WQ-005 +CASE workq_item_belongs_to_one_queue_at_a_time outcome=passed asserts=12 skips=0 +TEST workq_resubmit_while_running_runs_again + -> ok + req KRN-WQ-005 +CASE workq_resubmit_while_running_runs_again outcome=passed asserts=5 skips=0 +TEST workq_runs_items_in_fifo_order_on_its_thread + -> ok + req KRN-WQ-001 KRN-WQ-002 KRN-WQ-005 KRN-WQ-009 +CASE workq_runs_items_in_fifo_order_on_its_thread outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=264 +16 tests, 0 failed, 0 skipped, 111 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-log-soak/log_soak.head.bin.gz b/docs/engineering/hil-runs/2026-11-13-pico2_w-log-soak/log_soak.head.bin.gz new file mode 100644 index 0000000000000000000000000000000000000000..0afe00c5c1279aa26b9eaa4ed639336f431a721e GIT binary patch literal 88943 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 %_|2Wra6COa=_)O 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 SSAX#MRIq0~jgF3i?*9P4iw+6^ literal 0 HcmV?d00001 diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-log-soak/log_soak.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-log-soak/log_soak.json new file mode 100644 index 00000000..111aef14 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-log-soak/log_soak.json @@ -0,0 +1,30 @@ +{ + "board": "pico2_w", + "capture": { + "bytes": 10012148, + "sample": "log_soak.head.bin.gz: the first 262144 bytes, gzip", + "sha256": "fde0e000513babddaf1ce2a6b7d600ecef6b4f4cbea04ce7a8067b1fca86c0c8" + }, + "damaged_frames": 0, + "decode_errors": 0, + "dropped_counted": 91749, + "frames": 145624, + "git": { + "commit": "1b58e07ba8f51589ebe35a0fb382fe10b0d08481", + "dirty": false + }, + "image": "log_soak.elf", + "log_records": 270615, + "minutes": 30.0, + "missing_not_counted": 0, + "numbered_records": 154761, + "outcome": "passed", + "started": "2026-11-13T04:53:46Z", + "target_counters": { + "log": "records 270017 dropped 91545 sent 270016 high 1020", + "trace": "recorded 6299436 overwritten 6020401 sent 277371" + }, + "trace_events": 277999, + "trace_gaps": 25951, + "trace_packets": 25953 +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.json new file mode 100644 index 00000000..5d3d7a10 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 60004, + "unit_hz": 150000000, + "units": 12000884 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 55836, + "unit_hz": 150000000, + "units": 11167307 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 16438, + "unit_hz": 150000000, + "units": 1643889 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 121177, + "unit_hz": 150000000, + "units": 6058882 + } + ], + "board": "pico2_w", + "cases": [], + "ended": "2026-11-13T05:41:40Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/benchmarks/bench_compare.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "bench_compare.uf2": "9112caa35ce87c066bfcdc91f36787b87740d6436c91bae53e8150da0dbbfb03" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_compare.elf", + "image_sha256": "8e4e7f596b71658ffd03ac8e242d7c09128a5ff85d4c34a6fbb8168966947e61", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:38Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.log new file mode 100644 index 00000000..f9346a0e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_compare.log @@ -0,0 +1,7 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image bench_compare.elf sha256 8e4e7f596b71658ffd03ac8e242d7c09128a5ff85d4c34a6fbb8168966947e61 +bench_compare: EmbLinkRTOS 0.2.0 +BENCH v1 name=notify_handover units=12000884 ops=20000 per_op_x100=60004 unit_hz=150000000 os=emblink +BENCH v1 name=sem_handover units=11167307 ops=20000 per_op_x100=55836 unit_hz=150000000 os=emblink +BENCH v1 name=sem_give_take units=1643889 ops=10000 per_op_x100=16438 unit_hz=150000000 os=emblink +BENCH v1 name=isr_wake units=6058882 ops=5000 per_op_x100=121177 unit_hz=150000000 os=emblink +BENCH_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.json new file mode 100644 index 00000000..7b53c5e8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.json @@ -0,0 +1,42 @@ +{ + "baud": 115200, + "bench": [ + { + "avg_x100": 13458, + "checked": 1, + "max": 2111, + "min": 132, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 150000000 + } + ], + "board": "pico2_w", + "cases": [], + "ended": "2026-11-13T05:41:38Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/benchmarks/bench_irq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "bench_irq.uf2": "e94be2140a4390c4aa7ebefd776271e0622a45fcdb6d6f30f317d519778bf7c7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_irq.elf", + "image_sha256": "7f45b44caa3941aad25df8ab0b98e7d27cc09ce05e9eb17d3bb9e5c4b3e00a1d", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:37Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.log new file mode 100644 index 00000000..8afc86e1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_irq.log @@ -0,0 +1,5 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image bench_irq.elf sha256 7f45b44caa3941aad25df8ab0b98e7d27cc09ce05e9eb17d3bb9e5c4b3e00a1d +bench irq pend to handler: min 132 max 2111 avg x100 13458 cycle-units over 1000 runs +BENCH v1 name=irq_pend_to_handler min=132 max=2111 avg_x100=13458 ops=1000 unit_hz=150000000 checked=1 +meta: board pico2_w, compiler clang, profile base, checked 1, cycle unit hz 150000000 +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.json new file mode 100644 index 00000000..69ac4b02 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.json @@ -0,0 +1,41 @@ +{ + "baud": 115200, + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 59740, + "unit_hz": 150000000, + "units": 11948186 + } + ], + "board": "pico2_w", + "cases": [], + "ended": "2026-11-13T05:41:37Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/benchmarks/bench_switch.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "bench_switch.uf2": "4d87108f2bb1014b726b64a836e5125be01c5033eb0dfdc33d58bf842436f2d6" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_switch.elf", + "image_sha256": "f9a66b08eb3ca0ece0c337e0a85fd18886e586895d3f752379ba236a5f3970b4", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:35Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.log new file mode 100644 index 00000000..8b953c0e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/bench_switch.log @@ -0,0 +1,5 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image bench_switch.elf sha256 f9a66b08eb3ca0ece0c337e0a85fd18886e586895d3f752379ba236a5f3970b4 +bench notify round trip (2 switches): total 11948186 cycle-units over 20000 ops; per op x100 = 59740 +BENCH v1 name=notify_handover units=11948186 ops=20000 per_op_x100=59740 unit_hz=150000000 checked=1 +meta: board pico2_w, compiler clang, profile base, checked 1, cycle unit hz 150000000 +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/index.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/index.json new file mode 100644 index 00000000..bd2a6e8e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/index.json @@ -0,0 +1,978 @@ +{ + "board": "pico2_w", + "build": "checked (Clang 23.1.5 with LLD, 150 MHz)", + "configuration": "9461e3c42192b75e", + "date": "2026-11-13", + "format": "emb-hil-archive v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "images": [ + { + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 60004, + "unit_hz": 150000000, + "units": 12000884 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 55836, + "unit_hz": 150000000, + "units": 11167307 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 16438, + "unit_hz": 150000000, + "units": 1643889 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 121177, + "unit_hz": 150000000, + "units": 6058882 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_compare.uf2": "9112caa35ce87c066bfcdc91f36787b87740d6436c91bae53e8150da0dbbfb03" + }, + "image": "bench_compare.elf", + "image_sha256": "8e4e7f596b71658ffd03ac8e242d7c09128a5ff85d4c34a6fbb8168966947e61", + "isr_stack": null, + "log": "bench_compare.log", + "outcome": "passed", + "started": "2026-11-13T05:41:38Z" + }, + { + "bench": [ + { + "avg_x100": 13458, + "checked": 1, + "max": 2111, + "min": 132, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 150000000 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_irq.uf2": "e94be2140a4390c4aa7ebefd776271e0622a45fcdb6d6f30f317d519778bf7c7" + }, + "image": "bench_irq.elf", + "image_sha256": "7f45b44caa3941aad25df8ab0b98e7d27cc09ce05e9eb17d3bb9e5c4b3e00a1d", + "isr_stack": null, + "log": "bench_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:41:37Z" + }, + { + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 59740, + "unit_hz": 150000000, + "units": 11948186 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_switch.uf2": "4d87108f2bb1014b726b64a836e5125be01c5033eb0dfdc33d58bf842436f2d6" + }, + "image": "bench_switch.elf", + "image_sha256": "f9a66b08eb3ca0ece0c337e0a85fd18886e586895d3f752379ba236a5f3970b4", + "isr_stack": null, + "log": "bench_switch.log", + "outcome": "passed", + "started": "2026-11-13T05:41:35Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_cond.uf2": "70e199b803a751e15e55473582244f2c8e0d79b4b8a7a84a49373f35a405765e" + }, + "image": "test_cond.elf", + "image_sha256": "c8b8fdaf6f0f7e28977986a43056af95966ab3ab2fb86bdbd30b6650337071eb", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_cond.log", + "outcome": "passed", + "started": "2026-11-13T05:38:26Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_crash.uf2": "e4307ce3873ed38ae2b5e4e50524260c0028ac707afe938f2b2c277a618c151a" + }, + "image": "test_crash.elf", + "image_sha256": "c3230fa1a8dcaa41aafb4d9d9beb5f450d8338f837f15b5b4d9ac7a527386b93", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_crash.log", + "outcome": "passed", + "started": "2026-11-13T05:41:24Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_hw.uf2": "76609cb550965b89a4f04ce0dfafaad18a5318168cef70447f8779ea9dd19313" + }, + "image": "test_crash_hw.elf", + "image_sha256": "65f7143807182575836ae905d99a6d26750d0bb47f65c2b02d125eefa02e875b", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_crash_hw.log", + "outcome": "passed", + "started": "2026-11-13T05:41:27Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_reset.uf2": "3288a4327ef162fbbfee93e903d36ff4d98869a2bf194ef58d383301c2b3145c" + }, + "image": "test_crash_reset.elf", + "image_sha256": "8efe9d6707fc79ce70cb4270532b11dcdb6927fd2eb9aaf0b0f80405d5a1e9b6", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_crash_reset.log", + "outcome": "passed", + "started": "2026-11-13T05:41:25Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_debug_descriptor.uf2": "62f79a791d3152cd126618687d3fc965c826960c9acfbc04ea164ea425c028fe" + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "bd8b1c9d0cff9567c939d52113c5bdd46f2e70e9963be7c37618f8637e0393a6", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_debug_descriptor.log", + "outcome": "passed", + "started": "2026-11-13T05:41:31Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_device.uf2": "00da31bf8c123e20245ff43b380f091b9fc88b787c9f9934809aa128d5be39e0" + }, + "image": "test_device.elf", + "image_sha256": "e30f5ddd58c786ffdd58515d68cee0ebcf99e0d5958e39420a88b0dcfb7d1d53", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "log": "test_device.log", + "outcome": "passed", + "started": "2026-11-13T05:38:39Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_dma.uf2": "0da54e553f167d11a25d9b8bfe79fa9c3b7d1f1dfe49e52f6c12ee860972925a" + }, + "image": "test_dma.elf", + "image_sha256": "2339e6d4f54b80b1d2264881c7589bb36857dfcac422337efbfbec6f3222bd3d", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_dma.log", + "outcome": "passed", + "started": "2026-11-13T05:38:49Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_entropy.uf2": "c05ca6d9de37247649c39bd364f0884354e3033b07af98a1fb869b5ce300e81c" + }, + "image": "test_entropy.elf", + "image_sha256": "9374be6b9c7367405a2df020957d1fa11eeefcbbbfe172113debe8b43d60cea4", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_entropy.log", + "outcome": "passed", + "started": "2026-11-13T05:38:51Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_entropy_board.uf2": "360e22cb3503d3b4c7707fd13c2fd44f9bd43d380e2c72b6a2b9f4d0dd584d47" + }, + "image": "test_entropy_board.elf", + "image_sha256": "a7e82e035f1d1996f83b55e47f79df2a8042fec644ac4bb23061cf559dd6bb9e", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_entropy_board.log", + "outcome": "passed", + "started": "2026-11-13T05:38:53Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_event.uf2": "3b7701d9c5b6102ab2cb6b6ce0a2c9691a96255fd46e04242166f568dbccd03a" + }, + "image": "test_event.elf", + "image_sha256": "7bd9ba6e0bd6f767cea8a6efef81c6310ec38764d80e6961f4d5d25e9217bf44", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_event.log", + "outcome": "passed", + "started": "2026-11-13T05:38:24Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_fault.uf2": "6f562b8467f7451b71e69cdf18b9b598f61ea4c70142e9e26a6229d8325f56b2" + }, + "image": "test_fault.elf", + "image_sha256": "f2f9cd113d2d8e6d5ad9cd733c7cb800174283aad132fd795df5dada9f4fa8cc", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_fault.log", + "outcome": "passed", + "started": "2026-11-13T05:37:58Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_first_execution.uf2": "f887b9afba507495ab94847033e92076053dfcf5ce11e21b443854e6883fe8d8" + }, + "image": "test_first_execution.elf", + "image_sha256": "d06acd9a2a7a874f9bf0dbdfb82cce73765eefef7a1e23d2c533b80a6db6f92a", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_first_execution.log", + "outcome": "passed", + "started": "2026-11-13T05:41:22Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_flash.uf2": "3d2d1fed47631933664cb7011d46f67bcb6ce61549d2dc842c8d082c76c4be92" + }, + "image": "test_flash.elf", + "image_sha256": "e8d2918bc5d792c63032b68ef229d9ab308fce70be0df09e0beab655180f7749", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_flash.log", + "outcome": "passed", + "started": "2026-11-13T05:40:57Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_flash_board.uf2": "bfff671dd79b57358a0c2cfb59cf10f713f5a36fd43b4121d0d25d2a407f27a3" + }, + "image": "test_flash_board.elf", + "image_sha256": "b46f69f4536a313a7d5353d07174ce97fcddeb2541b6dbe5a257fdae7c45300f", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_flash_board.log", + "outcome": "passed", + "started": "2026-11-13T05:40:59Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_fpu.uf2": "3303d710bcf76d4bb0fad6da841b987481f1c32b4467225fea5eb41250f78591" + }, + "image": "test_fpu.elf", + "image_sha256": "4b7978ee891ea064c28b31ec845ffda1c372d0e595934f5eb5e013b0f73193d9", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_fpu.log", + "outcome": "passed", + "started": "2026-11-13T05:41:33Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_frame.uf2": "7117f1ea327411bab56cd2a8ac4c41e450ce57d15ffff433f6b0b3814d6a0208" + }, + "image": "test_frame.elf", + "image_sha256": "3532d4475a86bb81bce919a444d8a6acf037c3634a9339685fa5e04501cee0cb", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_frame.log", + "outcome": "passed", + "started": "2026-11-13T05:38:35Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 10, + "flashed_sha256": { + "test_gpio.uf2": "32dcb56e4ab71039510ac0a04f0496e467753cb4c64de0dae6f9df2faedbcc12" + }, + "image": "test_gpio.elf", + "image_sha256": "f0ff4fa601dbf0bf7bc3be5383f0595f29aa6173798eefdfbe55013e2e86eca4", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_gpio.log", + "outcome": "passed", + "started": "2026-11-13T05:38:47Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 12, + "flashed_sha256": { + "test_i2c.uf2": "7c8b1c5a4b91fb62164d9e8127097c12d935ce752d9b193e836cb5a330c4fa3d" + }, + "image": "test_i2c.elf", + "image_sha256": "22f658a7053025157eefd98b15e3d201b8c4fbb8ed53aa40b6d8b91fbcfc76c3", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_i2c.log", + "outcome": "passed", + "started": "2026-11-13T05:41:13Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_i2c_loop.uf2": "d56bceeb85264e9dab8c479aef52f95443ebd004d11c3423cd29fbe2968f1f5f" + }, + "image": "test_i2c_loop.elf", + "image_sha256": "5982edf3e236c5446b549c6cf706baa125a265a7204cb326a4e008e2fab61651", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_i2c_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:41:15Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_irq.uf2": "ae1e9cc9a12018c89946cf70755a85b8ab23f51f4243c2e84b5751b930d26db5" + }, + "image": "test_irq.elf", + "image_sha256": "22d2e76982fa0bed63a894efa90537af8b323df76fdde3867523de411fa94932", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:38:02Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_irq_priority.uf2": "3866422c4cbaab960b2f843922862222f4748c44643b24ad82cff84dab39875f" + }, + "image": "test_irq_priority.elf", + "image_sha256": "a4c1f89e90736c4e1c42ef7c635479cd773b38aabce747aa49e8b53b7780aa68", + "isr_stack": { + "size": 2048, + "used": 276 + }, + "log": "test_irq_priority.log", + "outcome": "passed", + "started": "2026-11-13T05:38:03Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_isr_stack.uf2": "f407d537ad3dd51dc8077a2477214c9139fce5e7b15e75ed8d8e93388f24df68" + }, + "image": "test_isr_stack.elf", + "image_sha256": "f19eb8775b333cb30477524d64579af70144f72ff0cfa5919200d2662668fdf0", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_isr_stack.log", + "outcome": "passed", + "started": "2026-11-13T05:38:06Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_log.uf2": "da37cc06f8129cb2106409a55c32c6f13650556d0cd62f05ca122969edc61d72" + }, + "image": "test_log.elf", + "image_sha256": "876beb8ce1fa273ff1679551726c1f039090b913bad71616d37adf8e3b8387b6", + "isr_stack": { + "size": 2048, + "used": 204 + }, + "log": "test_log.log", + "outcome": "passed", + "started": "2026-11-13T05:38:37Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_msgq.uf2": "d0e985b5d8f34db45d04c62ffc8a75766c10216cd27a01a8c70ee70eeb42cb80" + }, + "image": "test_msgq.elf", + "image_sha256": "30ae1ac59152845f03d20b5ed78ad7d370ef4dbca5f0424353188820d4c90e9f", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_msgq.log", + "outcome": "passed", + "started": "2026-11-13T05:38:28Z" + }, + { + "bench": [], + "cases": 15, + "cases_passed": 15, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_mutex.uf2": "d324cd971ec678a1c6088917970cfbadbc27e89cde1927cc5c31e6f2a8c3c871" + }, + "image": "test_mutex.elf", + "image_sha256": "b656a86d4f2712b05cc3f6034718aa337c558550ff9759c74f00b9cd9f9e2112", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_mutex.log", + "outcome": "passed", + "started": "2026-11-13T05:38:22Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_notify.uf2": "1e6a4a34d9eadf9ee3d2ec5c0b7d570f190419cd74f9ea26a5a2f26d1bd05ad8" + }, + "image": "test_notify.elf", + "image_sha256": "d2832c9296ef1a0842805a718ed96f4f65aeef0a2b577dcf460d676cdaa5b1b7", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_notify.log", + "outcome": "passed", + "started": "2026-11-13T05:38:17Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_rtc.uf2": "96b32b20c094c1e737deee5b3028f42d2f5e4d0dc2f78991a658c195c73a7211" + }, + "image": "test_rtc.elf", + "image_sha256": "fdd98d31cc64df055100511b15965085bdeaf41dd74aae0549888aff8e1a4ebd", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_rtc.log", + "outcome": "passed", + "started": "2026-11-13T05:40:50Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_rtc_board.uf2": "3f0eda624495f59a4cf68d72afde380e51f50d403bb4d660a8d6ae01083c4529" + }, + "image": "test_rtc_board.elf", + "image_sha256": "dda6bb821795355a7e5bf8486f8d5875ad9a97482d2780f8395a5543c4eb3f3a", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_rtc_board.log", + "outcome": "passed", + "started": "2026-11-13T05:40:52Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_sched.uf2": "30a00297bbf3d33fb1659c88fa47684184c4e0771167eb861fd94eab2751a42e" + }, + "image": "test_sched.elf", + "image_sha256": "c22f078b60b77560edd48ffe49572e7a9ccb51e5935d0f946401251bcdabecde", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_sched.log", + "outcome": "passed", + "started": "2026-11-13T05:37:59Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_sem.uf2": "6f18423fd668434c566bdede280ca2f6039bc045b048cbb1a2909da07648e393" + }, + "image": "test_sem.elf", + "image_sha256": "5edab6a7fbcf716f93046980dcad6aea6f602815ec12d6aad3cfaf05e321a955", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_sem.log", + "outcome": "passed", + "started": "2026-11-13T05:38:20Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_smoke.uf2": "735d46644c563df5c13ab728f9563da7c017f8e9f3df9412bad2176a9b638fef" + }, + "image": "test_smoke.elf", + "image_sha256": "8b0a81b3c1504a50059003c2c628f5852c7523363f32099bac319687aad68add", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_smoke.log", + "outcome": "passed", + "started": "2026-11-13T05:37:56Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_spi.uf2": "a9e4d4565425656201a9632ce5db9b88ea4f27587975013e316a0fda6261dbb7" + }, + "image": "test_spi.elf", + "image_sha256": "b9afc02f37255def25d0c1816c2ae371ee78e465531158d7ceec544137d1f779", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_spi.log", + "outcome": "passed", + "started": "2026-11-13T05:41:17Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_spi_loop.uf2": "830d1f7e61e2b2157fc4829e8cd10f4d7b10e2b25f06fc046271773501115fb3" + }, + "image": "test_spi_loop.elf", + "image_sha256": "582dfcc611c3917daa31050895f8080cc4c93b0418d89362bbf6f1a15dfd5c67", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_spi_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:41:19Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_stack_limit.uf2": "b3cd2160ec9e328bbeb80ed7fd97e6d9b83bfc014af1adc52315dc20a03cd0a6" + }, + "image": "test_stack_limit.elf", + "image_sha256": "a58bb24b8bf9bd856545bafeba408e124024ff93d9030756b4b7c4d2ddef6bb6", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_stack_limit.log", + "outcome": "passed", + "started": "2026-11-13T05:41:29Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_thread.uf2": "404df19542fa6543ea67f5243ac710e99d26677cf0004e85e06b8e74c9d359d7" + }, + "image": "test_thread.elf", + "image_sha256": "07b382a911a01b3b2bcb84469194c1478ffdbb7c428560b747e03d1814fcf3a2", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_thread.log", + "outcome": "passed", + "started": "2026-11-13T05:38:07Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_thread_identity.uf2": "cbbd99283832ed2dd321dd564dedd1642d07c91a3c4eb089586f92422afcd7dc" + }, + "image": "test_thread_identity.elf", + "image_sha256": "8420b49b1d3dbf774e32b1d57807cc179f7ada0806bbdb587f183afe1cbd44dd", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_thread_identity.log", + "outcome": "passed", + "started": "2026-11-13T05:38:12Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_thread_join.uf2": "db02d1cfcf824a9e83218e9afa881f1fed10bf251f5f7e84094dabe0a5583b2f" + }, + "image": "test_thread_join.elf", + "image_sha256": "715695c9b7074b21f28345a89e3c71a0228f89e3903978aa4e05f2a6a091ef87", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_thread_join.log", + "outcome": "passed", + "started": "2026-11-13T05:38:10Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_time.uf2": "543238cb62a12be6c9ad0e069b36a20a80012ff9172707b209d2940af993709b" + }, + "image": "test_time.elf", + "image_sha256": "cabd995e3c409e7e11c31ca63bc437364e3a2a5e8e58094e1443f0be47ab2bae", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_time.log", + "outcome": "passed", + "started": "2026-11-13T05:38:14Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_timer.uf2": "5da7821af1ac0d4bcdd6b2f4b4d129fddde79354bccdafbcea33cd0c2117dab0" + }, + "image": "test_timer.elf", + "image_sha256": "30f47b94a231387d3c0c8e9342bc7533155d61e308d1381f6202ff7faa1c3390", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_timer.log", + "outcome": "passed", + "started": "2026-11-13T05:38:33Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_uart.uf2": "13362e6d96d130667c0f57b1ebf726dc2fc48edc1d6d38ae3c6e51536f4f361b" + }, + "image": "test_uart.elf", + "image_sha256": "b2dada8bc79f90e494200765166507529dce10257bbc4be1c635929cd1a482aa", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_uart.log", + "outcome": "passed", + "started": "2026-11-13T05:38:41Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_board.uf2": "867f2872df9cc392c0367585c0e9a483bf3a8f16483f269938cdb4b8c0f683a6" + }, + "image": "test_uart_board.elf", + "image_sha256": "7fcd495388a1bea7d9e4191a73b897c78e817a59ef3b833474bd5ec67149c3d8", + "isr_stack": { + "size": 2048, + "used": 200 + }, + "log": "test_uart_board.log", + "outcome": "passed", + "started": "2026-11-13T05:38:43Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_loop.uf2": "18b1a261b3cb04730df91d3b35d2a44b423836dbc63b0875dcdcf1d67f1fb672" + }, + "image": "test_uart_loop.elf", + "image_sha256": "0cf27356bb71288911e8059becd07d40fd903ce0017809926ec903ce562bec82", + "isr_stack": { + "size": 2048, + "used": 200 + }, + "log": "test_uart_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:38:45Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wallclock.uf2": "3d222c1f93b851c0e83fcc0ef79c6febeb05e33ba73b480e01927fd3ff812d41" + }, + "image": "test_wallclock.elf", + "image_sha256": "462dab3b90a75b5b48665efb2ebd42465d99b9e28705e7f7c108d102c005411a", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_wallclock.log", + "outcome": "passed", + "started": "2026-11-13T05:38:16Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_wdog.uf2": "5747cbf9eaddf8361958bad14ebf22a959831fc40b952e5072fb6a3b4c135d9b" + }, + "image": "test_wdog.elf", + "image_sha256": "393ada9ecb38140bdb660fe417959c3f471d3b05e4ea938f2e84fc19f9aa9e41", + "isr_stack": { + "size": 2048, + "used": 280 + }, + "log": "test_wdog.log", + "outcome": "passed", + "started": "2026-11-13T05:41:05Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdog_board.uf2": "cc7b4b7f14e01cf6891f917b5f833bf56451176ce133ab6599ff03e543fa4ba8" + }, + "image": "test_wdog_board.elf", + "image_sha256": "23eb667e7ebb15dbd42c8325ff23b28cc57986681335bd218fea910856dd8b17", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_wdog_board.log", + "outcome": "passed", + "started": "2026-11-13T05:41:10Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_wdt.uf2": "710b0c04c3aa2deab11febc6c668161705888d5a9dad82b97ba383491d4698d9" + }, + "image": "test_wdt.elf", + "image_sha256": "7716889f5d71a5728f172771aa45f012ac0db08e74427991ffeccafaf06a3c3c", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_wdt.log", + "outcome": "passed", + "started": "2026-11-13T05:41:04Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdt_board.uf2": "ad4e483f58339d9898dd941c57bc34f4cc6f855d5a5b80688d41628839f1a7fc" + }, + "image": "test_wdt_board.elf", + "image_sha256": "11e7f1f3d94adad79c47e64922ba7996d2a5813a2159e054e489ffb166b4997e", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "log": "test_wdt_board.log", + "outcome": "passed", + "started": "2026-11-13T05:41:08Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 6, + "flashed_sha256": { + "test_workq.uf2": "a34d0d70e96ee541d937ecc3dc418574c8f10ddbe868f03d8cea9ef17f6c9fc0" + }, + "image": "test_workq.elf", + "image_sha256": "1173072cd38f701efa119aee51555d35871b03a294c2e08bca225ba281934d3b", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "log": "test_workq.log", + "outcome": "passed", + "started": "2026-11-13T05:38:30Z" + } + ], + "isr_stack_max_used": 280, + "passed": 51, + "preset": "cm33-pico2w-hil", + "total": 51 +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.json new file mode 100644 index 00000000..7e7eb8dd --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.json @@ -0,0 +1,109 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 17, + "name": "cond_signal_wakes_one_waiter_which_owns_the_mutex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "cond_broadcast_wakes_all_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "cond_signal_is_not_stored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_relock_after_timeout_waits_for_the_mutex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "cond_cancel_returns_with_the_mutex_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "cond_destroy_aborts_waiters_which_relock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "cond_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_wait_requires_single_ownership", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "cond_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "cond_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:28Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_cond" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_cond.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_cond.uf2": "70e199b803a751e15e55473582244f2c8e0d79b4b8a7a84a49373f35a405765e" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_cond.elf", + "image_sha256": "c8b8fdaf6f0f7e28977986a43056af95966ab3ab2fb86bdbd30b6650337071eb", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:26Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.log new file mode 100644 index 00000000..19d1ddac --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_cond.log @@ -0,0 +1,48 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_cond.elf sha256 c8b8fdaf6f0f7e28977986a43056af95966ab3ab2fb86bdbd30b6650337071eb +EVIDENCE v1 suite=test_cond config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST cond_signal_wakes_one_waiter_which_owns_the_mutex + -> ok + req KRN-SYNC-030 KRN-WAIT-001 +CASE cond_signal_wakes_one_waiter_which_owns_the_mutex outcome=passed asserts=17 skips=0 +TEST cond_broadcast_wakes_all_in_priority_order + -> ok + req KRN-SYNC-030 KRN-WAIT-013 +CASE cond_broadcast_wakes_all_in_priority_order outcome=passed asserts=18 skips=0 +TEST cond_signal_is_not_stored + -> ok + req KRN-SYNC-030 +CASE cond_signal_is_not_stored outcome=passed asserts=13 skips=0 +TEST cond_relock_after_timeout_waits_for_the_mutex + -> ok + req KRN-SYNC-030 +CASE cond_relock_after_timeout_waits_for_the_mutex outcome=passed asserts=12 skips=0 +TEST cond_cancel_returns_with_the_mutex_owned + -> ok + req KRN-SYNC-030 KRN-WAIT-017 +CASE cond_cancel_returns_with_the_mutex_owned outcome=passed asserts=10 skips=0 +TEST cond_destroy_aborts_waiters_which_relock + -> ok + req KRN-OBJ-001 KRN-SYNC-030 +CASE cond_destroy_aborts_waiters_which_relock outcome=passed asserts=9 skips=0 +TEST cond_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE cond_destroy_with_waiters_is_misuse outcome=passed asserts=11 skips=0 +TEST cond_wait_requires_single_ownership + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-030 API-013 +CASE cond_wait_requires_single_ownership outcome=passed asserts=12 skips=0 +TEST cond_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE cond_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST cond_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE cond_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=188 +10 tests, 0 failed, 0 skipped, 25 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.json new file mode 100644 index 00000000..5b995cb1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.json @@ -0,0 +1,67 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 38, + "name": "crash_record_round_trip", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "crash_record_corruption_is_ignored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "crash_record_get_refuses_null", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:25Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_crash" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_crash.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_crash.uf2": "e4307ce3873ed38ae2b5e4e50524260c0028ac707afe938f2b2c277a618c151a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash.elf", + "image_sha256": "c3230fa1a8dcaa41aafb4d9d9beb5f450d8338f837f15b5b4d9ac7a527386b93", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:24Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.log new file mode 100644 index 00000000..e9c856ca --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash.log @@ -0,0 +1,19 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash.elf sha256 c3230fa1a8dcaa41aafb4d9d9beb5f450d8338f837f15b5b4d9ac7a527386b93 +EVIDENCE v1 suite=test_crash config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_round_trip +EMB_CRASH 454d424301005c005cdf07599a09c881e03a94f94c2d8c8389d12ee5302e322e30000000070000000000000001000000050202012900000003000000341200007856000000000000bc7a0000000000000000000000000000b35d6299 + -> ok + req OBS-016 API-017 +CASE crash_record_round_trip outcome=passed asserts=38 skips=0 +TEST crash_record_corruption_is_ignored + -> ok + req OBS-016 +CASE crash_record_corruption_is_ignored outcome=passed asserts=6 skips=0 +TEST crash_record_get_refuses_null + fault checks that reset the board: 1 + -> ok + req OBS-016 API-015 +CASE crash_record_get_refuses_null outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=188 +3 tests, 0 failed, 0 skipped, 11 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.json new file mode 100644 index 00000000..176fd952 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 9, + "name": "crash_record_keeps_a_hardware_fault", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:29Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_crash_hw" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_crash_hw.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_crash_hw.uf2": "76609cb550965b89a4f04ce0dfafaad18a5318168cef70447f8779ea9dd19313" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_hw.elf", + "image_sha256": "65f7143807182575836ae905d99a6d26750d0bb47f65c2b02d125eefa02e875b", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:27Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.log new file mode 100644 index 00000000..3fb0ce04 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_hw.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_hw.elf sha256 65f7143807182575836ae905d99a6d26750d0bb47f65c2b02d125eefa02e875b +EVIDENCE v1 suite=test_crash_hw config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_keeps_a_hardware_fault +crash_record_keeps_a_hardware_fault: first boot, trapping +EVIDENCE v1 suite=test_crash_hw config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_keeps_a_hardware_fault +EMB_CRASH 454d424301008c005cdf07599a09c881e03a94f94c2d8c8389d12ee5302e322e300000000d00000000000000020000000a000600000000000000000000000100420300104303001028250020000000000000000004080000000001000000000034ed00e038ed00e045030010980b0020fb8001000000007c781500204303001042030010000000614aec594c + -> ok + req OBS-016 KRN-IRQ-030 +CASE crash_record_keeps_a_hardware_fault outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=188 +1 tests, 0 failed, 0 skipped, 45 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.json new file mode 100644 index 00000000..353fcdd1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "crash_record_survives_reset", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:27Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_crash_reset" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_crash_reset.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_crash_reset.uf2": "3288a4327ef162fbbfee93e903d36ff4d98869a2bf194ef58d383301c2b3145c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_reset.elf", + "image_sha256": "8efe9d6707fc79ce70cb4270532b11dcdb6927fd2eb9aaf0b0f80405d5a1e9b6", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:25Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.log new file mode 100644 index 00000000..b5e168fb --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_crash_reset.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_reset.elf sha256 8efe9d6707fc79ce70cb4270532b11dcdb6927fd2eb9aaf0b0f80405d5a1e9b6 +EVIDENCE v1 suite=test_crash_reset config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_survives_reset +crash_record_survives_reset: first boot, faulting +EVIDENCE v1 suite=test_crash_reset config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_survives_reset +EMB_CRASH 454d424301005c005cdf07599a09c881e03a94f94c2d8c8389d12ee5302e322e300000000c00000000000000020000000b00ed5e0000000000000000000000004d0300100000000000000000000000000000000000000000a69a5182 + -> ok + req OBS-016 KRN-IRQ-030 ARCH-AVR-008 +CASE crash_record_survives_reset outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=188 +1 tests, 0 failed, 0 skipped, 37 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.json new file mode 100644 index 00000000..00533fcd --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 12, + "name": "debug_descriptor_header", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "debug_descriptor_finds_the_running_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "debug_descriptor_isr_stack", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 82, + "name": "debug_descriptor_reads_thread_states", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:33Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_debug_descriptor" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_debug_descriptor.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_debug_descriptor.uf2": "62f79a791d3152cd126618687d3fc965c826960c9acfbc04ea164ea425c028fe" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "bd8b1c9d0cff9567c939d52113c5bdd46f2e70e9963be7c37618f8637e0393a6", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:31Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.log new file mode 100644 index 00000000..eac9dc6e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_debug_descriptor.log @@ -0,0 +1,21 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_debug_descriptor.elf sha256 bd8b1c9d0cff9567c939d52113c5bdd46f2e70e9963be7c37618f8637e0393a6 +EVIDENCE v1 suite=test_debug_descriptor config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST debug_descriptor_header + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_header outcome=passed asserts=12 skips=0 +TEST debug_descriptor_finds_the_running_thread + -> ok + req OBS-008 +CASE debug_descriptor_finds_the_running_thread outcome=passed asserts=7 skips=0 +TEST debug_descriptor_isr_stack + -> ok + req PORT-012 +CASE debug_descriptor_isr_stack outcome=passed asserts=2 skips=0 +TEST debug_descriptor_reads_thread_states + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_reads_thread_states outcome=passed asserts=82 skips=0 +ISR_STACK size=2048 used=188 +4 tests, 0 failed, 0 skipped, 56 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.json new file mode 100644 index 00000000..a556fb56 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.json @@ -0,0 +1,145 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 10, + "name": "device_init_reaches_ready_or_failed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "device_on_a_failed_dependency_fails_without_its_driver", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "device_list_initializes_past_a_failure", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "device_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "drv_submit_refused_unless_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "drv_request_completes_from_the_interrupt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "drv_completion_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_queue_is_first_in_first_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_lanes_run_independently", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_cancel_queued_and_running_requests_complete_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_wait_returns_the_result_or_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 33, + "name": "device_board_devices_ready_in_dependency_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 23, + "name": "device_optional_operations", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "drv_setters_ignore_a_missing_request", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "device_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 47, + "name": "drv_status_codes_are_named_in_their_ranges", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:41Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_device" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_device.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_device.uf2": "00da31bf8c123e20245ff43b380f091b9fc88b787c9f9934809aa128d5be39e0" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_device.elf", + "image_sha256": "e30f5ddd58c786ffdd58515d68cee0ebcf99e0d5958e39420a88b0dcfb7d1d53", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:39Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.log new file mode 100644 index 00000000..6b95c942 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_device.log @@ -0,0 +1,71 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_device.elf sha256 e30f5ddd58c786ffdd58515d68cee0ebcf99e0d5958e39420a88b0dcfb7d1d53 +EVIDENCE v1 suite=test_device config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST device_init_reaches_ready_or_failed + -> ok + req DRV-002 DRV-003 +CASE device_init_reaches_ready_or_failed outcome=passed asserts=10 skips=0 +TEST device_on_a_failed_dependency_fails_without_its_driver + -> ok + req DRV-003 +CASE device_on_a_failed_dependency_fails_without_its_driver outcome=passed asserts=5 skips=0 +TEST device_list_initializes_past_a_failure + -> ok + req DRV-001 DRV-003 +CASE device_list_initializes_past_a_failure outcome=passed asserts=4 skips=0 +TEST device_suspend_and_resume + -> ok + req DRV-002 PWR-002 +CASE device_suspend_and_resume outcome=passed asserts=10 skips=0 +TEST drv_submit_refused_unless_ready + -> ok + req DRV-003 +CASE drv_submit_refused_unless_ready outcome=passed asserts=2 skips=0 +TEST drv_request_completes_from_the_interrupt + -> ok + req DRV-004 DRV-005 +CASE drv_request_completes_from_the_interrupt outcome=passed asserts=6 skips=0 +TEST drv_completion_targets + -> ok + req DRV-005 +CASE drv_completion_targets outcome=passed asserts=13 skips=0 +TEST drv_queue_is_first_in_first_out + -> ok + req DRV-004 +CASE drv_queue_is_first_in_first_out outcome=passed asserts=8 skips=0 +TEST drv_lanes_run_independently + fault checks that reset the board: 1 + -> ok + req DRV-004 DRV-006 +CASE drv_lanes_run_independently outcome=passed asserts=15 skips=0 +TEST drv_cancel_queued_and_running_requests_complete_once + -> ok + req DRV-006 +CASE drv_cancel_queued_and_running_requests_complete_once outcome=passed asserts=15 skips=0 +TEST drv_wait_returns_the_result_or_times_out + -> ok + req DRV-004 DRV-006 +CASE drv_wait_returns_the_result_or_times_out outcome=passed asserts=8 skips=0 +TEST device_board_devices_ready_in_dependency_order + -> ok + req DRV-001 DRV-002 +CASE device_board_devices_ready_in_dependency_order outcome=passed asserts=33 skips=0 +TEST device_optional_operations + -> ok + req DRV-002 DRV-006 PWR-002 +CASE device_optional_operations outcome=passed asserts=23 skips=0 +TEST drv_setters_ignore_a_missing_request + -> ok + req DRV-005 +CASE drv_setters_ignore_a_missing_request outcome=passed asserts=3 skips=0 +TEST device_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-002 DRV-004 +CASE device_misuse_faults outcome=passed asserts=11 skips=0 +TEST drv_status_codes_are_named_in_their_ranges + -> ok + req DRV-008 +CASE drv_status_codes_are_named_in_their_ranges outcome=passed asserts=47 skips=0 +ISR_STACK size=2048 used=228 +16 tests, 0 failed, 0 skipped, 24 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.json new file mode 100644 index 00000000..5d5b22d1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 10, + "name": "dma_job_starts_and_ends", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dma_stop_gives_what_moved", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "dma_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dma_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:51Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_dma" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_dma.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_dma.uf2": "0da54e553f167d11a25d9b8bfe79fa9c3b7d1f1dfe49e52f6c12ee860972925a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_dma.elf", + "image_sha256": "2339e6d4f54b80b1d2264881c7589bb36857dfcac422337efbfbec6f3222bd3d", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:49Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.log new file mode 100644 index 00000000..21ae76c5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_dma.log @@ -0,0 +1,22 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_dma.elf sha256 2339e6d4f54b80b1d2264881c7589bb36857dfcac422337efbfbec6f3222bd3d +EVIDENCE v1 suite=test_dma config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST dma_job_starts_and_ends + -> ok + req DRV-004 +CASE dma_job_starts_and_ends outcome=passed asserts=10 skips=0 +TEST dma_stop_gives_what_moved + -> ok + req DRV-006 +CASE dma_stop_gives_what_moved outcome=passed asserts=7 skips=0 +TEST dma_refusals + -> ok + req DRV-004 +CASE dma_refusals outcome=passed asserts=5 skips=0 +TEST dma_misuse_faults + fault checks that reset the board: 8 + -> ok + req DRV-004 +CASE dma_misuse_faults outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=188 +4 tests, 0 failed, 0 skipped, 10 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.json new file mode 100644 index 00000000..3e77e304 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "entropy_conditioning_is_sha256", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "entropy_read_conditions_twice_the_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 54, + "name": "entropy_read_raw_assembles_blocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "entropy_health_failure_delivers_none_of_its_block", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "entropy_timeout_keeps_what_was_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "entropy_board_source_or_its_absence", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "entropy_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:53Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_entropy" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_entropy.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_entropy.uf2": "c05ca6d9de37247649c39bd364f0884354e3033b07af98a1fb869b5ce300e81c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_entropy.elf", + "image_sha256": "9374be6b9c7367405a2df020957d1fa11eeefcbbbfe172113debe8b43d60cea4", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:51Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.log new file mode 100644 index 00000000..3d0cfd00 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy.log @@ -0,0 +1,34 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_entropy.elf sha256 9374be6b9c7367405a2df020957d1fa11eeefcbbbfe172113debe8b43d60cea4 +EVIDENCE v1 suite=test_entropy config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST entropy_conditioning_is_sha256 + -> ok + req DRV-001 +CASE entropy_conditioning_is_sha256 outcome=passed asserts=3 skips=0 +TEST entropy_read_conditions_twice_the_bytes + -> ok + req DRV-001 +CASE entropy_read_conditions_twice_the_bytes outcome=passed asserts=6 skips=0 +TEST entropy_read_raw_assembles_blocks + -> ok + req DRV-001 +CASE entropy_read_raw_assembles_blocks outcome=passed asserts=54 skips=0 +TEST entropy_health_failure_delivers_none_of_its_block + -> ok + req DRV-001 +CASE entropy_health_failure_delivers_none_of_its_block outcome=passed asserts=7 skips=0 +TEST entropy_timeout_keeps_what_was_read + -> ok + req DRV-001 +CASE entropy_timeout_keeps_what_was_read outcome=passed asserts=4 skips=0 +TEST entropy_board_source_or_its_absence + -> ok + req SEC-012 +CASE entropy_board_source_or_its_absence outcome=passed asserts=4 skips=0 +TEST entropy_misuse_faults + fault checks that reset the board: 4 + -> ok + req DRV-001 +CASE entropy_misuse_faults outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=188 +7 tests, 0 failed, 0 skipped, 10 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.json new file mode 100644 index 00000000..d7ad6745 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 1039, + "name": "entropy_board_a_mebibyte_passes_the_sanity_checks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 259, + "name": "entropy_board_the_raw_source_has_the_entropy_conditioning_needs", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:40:50Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_entropy_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_entropy_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_entropy_board.uf2": "360e22cb3503d3b4c7707fd13c2fd44f9bd43d380e2c72b6a2b9f4d0dd584d47" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_entropy_board.elf", + "image_sha256": "a7e82e035f1d1996f83b55e47f79df2a8042fec644ac4bb23061cf559dd6bb9e", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:53Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.log new file mode 100644 index 00000000..7f2dda2a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_entropy_board.log @@ -0,0 +1,2065 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_entropy_board.elf sha256 a7e82e035f1d1996f83b55e47f79df2a8042fec644ac4bb23061cf559dd6bb9e +EVIDENCE v1 suite=test_entropy_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST entropy_board_a_mebibyte_passes_the_sanity_checks +ENTROPY 7f9ac4cbf3c57dd999dc27c3a8916235aaf033b0a1a1731b18cc47d6e9c1e738 +ENTROPY 4faadeccbf80b374995968f25568c262b7cf42d6702cf5e902588d0483af6f38 +ENTROPY 4008786a1d92c15f93f1f7176e4e6e416b9f71d14fa257c0840c5f389d3a495c +ENTROPY 61e75269a676ca7c78fa4fcf54b85b5ac53b1eb22144b0283e2ff0d4e8e274c8 +ENTROPY 82d5c2aeff58cf77d5b674cecc594ab51fdb0809602a6cd0395933ba97e0fdc6 +ENTROPY 07a07febc58f4e788d0b052f321a4162566d689ff8c3d6d53a19d2f86fe32490 +ENTROPY b9b9ddff5251ab09ba3e262702620a98e0c2fe839ccb8cb7e0b8216542522b3b +ENTROPY 5a4f434b6f4a18ff44e68e2285cafd470080e45d113af3f51c78b72c842b940f +ENTROPY 23f068a7a713b3f4f4f71c4675b1530a3c44b8873ea9bde57e04eefef3ff7608 +ENTROPY b417f5e987edfa5de0cf4a4cbb9ab0845f1bcb9f35a90b51d86d1e14029f0bf0 +ENTROPY 3c27620ae19046eefd8f4280a92443c6625db8fabb81b0311d0e398d77248efe +ENTROPY bda269f2e4de13dfe2feed445abde4f96214febbacd981ed5f62fcd88965c8e7 +ENTROPY fb686e6238d7675ec0011ccd2a1036074db06d2d78dbd70df983e8ec381a6e7f +ENTROPY 41e5336d8de3b4c076aee495c174436fc6855340f7cb495b03e61e4a5614ae42 +ENTROPY a3e8f3a74860b35c51d8c3ad2d9fade2e8a97edb151689421890289a82bc6cce +ENTROPY 0124c367b1fcec55c5ea8f5763623b2a56df95a26d6ed19d64d32b1bbd5b4c52 +ENTROPY ff4b14c143e500a4169388975d1e8a5038e2bf689a1b927c2133a96a80d4b14e +ENTROPY ddd4496e92ff7daa6efd70bc1c2079377cfe2eaa5f8118526267c9133449b77f +ENTROPY 88fdb52c0913d3cd5119c43951b3cb5ad07410a6d795941674cbe25e9ca8f8fe +ENTROPY 9f6d8ab84da3e7e946e5a42d27c218a3448e82f9468732762537eee8caade2d0 +ENTROPY 52912c1a61df03af8ed39701e5d48edf08ffd3626e1855df42497e72f65c79af +ENTROPY 7106b5ab9ec3d412abbe39d7a809dec5917aaf8b751354c52962c81aed30833c +ENTROPY 20b56114d95d4bd14a90cbef7bb53b226e7eaf8e5c61d535982ee4710d28968c +ENTROPY 96f9a88b51dfef27fc028f3b8c5a7402fe8b9ece6f821b96c3f65318c0d31d1f +ENTROPY de8eac3ac23f9b8bb3dc8d7083e93903a31740363847b58faeec3aa7422b4915 +ENTROPY 8aae32b0958d3096b1902ed03f6e3cce48f6d4023eeb98badb6d514ac3fb7ca0 +ENTROPY 0d32eeab261ec1d2cc119b4d65e20cff8fa8deca9be9f599d6c91e663d210ba8 +ENTROPY 0b797cd6c6f3b5bdcd44c1873065b6db60bde4534e13f5a61aaad6801f4501e3 +ENTROPY 782e18f03553f7123f13cf3a3fc996e94bfdb5db48e3a32802f0e8d5fffa061b +ENTROPY cd303a419ce2ffd20351947e71ff182993be5632408dd2d87bac9ca388f80095 +ENTROPY af0a7a3773b047ddd69328065ec41923c378bd21769cd32ae3b1730f6371cb9c +ENTROPY 8ac5be83038a9e4eb1f432d7ae34f331558367c07dd1088c2e8a92968779c5ef +ENTROPY 7dd147d238888f6c46a14e0c2da7856bd914917104d52c75d47cbb090a6d823c +ENTROPY d944d802a659bcfadeb5a61a77b8b5d50455166d0cdb8571596ee1b4ffb471f7 +ENTROPY e317180224c5c80480eda27b4238cee6a11b6862d9ada5d217032f329947c7cd +ENTROPY 4e819652d36b2c8dd51676b10724d7cfcc8d5b28dd686adb1c4cfe13ced5cc27 +ENTROPY 583c35bd5dda4222bf88bac87858b051e0cbe587a17a72e19fcc8c395ba93cb1 +ENTROPY cf4d141b81dab6a7590cc7b9c642a81a4ab66943a75f369fc64c199b6670693b +ENTROPY b58f3709ed9e833300a56c69b2f0599fddaf54ea2312451d02ad0948ce9e9388 +ENTROPY a97da8faf92bd0a8ac85c096c2e5a1c0f1a007a848e453898727ae17380a6788 +ENTROPY dac0f973a376cb1578752d1676045e412e4036f124b552d4a41af1886ebcaf51 +ENTROPY cfefecdf78943adc2b0621afe892cf2c56856b99eee2ec11eb6861062762d21c +ENTROPY 62fbd45f2e96a68b0606d7ea734d4507a1aa13e81fceae3c24ed575c6afe8330 +ENTROPY 2123c170f7f2e797ce5906cd61daab70195a7ccf79da5e66128a9f04ccbc3cfe +ENTROPY e01244d941d42d17618f7a12416117d8c6fd01c570709dc0a08dbd01c653b0b3 +ENTROPY 570561e84c6c37bcac58ad99e3ca47a4ed942faa0feef511dc191a9ba8858376 +ENTROPY 5b94831109509311f92dd33274bcaaf29ef5cc1b08a283e579ee69fc344b1142 +ENTROPY 324a655edde2c1bc6a13bc30abc88e7abcaa0db0ddee17316e5ffd9f99606c31 +ENTROPY 3a57546de0be81937100dcab4722d178b78e7c68d805bdfd5941f56ace8767b6 +ENTROPY e1586ac1a92634e045acf81ba0a87a27e1fe7111048c5ed605e8c32aaf71b94f +ENTROPY 21cc9e98474c293d26792c80aeb9627aaf57c13684e2303fbaad569cfa951307 +ENTROPY 0b291aea0404ede57fc8c235dd0e1bfb573f60f36c2c1c8e2c94bec23182636a +ENTROPY de7295c0729752d4f5582f987fd102fc91c0a6171f8d55a711beaf8d8dcd54d4 +ENTROPY 20110e4d3ad428f2d9e0fb4a5248f258e505f41d5c4638de58d39a03097d9ea2 +ENTROPY 1a8d1fa122abb6d25afed5273d551b7ee4ef5200bbcc865c324b3b8e466f089d +ENTROPY 12a5b4c7f4e62d5eab8324ae50610485eced52189a855eb8599286b19e4f074d +ENTROPY 50ed6df0e1f7583f0491d3e707c881d2befd0ded0eea0b0972d017f711cc91ec +ENTROPY 660886f35a703586d62011d0ea699a19a78515f8d6527f8fd6bc1d4eda385919 +ENTROPY b5db9f7da1421bba48dc6828583becec51b04a8d9c62b9a9672c4d5a72ca1e65 +ENTROPY d98ac4e87bdc34fceb15960bb161f2fd560ce35f5cb2901a0fe34e3477091cfd +ENTROPY 76444f7eae622c166d74cb15ac7070a3579368cff752fa7ead67ed1016c755c7 +ENTROPY b139e1025f0267ee71df1c15aaef13f46e1bfc2064a3f8d96873e2f3168e134e +ENTROPY ca5c28d91cc9c8004c9479284c3839b064afa0a0d9d6b3992cfb90ea80a3c6af +ENTROPY b1a870267899349fb9b8b02782b8cde376e6ddcd59566abf366eac3b86fe131c +ENTROPY 7fa80a4418a1d9a29c31d4a7e58ac0edfe4333b2ad47d7aaac6a892188b8b436 +ENTROPY 705c3c7d97b74058580a30734c2e03c30851103b5dc5ba317611fe4f5aed85c8 +ENTROPY 088a54064279c90ad9098ff5063b80b451fcf58db4bda8fb6e1f93612b88411b +ENTROPY 4786abe6c6f55304ab50ec5d868875e436341ec600b367fd3946eabeb8b39b97 +ENTROPY 3e2a8fffa8eb64fbbc90f6396ac268ed0892dd368601a691eee0c48d9a2ed32d +ENTROPY 5eb632aa4e364f92cda1b937ff801ad724c36130b702df174e4c760d0b3a7c2c +ENTROPY c0c77c49ef512f67e9ca8f121852e04ef87f85a8a0e74803555af8cccbea067e +ENTROPY 079a4b2ecd292b2edd313f81fa55e2e69478b0d64bc2102351ff334b1ae3a377 +ENTROPY a7eaaf71957fbb6747462fc730e1a95a17b952f48e2d8299975dcbd0f66463a6 +ENTROPY 164b952feaa991157835e9a856e83856619a3b9499c7ae76df1df296f8bba4b8 +ENTROPY ebf8fbe814110627e16f297106de6c099ab1177fe02932c534b17f84a2d58c05 +ENTROPY 8610fa9dabd9c08598cd3d33e8869fc5dbc44fa31b3c53bd6269823fc7e73f06 +ENTROPY a07bd1e4c68e8c66d87afba95b78db6966a45844678cfce7fd7bf13d073af713 +ENTROPY 59be163640d5b305568422aa6a22e3d791be0070495c3a909fa535fb09c158b5 +ENTROPY 133d2076739669560009cf13cf2c31b8ad37e9605631316ed5df33814a3c4c9d +ENTROPY b9aff9ca4ed094c797db98315dc940dc4918515c54ca604cd6bb8dd4de7a317e +ENTROPY 6996e1b51a55f0b67e0789949641a4b42f856ccbade3a8b44123d0fe3f2f3ac3 +ENTROPY 28600bf8a6431e532b5410b85610214586d36704dbe034b84a3830918e87a32a +ENTROPY da97ebbe9e3c7f010d869063661d846ccb0146244467e2704721cb937f09eaf2 +ENTROPY acd90c5fe1589a1992ece2cbf5875a64afb9632abfebfde2ad8a17d743c429cf +ENTROPY 19acc86804d632b92bbcfaea807fbd8c4395e2426e3d566fd3ffc494a2e40ba2 +ENTROPY 42bcd498de7f626870d1e2237a9e81560b8c00fe0a800787b9db24c5f34c3943 +ENTROPY a97842ae065137124cb74a000004be1ca6830566584c383a557f32988e204b34 +ENTROPY 33f48a813b99cb432da102bea73cfd6fb8857d418556b0f9375e83248ce65c59 +ENTROPY 2e51bf0398236d87d4a805a057276e08b09ff31c9e5ebbad7b44b77aa61784d6 +ENTROPY d91f73ff49ceb27c29029c3b48d755255ff297455051446df67b3414d435a6a5 +ENTROPY 75226a2d535f303cb65d6d72c4d44447c286ca5d3258ae18717f1760605e08fa +ENTROPY 00174226dbb5ae186e0f240afca7728a07ec8cd18639be8fae7ba934cbde84de +ENTROPY b64bd7536527bb9d75cf7dbc1f9f14ee05fd1cab0692d000315864832261ea50 +ENTROPY 80fe29436659ab4f186243f1832aa6e2349db40b429de0cccf32828ecf68fea8 +ENTROPY 7fbd313e422af851f332b9b097cb64403bd618b5412984fef5cf316bd8c0f49e +ENTROPY 14ccae829c7e35f5349afefc74ad6a66caeaa735ec99073b02b730a432961105 +ENTROPY bd3fb49a94030a8a0f5b8beada5956df232c0e7d6f9f80c56edb3da8bd83b08b +ENTROPY bb97ef214d5500579a44feb1124144d2a67d162c8149717024332f371f0359f2 +ENTROPY 182e32d941aecd7531db5d015ad436e678152085ad049cae39194aef2a945e7f +ENTROPY d0e41189405f5f45ebfb3dc79d61ccd2e989bf685b355500bf302d733ada4b68 +ENTROPY 97fbc9bdc7135961e664e81e7c0af271f32915e383cf2ec88ae99d87215f26ea +ENTROPY 1be15e656e1821d5c04301709e922e402debca1ee3d772d4e5eaea81e0cee963 +ENTROPY 61a189bcdefa1a0ecf5e985703058903d9c7e6baceed46e82110fb338cd15511 +ENTROPY aafbedc62a678d8d84b52758e0ec6de109db4e71f2613d89666fdf71d85a2b6b +ENTROPY e0c73228cd15f3129dd7c1526b03702869f3f36d4551f2f03749ffaf783b321b +ENTROPY f3afc971458f0459f1d77f1fe8257c697b441c99bf5cf1fc1cb12abf08dfadaa +ENTROPY c1fac5e91002713b561fc1c63a2277c0c40eec933d9d24e103adfe6f14701b1d +ENTROPY 505aeb5bab3923a3e99237556f50403571e437d98493da2eeb20c5f8c78993bd +ENTROPY 37a061d27828c1c6b1acdbbda9d1d3a5bdaa5915fb19dddba9854af64510e2d6 +ENTROPY 80bf5a9a59faa4d436ed75384d2af587a769166b03a73279f7c53b5a8c0273dd +ENTROPY 6b284091902a171268956d1ceb5bda938f7b2aad6392867f43bd7e7ad89b61ef +ENTROPY b83502b1b7b912eadce338789dd3d632d1f4664c10fa0554b24250d796a51671 +ENTROPY 25c1dbab6c561d01f262e96ed0d3231e9215a83f514526314aeb7d1d89ab479f +ENTROPY 6e4a6f1a4f3562589ca75ea622037bdaefa5e6b007ca70fec0d784de341f369b +ENTROPY 1a5e7b3408752cd89a239a0e3c7146c6fb5ad499aae0dd37c577309a3fbe3d4f +ENTROPY 38820d97e4c25b6bfa18bf072d822ce70362ec1f36f7f84ca4e4247edc07c2fe +ENTROPY add1b2c777812df2d83d1041282a896ff7be360149aea4a5f427dbace400cdc6 +ENTROPY 16b49f466e98eb94c7b2ca886e7fee7b4dc3504cbedaeaffcdee5a6393e98569 +ENTROPY 601d82d0bc5e0a3240e64633cc0e5d2a6e0448ef28fdb59d1736f623dbe3b988 +ENTROPY 9ffcacdfe10048e6cfdc5a7ff5b6967a6bc357b5763085c95f512cdf7a2d97f6 +ENTROPY a966e21b305ab513585ae638080a44ff5057fb8a662c6992da3575ede72ed245 +ENTROPY 70cd96f3171e992d2bebc50dd9f0e6b7bd5dc1ea5759eb7f600f66ca29db9166 +ENTROPY 58d1c488ed50fd340580418b1637e020a7cb5463e9665ed408b98210c03d3d0a +ENTROPY 8a0a7b5a769eb77f267bf0a2604426b6076e2311649e0ebc16381aa426d0fb3c +ENTROPY 8aeef123e7a6f8fe1cb65f717dd38850f344caddc4e624876ab45bf5796ad135 +ENTROPY de22ad33ec4e84c44511e6ab38712818270a73f9a6ca213b8658da60d92ef6c7 +ENTROPY a913106d8a42ee926f0549df443e93bf65a5e3cf4da42d429b67708e256b9d2d +ENTROPY 0dd58d901e50f533bf7c2249ea8f62af9d17c066766c40bf0407b804a31cf7b6 +ENTROPY ce61538a9e45855c7422a3ac6bb8a1b3fada6b8ff1c7468e08fca194cf998e5b +ENTROPY 19ef8eb6dfa70ef7d96828ac9b941d6580a153f6b6201846dc08629f0c5d0486 +ENTROPY 46493e022dbd723c5a18e3bbaaea5f231047449b05a4c787bcce2c904bd1ea7e +ENTROPY 997c34eb19b1c6f01d3bad344654a14b36c2886d92d834500f5e432ec162fc58 +ENTROPY 65971453a08ab71373a6e0974283ec967a0800c10252204ef82f0448b659f80d +ENTROPY 3b550004c274a47a17f4030085b418145389742fa05350fe4d4fb1eee17c09d6 +ENTROPY bab93032fa6cb616881fdbff7725701b3b1e4927ed756b933360b7b7f4813672 +ENTROPY 1e13531328b12e79517171cedd9b4febec92871497e4581f2bd5ec643da84aad +ENTROPY 21c33421b4d92299680b8940d7cd696f183470f675e6d0cf13a8dda60a02a7e0 +ENTROPY 0f93b04c796d85688340e857f84c8a89467aa8cfc077c11d82f5ce0b0fb64ca5 +ENTROPY 95afbc97fbf28775b6b19d13f60e5761553e547d00ac15abbfb93fa1a49a5ca1 +ENTROPY ab01f6037218f8ee1460c3334862b50c85b3a39550dfb5f0e0c6f3052a8684dd +ENTROPY 9504de8ab0505f805334151cf7c48f68081c5400f458d7787f647f4867127668 +ENTROPY d0e069aef2ba93e4d133792872f734162b34ea259b0124ae9a31397defd8295a +ENTROPY d7aa3a2fb5aeb674438fbee8fd9874e80bd51d7178f61caa02d5d665d33dda0e +ENTROPY 79094eb610d6f0caaa29d9e40b16045a369b0112bd6f257515585c9711a2eadd +ENTROPY b9486c9441ba036119a073308db78e55901365d3b002124ccb68137a3fd94725 +ENTROPY a92a6de952527ed4090d8fc886c70ec28640c395ad6bbe394dc3c45e70d40d1e +ENTROPY 5a4a5d4919971c62202abacaf1167589884ea4bb4595c777f78f7933719637b7 +ENTROPY cd26ff6bf6609dafd2f4f7cbe94ece39bb28550176557d2dfb73063993b089b3 +ENTROPY 3619481f0eb4bed7a44d4cc617c2edb6361e241bbdc692712127d095f427ec97 +ENTROPY 6606afaebb61395e9390cf17c87518b97fc2f803c5d81b03cff8e45dd184b138 +ENTROPY 3796be02d27cfbd161344fe147bb38b20093f7d6d64a324fd775a4fe8b86fdb1 +ENTROPY e15850fc99eb4d2e9e2cbfbc15e400ad54f80ac39ede2a6eb81b5e85302644a2 +ENTROPY 43a24e960c82d10fc566a17ad3647272d4f29c83a93d18ed23e8a008bcf5a1a7 +ENTROPY c97ff35e1953644e2eb6ffae09f2cb70654aef761b1b0e5cf417962aedc9b545 +ENTROPY 3c38d5216bb0223ab711cb1573e9644ff04ce81d278c2e588855fd48530a47a2 +ENTROPY 8cc1d6ec3f21d07dd048e564ffc657ec6801d5de67111b54c9425a0b54c6703d +ENTROPY c0befb977e4a8947448f06506b1e6c08ca61c3853e5ab7b1a0374336d3bd20dc +ENTROPY d84f206a55d40978cb766fb54ddcdb877125e9d371ad096f2979a85c345a239b +ENTROPY 7848926c3eae1ed9d8b914f478e51df9a596eb205164f81f01b1d44d7ac58fcf +ENTROPY f9473e4a5b84775c7a7e1ca8de5fc48518fa9136dec4ed4b386df365fcc15dce +ENTROPY e1ca20ca35a474db873a338bd6f0a0f98956cd1cd2211cf694fc7400b4890871 +ENTROPY aed8ccb8b3c3dc33f19d5d54e0cedc95a084101f57259d6194948961ceba625b +ENTROPY 9d64c825f0a1e7bb0838c2ea4669682e7a55a376d0882c5ef0c4965a3d2b6947 +ENTROPY af4535dde7bfbb860b46631b49d37b8d3e40c15198d01aef1e29669439f93497 +ENTROPY 8e42de221efd601ed682e4fa8aefb5c7916f5ddfe5be0d479f1f96d0e0ab2c04 +ENTROPY 2a7be0a911d57c999488c7e8826f43a7de83da3097633e322bf3e6017b04d0f7 +ENTROPY c29e98591e115dafe16cece4df0f28dc9dd3758188906bb21b4e174ac261f381 +ENTROPY 6ae407888e9328f6740087c5693f76934c271d6e83867a1073797545f5221a00 +ENTROPY 72d421fc7663df614d51b20cc0b97b0356e83f6f6a0e94d6f1b576c725d0192e +ENTROPY aa841f47f6184f60b11e7923c43be88360cb4d6ac563917aa5c17c638bbced21 +ENTROPY 9f9c3a9ef2cce3d796bff084565934043f8776ef14e6d6039af80afe4056b70c +ENTROPY 3e6510fb7cbe3d468e50fefaffd2a983f7132fc958afa7a0fc7ebb242aca9742 +ENTROPY 2463a179641168a3f90377e09376caa4760c611478eaa54b6a548200ddfb3bc5 +ENTROPY 84fd71380271bf1aca4ba5ccbff5f6af72385adf991fa62828f2534c1fae450a +ENTROPY bda1c3e2cd6557aebef07b841721b18a8bea6e32691db37e50eeb600fe8151e4 +ENTROPY 73d3312ddbb433add9d2272a0323e8f18ab02bcf63d9b3756fe3005d3d353f1e +ENTROPY b3901bc84efcd2a9c9c051edd2f81382bf74d00d62ffc1754c8e78646ca2a1ad +ENTROPY fdb9608feab791dc806e0c534eaa57342201bb98745502b3e63ec7fe66557260 +ENTROPY 271355db10699001b46a7c6eae15665f2f3b40b428b06cf5be2f1f07a0e12422 +ENTROPY 466782a81f4b93e6b8a73b75948574befc3128ea3607c1bf78a841dcb3b13fee +ENTROPY bc07156eb021700faccb6f8e0d9c01eec3c0772174a7e365691b76aaf8efe041 +ENTROPY 492416a45bebfe801455c651312bf7d421cbb6875954129299f6cbb46c1f1769 +ENTROPY caa71ed7018f43843f0892362513744f6289d48de3231f0669ae18d0bb8c7cef +ENTROPY f7976f626ed11d98e897068e5b0e9c45ed4fccd3b5088675cb2e05f860c95bfd +ENTROPY f234cc3e860d4d744e4bae8b26b0c5715c73b3f21a6988113bbc9949bbf8a1c5 +ENTROPY db73d9a5ae7125faf7b792c114a8b37b344b0cf008377b303d0aba4cb9323879 +ENTROPY 77acb8e8b2a0945c269f542f28e737a69293b8a4cea84b96f694ce4d58dcbe64 +ENTROPY ded7c7d7c9772d467c576615991e03b72907f5514bfe715e7125ad3dafded08a +ENTROPY e3daa1778a31e340b0d9d86527c78daa9a033a86ba49c5a7f2d4eca5df2b3330 +ENTROPY 4dbfca542203e51f1515cdb3241fe4ea2ae3f65c2cbbd1aa463cd628e2cf26c0 +ENTROPY 28406ad1f262cab6c4af597e3aaf34aeaf76feadffa58d7a9bd4c0da5077b2ed +ENTROPY 7dcf800a6a006b61da25ab17d0fe765005b3b8e1232d200a503574dd931947b9 +ENTROPY 6554650a2dd6192c7d58a0150dc9cdbe291e327a15b4f5910166282460072884 +ENTROPY 26a0c846b2ba89cf671b7d798f4d7910e2834a5f95809bea790ac94dd20bdbea +ENTROPY efeeca487a33c95025da8a50ed7cf3fe69ae93a43d15a8329df8b3dcfb786575 +ENTROPY e66e17fd6b0c530ac00d8d7fe6154f2439aaef46169affd023484a16db5d806c +ENTROPY d29954fa9f8e6b2d53eee2b3a70213adad1b66833d81aa0dfe0dea288df8b426 +ENTROPY b69ea01df7a3bbb7d271d7d36e188dcd24e8ed50d9e625e2eb4e5eadccf4f72f +ENTROPY 1db1092201bd9e2da24aa796511221b5bbff12459a5d6f0da1f98c3c68b71c66 +ENTROPY d305696ad5789ecbf49d5ec532627e819b23c598e8badc3782337ec2097c5a65 +ENTROPY dc172b3251aef97d61df2cd92ffdd4779155b29420566ea9af52a4867694772d +ENTROPY 5d1c3cb17e70da7337fdba03114e566c352e7a4765ff0587d92ce6f7e0a9db30 +ENTROPY 5257cd4b6da91fc19b0611f38b3e29ff86282fe12d9f052387f766d17826fbcc +ENTROPY 55ccca8a7f3c686a552844fd1a8dd5c246186e55b05a0ddc630e3e22e2b70a3c +ENTROPY 02657ef42fed065fa606fdf5562a5959237ba3e5648b975e422e39d1a87fc4f9 +ENTROPY b22e9ebb8a7f0ab9e3ad1bc94b73345c4864e18746c125d89304c3e9e2242952 +ENTROPY 8f26ffb5e9ce0bdff22b5fdb4d940e37dc1c4f20503e37edb6a1acaf2bbc7cd7 +ENTROPY 7652fb70044ddfc6a45a476bd0a8dc25733fb518735ddfb0d389032e2134b38b +ENTROPY 5ab97e614421ee839ccdbb81b3e1946baa6155a70da4d7dfa406a1c9a1901ffd +ENTROPY abe30716c82f681891cb4ed29f3f13c9d2da2d4b2e568fc68dfb83930026b121 +ENTROPY 7734f99b110e0953936534418dce1b33b92ead9c567faf363f3e1cfe19fe6d53 +ENTROPY 30ebe6ba4fc3f08b4e06b726b0ddabf9a34f103a7d4c9f2c04c2c361300d29e7 +ENTROPY 19e3c20becc64091a9719f6541b21b5202e4ffb4c1c1dc183119020e3049b75b +ENTROPY 7b33968be01dde5ef2e44cf3a94ccc0efc6b56452812c62f3013ef34c01067d5 +ENTROPY 980dafdfbec32e6264f1139bbe4202b155cd8a5303c5886fe10f5989b1f4cd4b +ENTROPY 30328982347400f5b52c4b4e3f0622a1f105cc9d56240acbbae0af56886ba142 +ENTROPY 89a8d1f877026abf46931a085aaec1e8bb22520a609309112058ecc23e4e6e79 +ENTROPY f356c908a686930a628684b2c5913240b6ee3cc750bfb091cde1ba0514b982ba +ENTROPY 64076744ed49a645f22a63587b6183ddd9f23433a221bc4fe0389f0375df1e13 +ENTROPY ba72e1f6c627572dfc09993735ea19d8cfabef28025fe63b1fd76ba6697672bf +ENTROPY 71649e5a9554aa93f1cc16014a72e85cb2a643328d4565b9f03f209541b451cd +ENTROPY b422a1422ab320986413565c0de35ac2fe19d516c789f302cfc5bf11532d93d2 +ENTROPY 8163c7c049ee5fbacee0f42ae7970af956f8412afa90c5117cd6a765f84bdda5 +ENTROPY ce4d360fc67fb59235625dfe4f1f4ff3277c3f819a9696dc739ada3631059700 +ENTROPY 02503a1a3f65e3a7f9969a5759e6162ded3d0ddac0cfcf5ab4999bab598dc29c +ENTROPY d426ee156d19d1a5da9f0109bd74391bee5cfd26994a613c2a6e52b5b89f7df9 +ENTROPY 5b665c455e31904427d250ebc089ecf3487a9b6b196c6b67337dbb2913c4d858 +ENTROPY ff6b34ab35db957dcd9cddf6d6c38db5a770e57deb3e55b5bc67a003a564cb44 +ENTROPY ed00bf1813d307c49b0b6fa1a507228ae2d3fc7791ac3392025d12cf964df321 +ENTROPY c10f0ac8d56e396a12fd057d3088b05dc6158d3c7b15fa1504dc9a9248495cfa +ENTROPY 496c0b06bac61aed11157a1d591f9f3b1b62ae754250807f2299732307caee1d +ENTROPY fe0ef3ae360eee8c21098d1343b6bf439cea5406e804b9b49b33809f4f88a293 +ENTROPY d0d040c3a0aca0c1338f4c5421fdcb46b80f854f3135828a9b6b80b7f1427f86 +ENTROPY 357106b796117e53dd601b285351890b20dc13a332b7fdf579b4f6d7f8ec1419 +ENTROPY e9fc1341605822bb06c40b8215e3f43f09ab0612a4685594b7f1b544397ef30c +ENTROPY 5b71acf52491ac34ab6d2be26492ee458a8a03f147e857de4a0e095cca773702 +ENTROPY 569b6abab0f522e716deb6853b762e6c09be19ec3dfca0ace5a1eb1b2ba1600d +ENTROPY dc56aed4e95149b4356de22686bb5acab917187f40d84eac7a0dc7d76f4bd357 +ENTROPY 7bb4c5ecb39e96f87babc12476c627c2b0591bae765312c2a48d21a6cb4be6a7 +ENTROPY 6bbdb186b32e9a3568deb172dc0816861672b24506f08cc70287c33bdada5472 +ENTROPY 576196a2b2e8aee4eba88f522d678c4ad1e42f569142070cdc708f3cf3f77933 +ENTROPY 09d51cf67063b2ce70dae55e83de73f0de719cc231e7c24ffb0e3c1ede414fd5 +ENTROPY 8f95297ce94143731047dfa564dbcb83440e6adbef2264c313898635f17151ea +ENTROPY f761ac3c441e2e9dae1512a5b01545278136b2488cf8ece9d171f553f7ac8a40 +ENTROPY 4e1a56f5a537738b67607f39877b2300f4b94699482b325075dbbcaac4687d19 +ENTROPY d4e69a237f5fb170000481aba8f0f3a7e55d77f5410a1a898168847d0fa78f2f +ENTROPY c80fa757c62f0143903bcc2785f98c40a68bcf83678149bcb7571acce7e8cefa +ENTROPY dec2d87ba9c6c7742cfe0041ba4a5614c533386bb22674d71ae30d25559cee94 +ENTROPY 59480b1ff5cc960b427b7b38184ba857430ffe2fafa6485a8c70fdc9e52493ba +ENTROPY a4f026cc563b279f30f0b4cdad60da9dc55fbd1bc373e9a070af7a967265a67c +ENTROPY 8bfe5b3c2535da75b7cc96265e5ec7e6a72c4f2a5cd43f985b3946271fee68d5 +ENTROPY 9515ce895d3c42849be81c5e629dd6abb36054dc902c7f26a4a657f5003d69b3 +ENTROPY 256b4028a40dc3b526c5a8c7df611d9ee3b401914626a765ca55b4ddf4730b84 +ENTROPY 7f7d8996433124e552dc2211a8d23fb342e0278a34629d3e258316a65eb20c81 +ENTROPY 3be257a62cd07fb07bb2805f4bed3acdb561ea79c4e32dde3d78ab386f860eb4 +ENTROPY a5b439888c30f687c7181a9ec3836ca535f3a34058af3cc0b0f753773ad84952 +ENTROPY 2c23ec99bd7ec87bda1baf6ab2d96d0738e41d116fc0a798fb3fdb9aacbbdd54 +ENTROPY 171c4e7c25697c901897fc81b6de913a745a21b1297eb1d1ae46a772a397f811 +ENTROPY cf11552daed64138cfce911c72b2292c6063a97bc4b726b3a4af7c6a74324afd +ENTROPY 0f5eb42a58c928617bc1b299cb970a6a8c55c84bef7183e776bb9281a6111be4 +ENTROPY 7e36d0d53f60120d27c83c98b3d7966be69c148248315d28ce45cd5503731811 +ENTROPY b5efc9c76f92e7869fae0752d77ae1043e30073c9c4d0b3b4626bded7371c5a0 +ENTROPY 08de02ceb455e3d5c81f9e18a3eff2d00f93c52b48b0c4ddaab3adf4d94d3339 +ENTROPY 45d46c0192bd896a8ebb97badd8c7d5008a91492e7b046bab6b5a299e77e9751 +ENTROPY 8938eb3af323a7286bd4c6077d879f17c3807386bb9745d1060c44ccd7a3c5c3 +ENTROPY a7d45f0f21cc250808db38e50b256346e98f63c58383d8218c030abd81656035 +ENTROPY ca6af10ec25aae97d1c58e6c908178dcc201aec6a91e4891035caa20acd1432e +ENTROPY 2b50b9d94fd57879af2d8b9e1b73e82cce913f34b02f6ceaeeddf10da2dded57 +ENTROPY fc02aee88c87664c18044f50a890e3d6154ea76aedaf100a98016716c6559579 +ENTROPY 63abfcc92b22ba2e49c315db7ce05f8abcc10a9d0547dfd98a991ada8493311d +ENTROPY 4bd40a3e49b81ebec0431464649f97f7e40e2f1d5672471189ea44756f062382 +ENTROPY d63cb5186087e7335ba68991ac3fe0e794b2ad53aef28c52977d923e1606726a +ENTROPY 19b1ca3b1611fce39efbe5f896c380bb8e9c11c64133b567bb8aa3d2c0726754 +ENTROPY 0b3a75ccdcb6968ff0b2db5f7ccb629dd224b5729e85d4778fc0f804b9168818 +ENTROPY 3e1df31c317f422799db1f49a508b61f452289383c4d0af4bdceddf31d0b4546 +ENTROPY cfc68db8a58479168c6158619cc4395e984e37329178de7b86ae32b32f2f27d5 +ENTROPY 2442d36f6747655575bcbf640e601756da4e76860ff723b674a5ab4a4691b9eb +ENTROPY 5086cdd08b2ec64b7ad135adb10693a5519b34dbf66bc4dbdd2ab0def2f09b46 +ENTROPY 7659ae82e99a425128e3db6a85420f649ec7d4833d632b02a54f092c96470961 +ENTROPY 088a63a75ae07f1c14391fcd612f60a80cc8c06c0cf88595e89f696be566187c +ENTROPY 6dec0f532b55dd20b046c65130bfdab2b276539cae676529b757ff755fcf0530 +ENTROPY f065b1a0480c264fb00bf2f789b5129c2015cc78182446b35f15a80876000079 +ENTROPY 5e067c6008c34a7e0cdf06588869d2dc89ba859a612643083c491bb9f43f5593 +ENTROPY 355d3764429da7b82663227e77cc9d06303209f6b9133f1cc7a01719adf915fd +ENTROPY 47f09ae887e99fb80172d38c830566f095127786f5c7a4a621296efda0808d77 +ENTROPY 9361df06a3b6c4723578ceac22ec4f4961e60b2cab8eb96962a9ba967b6abea8 +ENTROPY 2431b187628115a5900c5b15a65224b5024a9ac70ff7ca3107f4b97c951960f7 +ENTROPY 9a9cd2dbe62318d8d0d8f6e6356f4a61fd269c5649d73664fc834d18a4af5042 +ENTROPY a3751ebcbc643368051dab5a7ba6cd190f0916a695cc1f566d37f7712cd88cad +ENTROPY 32755081dce9603548db9b226ecd0f989c78a0ffbfd5e738989640ad764f7144 +ENTROPY f9db19350b7210ca70cf80dad9c51f66ee3a8b73691e2e93a096ee860dbcf169 +ENTROPY e1441fbcba638dfaab2d15ea67f4230995668a04a97786426e6ba158a21ec502 +ENTROPY 7ce070d55c8ddc6504e0482f61353ce1c36d30d61836b9f57a713ae5114ad534 +ENTROPY 13b66089a6f8cae000ffd6cf3eaf1a269b1c25fe014cf4f7918459898eaa5ffe +ENTROPY eabc446dae4db8a7814b7dae4a60ad5a61809faa9f3d2139c2d898f779d23669 +ENTROPY acba55f202bc24ebda1671ed8d0961bb1b0e35955850d271e58f4401193c58aa +ENTROPY 54b0e61e89fdb94a1cb66a283d0b50f2318e01ea55c9c8801112a694456472b5 +ENTROPY a6c88e3eacc163883c90e91fb4ca782a3a9f7fb0917768cdff2fdbe10c3f4878 +ENTROPY 7592c04affb26c4ce23a982b54a3611453fb280032e4f45871986ee02680dbef +ENTROPY 9ae93448ab3998eb5db3e19092d13666e0ea01f95be0625beb188fa482404402 +ENTROPY d411578d3375cc62d199ccd088edc59ec6ba888632c9c8b5f2bb47d98570f39f +ENTROPY c95e235d732ba58929cbb940f8d3f125d0b7d1e87c4e316db808e294d7dcfe1f +ENTROPY da305a1ea9c5485fec019a77503627d4611e81c700c6c7c2c0dcd03d51bc3149 +ENTROPY def92845b5d2ef81450d41ac148a6a41af905f2e006921b240240c6f319908ca +ENTROPY 0db013811980fd69f1c5f727bb45c593aa8c8d91538bf1d6a3df3ef86704486c +ENTROPY 0108281f593d325f558d1d67c2accf69c5ab118978c0ec39a62a40bb7bfacc1b +ENTROPY 38e45099756050cc91da4e42b79fe050e52eab6018af03174ae6c372dfcf7c01 +ENTROPY 7e6fa61b5986001007281897213b351f306522bb8edb8bb6dd30bfea8f46b2dc +ENTROPY c47955dfd35d9e074ea956766729b5ebf5c496522269cfa1918fe786b2fdcb58 +ENTROPY 67f4dc3dbef6f928156024ecc7f632a8fd0b6f90ec6fd528c39a85a91a54cc08 +ENTROPY 18a583d5548fa735469416f58b33cbb5230b376ab87832c7de2f7d22a444d663 +ENTROPY 1b755eb6dc562b7de157ce6474c0431a8696a6867ce2b431856f85c0d042d2ea +ENTROPY 7b6cdb47ceaf333c71fe061161e00bf42916c65914eb85134494c9b7831af534 +ENTROPY ccda1cb828048616394770936f5c3a65a2fd20b2ceafec0bfa90323a9fb93bf1 +ENTROPY d5a1cecb4745bfe069a8e284af3a2c99fabe698a3c794cd07d29b29368763497 +ENTROPY 0bec27d6a7c10cdbd5f96c6efe742509180a08c936e8737736acd54def1c8aa6 +ENTROPY 20216f500007fcb0f8cf5de6d874ae2a684d9ebee1599261b382956b323c0bbb +ENTROPY f9b472ab2ac955f90a05162d65b16b0fd5148c81d71afb6ac8d765662024ff08 +ENTROPY f29e212a66dbcf5b275dec071e9fb18d10619d2a4be82f11fe88732afbd48bcb +ENTROPY 504b5af2d8cab260b9f7b28ff101efb3210592422c62b05402b5cf97809e91f3 +ENTROPY 5d3a39601c5e15f912ee1e5c9130d21702fa99f3648a02cb0f5f80e0698e6d0a +ENTROPY 5fe061c02544899b7492375c27270c084a579a27992f5f4458f3ad2c5b120356 +ENTROPY a7cf2c7148ba9934aba882ab3e05a7dcb66691ba662f0d262ee24a382fde2f66 +ENTROPY 13e762527f15b23ac3e526fc1e596bb3212f7e0afeadedae42d5625c90de7178 +ENTROPY d130e6fa713a2d2e201add92820ae79bb643d7ef904b190c8b0122f11ea470aa +ENTROPY 0a42be8aff0b071c4edf0b05839ed4d494b82510367fec25eb70491d4d355673 +ENTROPY f0b04fda3a8359c5e7cdb2f554754e37dcd9d46982d28cd3c4a3447bc78ab109 +ENTROPY 519c8182ad71e62f84b0735601b25c643c7fbaa0a6d937774253b7974c50e563 +ENTROPY f1c1c2c5abd1e5774930854f4a292e550572f71b11db52c5fc60e60571ca35dd +ENTROPY 616a1c54d9b1962fb9ab8671373d316b346609c3d8c7a62032ae0e38c6543844 +ENTROPY a4e6daedb6fb42f83dc20b7f2de964835747f055a5f4832a46ae5bf8e312364e +ENTROPY 6fe98a3d4ad283491dbfd34056bf725f9ec57efaa31aceedf7eb8bee09dac5c1 +ENTROPY ca5dc5e1b9a5dbaae1b45b5c6de2774e55002eb049c83442e518abd373cf75c7 +ENTROPY fa305b7c5475ff24f93b2bc47e192f7df9d853eb116bd4fb157d567c60ba5a23 +ENTROPY 2985e09802a28d2237988240057e4be77a04a3ce279e3e3fc83178cf22daf635 +ENTROPY 90f16828ef6dc431c5845e2093a4fb4088ae16a2f55011e79127af281dbc0da5 +ENTROPY 24c0d0be4a8f5fc8694d27a8d945d925364058c95bb67e17b61a7ce4abfe2d6d +ENTROPY 8aa6acc1d96941d7ed3aeed5d881154c4128278e4c6f761bee271b163088aa56 +ENTROPY 4f0ba1eb5360b944ab2b17487f6b66211e8b27d49e86f6c1f8821cd1ce6ef9e2 +ENTROPY b2446489fe1abeb468d17835ba0614e7aa3eabcf2aced73bfb98355f3fa22053 +ENTROPY 3bfe9a9773d8fd6ef713629e0493344bcafd71a333c7d2be0406ca36a16a6fb9 +ENTROPY 9ea0f3016928e70a14d1ddb68232777315ff16d6b589e0eabc4739ea23471789 +ENTROPY 170a89d416bbcc95a7e1f80f24b309d070faf68f0f2889e75a3a7cd3f82c6f63 +ENTROPY 7907cb5bb3f3c6c866a05878d66235ba717dd1353142036c2be4d6b9beb7b30a +ENTROPY 502bce2864b27db9de3f0282bd88622d1f520b77f0ef99f3a612da5a69024176 +ENTROPY 70cadba131f1e124176c4856a01df28f2855ae8dba358f534273c2768abe4ebd +ENTROPY 8950e21dafa03969127030290865bec7e9c72da2958bed201d2475f02ad5765d +ENTROPY 2d5038bbedb11080f20467eb0400651717b16b64136fdc1a5576951a0fbd8ed1 +ENTROPY 67dab4d4cc343649718e1963d9cf4bb215ad385ed6aa972d6b4dc902c1383d1a +ENTROPY 1eeb7970cfb165d66df63d5a397da87320333d4e72402dd15ebae99a10c3ae86 +ENTROPY 74eb57155bbbe67ad78725f5690b816d9e95e0f46d88e60b481a3154718c0072 +ENTROPY 608561b7fb17c1ac4cc5a42f27d9f4e9c67ecd4f91a38da835c81971045c54bd +ENTROPY 5924759cb68e332bbaa0f67dc610372387e9d94ec6a970325be15dffe080ae66 +ENTROPY d6245b9c4b701208a573136e433e15c0eff22dd72dc5df9c5e49e9fbca8b61f8 +ENTROPY 9bb7fea6da7ad1b0a2171194a65dc19bda65b6ae3d029aeb476d29b0a8602e83 +ENTROPY 5b90276fd88d31ad196ab29dbd5bc6afdf7157194a2b22693b1596345d37efae +ENTROPY 554903d41bf8f64a583136509c1c19a36688bf2b80aa4525ac7f42f3eb561a46 +ENTROPY d813463c2bd3bdaf324ee1593214b9440f15ac582e67c2ee0616fcecd44bb3f7 +ENTROPY eceb39a9c805ca1af3fff9221762b02c5c2bbb4cfc7b21bc25e8f8f5889d9ae9 +ENTROPY 33e8313222a0fff3613d8cdd8ff5dba1b02d8944ecdd7d9244259c959c405477 +ENTROPY 91435b95ebc8a36644a45728065abcc0b57c21cbf650ed54bec0de7f2f347899 +ENTROPY 4ee69ea4e16b0784e72077ae038533eec5654e323002cb6f4b12df850f7796a5 +ENTROPY bc430dfd3bdf277f345ce133287b6200a21e5ffe5f85ebceb0a341caa407ba53 +ENTROPY 1fe313a0dd3b1848c41ebf6c3964ceb63f596d72fa067c353bb741bd2ecae850 +ENTROPY de412de6335fca9362ec8a00d2cd374363ab7b3685116ecd07c5e8d1eec72ac5 +ENTROPY 58f469ae5e1636b338766a4e9c65df954f6d485b55be4eb906f0bff0498a803e +ENTROPY cedc60f77eeb415fd129aa3b21fe0db79c7bb488e6e95b2ba9606ed3c3bd7eb4 +ENTROPY 722fbc2156ead1c587f9aee7e92645bdd7684a89b2623206c9a43831dff7051e +ENTROPY cfb9b88f76de9ced6c4f282e295cd8e470f305a81628dd13c93e567094cd30e8 +ENTROPY 6e9a71013686bb25a658bd792a9ef39a4c4881b67745c6d74c5c505f876a1161 +ENTROPY fc82b67e05a26c959b309bfa9fdc3aaedb63c0f4a6d6dd9daaa6570bff1f0538 +ENTROPY 63e3da25aea1d2742ebefba260bdd35961ff80e03f21a10d28913707172974e4 +ENTROPY 7a7628837991d7d8df5c7fdd3cf2b6037dd0e009932e3b769a383efcbc62e776 +ENTROPY b6506d2c7a5cd74c537c9793bb2d789a5e863281621577289c0222492ff7a3be +ENTROPY 3a68b878b99aea3ad9add05988d59d8bbd00a2a1b2f497e0acc4250f7e3061e2 +ENTROPY 41a854b53ac457d67b8047489722de175247732b8c0657301d757b0fed9ecd31 +ENTROPY 8605f617f2a08d4645500830e0cb590f47df5f0812ed4506aa8e5397ba0c7610 +ENTROPY 72b5ec2bf0a35d1d443c9b98611fc5d32164028f0bb9623fb753f8a52e8c9948 +ENTROPY 4d3d5e256c914ffe5f2c54770e5e36f574d19bc6cdc74424d63153c050447e69 +ENTROPY f8d48b4e546c5dc4bbb3a12baddf63609017d228a0a642a6fc276f42bf32bff7 +ENTROPY 727fb50e13f054a0b3cc595dd9db97415086ee192fdc965d33ad005250214d1e +ENTROPY 099ca9b324a802d73024a506eef5e1ba060d54dbdd7fa4b46775794a51297a41 +ENTROPY 5e251b9c51e0d85abf7b010b15d287849bd28e530379f77b152bc613f2687fb7 +ENTROPY 447dbfd79cbfc9a30b3f57d8f398e32c2d37968bd0ddabd9fe8fd2f46bb5d18b +ENTROPY 41996fa9bda923929e8b22db2f7dd65d4d0e0d089c7d6afccdeadad8825f688b +ENTROPY 42cc6074d5b5e0921ba5938c400e168f12bfe54ebfb45f9979a5a02996eaf7d3 +ENTROPY 6152dd93d148a2032f41543e9cb0ecadf9a03441d60a849fbaad12c5ceeb3c30 +ENTROPY f54b130cd8e9846a5abf1baace0b668cc241830bdc2a476871b78a622bbeaac5 +ENTROPY 05d646d615d21b5ed10b684d5e4f03adb20255d6c86b58f3e8c6fd7c97780089 +ENTROPY 9f2b26bcdbd4f84afee031a25fc2aa196b443403362637bbf7355780d06c6ef6 +ENTROPY 37de47fff16b2c4b1d08050b27bcd4f027b1aee0e2843424883b537c14d0536a +ENTROPY 80f9347ca5d9a2c1ca89dc4a0f7bdc2d58feffaee71641cd2a9b54a1aa582724 +ENTROPY 82a29cfdb6f7f855382d999ec3de892e0e70d8b56db9f2306d0b8072a393e3f3 +ENTROPY f0d266a9104aa03364aa2f9d6f7790cffbecb8ae02335a2997dd944381a5a962 +ENTROPY 33aadc5f48067a10090899783ff581c21c236222dc3555313c1d5832f25e9a93 +ENTROPY f58bfa3ab3a82cc5c4895e6cc8485efca4a791538ddc1289dc730e9350300797 +ENTROPY e64cb1370d4ad0821367f1f945b599ca6edc1cb72285626029e633164771dc25 +ENTROPY 18cdfec80e2479fbae1cf157963f34c70c5d7f556d45510ebdff19363d0d00a6 +ENTROPY b307147cc954beb17136d556e8f926c4f57fa1279a709294dde92bdb3944311b +ENTROPY 840dc5681e143fb70a0da91b83fe7bd1c858d1873227b9e25cd1e4ed60ff1f8b +ENTROPY 96a3494f9f4c5b4101b97f6d4145f86990341b60ff762ce7b9a202dc2c50fe45 +ENTROPY 5e8963399685327ca7fba1fa9e009ef0ab0cd781b532451744a4ecbf0d29977a +ENTROPY 240787c9ee7fc6f45f18e6f5d63c4d33f2a66a458b88ef9d5771fd623b0c3a6b +ENTROPY 1609373d4c9dc28f62c1bf36d8f2144c306a481da0572e3801d555bfc95c4c65 +ENTROPY 55375654c925db2c2ee728f78e7a0caa0893074869d833f306a3e5c74c1fb959 +ENTROPY 95b1aa46e0c02587bfa9701fde932c2db5b6c86f71719d1eba188d47a032551a +ENTROPY 264d957c36e7a576f27968dce27d8a980571bef9e892834c8107da2e855e45d4 +ENTROPY e3a946e62ef2811f0b88760951ca17723fc7702892a9aa05fb7a994f58adc24c +ENTROPY 04a0d5dbb99f608a7a5fb44afd154adda6756c36aef8bbc99983e89493f8804b +ENTROPY 31a687fdb33a4fe9ed84088f4034d205fc65ffc6402e570cd6e159e5e3b31ead +ENTROPY 7ac2114e9e1fd61ff6bd48f23a0640cce406b4238729d61fb7ef3d4852babf93 +ENTROPY ab413bc9e9f6d1fc98b9e186fccfaa2dcecf4fba6374559f3e05db8586e33554 +ENTROPY 707250e13d0ebf67e4f69d756346e959b36c7e92e7d8464e7077febb511e9abc +ENTROPY 6187c7ae91cc4ba12de586d48752620003467daccdadd27f69f7fd8d20a3b3f7 +ENTROPY 0e48d26aaac14c4f7a3aa1df6fba12bdde0f8c5193128c6553744297720f2d2d +ENTROPY 235a8c8d69b4cd6334975db3a9dd6ae3532a81bd9866a80a644202d18d9d8842 +ENTROPY 9c3d134a9f7f4e3b4dacfb506ab8753f96a8f14a1e14eb8d18f64c110fd5d4e1 +ENTROPY deab22fe09c48022cddcea4b0f02a805d4d89a9efbebeb09365f40353aa84280 +ENTROPY 5ddb026b722ca027093cbda4874f49d4aaa9c275964e0f12e42c78efda0c0da9 +ENTROPY 99b923a8fb6b51778b7d700bd0132156ffe928f6d32c40f6bd1dca0b1c3a35ac +ENTROPY 69fdc9a34c17e6d1efdcf47bfb6feb06b887313bf5be2d093569bbe94aee7161 +ENTROPY bbb43db64d3464d199bd35dc011bd450e1ff187e14f7f1dfd5d2da7dd50549fb +ENTROPY 7ba3f57e8a29aa2e39ced45ea0d41e7b6c85b76c8b7c784c23a88da3d7a0ff53 +ENTROPY 7d5d21b120948b4c518298e018a1867722b9e88af77a89bfa141e156c1ea9518 +ENTROPY bd51364a905379a49e55e294379e93338c2171e56efa94d3557e2f9159e0cf1c +ENTROPY 111e7580e209a4d6401bbbbc995503d52e30a004eb9b606bd884755dcbd10b28 +ENTROPY 55e3976ad046121623d21358e63da17030ee343c8865537dfa234abe112b5c51 +ENTROPY 135141e7098e06a7b67b6bee8ecfb8a1b5720a275b7c2d1571d6c551f5645973 +ENTROPY e86ba51e4c2cd7ad3d80a335d6b92ede42efe1bdd17644b041e8fcad0114fff6 +ENTROPY 629f41fdec4f96ab097d1f3b057ec705a9bfe432fecc51943b94030b33bf537c +ENTROPY 37c7fe083d65d82cc286adf4ccdf228810818397e68de5d5ad4834a2462f42d7 +ENTROPY 1e2115ba1cc38de802f4457be15f6530df8591fb0c411e3a9fe6fce9e169700a +ENTROPY bb28f762f5a2971b6df3a0035cfca75cce7dd1280cd86fe708637932a42570f9 +ENTROPY 6d158c38089d10e69b536b0308d059893150d825c3bdefdf678367e6aba7801f +ENTROPY 5e4c70bf28a02e1651265e5d37f1a4f456b011c088cd58603950fc5519717094 +ENTROPY af80c5e5fa65a32532278acc2e0a4ec980217ef813653fa2938809a6dd3b868d +ENTROPY f1270c48b02eb6729c3ebece31b2029c5a5b5bb6d236af2100199f9e228f3c2c +ENTROPY 6193208a63fceab5fcf312cfbcdf5d2449b934600bc39e0d7270f94f65e38c13 +ENTROPY 72a8bbe9faf3b5dec58b5e1457b8728bcb652fc10b2b24803c78749bf9a49f7d +ENTROPY 50fe9aa2ff76787db9b0606c2418bf86722214ec5792e34f119afd627a159d45 +ENTROPY 013b909c9a1f74de325d312ad02c743efb9e12e9afd9b8da3e72b802fe30a17f +ENTROPY f47d66adafd33b0ee717bf3cad348b25efd60d71eac312107fc2f500943b4148 +ENTROPY d82034686a52d19fc410865c4386ad548de8ace1777e6b2882c59e076f474234 +ENTROPY 889025c2c2df3523ad868020f1e71c5be95e8a450eddbd3cced615943b323008 +ENTROPY 20fdc192b7bbd6005a3d8563474e7ced899f15dbc6423cd8005ae03845877363 +ENTROPY 04262025d0419abde38092cce1fe59750ed0f21c7c4c8f7a109e1f6be7cf047f +ENTROPY 64d91d6736cf925c7ea27843375bf739e965ff03ef8844c9bbf819ce3cb466fc +ENTROPY fc5df20f383354cf107ac5e6f422a52c4740b2b0e87aa900bbc9d97b57ac2294 +ENTROPY 2c845b88aa6aef862db4111e0d2aa72ec59995d8de303f9763b9d79152342dca +ENTROPY 90a3e8c12596f1978691ca8929cb91627337c4738c0bedae77082c7a722c196e +ENTROPY 67854252d8f199378fd5027e4deb1271a471e6e1a0b938adc3f770a566641fd3 +ENTROPY 22e47743329edc2555fb07b2e0b1f339f5e8809e30850159a94021d6aa04c42f +ENTROPY b5ef608abc20c60ab907ad01678e2e84140e4ee1d5afd054d4bcc96e60be1f92 +ENTROPY fd66c20cd5296ee6fa23bc7362535dc9d211f298ca7314a8bf8aaddd64814e3b +ENTROPY 863e287a248ba794ef514fd61005027e51a9c6bdc017248b18387c8d73e9aff4 +ENTROPY 8c74878a5a896008b06507222bebfb5d9034688250a0a56d03595de302d1777d +ENTROPY 7a054e2ea13ff64d25a0ce9cc88a54e4ac0441fdefce253f797c4d596a80ae8a +ENTROPY a33aa24078a3692e66f236868d93f432164d731d2be119685767ccfb7e0d475b +ENTROPY d8af02a17f71eb8887112fdb0491e3b374be5c69f7b25e6764eae479e087cead +ENTROPY 236c5b9e7d0dff16e3fe3c8ca84a31662703ba43c465e0936458221e93c48730 +ENTROPY cbde2b76b82491f8703b364f56848aa4245383be51a6afa25c70658add2815e4 +ENTROPY 066d2892bcd46d6f577333e23d7c02eda68d07c0f016084a7c4b7b2214aab9d4 +ENTROPY 40b35f9dbb5eda96697290f4053c0516d1f4662636959310f30a531145c8fc2d +ENTROPY a8ff772e5f2f3acbb0e05610a144e0a497b4697f2cba880c26fee5fc280d9a30 +ENTROPY d23470b03b1a9194b76204736464baf6ec554776cbe0574a1bf868d88e79d632 +ENTROPY 618ec83cf672f296023ba25819374bddfe4a80945ff11732d43bc1e9dc1047a3 +ENTROPY 5b0f8addc7c44cc964168cbe2540d8dfbd7a217d628e965995eb66f7da3f7a29 +ENTROPY 64f8cb76b47a07fcaf367a7a5eb2837fa14539e624f79da76d800ff2bb7a828a +ENTROPY 68a38c19ea49a41ba53394442cf769c2900daa149f2dab1af03ead04cda0d715 +ENTROPY 346deb217a7347104693d6ce26129dbd7f933f9625e7d16e74e2258d694db3e5 +ENTROPY ab6dc0353ac5d4db20ae8f74fa5644ac1542a32f4b45cd6e192848825f3274c2 +ENTROPY 62261c6fb7e702a361c9e8224f12685c41d75450eb4cb21297c535a2c52574bc +ENTROPY 53ca578aebf274db9e365e5835a6a5972d7a5931c0e53c364ebd70ff93ea954a +ENTROPY 11a3460069e96d60fb3a1dc0da735b7497de4d8f1b0d09f5c08869c44664cf80 +ENTROPY 27e10df0160424dfdb815005150a8a5b77906b6908d1af6648c16dcfa4782514 +ENTROPY 95ed6d6e50230ab3014fe6fe51f91654f8e837b4a992bc043c115b0ec5ddb80e +ENTROPY 9bfbdd161f5dcfd3f49d02614453b75dcd9c911ece2d17c3a18b92d0e6cde838 +ENTROPY 5d2591c47fb2cebd8b235bdcb473db5934878233d28cf26f41f1f87fe45273f8 +ENTROPY fe4acecc0672261aadf303e97f0811769ab3aecc68ecb11a2faa1140ff15e4e4 +ENTROPY 9ab2c1c1d97c0f6682e87222430d45143dc590c38503330288d5d031139bd855 +ENTROPY ecec259612c3a01671bf3466eb8367e148dbdc734acac4256808b20189d721de +ENTROPY a03caf41105ae30bb2ec36aa8908ffbc6f8f936e000f4c859cd442dfb43f2fe0 +ENTROPY 5444176a440fb9eb8affcaee469b60222f26100265099c1c58fe58dfa746c39e +ENTROPY edde45af725db0ad4a09a80faa1578fc8e541bc027a681e2c7a050fcbfcb873d +ENTROPY 2c007e508de106ea3710cc44d9206f61aea871c8fbb15fc7fba8bc1698976d8f +ENTROPY 00882c5f1455b75abfb5f7d0489a98c229a285ca72fee1b75acf1c453697f9e3 +ENTROPY 306dbda4d8569662f2b3bfa2c27ff019f3d8d470dd31acebb07b463ead05e784 +ENTROPY ef3f2a77362bbf7f88c77ac3744cb899e327b457f868a630123feee759f01c9f +ENTROPY 4e5145fafb2224b3e5b7c5419ce702b91ac7f4ab4522345ad44138e3169159b3 +ENTROPY e1fbca1eff2279ac21099b55c1da1ca29269030830997607c5b4cc1c2347fcf7 +ENTROPY 285dd798651e92f7f8774e0f87c7c4d6c26079f9c55a308e7b8172ca63d08ac2 +ENTROPY 226fbdb2a104c1d9d58e6a062fa43f1e0656db38a83fe746f8b464cbfdf318c1 +ENTROPY 45d6a2a73925b526942ee8dadb798e409d145b7f00cf00b4898ea232471c9820 +ENTROPY 971a3edf650b95b349c92cf72fe3f73d53f7d9ecceafb47328868879fecc286f +ENTROPY 6c0175f972457a844d5647ebced8308a5ff2352c66d7b67e1b9008cd647a52fb +ENTROPY e346af19bc2b15932397ce7d81b80b79e61ca2fde3086f5265c5ad79e2d2e250 +ENTROPY 07b2d9fd22d27774a9ef752898bc954b4af08fe4ba8399e6aa9f9d0b276725d5 +ENTROPY b31be87b82ddc705e6349b6409b8e35463ab5e63aaec9427c94f5a09349f72fc +ENTROPY 289f148f319ce5084d5ef5db789e1f559f1cb5f56145e11de42e36a167a1cd5f +ENTROPY 40b6e7f60e6388a505ea08ea2c0a19f61f1b7d35c38340b62161f774cbdaef28 +ENTROPY 42d7ed1881f629b082887dfcc6fad612cafb08f7cc49ce76da5b233b3106359b +ENTROPY f25de86a5e6db2957d0587c076caba9f7e29bd594244cdbc6fdedd0ac8dee081 +ENTROPY a26b421b8c6cb6bfa21d5315dbcaffc4ce2876f3f82c2c63af11945ad9d8c122 +ENTROPY 3ba2639ed6978de61da57207a95752d78edee7f3fd4e97dfba3aa440fe3234fc +ENTROPY ba433eb0a6157977ef09f5101e160c015b5825122212acf02fbf676c6eb1d14c +ENTROPY f75aa40c89576065dd27217e0ae97e829e4e250ac608e5dbb357c0f81799c10f +ENTROPY eacff83a08fe2086d893407c63283aab3501dccda438b0480924dc81481de4da +ENTROPY dede6e9581fe863fb0405c675497e3bb5125bb01e2567972c8ed66e0d3c721b6 +ENTROPY 1f366520f831b6d11d820e301fde97af185ab8cd1bac1003e3c83c761c37fabf +ENTROPY b563b79af745ab731907664db6676176d3a9973bfc92624b9f8815461bc6d363 +ENTROPY 13cfcb814dfe7265b6222d7a83cb90ad59cfbc01dfeba4d97d6e281c80870f76 +ENTROPY 932a3d9546dff28535044e62eb427d5de8311deaca85b0860402cf29a273c962 +ENTROPY 95ceea9b4468d91156ced575816bdd3730a176c9015d3b12eb73b9c654f9f418 +ENTROPY f349fad0d229a35cf3303dabb4e9fe93e9a8ae5d8b8dc93eae68ae3bad5a9851 +ENTROPY d101c8e0b0512917287e43658672bf4435526ab8ec132251e4ab9b815b63a081 +ENTROPY 602fc23c915408a9a26baa90229bab5f27faa784b8dbf3ee3c29030a86eb126b +ENTROPY d958633d8f74d9631a061935af5a7d2aa47b76c512dab260dbc5dae2ee458929 +ENTROPY 35f63229e511e539c81db0658cbb124c28130e752f31828cacee345fec564ba1 +ENTROPY c0c3b294afd8c7738d1e91910c1a533dbb350044ff879032f2f8ba6e77c89267 +ENTROPY ddf0395c0ce59466608dbbc9041d70a7814b917312c08b4390859840f416864e +ENTROPY d085c045333fe1e307af5f5a9096f994c9637e0a0eba3290a0e5a629fc9060b5 +ENTROPY 991aa919472ab90d812c0b07cd10a632074248c1fabcb29bc300b9cbb4115f14 +ENTROPY 40a06646a792031e3c572ed06bd6952f7b0211573f8475132849bbd04310536e +ENTROPY ed25910fb73f68fee859df28d27c979f19c9191506abf77ebbf64fcbe6ecfca2 +ENTROPY fa1bc9139f12e0b68fa2cca6e2aad735a141da59fe72d23b35c5c240665b9b1f +ENTROPY ebaebe7ab8711c50c93fee2c7f00ce5968f941bc94a0c5a3f8419b1a6b971821 +ENTROPY 5c9603dd4889c67d659683f7f782f360dde8e7d29a4f10f7eb9fb4ddcee16605 +ENTROPY 28508120f39a5c83591d0cedea37f4e5c6f0430c595bf1a083ed35847be03c90 +ENTROPY 124e1fa836f734654fd52b16ae49daf47c90526bf1baea9ded7af727ccc5c6be +ENTROPY 893fbf40a0e30aa2ed743e404d9b08ebd7a78812468d8e7c6e08a5b32322c4e8 +ENTROPY 989f2b0f8471d49cc5b86a8b440c82097be75a8bfb0dbe987c882a1700ec321e +ENTROPY 345983a2acadd3ceafabaa2d68c2be51236b124ada1adcc6ce0262cf23d32fe9 +ENTROPY fa135a2f3d47740cab8cb88e0efbda2562fc6b74c5657e72c5d3a798e10ee29e +ENTROPY 334e872a5dac7b6fe7add440c45434f7fdf8b327dff2a3dff70d322d49e0c225 +ENTROPY 72f7507cfcc4fd9df252178711bfd78c7f46fcd3a4b80ead2149b87945a7f742 +ENTROPY aa9ae7c08e0d290e69e623447f1d81a773ed9363252d9300859b7dd5266131b0 +ENTROPY 8f10ebedd77513d204ed5400215dd2f910cb59f91c20779f1d5f0a0dad795d9c +ENTROPY fd70821dedc69d5a20f18f9cbda8e09f1384449e1f083afdf2ebf2624cbeb2c3 +ENTROPY cd6670c92f914f0019a1cb8ecac3314018a82c64d50dd18d29ce128015ae102f +ENTROPY 62e1fc19f5614ee0ebabd713e8bbf8e2855b83abfd63c645f87d3b0bb6de4e3b +ENTROPY 7f9adcf8c9abea1f06f6fcf9ce9cf8f5f2f6c2238b3d4da5db723518581bd9f5 +ENTROPY 8eba91be637cad34c11894d52cb5275049a56f09e972b075416fda205f7ba941 +ENTROPY 05ea3f3bac574f107880ceef0b093b699b4bab3b1e44b9e6d27f2b0873b007fe +ENTROPY 6889670e1954142e9ddf0f8ac7f107626898077d7d5374734ed07abc743b77c5 +ENTROPY 4a0f80c4ac48993ac2e3cb6f3f28899baebf4f6f36f928fca03680211e92a546 +ENTROPY 4325604f7f4de6a584e2c1e5ac3dba8e527641b568cd4dcaa71adafb86ccf8af +ENTROPY b1082b4d1c704472ed6674c847f717913afcbb7f4fde6666b836287580a0e482 +ENTROPY f0fb178403dcee02a37c81b9f130e1851e2f103055ea52a30ef17ed76546d4dd +ENTROPY e617e154271cdeb2b6f450483e83139c7a60998a56b065c710114e1d183332e0 +ENTROPY b4f26a9535d8e0fb0bbe4b0108802b947e9224092feb38a95197e0f5a89f64ce +ENTROPY 563152ff57308eab65ec6f87ae75013bef54ff2a8da710769059d1f3793339ba +ENTROPY f9b3024aeeabea5c4bbb6f9f128825e21b10441cac956afebf2d5e57dcb34f25 +ENTROPY bef96150f9d2c36ede7bebdaf4ee2fa12bd7f37ae8292dd943b40ef82581cfef +ENTROPY 543d1aba00607f7b615e88c0a8bcb15187b1d463a4cabcf0daf59eb2bda2a0e2 +ENTROPY 757532853e30d5ee4989546bdc334c956994432018b287448ac5ed64349bd354 +ENTROPY 26d3d1e62d23757523f0bb0ae4133738a12a1388f7e96b88454287e4633e7142 +ENTROPY 9a9f4f9db23fe5c8426f89df15a05882ac0e52bd48be645dc0b86e17e51a4554 +ENTROPY fe69b41c1a25130be91f8f28bb72fb2f23866198adecb2dba97bb104768131b5 +ENTROPY 88a8fe6422f83fdcab90f902ea7d4f6d9afa9f5234ac8d1bbee92a3c287f792e +ENTROPY 79621af5969003d3993a1f4f5115b6480d1f9f560624a700a4559bcf71c07a5b +ENTROPY 8c12e61d967a12c8be0eece3e7858c53e6e7b54085f1e7ce6b5054e04315f7b5 +ENTROPY dd83c4537a666679a37f3bac986e229f5bae02e794ad7551f76f2c8365e52176 +ENTROPY b06ccbd0e47780ba427025ba933ca8bf8aceb832d71c14efb7b8a2f59b738535 +ENTROPY a52fab39938e3997296d5b1d7e7f229334557d26c5a2f65992fd2ed39536d9b2 +ENTROPY 443bfff2df958d27d7c53acd26d8555b8e8194f8fdae34e316e5526db2bfab8f +ENTROPY 5a06aa9a3113a4fecda6e60ea0591f32e347104d81d21dc64a33b577e9d48ddd +ENTROPY fd03e32f05d4d81889b09bfdc44c0cb32ccc8f594cfa76bb3ffb847a6f1224a0 +ENTROPY 07c878b2a5170833afaeca89e64109ff0ef558bf055cfc7e0269957b2402c231 +ENTROPY 3693e89121e13b6962c417e24526ebd75e299e611f14841f5aa7c7c24507ea8f +ENTROPY 95e3e056f555097e69602c338c388dd16e947fd051ccb65e446675938682a0a1 +ENTROPY f7393cc512c26bb0729b0e064919c33542d411f7c4dbbc6b5042b05f4ffae2c3 +ENTROPY 05758a540e03cd7b4a7556d4ae4444a319e8654f16223f254dd1ad1347218135 +ENTROPY 3aaf06e160b2aa99c14c85cfd665ac7110efe6ea875938ae0fde4b3811788623 +ENTROPY 0e024b6e861698d80aa0ec3b8a0451b35a31e26dc13e55a0b6b3ea1285ccb7aa +ENTROPY 7e53c8a135ad8e7c40bb4e66bb8083b8beaf6d6c7ebfaa42512e61517940c46b +ENTROPY f39869d971c7e97849949dbaf379e4c9b1eeff4380bcd940e16e9d823242fe1e +ENTROPY a5a634c539063a6b177d99d95b2896ee99f20f52159450219c1632b74af3f327 +ENTROPY 0c0812cc1dbb83e434189054a0c06edaa6e0faf6a37caf344aa1155c3a6e154d +ENTROPY 3baece8237977a41609ffddca01e0f851032a5efbbec5473ec7ff22579c5330a +ENTROPY 2ed934fe2f46d80e757a8bc654c96091c7ad72b1b5656d882f09d96e7a078ebb +ENTROPY 18810668ae62ef60558f9e00863eecb6b047e9a121a3fdb0dbe6a36ec6335508 +ENTROPY d45b285e31ee4e2ce7f9a3a62ff49d9098ee61d4347c1dd4add36d7edfc5cdb3 +ENTROPY 26d765e5def16504a684fa77b1ab8460b0453e84db6d932544d60dbef239dffb +ENTROPY e55ec4578e2509f067594e7dac80e0975730413fc312aa739a6d039758562fe3 +ENTROPY c86dd4c6a3c3e656f570d4fb1420c17bf5221ef48fb0349415b13234573b4f8e +ENTROPY 6e7fc482e7d35ae375c95a4841d4e9e7054d421bfd5c6dfbcaf0de42a92abf60 +ENTROPY a799130773df9099f05b817df8b43ed353065d2917aacc1b232061ecdef7d918 +ENTROPY 7e9c6471a79ffccdfe15bc1eccb99848b83680f290e78e4b74b89723bebabeea +ENTROPY e26e630d381d79aaea351ecfb2bc89a0babdd84b2745b7501fe2d46ebea69cc2 +ENTROPY 609a6bf601c4cb4e62598b67fb90cb990f4dc9fa0f6555979c11cc9cea08f7a3 +ENTROPY 1982b41fe2efca84aadcb7fd833c8a1f06446709c8c9cec20b2c94ff9c9c9552 +ENTROPY f5c1a4548721ce8fc438acaeb098ae22b93321357e720d434bee880996e33f4b +ENTROPY 6143e594f2627b704249195053b5765087f8f8fe674afaf2a767c506267b4f30 +ENTROPY e2489f2e4006f308354367a42c419bac18f2d803adeb565d747683ba6c4c7950 +ENTROPY 26e74c4be667e8c5bb12dd4565c7f168d02d236f726f924a0d08842373e8037b +ENTROPY 3ec7066e9ba2323767c6cb7466229d63327c391919d26943ec509cbf2537e42f +ENTROPY d50230f6af0022e0ed42187ac10e0c6920f978c81695675c5abf5fea8ab7ed1e +ENTROPY 8ba5fb2380a69a0505af323b99b3c000a1bb8b8f7040ee1856dc0cf32c61f227 +ENTROPY 739dddedce1d1397bf5ad041e7fa900f31cce80630bb0ef2feddc68f699ead07 +ENTROPY bf3ea302cd411cac1ae4aa448aaccb49a1d7f4a392c62025888b4433775923da +ENTROPY a266ed4025e23d449ff6e4a67d5b05515b113daedcb79948a6a5f559afc0dea1 +ENTROPY 7f793594c1a05f98827376a7dbf3c6ba3b3bcfc8d0617e2eea34d008c0aec8b6 +ENTROPY c7b180609638d7a6668a277455d08d5a35a26024d9975890813aeb67bc49846d +ENTROPY b830e6ea8c0b465db726c5bf32bc6dfb594f6e54b1aecd45972839a65af46050 +ENTROPY 6eda88e99f7f08d1817069fc1f41bdcf2175ea4666ff83230541aef82fd5052a +ENTROPY 5acdfceab342b42679aaf94aebaa3fe69eeaff8d1fe308ce1dfd306f0ebade45 +ENTROPY 4ac8a3c0bb99e78679d300d55b947d8686ff9f9a7b97f6d5157af88f96f861f7 +ENTROPY 022cca3c21e9076c2b668e0b2b8191c73cbf9e879353db92928e1160b0d02ed6 +ENTROPY 36ffca5e07a5be0041e8fb38f3ebafba15f4e61e8f395a121571666b6bec088c +ENTROPY 541c0cfd9f91906535ab7d36e75f55533871057e37847d4617c73f0d1bc6be89 +ENTROPY 25e2f678847253667eab2e6daa7d396b82810ea12c6202da8daba457f312d980 +ENTROPY 04b7d231d716bce9ff76188155024703bc6f2d3bfc87d1f8ca40d5a4127dddc8 +ENTROPY 5f018e345522aa99b39d31ca2142f9ccb4ef6b42cdadc029697d504d052b8e8f +ENTROPY 98292247a2a06eff85a0e239f439951d2899ed3eca5ff10db77ba6a7587c4445 +ENTROPY e52051169af77af135cd91e4fb8bb0f4c4e1717f84db5581200385a653df509d +ENTROPY 6d744953aee83bf6050de2e2638743781a5c7802977c60502d73baf70ee94ae3 +ENTROPY 5fe76872fc0e50ee4ede98cfb5b363a44609aa4d01d3479f745012c32144ece0 +ENTROPY 55e5c6c48fe12c304ac24385a2957b8a25e1969d20710e55f18a8c68fb4d93f5 +ENTROPY a646ea6ed2fb67632a3e84d4881e20d35c6d6573631ea7171646ff1a1dd6dec8 +ENTROPY 3353be9c229c017d32aea877a8e14c2086f06858adc0c5ac2dbf9b0e0d9356a1 +ENTROPY 1e8fc98b200eb6a39d1e3cefc2f3e16a0d674d0f813ee9d1095216349182321a +ENTROPY 1eba4dbc1eb793f4132bac5eb6aa672a847740f561a58c4a7c0cd6009b8d1293 +ENTROPY a6e6f570b3058dbc898a79e6640b10a234560effafd197f9085234bb16c75d39 +ENTROPY 0b34516a24dd15eb1fc201fbe978d3a26b1465bfefd211f831d21524673a7a5e +ENTROPY 04957f9d451babf5eec62f73c304f6288f9c58866709a688eacb56572d0bf287 +ENTROPY 6ff981ad238b58f5e2d33fb41bd5477207e9aefa9521d2c7adc4cfea6a3cded0 +ENTROPY 4237cdd5fa21301b07660b577c35ae8071a6aa8f1516a41a205937cc332d11de +ENTROPY f54e6b2171b1497f5067a112d0f16b4bf7f9b001dc8d0df76d79edfbdb02df3d +ENTROPY c2b37dd7b9b26030dfa69363061e5e57d7f05e0cec3acf8831fe0c1a96c061a4 +ENTROPY d64c373fe86d75718e33bb6f38fd1453c73a789366feaedce1ec65101baf058f +ENTROPY b2377e3150232093c5304898a3599ee8bca76d268c01b7d7b2b6c52b18b7e7ac +ENTROPY 50483023e8c29657b57bb36f4d20535e1ce69b8313126069ab0f89aa46f61c11 +ENTROPY af8eb60b205b6f4937e121322b0440d159b0b65cc2e63f17aae6454317983439 +ENTROPY 2402302d98930254f91eb9c0dbe2533c1278804973a7f1e73143e4c08a4dcfc0 +ENTROPY 8966b98e076ea9c05193c7f276ebceafb56e60a9aa99b0a7ccd5f383ab2a19d7 +ENTROPY 34a675cfe5ed3c20945d1327d43b500ff416375fc96567f3563e487580f0ac81 +ENTROPY 1eab4a126f58e7f3c0f12adfaea461a9539209a8c8dcda684881827ae456280e +ENTROPY 802d7ad30b27fbb7a0dab07cf1de98fcca2a535928e4619fa32d2ac37bd0151b +ENTROPY 6f46009108c7481dda11053fe954297d096ee7e3853529022fe5d344bec39a57 +ENTROPY 3e70c89c7cfa89b09c67c6c84b8ea13982aa04cdbb4ef89f3cba89115cb442ed +ENTROPY 790d4714435e7f54c8d5a19a8979bc29f626504f708db754158137513f8d01ca +ENTROPY dbe7dc19c385774244ce01c6634d0b7920f9f803279db3007b41e3d4554cc40b +ENTROPY 3205221f1be944a40a1e7befe802ab31a0c28b39be44592c3b358843356f1544 +ENTROPY 3fffd3b29ee7d8f2c9eeb5fae6331007e647deb4abebd902a203a5ab9cb2e4c1 +ENTROPY e7c34655bc87a21ea8b3db0f05fca9cb4fee9844a06c7bcbc95dc596f6a14988 +ENTROPY aa8b8ae578a778d85e3807aaffe8fbb9a89bb0add80d18a8a04e3a48ba75a033 +ENTROPY 0a9538b6884832094ea9f9610720b38baca16da15937679473416c0ab9753a6f +ENTROPY 08eed9ca279d9e6e83581bd8358c0d0518fff7a7ef60be524cea3bf850fbe611 +ENTROPY 702dcd7184000257643b186f465bf92afba20169641f51e69f2f153e6cffb424 +ENTROPY 58cb043cf5524e5888bda901bf7341b3634fb812613ce4c335f08873c445252a +ENTROPY fc9ccbb7dae38b2c1b551b2eb1e7a749f71bee0a167ccbfbd8f40f095affb8c3 +ENTROPY 3243cfe90929db41baf7f0df3d2d2293fba9940062bb63b979124a62daa1111e +ENTROPY 58068e02c409bea104b9aa418ab40b5a9ff2b2490ed6e4b01625c342b38f828a +ENTROPY 01e4da18f37a26b873963a36d270b9d8aa7425771c52d8ddf0b56dae1d1370b8 +ENTROPY e33ef368621dde49ba376241b8c6fe82ca83cc17e54f0b8a608aba02dc8a8d94 +ENTROPY dc398531b9d32970919f6ba120a8196c3b7ea90f2b6eb27ac74fc1888194ec76 +ENTROPY 99f5f28ebb8879dbb5e76a8bdd6bd34852f5a7e329345a90c9c4fb5da654b720 +ENTROPY 2203544c97efe1a21d98a238fea4c6f9840eb78a4ac9bbd9f67c77ea7eaad0e7 +ENTROPY d3b5b42d2a94a5daa25ee57c28700e756567dd02c2e103f4beb5b302f6a56a25 +ENTROPY 528ff88b40a922140d23dedb5736bedb3ec541535a4272cbdf69baebec456553 +ENTROPY cf2a2e69fe472e76b5219ebe56472f7722a9d3cd9098598c54a1d2ceed895352 +ENTROPY 88b089385a1cc50051899f25982346bd629fc76e89d6b3b9a884af076ff4e456 +ENTROPY cc06c7c5582152ed7ee0fb0696543be066b47a260eebc5394a62a348ef48c2b1 +ENTROPY 83b4b757d483714de6d382550fdf7eea45dc13a27491d028ca1284e9297454ec +ENTROPY 78ac6756c25e1d063fb1b8ab6826eb6aef1f4f5ede9e5f36db5f4139bebdc77a +ENTROPY 3ca524a2ce8e14a3363bef88b9bdabe3265029e54d0d4a2798fe20eb179e9693 +ENTROPY 74839d70455acafc43de523c69fba14fbbb58626f5bbf5826c570648aa4cda6b +ENTROPY b00ce217a3862b85739448d7d6821fe8ee4682780ea68d98de38bef9bafa3880 +ENTROPY 66f2b305a30e88e92936deff29575a7cbba93924d589c37cddb057e285ddfb9c +ENTROPY 55fff58fd395fd8ec72ffa762f9236c15cd6b233ccd9cd89f4ca3b02b9d4b6ce +ENTROPY 5bb7966d05ca479d6c4795921a32683a4372ff786726e9efd4d7fd2ce32b5037 +ENTROPY aab4c96597978630a15f3e89c0ac45ba0d5ac83f7bf3c747fa4a149f15b67390 +ENTROPY 19e8828a6a4104f70d721e8ea902be8ef6ed2a5f4be614ce59265992bc9fa6f3 +ENTROPY 07564669c6a9dd673571f31f0d8a86b50ffb82bc644add8155d8d0493a415546 +ENTROPY 688aa91f38a93baa06c50570f49f2b6fc65589b31a8158adf65e371da39e5e1d +ENTROPY 65dc61993bb410c865bfc9b6eb3239aad4ed5d9296da5484fe1dabc7755a2e92 +ENTROPY 94dca916b468cb8935607a5d88fe45ceed101ed498ede4d3a1c907ada0f28232 +ENTROPY 74e6feddfb8c99e075bb84a9e024f16a5581ceeb5e1781fa3e825dba4e6e7961 +ENTROPY 52af63e289b13fc74c2f20486986d9526e0d85dfd9c23865e838acc19565868f +ENTROPY 9e0a925d28403d04e77f5818e29eee0aabc8bcb609d13ff7763c5bb35f26a662 +ENTROPY 4a5bb6df75f49fde32a1292dae80f93308fdc32d9e9de4e783c8c606cdb0f065 +ENTROPY 321d93a0abc2bb6c210fdf0e72dd0750ff7db94fab61d79c838dcdf2a0badc75 +ENTROPY 49f166ca5ef441202af3d03a4252cb6cb844a153964f0f5da823c3a2d7936715 +ENTROPY bd47fa549818c0f296f753844df9442a04190b793437bd1fa5e45a9b3490db16 +ENTROPY 66bc14224eb252335b073ce9d04b223572605249596545f599768ae013c0893d +ENTROPY 9a767953a01c39a8710942baa33184bed7d5e1866718712726e5a50344bb65f3 +ENTROPY 106d897ca78f0acbb91ab7a1e11c7b3ec188291af390d2bc6f401d4c65b7e0bf +ENTROPY 28385e9074ac667abb2f4c805484876ca77b6c908bc82ca526f99a5c8415f52c +ENTROPY 45cc74ffcce61bbe5d64cff391602fe26c8d0f84fc2360a26c4c2e5a67260c9d +ENTROPY 545e037e185936109956c2be05d84da360153fab0f91ddd265e327023f1b215d +ENTROPY 1a2e006355d93e28a3664f3a7aff18457bfe1e1bb202b7c5bd58ac22bc94cfd6 +ENTROPY 4b9f5c1d53b5f03381157aa88bd18f18bc50064961868d22043da7a0d5f8d977 +ENTROPY 972012d7338fdbdc89074a70269217d4fbe46ce1b764f7581a809cad63365153 +ENTROPY 4a7f2914096f19944d919dbfef9263dfa66a73c117dc976c267dbeb6439774e1 +ENTROPY 97ec859ada01ced68e8ec1cb38f27eb63dd183ab5b65f97122c736c81bcf952f +ENTROPY c7b53186e883a89d4e7b5c23bf359132332017d3f15b4ad6fc4478a9d35f0970 +ENTROPY 53eaf5e1af878e173bb2912bb5fe10b68671cbd28b5f2c8275cc3dca7b993a97 +ENTROPY a59bcc67b396f6ff2a2ca067879adfd4c9e1d99ecfac6f1a77976120a903aac8 +ENTROPY ea11a0a0d34fab594290546034d0fd9c6eb2d5c0abcc3d08dbe79904849e8cb7 +ENTROPY d354a719f8702c7ae8c371244961724fc8f000a67d7eeb4e91168803d42808cd +ENTROPY 5574aaf02b76dd9430fd054e65614c3a044cab1fecbbe477ecfabd2eb752359f +ENTROPY 1bd46a95dc01f8dd9766a8f9aed48de1bd13114b446554a3acf182bb3652e3df +ENTROPY 5bd4e9298912ed7b8c804da33c0390f4295474e67a9f1cff811dc424460a1d94 +ENTROPY eb75feb759c5d3987b03c0cdcf5988e963b7337ace84765f38154bb583d2d2e5 +ENTROPY 1aed4b2cedd8104f6c36b836023a3d86a428467cd11f250afbeb404825703d53 +ENTROPY 0a7022656d5b3d6fbd2bcf057bc3e5c6feee85c0afc55993d444081ad4297ddb +ENTROPY bf6adff398b69163cd8bc9b78d1d3acc5175e7f52bed1acb8097d2a7fb192e66 +ENTROPY 3123a1c6d9219544cfc62529cb6c73004922a382271884dbd5b923ac2dc026f8 +ENTROPY a8ca58940383d95c66df3186ef28d3754c019ed01d2d9b0a369cf8a024bc42ab +ENTROPY 932d2a86f36475a9c2289970fd0af362c40271a425228bcc22e460eb3016f421 +ENTROPY ea9e0e58daa4fcec6aeb6d5125c3486ae313a9dbda7cede60dc803b2d7eb3e80 +ENTROPY b01c2d2c7ef4f361c04c90695c84e8f83b1dc380a54a493c5b104e443d24a2bb +ENTROPY 0896c67191090d8be044c57e985071cc04b6381eedeaaef9a3b66043bdff42d0 +ENTROPY 73e1190fc1281794c41ce48ca0d3b02cc17b5971c1d57239fdcd1045aa1d43a7 +ENTROPY 6805c368b7bc70c777be564959858d8ac31ce68606e9b3b39c2db4c183e32353 +ENTROPY b1822fafabeb6413747b06a6269f99e4ce4defe9b9b70778c1b665e8215709de +ENTROPY 63c6846ba966dec8635d37735eb92b890da5977deb81b9ca58db2e14cf82eb8d +ENTROPY 21fe1a43913e8cba11fbd25ffc02fb9bf79ef0972d78203c8e94cfd4e4d5b8e0 +ENTROPY 546dbf51b679fa3a1dd247d66cf8ac2821cbef7182228fc464c90743be4ba29b +ENTROPY 25b4b9d8a98a6a78b63d34b18bd36aa84acb3c52ebe488566274583f022203a9 +ENTROPY 1846353c4ff2e77739c84b50a88ca9d04cdabf18e1126e203445fcb73e338f69 +ENTROPY 5cf142ef9b7f18d18c687f4d1b20e005eda524ae31914f68405faa8ec5a18750 +ENTROPY fea4ce8e3d0532cfbd491c794988e45799d5cb83a9ebb429f88020a7033986e1 +ENTROPY f97eed869cbb0b853deb3ee2ba7b7525561b4e0ace84e2b8fd541cca396acc43 +ENTROPY ceb9cbf48156610effc86d3c70efe60ef57c4dac2362d6a069be9537e0e28e83 +ENTROPY ef5495319402ae8245e5be97d906a22c8fe6e32f65a91e361a2ecbbb1a1ad833 +ENTROPY 65a20b74b01baf2b4c9ded2c56eef1d735e653d78898e39fdbe91c39cf33eaf6 +ENTROPY e6bb9bda97a7e51fe53a86da16444b24e9d4f72a3991d6ebcb012b423a8b631b +ENTROPY 95ddf9f1be5d7691d230cee91397e589001a176b73ee5fdf8d69ce96335d3462 +ENTROPY 6e8cbcf491123118456c8b50403e4bbe804b5317462ee494827acfc1914e6e31 +ENTROPY a9d5e063d1c73b5e344de502dad0b602722fa6bdad352320a5884c6ea822bb73 +ENTROPY c499a1ac7a5749eeeaed394dc0354dd71ff26e9cc8ddde27c1732c1a3e56a8c7 +ENTROPY 424e42cec41b6456373a95ff94a339617c44bc864f81b91bc5881d033f839eeb +ENTROPY f28d3906582f426ad6a638825bb8521e1fcc038454831b574c1037630a324d0c +ENTROPY 72f66e8c3c5878eaebbf9b73b76fd29360ee95713ec450e35fd74ab3b1769603 +ENTROPY 44893be96043de8d89a4912c2940db1966fd85e6a06dfde356509da7e065b581 +ENTROPY d86f2b3ece70657cdde4c5480b71a9e1efd39b753b4fffc5a7bdec1e0cf6f0c5 +ENTROPY de4acb64e1b43ad5ce8bd36838edcbde23479ff15a9b9caf8d4e992ee04e7da6 +ENTROPY 98f7e72de3907eb24563ac93b2772285c47bccdcd79f0ab999f453b32f360eb6 +ENTROPY b9ef446bea446382d2106402bfc69153385205eb907b615955566b790c94f2fd +ENTROPY c0f1b09fc31353cee7157897ca23260ab6603c5318b6defbfb86ef0bbe111972 +ENTROPY a5a9204da5e37cb996d50a96e7e415cb551442a61b6229c1bcf27817910ee7c2 +ENTROPY dcef59b16e4c6fdbae2b7aade9df0738ef74c9d8743ef95dfcf454d087b140ac +ENTROPY 4f7a1f0df7262f4a195b46e5c2342a271199dd79d8688fa5a036a422eb06e228 +ENTROPY 0024f9f4a7eaa82ccfa82dfd3cd183075ea5a16216b77c2ef5add77e8d49fc88 +ENTROPY 23f827b8c577529b1620f706269847c93aa565061f4311edc322d90111378d6a +ENTROPY a96bd58a209491d2ab27f4da6237a26c61ad46d052db5f48254773484248d2f4 +ENTROPY 806fa6dd8b63b65611e5d241940e2471e73488b67fcdacdb497874143d8ce827 +ENTROPY 8ddfcfe1e91123646858527dedab4067e35a385ea3b908bb5ab03b032c53096b +ENTROPY 45d9c0e865297968ca5053b9c6ba825f99d633cadc8b14efecd1711cdd2afa51 +ENTROPY ab4a2576d35b53f7e00cad7906e24ae90c2bbd9652ade356ff6538993c58e615 +ENTROPY 2b6ee02e8cb16d45315b03a5b2ed8c6bfcb0b9970079410562b79ffab3bd9729 +ENTROPY b4d8078795df56252380b9354e9ae930bdf4a79828b8823054a2302cf0879ebe +ENTROPY 0396343a2cce9e8fb7d353fb344bbd1bcd9632d64f6ce6b41f7c09de80736e3b +ENTROPY 92d16c0a4e8f39a5f5b3034ab47a644fa35de662f42dc2725e7752e57cb792db +ENTROPY 9ce2d57f2494150ecd0b6f0f06c70ff53d5a0b2800287f2aabd1421a42c0b620 +ENTROPY c862c0a71cc5710c2a7f456228bdafc1f849c5a7179cabfc8e9c905479ecda55 +ENTROPY 15ef882b1ae54be87c839a59231b1d011bf83fd7e5132d265d8a1b2b008ffa95 +ENTROPY 251981d11487d55c6c6407aea790dce05ae3cd16de11d7b5434511b2a51d1459 +ENTROPY 0ff3675d9642b587f8ffebcda154cf7b353156185e5a0cceca61d1b382c9ee94 +ENTROPY b2a604c88696bc325a44d2f1fc7d72f91e329c70555ecaad07bfff426c8fb53b +ENTROPY bc1a4e53708f9c679a2fbe2255b23d238844a42e205e7b8ef8aa5ef0454f6163 +ENTROPY 74c0c3f74c7a382aee86418ac042cc58930febe1264a60fb9e5ed5d5e528ce8f +ENTROPY 63edb5710d2b41b6ad42bce110fae75cbaeb603cbe0b6c530afa3ede10a88abf +ENTROPY 6642defee8167663ddd445159e31fb6cae484087eb280e8114245bd56dbb89c6 +ENTROPY e0de7c418dfa62d4c91c1fb3baea028bd88d63f951577d495e2528a3b75505d1 +ENTROPY b59faf8c388cba271ebda3849433ff932157920f2d42f27ef23ec2b7068caf72 +ENTROPY cfd4c5542b7a9b76b7485a15108638d28ad699f8c4fff310af168322c32f102a +ENTROPY ffee6c28c4b280da8e2eb0c9bd49bd6560d121274c0249653955bc1695cae975 +ENTROPY bd92ae49b9323fbf728794f4103fcd5c34225019e1424c5bd428376f8271370d +ENTROPY 7b883205f4fbb25a8fd428249ee402d06d9fddac29ee7b1c6a1bef5184a017c4 +ENTROPY 8c7eb36733e55326477fecd3a0c6e51c2dcfc70365ca3de830978c4efb8b6fdd +ENTROPY 21c681519e411a186c9f1eb12939f71f3d74da44245f9fa8f02c9a27f9a6fb90 +ENTROPY f4bf7392fd2871f359825bd2375486eed099db6d20ad9b15858b04a420f1e70f +ENTROPY 2edbc2f43042e020a57c6ad938a445f4f53871356a197465768e6466d908ed2d +ENTROPY fdb7a280b66324656b248b1459b724d265a7bd0bada5a42138c72098f763c271 +ENTROPY 1712412ee4cd928d52ef2c0c6c5075602d86a7ef71c7310d2a02223baff4e489 +ENTROPY 4dd7749b43ca07e3135ad43c4a3f84db19d7c92aed0f733fd2ca9483361b72a1 +ENTROPY 5127c5399c591d5c5a5969880e477094c51d9c98a249a6d7ef3ab4f88c3b70e8 +ENTROPY 19c08e83124b73f599ba89d08f8ded2083a6d2d91dd198bcdb90c426beb9c326 +ENTROPY 660b8c1ceead442db0be77b6483ebc69a89d937f2abfada5ef1e0ab89f83cd80 +ENTROPY aa7a5d9beffed67468d50c394d7aca3a9f66a20a1edd9469751f3927aa786c9a +ENTROPY 964456364f4e62fd6a578cac08abd3d8bf6b315a44b3ac71e51ef7d6c0031080 +ENTROPY 5d45163f0865bb393047b4ae954619696735ac42fabbc130f5f02ff35bbc7141 +ENTROPY 6219677948505c4a92cc9a7ca22b6fcbeb60d0007565505ce30b767b3b9b7b9a +ENTROPY 41298c869cbdde02f02177154f41c04437a493ae612edf139c0987dc62b1ca9b +ENTROPY 1cdd4c28bc98b34544ab491a691faec7fc2b4ab91637eb271eb22638f17803b9 +ENTROPY 348d6b3997e8a5d40a90467d2e545bf9ebe3538a63b4025644149cd2453534f3 +ENTROPY 931aa80321fe0103683d75e1d69e5ebc5b02e5cfe2820f8d0461e421412f2e30 +ENTROPY 0457298334123d0fd3de86b0a0a43f1d2ef392107733471e29467f8878fec5ef +ENTROPY 16453c422c16738341007998f1fe5e222722bc8786be7454fd5873073c3d4b64 +ENTROPY c752a22e88d559a358da48fcaa5da5d862bffc57f19790df3cb4b01eb55fe639 +ENTROPY 529d879c89274955e918cea6f9825ac7f3b842644d5ca25aa55b28bc39409823 +ENTROPY 9deb303de1c6ab13d7070a156e037e26223ff4234c8e03b76fca60ca1e23b767 +ENTROPY b489aad50d3459e9eb90ceabcf9e146bdd4d4ef1b534122f432c0236ad04d54b +ENTROPY df85c5e8539df7740109e8d911f203824ffae2016d52a6a670881032c97b9ee1 +ENTROPY 4876f04d3d7a8d26e33c862db55ab3531d8956e9981cf95b7623eed9ed8989da +ENTROPY 259c240635cd804faaa69236dc43bea51d76e73bc45ed284df4b1a030354eccb +ENTROPY 7cbed3dc3c2a2df1551cf5da0ba4cb3079a4abfbeaca58ab5109a034559be547 +ENTROPY 46afaa25b3f0643a1cca327d4d300f106c63f423fbd1abc7056d6d0180b06b7e +ENTROPY 4c66761d329bb08833101692ea805c01ef51e7e117f44dfe6fe2721347f23dd8 +ENTROPY 28a867619fadb78c3179543d05eb0036e2b8a3b985a13348375df1e2265f3564 +ENTROPY 8d2f6b06ceae062c9f12c518393ae68ee37dd95a734efcb88b5d395c461c12b1 +ENTROPY 37edc3e3b16b2388aa48d65207f4b8e0269bc81b0a5bddaeca80821d39a4149b +ENTROPY cb2ba86d91ae08ee9312c2c985822fb6ee29a8b65d1afd175b4134569f1e2d29 +ENTROPY 69a30aa340e7171ea04f15b8fdddd35677264449be99eb67d4bad393519231b8 +ENTROPY 9ede998872bffd3eaa3bb33a1f536358cff8e64e427e30420f0cb79d2064a8f3 +ENTROPY 257c2497a9d6fc2f1dbc55dcc8eddfdd80b7d33cbd98b1eec64fa4baccb146d3 +ENTROPY 30e4fe90344797af008e1b296e488fa94ac5843eb9acd61e23bd37466f5a4f84 +ENTROPY 2934b4d9570e5ae4348b82c1c44275e9c58b6354ae6ba30395880f34963d8e19 +ENTROPY 890bde4a0f948fb79daab58df535d224328d98a0c1d8c00767f077c869df3c8b +ENTROPY c663527c28b9e32d481ca0ae5db75c9aa801c496a5d6882b532800d1508a82ea +ENTROPY 9219a48e53c08f750eff45dc7312232445452c91c4c8a20d4bb4bed5afa01467 +ENTROPY d805972c7f621739397f2839924513bff652a6aaeecdab649da7c9b0650f73d1 +ENTROPY 277542025b5f2ee8deefec9ec45311359070bb6a7eb90b0fc54a113a8bf6cee7 +ENTROPY 166ff41d2aec3f9975d56ee4ce8889fc705394aeafb78d90a8631e0c82ddd08e +ENTROPY 78d656dbad479366872fa4835572740b2b155676e0bb2c2fcf7ab1e186d19664 +ENTROPY e82f6a327c93fec37ac5356dffc87969e0df8511b398d94e2c5777dc934bc5fa +ENTROPY c1992411950e2c3bdce34d60f8995c1d3c0865be3341d55b6899ff697b3c1a4b +ENTROPY 2f889ea758590a3835506f5ddaa22a85298860e21ff824d507a58badc2751300 +ENTROPY a56a1392eb3339c3da4f92d5847b400ec029712dbc82e2fde8e1e4dacd172136 +ENTROPY c963ed2557cd414cc025118291a65f757effa33a868cb590456efc189fd55a0e +ENTROPY 9999a3beaf712f592e3c09d247c859630ecb278c139377fefb48e8b0462585a2 +ENTROPY 86d18224da796a90dcdd4fdeda5a4adc242b5afab88c921267e86e987b817484 +ENTROPY f9886436062f6d63cbf016fd17db6e56634af9fa1be859ed539fc06bb450a16d +ENTROPY eb41c4cfc17d572e7639b956d3ce70d72c73ee9356e929f907b26c228893f475 +ENTROPY e722ff365d7729cce1d89e13820166e6a2910265a991cab172d77d829d152f33 +ENTROPY fdcf8b743e3288501ec022fdb078548cd579d0ce2986ba34190fb3d0c97bfbe1 +ENTROPY 4a30c62359a1e0c9ec561d526ec67c95c23dbdd2e5dc48a19e42cdab217a952a +ENTROPY 2feb964c846595233dc241f6bdd9fdcebb2a460d82ac0476dbca9f4bb13fe032 +ENTROPY 391c23820233bbda7b663a6f9096f25c394f2bc00b67a70ea7f3247fa510f755 +ENTROPY 132e54315d1af751a43fa4642131021cfc1bc59af4e0a10a0da6ea5bfca313bd +ENTROPY dba2c396d1ec692582a837cdcba41b504bd474e66bc0130a9128af7e640ea0d6 +ENTROPY e0f9504ebdcfa5ab4a3bb8d438f9790d7afc877fb68d46a8ef1dc70199916529 +ENTROPY 5af8bb512b0afea64ac9137cf4e61864680a094e6ea71ca2a1846abf6a1d55fa +ENTROPY a0d7284f431acdf6161745e0846a2579d508a09e4ea56494a1c7495094ba478b +ENTROPY 7caf3ff4553c3b142893dc3a9572bf427d36644672b62052829318a36052caf3 +ENTROPY 8d60be912029524f418cd9ea64340753ddbc3ca00cfbe138a90fa187e4c97de7 +ENTROPY 0bd6201dc398acd855c56807dbb8748d6e710248df9679b6b51290b0475c9d26 +ENTROPY 81f33e9b31794371ca3c70d50ce3af65d4a2d7d654f46a2afc905ee4ba78144f +ENTROPY b89b505bfa22c93d720297fd2456d6d216622f8e1185bcde39df8e9d0677a91a +ENTROPY 406fc309b907d572b33d360f5bb9f394fd3edda0b4b3261ec494315666b3a94e +ENTROPY 6f43e723a86560e0075cc91c2bc84a189b39e3b9eb10294e4f4f5f2d5fe824ff +ENTROPY f22d3471664c1158b1a0f698404cce177e3abe08736c5ef294be5c7a74a5ba0d +ENTROPY 9281e8e3e677a87de859ae95fd32c469da9736491a74296161c906367e19cbbf +ENTROPY c12eb06b67f5bd20de755706fb979fb594467442f5d8c9f27017629cfcfc71cb +ENTROPY c16d5e38ed26e398721bae702654476a7e738e351e68603269f18ef7b8221f74 +ENTROPY 1ad9a8ee12000e0805d249de7f8fcb7507d2452b21077bd39235e5d6fd28d8df +ENTROPY 48c25e4f035ce72892fbba3980a0c6a4cc7e8c1d22988e68b09fbe5244729bc8 +ENTROPY 385a9d7be8e18a37184c0ad7663a5dd9d00c6ae5026eea75e316a453c50a36ad +ENTROPY eaecba12c1cd6e3ca5fa5065b8961cc5ed28e73fd94d44bc57f20ddbdb1b17fe +ENTROPY 81bf1ae93bc9272171d4db3c177df0083c9ea90210b38d019dcff1242f742211 +ENTROPY e55fe3e450561b1a224a4642833a87160f650fcb56528571138d918033291689 +ENTROPY fde9c7b8399955e09a30cbc4e89f65be02c7e53e4ebbed9b07f718413e5a6a7f +ENTROPY 6a34ef81dbfc7c710d501fa95f42c0e1e632aef0109616e694930f103c0a8b45 +ENTROPY 2525aaaa93d0a00d1fa5c7c5bc3656307f8ecedeffe9f48cedf34b1fb2c963ea +ENTROPY d2fbb330a75854a692c26ee4d52b0c1731af7be2a18ee64df68c438506f499c9 +ENTROPY c167812f1cb9e523629b1b10bf5b5c5db3102261280bb7b7eca40385855916e4 +ENTROPY 4680e7c1fda4abab894ed1a84ddccda413ef4f3ca7cce010968ed227942633a3 +ENTROPY 059ec7ea80ceda4de5e4358f0115f0e38743d18a9d5bd07133189e155af6f917 +ENTROPY 1ceb8499ed9923ab56a5ac22a1fecb38146c05ab2829aa9bf6893cd5899b14d0 +ENTROPY b43886449b09e72b7e1b776f761b35c86cd12516ab9568f647b0ec765eaeea9e +ENTROPY 692d53025058526e09267dfe319321eff78746f894f89241ce4c4fcb985637b1 +ENTROPY 12ee6d323e089a667a50de7ff9abfb96f1025cad0ffb210b7fb816fb050641f9 +ENTROPY e29913dae566003287c0470e292382c8c1f24429c54d09a7f377bfdbfc979098 +ENTROPY e7ab50566bb1394e6ecb06c2349537bd71611f6013f85a59e71a50501e03b596 +ENTROPY ab05abe6e557f8b76973c8759f6233b8f66f5f1ecb84351874c4a0850f956b57 +ENTROPY b84d952210b58a507b1947a702f53870a0ead5d099757c40698d6e7db179a83e +ENTROPY 57d0deb505549d4b4c2278bdece4608b90b9b75df4b7a44f328dffc0ecb9947c +ENTROPY 7b85167a3f950996bfec2bcf4ee066b048fe921d91ef8b96927281400c94f322 +ENTROPY c645146dee9759d86d4c74aa37cd45c4b6618b375d967caa7eca5c5fe89a8ca2 +ENTROPY e6b15a87d233032f1c7bcb9a35be7b9e4f4d72bdd3269375d46eebf1063c91cd +ENTROPY 5610eb9e62dde89bd57be23997a1e361abaa382788b8407823e5a8853d12fd6d +ENTROPY cc352fc99f28969c492c2e9936529edfbc9eb7f63650c1fc4f47ab678c54ef95 +ENTROPY 227d04c25161e6d32882fac3059b2c3b4a2156704bb932e9c7fb2d602c7cb7c2 +ENTROPY 7cf840a7f412fcdc8c3c713d1cbf7374af5da5323b5cb531210c3e7c1e26aec1 +ENTROPY 339e95801ee7dc9eb2cbf04be5c06f3ce4272b0e07b1cb8e8fac01ef913d5a64 +ENTROPY b03338a00337f02c758c5077f1c0836e69afb09b0c299e2fc27fe145bb6bb53e +ENTROPY 0de1bf34732ef805da3e3cacb42b116efa2797a2b966458813a11555c76c4583 +ENTROPY bd95fe26433ec081f4ce6bd05cc1d25ee752915ea0f2eb9507a6ae83aea149b6 +ENTROPY 6609dc98971bca4695172a72959f458bed8cafc13f600d519e48a94aab1bb3a8 +ENTROPY a5b6b4b18742fa8faa0976021cde5e7a155b6e4e8186474cb06477e24d61286d +ENTROPY ddf3b463e3fd1f76898175d8ed3e9b8813f93f0d350c0f9884d9c62a27d4ecb5 +ENTROPY d83b17d4becf5e9205f9b9a0e07a19e095220e5f83d5e6bce85f569a3ba1c02f +ENTROPY 6fbb9e840ba9be5d354acfdb96542f823ffbda37c4246d1080a968277aefa2c2 +ENTROPY e83a0ffde2afdc1d5e8780a14abc05b7199d5f8fcb6871ad19b60ad38bf8517e +ENTROPY c4780a9f35cd5f428ac1af0372f7e578e7b1486b7a6014a2f1fea22d0af0f69c +ENTROPY d938ffe0579ea37a11697e64cdc31d807d307c1e0628806203674decf4f0d984 +ENTROPY 8ea1a30add2e17602d0f0c986f21f1c8e28ea52ae380da06ce0e08c0dfeb1ac7 +ENTROPY 6f85cc51a114d4f43fcb59581dea6974cd9996ad1371ef659863e7aa696acb22 +ENTROPY 9b8ae3abb9f8bfa70c23627d0d8b2bb34017fe70852171226f25c9324b06d283 +ENTROPY 60e3b99de3e285165db0e2bb234635093605253768719677c0b3064a60cdb661 +ENTROPY fdd040727606e396ae35d3c268afcc005c9ec79e84f8053de0260d6a41208496 +ENTROPY c1c4dbdf5ec551e92bdf3ec8b5f7f75c38ffffb25a0832bb96571dd0f4a3179a +ENTROPY f64fe2c132d6c4a595fe6d537c06129f750980c4dc8f5a762c29848d6efb5789 +ENTROPY c836a7f6d76fad8468cf8277f0c966ac20f7f80c51cc1e0f921b200c83cc60e4 +ENTROPY 9d09a243221beaf9c9106916916221f9ce3d1f7c860afd1d9bf4df5fe09a9224 +ENTROPY 014995c9e29f34f26f53882271149b2de4b9609c723fc8fde99a62d441e7df32 +ENTROPY 1c861dbf92edda8eb5864d3e87e5a009dc44e297af314f949cc98a18d30acd23 +ENTROPY 29739f07c19d4cb0d09fd133298894a136ab3497b4edd72da3b2f24d57eaf4ce +ENTROPY 82944f00b87a45d4f4bf6da8f7f5ccc1badf750404c682a5e59a80d2d52953e7 +ENTROPY d6eba102932201629e1e72abb67631127bb79dae118d9154c407a161576f91b9 +ENTROPY 84836084f9e21f0b0b901e7159b0a164bd9d59545c3cfac194cedac61d667ade +ENTROPY cd3891d85f9e7ed94310da9215fbe1c19faa577ba911a9951e8811f6c2d640d4 +ENTROPY 13dec01275e37c32b9329aae6dc300ee38b5cd23f32dc6800506953a14bb1e88 +ENTROPY fe7c80936435e3ce6de42bc3b8a90b228e6034cdd6b0d6e1bc11b2194e8cce43 +ENTROPY 15856f8130eede4d03062cd17ed18b3f754fde30b98e9bb79ab3e2d0bd868d4f +ENTROPY b831f3bee10490631b4ef27b8c658268deba741cce10153a9dfe7389a20f3b9e +ENTROPY a18bbee5e9b21165ccb51e0666e3ffe6c63ccb5c11619fa74e9eb237b54c5912 +ENTROPY 2f0d33a2c6d263cab563b0c770ae839e02310462c0aa271d99861fee8e54dbd7 +ENTROPY dc6c906ae2832859b6b3c18d678d5cd703100ca12107681ba472a66ad9cfdf81 +ENTROPY 108e6ace05ab36e580ddb17427b58439926623236d77434641e9b821e46d4213 +ENTROPY 1fd4738f9a60916736d067367cc0efe33441ae1a13caa97ede7cade7493b844f +ENTROPY dcb91f9a9105c5690c8cd427738681d1d6ed131b15ec12b76923a2431afeb246 +ENTROPY 4259aefc4952564a8bccb2279558aa352c10709912e30d360d163a2e9d386bf7 +ENTROPY b7e9ffaf099bce15d93b265fff15c4ca134088db7962b083a1e415467053c58e +ENTROPY db9505a5e69655cb55ca85848552615cf330b8eb2cdc8086cb66854e5b1ff0c9 +ENTROPY 23f2793260fe095982eb0be545865d4a01d427560edabe79d899b8a03f2d3df5 +ENTROPY 1efd9bd33f30727a9939f93ffd406686d0af92458545e456ef3885dec66323e3 +ENTROPY 471c466bf8d107414046528019eb8c453754386504669f5e8e148abab88af74c +ENTROPY a5d8f095e45e30604bf8febd9ce4302fcaf1ce206220c81a631ab390302404df +ENTROPY 0180d5a61ec077c0f911b8c949a6deddc48b57efc50f10a59c19c10eed54e309 +ENTROPY ebeb928fb60318e61c52ea2f55f86933712232ec2115825413e7d552cd7d909f +ENTROPY 9f1c2dd39e551e80d7749fdf823fce1deebab11f10e230067fc89e8abcaee881 +ENTROPY ef7f056b6d80a0f16920f939a8fcefe339c6fe69370208e371fedf355b88dad0 +ENTROPY 92ad3fc034b7d29631fddd45c49f6a7d41bb33d8e5fa7ecfa591ce75c1cdec3d +ENTROPY 7479374c66053f612b50038b4f3ca65af8635805bc8342d605f3c80f4e4a7a8f +ENTROPY 6818dd43c5a4ac411db9071e204b72a57b52cb9a26565eba1459a8eb5ee9c805 +ENTROPY 888a91c566d69dea8cc2dc6e391a2f0ef75303ccbd6260cbcf581e476d578c52 +ENTROPY 0890c73984618c44692c26922924ed10fd8b324921e726fade0dbb9d6331065c +ENTROPY 9f8aedcc712e3e92269926183e2792cbee3765cedb8305fb12894d663bf8d768 +ENTROPY 93ffadf35762a693c9c115b52459aa7ec61227ac6056fe08f46f732a200cb525 +ENTROPY 0887b7f4b9497832f257c49bbd60a4c0b1dc696bba8f2630eabc94e23d1b4ef5 +ENTROPY 2076e6474ab71bfb4a613188f5874c70f449f28e9232acd051285d64d70c7902 +ENTROPY 686d3a07a1970ee6a493f547036286da197beb7ea624647246842efa54c92e27 +ENTROPY 925d5c253f7871a5e7b12c3223a20cf1953d70389d6d94806bd8d50b6ca13b96 +ENTROPY d3046ca13054c112a2ecf5a756cdb058b00c71432423fb97a3797acd41f238e6 +ENTROPY 918b0b4ac70fbae4db7231b0c768eac9413f12e15d7f449a42bf2d1f5c147f01 +ENTROPY bdc7e8ceec3cf4e44672f2cbe60f60556191d2ef6060852ce0395597929f76da +ENTROPY 97badb9f08aab8ac6794257c8a277794449d774ff2628a68ee940b0e46e6c2a8 +ENTROPY f84abf0ed93127b5da178f402cb03cdfdc452b3c8745454c231c9bddb7812cfe +ENTROPY 61826a2dd01b2d397cac5667332bac50bffcbd49226880cfdb08d7f9fe617f51 +ENTROPY 2fa0bbbabc66c8d5a5fac35b1a959bcb2c82673a211816dab8840bd454f16c6d +ENTROPY 39be9b38f6b43d155cafeabba8aacbcf7672b7c0422a18a4dd898b3be2d21b5b +ENTROPY 84e6fe9fe92bd1ad76b2524fb63785aff7f64a5731a833cf9dee503c0ec542ab +ENTROPY b97c7aaa7e97dc2edd221b46660f1f523ca41f5e0c010b136380882648df3aba +ENTROPY 5f82666b534b2759cfa4798b2adecf25436676e0e3321fdbf07f642d08dee82f +ENTROPY 1fb926f6ed15c89a6fbc6a8a3ed0fbbbb559f92137738d83c2b5200a5201b778 +ENTROPY d6b11b79789c966addc42125eda78addd1bbb2f960289b965c49ae56d4a1e38f +ENTROPY d42cc9d5b3a6628fa307700b185459ab544b39ca5110b3a09894cbb5873a57ff +ENTROPY 32d45a6d050d055b26d48318dc282055e60aa9f4871f4c45a8e52ee5c9541240 +ENTROPY 8e29cc5747d8f03259c72a35fcb0ebbd9a792f7a78027a3a9a4858d41ab6db8b +ENTROPY a6c8ecfa753a27df1bcd46f8137aaa4317b38067522d27d124869d2cc802e560 +ENTROPY aebcf94bb43bc8456f39098bba1ad95f7e4848dbe282096ffcbb61b8c147c862 +ENTROPY 75f66cb35306600b051592a2e8e448ee343be57329230091bed9cfb6a9b89424 +ENTROPY 6b9797ff2b08846dc7bc9daf32c1a2158f32c91604e0d0bb7b364062befd2f58 +ENTROPY 7a859e98e69837ade4c407e3701969449f8c5a72361a7536abfb219cb8b0b19f +ENTROPY 5d941eae775e4e7b68c902eabb774bf41b240fe5e9b30a8c185f752a7b3bbcd0 +ENTROPY fe0543a4c28a8defa38296a9c7654f02777532bd6e417fdf6f081d329bfac81e +ENTROPY aab62b2190e1f8b0c4c765fdee1ba0d5e4b890770ce31d15d6ac57f66cb58597 +ENTROPY 1882bc72c01ee30c34f88cbbab6e139e52d5f084efe15320eaafc2aa1e5aaa90 +ENTROPY 3230dd496ba7033f108bb5e87a04c8fdfb9bc35e7b985ee364cb91095c57b576 +ENTROPY e93e232e6fbccf157181146acca607b7e0df9316cf3e8996ea94924ae7b9b982 +ENTROPY eb91f97402d4899becf00b13e99399c9a662dbf311a186abba181ce533cb1fcb +ENTROPY 2c1a48c1f5512eeade73cc1d87451ce1022f74c29ae95cb26741aa0719f78b60 +ENTROPY a7931b4d03434c025caedded9dd7fb6ec343ac6066b366d70c4beba0c7458cda +ENTROPY e720965ae3a27a1bf49d5fad74db868cae60ed2658e685cf07e607e53a528198 +ENTROPY 37b63c48702baafcc4f69ab3e7efe6e89a9f174885e94def6f06fde7b79d5ce4 +ENTROPY 473216393c04b9c9f720656ee09db4959029ef9893977314e06e6769c3ddb180 +ENTROPY 6025a1b71e07463079de97af22b522b11a16f2fb799c7eb0c100470f02297ff6 +ENTROPY 45e62ab926a8ea29d8ed7eb65ad9dd15a782a801efefdc45e224b4405a4fbf9f +ENTROPY 42e9503a6bd25ebe4e5690ccec73fee4f1866598fc3cd958d0334d11c6e70dc0 +ENTROPY 76ecbe51aa2814c1ea6cccee7e0f34105c7435789f38abb78ed482ef85e87a20 +ENTROPY a8f7ea762759c6da475d473ff6c1aa7e273f3aa06866f7904d6cd15e1ff0f3d6 +ENTROPY 9209b5bd81a9ed2c40d2906ab5594abb8c51c05f5e2c925b019f65c67b64724b +ENTROPY acf020ccf2f2566137f2623e84e7ffac6c5dcfa07309b8798e680415e2abdc13 +ENTROPY bc8a0238ddc530998f177c44397d2f8f2d2f4d03dc8177c973c264765913fd8c +ENTROPY 007f6858ed2dae70a2b6eb0b5e37587578e4fcb6ab178a8ab075ed542253ce85 +ENTROPY e013e93ad89c5065d35f3851b9e923340cef4610b0ceda1fc1b9b75dd7e5730d +ENTROPY d89674dbf4edae45b5350f8c2fcbdc4660aa34751157442fd9b90242734788b3 +ENTROPY 328df4f44122687a1cd4eefd84fe140601dc402c797f0eff3f7379bdd3b0d063 +ENTROPY e4f17efbb43b9e541ebb5ccdc3a84d97a0ec6e1a49f3209ee2de63fbc1a8014d +ENTROPY 0a39fd365e12faa386b5630317ad3a181657fca77b1dd438871d46b40cf6c38a +ENTROPY 2f3dc0836cc2d09a10f4c0d9c32d8dd91e727a797ea9f5f2c53cba00d777ae89 +ENTROPY f89e639f480bdd0222aff0c32fe356720a76f42805e8f8be2f5ff907503a1985 +ENTROPY 370e6d6ca33f0614e7ec1ba8288079a5809933e5831d453afac0d3c387d2d565 +ENTROPY 3a5e7d0ebf8b462c44b0dd66b47ca954cd72128cdb72b41f62aa1557b396e5eb +ENTROPY 9c1f9da46865229d29f36ff11380a41e69a6883a65a38263901d9781ab5166c5 +ENTROPY 744b8bb3df48ef4d4e960233b4499e667c62ff4f6af762876758d92d9c154bbe +ENTROPY 5078fe777729e902395f0ff2f0dac0e8f01ab990c48f2bb33319582687ca519e +ENTROPY 1d0ec538035f835156a2def482f598391f67296b05bd7d3c5ca81fad02a9a483 +ENTROPY 7a0875432a7031f0b75a4270569dc32c0af20cb2d801a2f4d30000c897942c29 +ENTROPY b79ad997a04e7560c0a62809d86fd7cfc3e3f7fc547f3d34d2d8eb4fa00544f8 +ENTROPY de1761fba6dee36584166dc5803af2c5728f302fb5ced57ff18e2f01c432e05d +ENTROPY 7da306bb24d230460f682cc0927fbed5544439b4655a57f43ace6c32851078fe +ENTROPY 5e88c57ba465fcf03229279a18901fdff2738e9c76260906ddbd7b62b06e91cc +ENTROPY ebda7e2d047ef50baef1bb0e8b8447e3e09fda66bd4df39cc4362152003299a8 +ENTROPY cdb3183fe6d9152c3b91d4886ea16bdee7000af2e2e5d257f22fb0e941f0c5a0 +ENTROPY f9118275620fa44bde994d44daf05f33871f273ca9048da8a09c6af173a8420d +ENTROPY 6a1795806e73ecaf4ea87f6b0e07d6001ac17c17f7d4b3729fea46f283cd7ff7 +ENTROPY 3f9cdc17c330abc8bf5e749c50cf4d05aa614beab2f3258fcdea9617b5020301 +ENTROPY 2b757600c623f2a62cdeeea78e7737eab16a12cd479594c7257e2e5da2eebc08 +ENTROPY e9dd3f2657611380b8ad2127468cc22da14af231276e3eafbf827b9f3ac3e045 +ENTROPY f2dfce916ff553f5ab7c15759156ea09fb249f2d4a4e49dd17aa84a47194851e +ENTROPY 3a6801e5e392f29d60c1ed7bf0ccd749ac675a8d663d7555e7977794e52b34ed +ENTROPY 2d232009164b62617bfc219eddfda71f702b1cb7e7e7f2edf835e06fb06242da +ENTROPY 1452eb04130025bef1bb97b5db07d9cd18c6c7dbea7ad5d3cdfb7970b1eedf76 +ENTROPY 5515f8162d854faf5bb2e25162f2fd394544c9e3201b3b267353364331aaecfa +ENTROPY 04a484fac0a0c218a2bacc6e395c004dcd1a081bc9935a428fd67eab29f2db7a +ENTROPY a7cec10505ac457430a890b97b972dce58166a54c7ad0f91a0441d17f878bd88 +ENTROPY a5488514c7bc5078e87105a7fa79381e9b5b2028fd0c4d9a0f5c337347fc7c76 +ENTROPY c2e1169e450002e297017bc0b38f10209a3a7b61ea8b2ef301840975fd0160cf +ENTROPY be6345261a3ca4b241579d218273f037a08f7e37c75e2a3030652341a91797c3 +ENTROPY b44a12866edfee07b93191ba6471c7e6bf596ce80518be92a64647df889fdbec +ENTROPY 61c4a41e4c19bdda461a191c4fdc60086e85a31aff2857445aec7ecb72256db5 +ENTROPY 2c54fbbce373a7606892521f3ba141b8731dfba7d16821a707d5b9fbceadc76c +ENTROPY 960b72c4f1d0963b8623e3070d9471a833e0b0b933ad9e0f4edb644a2901d850 +ENTROPY 03ee8ce61c6aac94f0c65ddd2a2959922d3eac227f3ac69e383918a9ab6b2383 +ENTROPY fd15722939ee8c79a6661236daf7e9401c35a52094dc01a5b76c956b142b1939 +ENTROPY a22af8c7e6cf5c0dcc019c3f6e7091f6110869cfcc4b51794839f43aa0c9d01a +ENTROPY 081e9fbf918dbd47798b3fb1ca6643898ae5ab03a69cc03d7af1643b53a7078c +ENTROPY b5cacea7fca2c1d9b7b11203ec4ee78606da68de9fa10a5cd56254f62bfc8f58 +ENTROPY 3fce75ac42534ebecef42f036aa8043083f57580e6c0c46ef563ebab9c80fdd9 +ENTROPY 158a50d207c28fdb311298782246af63ee50a4fc93677e1b47a8d933c53614ef +ENTROPY 0a6c43b25445eda3414f527293b7a43771263aabceea5be050b3b3bd40595b46 +ENTROPY bed4c7b4231e88c00198f41500da82adc9734abbda078b68c3b9166ee2ba9bdf +ENTROPY 4302a79c77c4a9618dbddecc8c3863fa1a8ab6172a8017bad18311cade44ce1c +ENTROPY 8c9b06d5fb592016944969379dd012cbe373305859e92324eeabd646602d0541 +ENTROPY d4946845360c4378253899766e92d9f67bdf08a893b94c5e501f9e0dfd892478 +ENTROPY 456d990e289c8e1860cb7bb7fdeccbe683416d72b685ba2ba3b110e81f99028c +ENTROPY ce4166009cc3389800c5267b06b5316cd21e3ed136372e69d4e0d8de907bccea +ENTROPY bbf9a4ad5794380e4c15c177c16c02e7b6c6c3337e986ec18fcf30bb86bdfda7 +ENTROPY 83ab2adf25c90a9453eba798c160cc11a19384b846fca88ee1dbe5b135779d1c +ENTROPY 5339354b8d9eb017ddd53d66cfb361be5258dd86a773910c1043f2f6a92afc5d +ENTROPY 862f77f0458e97a27a6b001b93162bee637cd04d68d340af3a6b411425ee5811 +ENTROPY a0319e2e1dd0e97015deb3f9b0b4cf54e5e9983a1b2340f6a21850d87e112426 +ENTROPY 6759f09a2060a5a3699149fd28184db0ea76b3502b30db27ee3a900e0e10eaff +ENTROPY 57c7b43d06187deb05521bc455b04e376d0cc398927d6d16483c1d4f6763776e +ENTROPY 0d4e4c174ef6e45a75ac04de32f227488421b00a5bb7d234256c1a5f0c72f1ec +ENTROPY fe221f3d4645746ad08a45bdbacc376f2556c0d99dbd318853d5d37bc48c3161 +ENTROPY aaa01a44a7c21af9fe86982d23d0d9791fae4c61f05210a5b5486ab915605546 +ENTROPY ae0ab67e44ca924530270a4fbf5dd55d82b1f62329d6537ce823a58748ab0702 +ENTROPY ac6abc2b171f2f168abac32f3077b5f45572fa2d6f777666d2c3f224a6f3d708 +ENTROPY 34f6810d922eef5809e31cfe6f200fa0a76abc9484518ca9a591b18faa9bb7e6 +ENTROPY ec84a5f197ba418f9889e608908dc369b0c1abf56c9ab7b4f0ea2c9c14644a17 +ENTROPY 1d22fc165e9e2254169a371e6f5bbc0f7b5b5144786c660fbb72b0dad41131ce +ENTROPY f41c75e5431282a8a10d0afbfc8734760afed9498a6f4ef2dc14805fb0544658 +ENTROPY b96c60de259f3dd941edf2ef4c5e79b61869c6dff8f97a10df2d04f570dbb5ce +ENTROPY e0882723bdff5af620d9a40c443e372929b4410ae7550f6b1a995da606863885 +ENTROPY ea3f3303050562b680778f88320dd50b714250620fafc8cda826c8fa8a23a083 +ENTROPY 521937fdd7c8c5afc18cdcce534a44376b96fe167feca705b06b472a144a2b46 +ENTROPY bab1a4e12b717dc637f3f6454d3992ff1c1cd77ab4bd9ff4ebbf1245f75acf5c +ENTROPY 867ad05175bd8874bc6bbb48fddbf7482e2daf5b35bab4015e6ddb4ec009137a +ENTROPY b41eccf1e5ddaf7a216e79bb3029d05aeefd3379e31084b41992256df5fa0b54 +ENTROPY 29a9f9bf6815fb6306e20cc1205215493559fcb1fb336d275580427d5b0f8a8f +ENTROPY ca094e0ab8af2b5ebad6f673baf0a56f0f2ca79258bb6b246aa783a8d4da6425 +ENTROPY d34675e557261da7b6ae8d62caa2752112e6031dff660b64f2e726b3d1da1b1f +ENTROPY 55017707e712cd8e1dc730d40cfe5690b7d91298d3150202705e5dd95979d23d +ENTROPY af256a568cc48e3a071859cc0536f189faf4c2b4dbbfb6fe7786e869d7e4ceff +ENTROPY d2ddb62ece138388bad7eb115d7ed5fdcf2fffb688277c3293f652ef6137ca5c +ENTROPY c7e12511f5db86af61bf15519f39c55c6017785eb6125f8db0be40f6a22de585 +ENTROPY 89356ce584439d3f986b5e485f7fd87781a96664974b5ecd628449a07d1a8023 +ENTROPY c962630df6863994d4d11a04d808714223a8cc299a8b8231171b84693e0389ca +ENTROPY 836c6a32621e734fe70431e028fec5d3542c637b168f72c233ab8833db0f57a7 +ENTROPY d1fb57bb065275dd7b83755566575e5e0ef937bd22f481a7f46bddb28c02f5b3 +ENTROPY b0bf1287e1088f6c63e37dd0168f405e3ed73bd4153c26388f908f67279c0e67 +ENTROPY 476bb7dac7e9817390951d3b6fa3a3ab5a98b16dac40567cb49f35fcfee5f177 +ENTROPY e56a52b45f1d3f22a1db45fd7cb2f808ded85799708b0c3d599228268ae3dc0d +ENTROPY 95975afdcbdde6ab95c1f09323679af05432560457b55acb7d883c636be35690 +ENTROPY 6bfe5a1a6f3987381de44614ba61f9a7b5d1e2c1f75b878612039171c5e779c7 +ENTROPY 82a5d42961603b04d208efbf006697ef5cfae576257fd10b6a88563a2a70e18d +ENTROPY 89a88d9c10a70df9fe91f60486a90dc3e7a1bf98f2dcf91a54d0150c2d22d689 +ENTROPY 875d1eee3f4850d13ab944d4326d721f0b30967c444d29efa91d20daea497eca +ENTROPY 37eadb517968e36538dfda25f6e811cfb94a7c6b7ad11f3bfcf2a07aea43bf1f +ENTROPY 9ba5de6bc66d3ddcc6825ec2a718e3e79da7fb64da6b625e272d9acbbb9ac208 +ENTROPY af0c654043721435fa7c953f47713a288caf4049a5538138ae5c92e2486409b4 +ENTROPY 31b23fcb3a10c953a6b33689e7801b0cf77ce6849a996d5bbbc918459a8117f1 +ENTROPY 7b3c6e07056db30ba31413e0d604f8db50a95149dc617858b7de88447f6d8802 +ENTROPY c09a3f25c42330157adb22b3d3c2504084c1748aba812be6b1b820d37cc7b129 +ENTROPY e1342cfa84a84767098eeba2db3912bcf504d5b6d5fc1c7ee12f37b5b5c4336d +ENTROPY ac1623a2ddfaf69d2a4d2719db1b3cc2e8600c7b833a14f142d4d91cc5750258 +ENTROPY 72780eefe596e24b838de5c66e93308a2723b76ed3d128bacced8b7bc3512036 +ENTROPY 4baa148b5ec0d15afad11d1b7a65fa311a35dfff820a1f55497047fe5cb2ea5c +ENTROPY f754d34a5d3304b84496b2bea7990f1ad3c0e7923d3d56c92a8ee125a51be7ed +ENTROPY 11d88b6194257eedd9a340ea85e9af91c6675a1216f9443d5e538cbb1b55d835 +ENTROPY 66acf1e6bd48d0c1443ad8fd3c1473cbde2d545dd07094e048dfd8b49c8f7f52 +ENTROPY 84e74962522ec4d44fcc9f755eda1ee4b2e5556c6c76f4f716166ae8c76d424f +ENTROPY 639ea38a8ba7d7b1b6a6fbf7f11a7b7a488981ee96a67faadbd91a15b3760743 +ENTROPY 66b6b12c5c3ef22a081d5dad03a817d1c62a4352c44e32b5936a1b216d4a2fd1 +ENTROPY c827d6b57ae8c8de70982541997b9f6ae51cdcc520e9801ee1d43a67e891bff8 +ENTROPY c7f622e75eea568743b14fb4ca404f1d9b1d3cc2c9fa4018b09236bc03451578 +ENTROPY c3ea8e46a0bd0f1ae92043badec231c43e2c11d3b232c78a444691296fa47785 +ENTROPY 23ddbdd14eac39c6ca17fa56c36ea2cd22fb84fcdf4776af3934cfc1b0f1f69b +ENTROPY beb2994d71b7812394b0d5ea7cbaf97241b954aab9a5dab0ce01080068e8512f +ENTROPY 84349775d6932ff6052bb6df354af010c4d515079945bfe7c090d9f1e01b62b9 +ENTROPY 22abb71fd32612527deb3a5222fe1a2807f8563b66f9be2e745267a9e8c3fa55 +ENTROPY 0cf20a18e8c92156e78c882542eda4276e7ba99be797c4d73e2c87bbf64d0460 +ENTROPY 8e75455b9cbe333887067927aafbaec92a4632519f1556f4df13fedf73482787 +ENTROPY 370b9f3b3ee54f6628c6d87c6b786e93d5861d3a6affe216384db5a1f4c01d4c +ENTROPY 19a3f4819888784e3d2a157a81e50efe711b5516644521907fc4603321538098 +ENTROPY 269ba6f2375526b676cacea878b09c7514deba0de979c079b914552b1a3c4061 +ENTROPY e4e46c53d1604cf28054cf4bc1fadf0d71e6a89c440d81909963b7c7661f6899 +ENTROPY c8133de9926d918f114ab021de11ae3b100e2089e3f906a7317db998c74d9338 +ENTROPY 27d368e9a171040af9dd2786a51620586eb33435c892e97c968d7ecadc805d41 +ENTROPY 69daf27c5630ecfe8cf40d4216f15fe353313e5ddbf040c6488dcefa3c83b6af +ENTROPY 6837ddae2cbab584b8d1bb542fd7bbb0a2731ce9d9f3b2a04b27a20e663c8986 +ENTROPY 4175b1784e14d681339778db0966cf487fbcdc34e3ef3cfba3ee442c06ceb50d +ENTROPY e3bf59bf9b570cb51b6f3c8e27900d84f623e3202982e0d62433aea26be3c286 +ENTROPY 73cf57727d06621e0b0e15a7c2e4655ddd7cb66d2a2498d6ff9778440d0384ec +ENTROPY bf510c7ad6f275baa7528ee909fdbdfec54d3da39a2798ee40b805394b7d0f58 +ENTROPY 8edad0adbe3c3c70bbf695b180d87b0fb7f9ecb67dc19d365c9c4c6079345790 +ENTROPY a7185ae213167920f8cd2a3061c468f13e2eadb3eccc9b459f9b3ef6986c8e5b +ENTROPY db978dbed4145f9d5e987bdd6fc84ba2e40ed08e6c514718c2c92222e604ef51 +ENTROPY 0cab723913555f51ead450ba659cb64dd97d1e31c614485df8063daacf289194 +ENTROPY 95bd4184ed25b8d972a31d943e3ae7d94ee2bd760791726de6a691a5545c33ba +ENTROPY c0f746a391d76c26f11da9b2dd3462a1fd5fa9050e7da10380d6269d25da7b4a +ENTROPY b040b03fa9c1eac4687617a7e1d9b6acdccfa3d41cd8adf608affbba3a17b1da +ENTROPY 623cf2b2c7c6d0f847a225bc264c1305f34f5d537ac6d4d4d8a94e1c838381f4 +ENTROPY 25e88512fafcd915a06d24c92133cbb66a8d1b4b9bc5f1696645392c78657f3d +ENTROPY b212a7864abf9692d6c6f98b5d977f515c874eee0e6ca7c7329aeaf566a57772 +ENTROPY c1edd57ea68ef866bae39f9291e3f3f5c5301d4a576f177c6a8be2e02c733ec7 +ENTROPY 8e7c0e05f720519db60932941355aabf6831ef28a19bee10404d1bef170f6de7 +ENTROPY 062d8b0cdff929572e28611e75463d82498350c25682617748bd1c68eea3b920 +ENTROPY 4470dfb584f2282a6490692b251438740250b63ef84f2523f51cf5655c454a09 +ENTROPY 9ad3f68ce0376cc2f1945ec61850a91bdbbbeaf60e9cc9c572f74a5105a56fc0 +ENTROPY 45571785b70c95106888a58be83dcb6cd776d05f905c4230ff6d7ab02245d10b +ENTROPY c484d7ec22c00ac852a90fe4288d20e5607c08143997991f3775f3459c64efa5 +ENTROPY 3389f9be7e40dc8aeed91b7c1b2ea9d942af213fde6b7c6caafbab3779edc318 +ENTROPY cef1b08d9d5fb43f6a4a23e444f6f89666dbda9a78079d38dae20cd42f5b0744 +ENTROPY a812e3853c50a27c284c3281d6994c00f456a55f1a953f909d725b4f7fec69c4 +ENTROPY a5e74a646946cd5e6ab1e96ce2f16319406fd58f04ece0ad97538fd5e1aabc34 +ENTROPY da1930480ebcc8fc142b1cbf03d523174e3757d6ff23cc34032c36efe8ccfa2e +ENTROPY eb611ace84afa339c98262c81a239b6a0cc67f917b53d3fa51575f845b89b9dc +ENTROPY 429e99403aef18e27ed463f2a9c371aa932bfd6119cfeb5ee7cf683c18f0e726 +ENTROPY d6157989d009f61a13fa6e2f80a4c5e479f8e5cb6dd04d4359dd275ca068a91e +ENTROPY e576668a0c47cd0151296a5613222a9dd76a78b688b4170cc1005a4d66d8e60c +ENTROPY 3bc2da9a877382ea0cf48d391f39f9045cd971bdd791ade44345992daff8a02b +ENTROPY 45476cfa1278ce0791159650b2d8d442c73d8872f4470448f3c908361e71d61b +ENTROPY 94cf868f6d88058e221e83fe47a0282f5fc357f7ac29467081f4ef9f857723cf +ENTROPY 2d37e67fa9169a84d0a26857fdf0f61aba9a93d85066c070f29984d3f8aa7244 +ENTROPY 406715a02cb0e50730478a7d5875294cb114ec3174f0bd088781972d931575bd +ENTROPY 5e46ff546c36e9255f0a25c726bdcec04c8bba60073f6e167af6eaa6f95da31f +ENTROPY 2c78fdbef3a0bc097d8c1a708a5a2b1a5167f5d1adbc3e9f8fdc65a877911d69 +ENTROPY 067f76928c4a45113cc3fddd511bb6645ab55359fdf051c4fce61fc2c5d117ba +ENTROPY ff723714f364f55f57dace455b5f062866d14832513efba22f854a8522c84b6f +ENTROPY 8c69e1fbd0f092f68d569b6b53876017578f7545316e8895d8cec383db6f49ea +ENTROPY 1b2565eca19c89a18e996afe2b0adac46980b6ca66c4bea15145e72a870c9a6b +ENTROPY 6d7963b0e759c0018ffef09b0e0f422d7ea9337f0509cf265b91ad8a47b1982e +ENTROPY 28da7d767f2aca539f8c29ff9fb37411a91f25928b032d74b670cb825314fbe2 +ENTROPY 3f547e2f0f766e24bf7ad3a6b7f279d5633d24a9c0c89a7dfc19cceac151ac25 +ENTROPY a0ed64ea2a64483488f8ad231431458f2fff6acb1a24ad549f10bfe905c352ea +ENTROPY 0cbda27fa571d0bded97a087bc2758758e62e4e7b4b749ed051620fbf71bc6f2 +ENTROPY d31a9af52d53a37c8279e5d4ec1e4c7363e16359c5cc96c1494ba6cb18e4fa2a +ENTROPY 3c07f944300a270b5fa194e2eab78db23401da3188b810152c9d09954290bbb2 +ENTROPY dfd3f9da169fbd88902c4b6e4a956779cf7b9da4dc8a50cd7b5866ee0eedc8f2 +ENTROPY ee9d1b2e88c96257a0904d8401322933cf9a60460eb3d3e4a834af3ddb5ada45 +ENTROPY 1cd51504a5ebea34a2aaf01c830490a2a508d25e461b552f5a9c98b7748ef6c7 +ENTROPY ba16cd209a26c3f727c9602fb69d008b098c8ab0bb26fc130c062d5bc66526ba +ENTROPY 6e73577e2c0e94cc61537a2b0e5947a5cdfb7747ae6df414988c16325a4c97e7 +ENTROPY 4c68f603f783f77e4b2a99b44eadac5cdf0357a761c4912d25f2861aceccb09f +ENTROPY 4e44b525427faf68421caa5dbd35f079e69a2ca179ace0101b9b4218b922c956 +ENTROPY 05ec09bdf8fa161a663cd203440c6be6d424e9f240dfcd74a82c30dc2904d30f +ENTROPY 3e8b1d9a0b8a1a93f8feae942bfe3b83557d304ffb781a1edfcd4f0d0d7b1fc7 +ENTROPY f7f3518236b51f91d1d74fc94dcd04a90aaf756bc148aa3d40217dcc31f91244 +ENTROPY a4ee8afdabdf0c979773f2b4ea184b6c7d10d7602c0f44b1f3de80bae159ef6a +ENTROPY cc199a4fbeea7a10641e310431d642db7714c3bf083e323d9a42952884131c5c +ENTROPY 4ff1a23c0b0a7b0eda9e2df46714c8a4d2773b241e2b73aa29f0c9b33819f37a +ENTROPY f94f5df8413a965d1df2eb7fd8b01029b773a0cba9729ac0840bbd6dbf1d4601 +ENTROPY 0e4a0496d1b8197b7c02f9d9ab2cafd15acaec551f05f10e4a5ab96419c6c1c7 +ENTROPY c898d25cd4e3e91528f3ec98395bfa2b1df03189004e261b2503988dc03a231d +ENTROPY 232f3195df548c4a804659a4cc7294985181f1b968be5e35e09b7e00d8d1badc +ENTROPY ef673d67bee9c10a853f78f6020a73035b2b78eccf647188c073a2679d27296b +ENTROPY 70bb666bb3a41da183b9083ba00dfaa78d779d53ed09cd6da8e888a14300b4db +ENTROPY 84b3d4d490b3a7a64d9a0f0770c696619b5bc3f0351c223fcd00c9a6aa79e92a +ENTROPY 3c02f3e21c53ef9b2b1ebb30b918c764542653935739771b941e8676f9a65831 +ENTROPY 598e7378519b9edf1247e408fd104d050e3795b2f2563f8ace4ab2ed3c04e634 +ENTROPY 9628096cbb5426af8d9d18033076dd7d1891cccfd38ff978c5ca487a3f6c338a +ENTROPY fd278a72b30f6cf9f0a4c1186ebd7523860f8a534299c95c2a34c9d1fd4bb25c +ENTROPY 586fbb9bb2281a856fd9684f8ecb7cca5856d9944b1bea03998eaf4d83f5ee30 +ENTROPY 0d73e50cd398db9886868df7f305229578944f95ae04aa4f9363543b5ccd826c +ENTROPY 5948e177fb20e204a8c4065244b99bf39f5c0051b31887a8f26890bb27078fea +ENTROPY 2fcfda7bf91f64d37a5f9f15aabbe876b58242734572d758f97dbefae3ddc2b4 +ENTROPY 6f11940e1d1b9f48e8f8daaff8535dbddc4f5100a0db400145699352b5ce816f +ENTROPY 95b75d2b7baabfd577adfe56a8217a56e51ae591b095e316af1138a28ec770f5 +ENTROPY ea6d3a34a892e2627bfaebc78adb2026cb1d15553c7d1bff527d42007a89b24f +ENTROPY e1b9521a4f0f9dedc61e8a3f922bb38500288266d6ec57b1ba3bf9be4d7dcb8e +ENTROPY ebf581d7b849b873a9a27ea46cdbbfb0024a1240e7dba9573846d0cb931ff32f +ENTROPY 219ba72c5f03e61e11c0817b6e9b96ac2de53162fe77efd36947b48d0e34ee5f +ENTROPY ccf178910077351bbb3b0de90b853917087e8daba93e4aaaec274f6e87850f96 +ENTROPY db188e86d80cc17e3edae109efaf1a834be02ebfdf08bcd7d4abfe26feaa4eda +ENTROPY 0aaac6c55f34f79d15c00c7561c61a60643dd0d2e7eba071c09d22b7279a2354 +ENTROPY 2e00688eec47d260519be65b36115bf223a6c34a2f8275bb94455e2e1dc714ef +ENTROPY 2aed9df70876a4cc36d7fc601be35298bd46fd89df506eb93b78ba779c621f42 +ENTROPY 83a92a9658698e0770ec507df7639a102a367f2904633a57a314fe50833c6449 +ENTROPY 83e91a868e074ab9d1004ba9041ddc0cec15c45c19b9489da70ec8578b57ab95 +ENTROPY 92594836016680168091775b06fd9dd65d600b670a9d00ed05b688a5bf74e193 +ENTROPY 882387538121380e565f668330df735ae0412015ab9e11695a3b0fb6f5ef9acb +ENTROPY ce59281ef697ace6f6a858920da17995ca0aa234e50f1ddaf7ba723dc6df57a6 +ENTROPY b46cd9b23a417e665788965fbe64deaba1296597a9b9ba2e32f61e088f099001 +ENTROPY fbd39cd67b89aebc8c9223e829a296a6bb306c0065cad2cb6ec0981ac8fc38c0 +ENTROPY 4a8edda555ccfb42fb6976c32e701d3ad000c86775f85741b38443b5c24e89a7 +ENTROPY 70dc16abdd8c85159c68806335d4b4188797558da5f8def9df425cc0df2d3457 +ENTROPY 84df446c4aaf9c33506a763c62f2577b5fc0cd1d2326c6f722284a4aca7deb1e +ENTROPY d9fa9ab56cf0c152aa1209dba63a4990de8c589ebacafbd1fead12f17fe949e5 +ENTROPY 3acfe032984fc38f324d006b74ab37ffa364221e55cffff9ad18fb0c520e3810 +ENTROPY fd923e7acba7b3d6c96b47ca190df2d0991dfa61719671e234ff128d674b31f4 +ENTROPY 0ebf20d80717620ec63052bd44388e5992b7116541747449f6deb61afb33fb8e +ENTROPY caf6df28e90dbfc3bd3cd0a8a1051c1b135ff7b557fdfc13a3c3fcb844037030 +ENTROPY 2be6cb0b3f641f13a5cfed4d75a58642097f293d9b0deb4c238eef57ee855a9a +ENTROPY ea373d0a8efd9c253075e930de836ad2f92b83e038196bc615ca3acbcd677184 +ENTROPY 5c6495d31cdd45dae178c66918ddb942e6a835d6b4537c3584f95a6c795b9add +ENTROPY 3e0e838f29440a446ec63b0aa7e5ecfbb40acf6cc8ce246aae8b1e438266efa8 +ENTROPY 3588466974badecb8d199227bdb856fdc25f05bdb9f5b4e56bb9159ace40e4d5 +ENTROPY 60adae9dc8d8ff60d03f495d74361183c515ef33a6991acc6380482cb1085e7e +ENTROPY df2f3e661f2d4e8093fc8aa4a2491c98c88739e5dac6f6c5e8c989d5365d21d0 +ENTROPY be38021104528eb9a6ccc33018b3e22d482e410f80c59dabbe8dced351d7efaf +ENTROPY b1fbf30e43b33eb2bd7438cc6f1d027162f4453010a971064e08c7e350c1fc56 +ENTROPY f65a561a7406dd30e595892876e7f9ee6a0f370c58c1eee6b7a06f670c150cb5 +ENTROPY 9348ef6f16d224cdfb18cd09a069bdab31fe4fcda0675ab0322b232660fba937 +ENTROPY 1ca0a2adda51c3a859cd311fc545fe3ef08dd98c83f311621d35899e294557d8 +ENTROPY e259d8355a2bd032a1d75a5bb19ea3858961219b58b5a6fa639ff1364f02233a +ENTROPY 7f000a3ee3fd46da9edf39d5d74e5848460fe8c46107670945e8913df353af02 +ENTROPY 6d29545bc515a3546dc17f9627df9c1ac965416604162b656a7b3591f58938b4 +ENTROPY 4e423a40817db6f1e33fffff8307354e015b9a6b478df244e0639f0de9a99e5b +ENTROPY 8d5606936f306c9c571423ccea33ae0f6c37574f80bd4c56a598a14d677685d1 +ENTROPY 6077a5066f115f513605a49bcdc79c209c9537ae73b8cd61054f279bad12ed85 +ENTROPY 65bb2fd4d5a8fad9b241e1933d9941058bd745d373e71ff0c87098e9c0237919 +ENTROPY 7811dd2a2ed929e9822c48ef03b4e6218a538260a7f6a34ccce6c26d3cd037ce +ENTROPY 6fe5f05076ef91644627d2edd78a49d59779b39736c453d118a37cf090730c0a +ENTROPY d733a7daabc4e48c8d5e9af3d22d525d537b003bd513e22c9adbe76617721f77 +ENTROPY dbbe989a7b6706e43f6d0abc21eb2971e0ad27937d9a17171f69bc0cee69e577 +ENTROPY 6c23c55b45fafd5dfb799a9e2b292a7e36b1d735a95f0e9a62b0a4e6ac6d0526 +ENTROPY 82026b05d3eb95b92da1c005b76e5e961a553ad7316eb1cb0bbea5aa4ad0bc18 +ENTROPY af0d831359d0565fe44cefa465f69e5b062a40e861275efcaa39b24951fb352d +ENTROPY 2a2fe501e74278f1d8bf0035809621dbb0bce9c82d8694e4a546ad4e181e2217 +ENTROPY 849854125affb470df4d92bb2ba56a74d27b904cb3bbfcae7e0a3787ad6ddaa5 +ENTROPY dc9052f2e6f108db4356723bfc00036014a4a0a2d470852c77bdb19b92d5024b +ENTROPY cf3e1a1483635c6f583395e621ffffeab3760685d4d292f4e44cd14eed897e69 +ENTROPY 3c680b5319b1bb355c5696e4a57aff6d138976fff96aa3eec26c41a1d315b9d9 +ENTROPY 5bcc6f6a14fa4e1534196ae2ccd41b3315aed95a3be59e91bd442b53f09a3c82 +ENTROPY 59bbedcb9ccd2b73f1e4676c0f0f845bc2716b02eb781940206dbabb99ea5197 +ENTROPY 1044049a54c90d871d36a73881284369985479a7c6a1daf21f40c2f23f1ade24 +ENTROPY 0756104a1eb1141b347e7e8d63b072593d83abb0e07b53647e867b6aaab1426c +ENTROPY 9bb8a9fd3c4b5953ccdeb89adf2324ecc7e2b08d57ff0e82a2833c525bf60430 +ENTROPY 3b73f9476821a401635ec756ab3f685fc1856029ba7ce8167cc923059985bc4f +ENTROPY f998ce2f065bf99ebb021710f6fc8974996cd2acbd828add1547b5ba9dd228ca +ENTROPY 88bdd977341246d1403d47130bb67eec8647e6013e1fe76a84f2fc40fc27af29 +ENTROPY 047e3ecf459329acd95a1e5193a7464b921d59f078dce48c0fb1eba8fb6daf7f +ENTROPY 12eba892b1623e55f17981f173438228f01420f0cd32728c7d9d2cba5977f51d +ENTROPY 38cda99fa8c8e516813eabc03c10468a51b3a2a9225929fe5148335428caaa6e +ENTROPY 56a6e3b3afc9f1ad94099ce2bef9513168982f847d386195efd0f2d67d941823 +ENTROPY c8919d90eb644e7417324b8e76c10789bf20a03fb6bd70f20bc1d546c6d8a963 +ENTROPY 67bd6a2285a0bc2c873d4932f0345e03f3ecd56d9d8245b8763d6795c9375676 +ENTROPY 3e098c5ef3c8a701d24c0acd24f5289f4f3b9e52bc995c09f910addc091f24ea +ENTROPY 1a0bd940692653c465ca2d2b3e5823b09d35ca0e8a863c8f80268f348b512d53 +ENTROPY 6e094b8e9b452273f4b05c9386c0144963b4feaf272ebcc5695d78be8a05a93a +ENTROPY b3687a69287814d43d10538b47aafb7edc96e29e8584ca36993ea154ca197ab8 +ENTROPY 237f5f3e1048e3f76f50041ee5bdc3dcaae09118a0e3f6c685423a3340c66ad6 +ENTROPY f8ce47a2eda40cf027ef368e77f50aae1e13b09fd8c76d80b6ab823d662bb63f +ENTROPY b4a15db2de0a1294d8eeb8d26a062444455b28829ab446d8fc3a1f81a83475ad +ENTROPY ed6a3b0f3345cea0d635abc629fa202752e42a08507c0184264121511bf5379a +ENTROPY 56e250f5596c813bb319aabedf0f639e7afc8a8e06516c97e65ec5b46d57febf +ENTROPY c308694d510783049e0db465f1dc8962ebe2e420cddafa3924e9c1d6596f7ebe +ENTROPY 84743b5d2ec31efc54df9c07f2030154d45aa0a722f3a844e3cfcf3bc8ed90ad +ENTROPY 21318ba65e354e8781048015ea33cf7da4961b8b67ff67d26a65d6aa73b0469f +ENTROPY 22a71a8ba5e589f371c36f574d77160ce9a3fe0332a7043a40e14867df6e51b1 +ENTROPY 0ede2890314b8d8dc959f95ce193d6fab34037a20d76e24712be385d211ec94c +ENTROPY 1cca1e65593eee8a52e412e44fb14f2ef96cec53763e79d1dbb13ff89e3107a7 +ENTROPY 0af0a9234352aa112e26537a01cd2970f0d7d80e5c66d5c797bb6988c7f9eabf +ENTROPY 5b04ee69238fbc0a89297bc4412f1dba001f23e0e4069b7c94e156a5aa362aee +ENTROPY 4f16af56644d6fe5059a60f21314dadfda1fe734f1435a9ec5fea9238b769666 +ENTROPY ff00b447a863267b5a0b2856eda88061c27f0eb681424b522bc5d291638959a9 +ENTROPY 8de4000c88ebbce8ac5703d3a694f65cf1bdcea138aeb617768d8ece7656a00f +ENTROPY 0d4bf2a2e69abd792890d95c781801e437af8389176b579bd1d5b4b57ad7f0ee +ENTROPY 4eef68ebdf3edbae7a4c8486254cd35e907a5f7f9c865f464375cc4cf6945d78 +ENTROPY a85de9ab749f8198501056d530dc02f173b031705eed60bd423cb958a195f2fc +ENTROPY 7ad5115239cdc05e6130f5e6949bab25116a4de7b311e139b58a497bd0708094 +ENTROPY da550b8065fa24deb9b9f2dfaa9d541c29eaed235239c4213fc573d0b6704370 +ENTROPY 80a74c93c648f9a27e86d4962f88d2b310f689e893ff9febfea2c05b924c2e1e +ENTROPY 01f493ab6b1f60a2fe95f80f19b8546b3a833d67c8e8c107fc2ee7657bf4ae92 +ENTROPY e4124779605194620121a431323d6a51fd6318f0f4a7387b489f98b467ff194d +ENTROPY ed0aea18b94d6cba28efd168a22f692e7d81c04a15860fb33a231351d44c1582 +ENTROPY 386ea26a40248857e0db730f8204f1c53868387e2aef4370e81d7c3287b8463c +ENTROPY 55c3fca3508346b4091633409cd41236e672228d28a3796035a93acb2b7afe9e +ENTROPY cb0b377905d1fc4c254a31c5a78ca70ce4d633dd54b0e1ffc53bd269797bbb51 +ENTROPY 2984b8199e6e417ef641dda3e94dc63f0275024b7c4acffc8c179e5e930adbcd +ENTROPY 8e2bea1abbf65f506e900db98a76b4bb9f1a696f6d28ab8b1473de08f8ef72e4 +ENTROPY bd7af2f2e8d00eb2f3687698f32c48d0a4f5820218170f152ec097418c7c746c +ENTROPY bdac6b1effcc38d61889d0c97ebe6e6bec4b430193a77f19aad2a6effaf5b7c0 +ENTROPY 04e2b0e82778d9e2e7910de53760809618508031de8c3fb0fa472c8a70e69501 +ENTROPY e803b8789af9220f50ae00bc1d57909ded3e21daf79cd4bc5ee5fe68f345a0c7 +ENTROPY 37982808e31670968bb6a703e3207dced57a461e12e640017283416e54982002 +ENTROPY a5850dda4d7fb04f6b3f0c477ca1f9bf49e5e0a2072f03070cb34cc5b0fe9b5d +ENTROPY 25adb3d74583ffd336427012d1f030a2f0db1410b6ff5227c089637b21967305 +ENTROPY e66665231a482ec0a506d93631c0f63bdedf4054618ecbd75b33df0bd1bed2dc +ENTROPY 6ad8bf5375cf19d032720040873d33c1be977aa3db6fa18669db37d930a5a85b +ENTROPY 7956af0d0673c1c752eda67a33f0d90ae2e0d491c141e10ec9502160f0417615 +ENTROPY c583d75c19ac89f2df82d1820ce12b994068c1d49650427b9b79564eac803186 +ENTROPY dd5d341b322ddc97b5ef7aad88cfb58794096ef91f3a022bd022477755d940a9 +ENTROPY f6784ade4bf22bea824448c5b9c4f82135370a1cee6186d072271f5fb0e447e5 +ENTROPY 7fa1a94f08a19958554eafe84159eab676dd78912320ff7582c6cc2bfe7ac32a +ENTROPY b674ae1666af8d12c6552f6373f8267fa4b371bafdb5d6318cf6a7f302b714d6 +ENTROPY a28294cf78ac833b56c12c453e99471c0cdd87e1bbd5dd28798129b7031d07be +ENTROPY 8804a9611d5b7f2e84f2f5a7f14fe66092ee659d0ecb29820e42f8d85d462132 +ENTROPY 0d35b63bc1c6d647a153664c0253dbfb0feaf1f760e60cd5f55524da7044c0a4 +ENTROPY 585223dd4e8aaba880f2d57d5db7666b3d553c3c6c147cbca015632676359eaf +ENTROPY 02da93f1150dbe4bde04bb620026d56611343704c06f05a03252c27c2ce98446 +ENTROPY 1d88a31ab98c5c10b3c4e581f2e4aa421c30ea01b6c3e7082dc74e424fa4534d +ENTROPY 052db6a30ccf20844019fdc70efd36ef2800c6ead2f83d2f99e17b5d664e3159 +ENTROPY 86fbe274cfb39c64b80bb210b4aecccb8d8c99d9a68e1d33d0edafb42a482787 +ENTROPY 94f45770dae3ba78d8f0743bc9ae3a9e11d676d722884fdb2ca89cfc4dae726b +ENTROPY 845171fc24e79157225b4da4d08dbc80685fd7c572132d9e1f8aabdc712c0f98 +ENTROPY 94952ddd3e5a5a1d3cdad6510a9f0ec4b81b91e7933cd83bd01f241324aa31b3 +ENTROPY 001b56e2d2c81bcc643bf7e091f24e2663c997af7e4de474adccb18e715ff2bb +ENTROPY bf2162c7bc65a09e850775ef929bfeb6de3c6f3c70ea21a332f6ea006c20cebb +ENTROPY 7fd25a57c2526873cb61e7a578156caf317dcefa03931a19c900bb86ac70506c +ENTROPY 03977b611552fbda965602789fed08660bd6c501db66a7b8c3c4011e40b87d51 +ENTROPY c966a95f7e2cc82e9fc798e5f843edb17ae90f47804f47cd5b650c452f6d19ea +ENTROPY 643583417a3e9423232c7119f74cd1a1e8ca202e2e06d33f540f4487484ae412 +ENTROPY a654e54351857096b8f8ad8549d00a0e3dc5a140de26bc16ef8a3b35890cb16b +ENTROPY d13ea951a4540c06d036571611120f32eace736be85be79b387f4c74b41b75bc +ENTROPY 5d60c0c9bcf07e59c7b8fa38b51d9fbe1eac97d4fc573c26585b23ded625d374 +ENTROPY 7b6ac14b4c922ff8dd16c57b79c06fca1e4e1ddd4dc36c61117a031173a7f604 +ENTROPY cae8f859e946f3b739783607fb8341c6db8e65fac7853707c883202dc51b172e +ENTROPY 1f59ccf35b11cfc9bce2be96c779200bcfc8df78369733d7c69bbd77c9c412b6 +ENTROPY f39072004a72d2c8350483537ec9ef4b7efb4603abb1a5fbb7ad07ea890b5301 +ENTROPY b687c7c5d494f13722239897fcf75e5927ad0dcd020e850195692f29f8ac0096 +ENTROPY de3ef8122cfc28794ed3bddb97b6329e21c3dd0e0e4dfc69afbe2702fa680eec +ENTROPY 90bee195bddc3ad92cce62acb28fdd5a4ef5f51eabc81f9393f922f549279a78 +ENTROPY 55a36db2a3eb7d8a7e98147c1382d738c354e0d6ed923109f781fda124332fdd +ENTROPY 7e61fb4a33a4332367a89aae2b738f8c77fd4fb40dfe3b218a98fc73221ce27e +ENTROPY 0bf9e129be39ffcba4cd4b5f91fd7042e1e1e5de0eea3b19d6dd7da9646b0266 +ENTROPY a7e7a171c50f634f00222f04338de6ea84fab160449e859700b52e6a93c9af65 +ENTROPY 56a4800748e462273ce657fb47fbd1d147db3240815928b76e44e116d73e9197 +ENTROPY 7b3a814835739fbf4e67af9fdf17b332cc6553e4a63f79842a55f3a846f12ee7 +ENTROPY c78d8cdcd529cc54768a2cc92f66df1bc4d374368c1edd4185f063c372d0a73b +ENTROPY 3e5bda6841129ae93969c2bd29d3b306194d4f5978f9c2eff4959175b065a29e +ENTROPY 673fddbd4ae0a50f438b853ebda8feabf7c5a651152b1df43e00d7bf78bb5faf +ENTROPY 533f86c9ae8de38a2fedff203e425b8ffa6cb18581e660f30fc7e66806ff5390 +ENTROPY b916e1d52c5c0ce6a71254506a5cd25ef5b2d36f8a96dc96d486804fb13eba27 +ENTROPY f763f5eb69da084aa678d615bec33a6e3e6a4616cbec637a5dd44a3bceb59acc +ENTROPY 1b670f0b86d87050cab0816170725ffadd868e2ef08d35dd9740c0082337941b +ENTROPY e425009a23f49eb9350fd44fe572288cb4b82aaabd6d31e7d9fcc52410efd5e0 +ENTROPY 4cb9e7d16710018dbd0858f6550f58635145964e989f1e79db69023d26cb3f42 +ENTROPY a28af06758050d5e8c28e3f64b55e6adba4228f08f3b527c593b3e75a1fe3269 +ENTROPY 4adf24889e071e44724cca94f942dc2e3369db4bb7c21dcbfbd9a1b3032b424e +ENTROPY 8841eb73b76e45b7ed7f6451df8d97d0e1559b7f988367555988b8022cbead41 +ENTROPY 876e3158bbe96a0e4f887ec13314eb388417161ee1e341e9e4d956f26ceb077a +ENTROPY 92f615da691ef4df11e89208445524d03ee4e4aaa2ca628ec5c4f8251f389274 +ENTROPY 757288beb64b0b9be2a5eccea1c14e41f4e954925a9fb2017a9f1f875b51ad47 +ENTROPY 386f8bf8a34bd72d550a7ce217c3915c39cbf81b31803be092f51d690bc2b617 +ENTROPY e56e903245f84805e387dd73be8227050387587f09495ba2add024bd8e17a0b4 +ENTROPY c730563fd1c7657d80abd208ca9a064375b786b8b1eba12c29b79033387e621e +ENTROPY 58f80f5d764a87b1c16496c9419aa1e17a7d9c8e041fd283a6d3e92a9c36408a +ENTROPY 7adfd8f54ac86e0ec3766f43d0a5ec5308fabccd9d2f5c84406c6ef2280a475a +ENTROPY 590171fa9b539829f6101d6fbcf162987cce8b1c6fcec2d76d244cce6ce377a7 +ENTROPY 325aa3a9d1c9a4cddb2538413daea88096f2c25ee09d567f6ec9c85d8c1043a3 +ENTROPY f28c8760cca69de6a9aa3b0468bc0f35820f53db0a055a15060a67af42469165 +ENTROPY 4205dace7fc1655d2356fa3552d6ba458b1f848f996bbfe021850069e43270f0 +ENTROPY 7f242566c8a49caf8d0c89da8cd6c36384e2ba41edb13e0223e2c7e39e11c198 +ENTROPY 77f45e37e093f7c6fd50d68885c23e2a3139bcbb1c6cfe2a6496628fe3fb8ac4 +ENTROPY 9d684859aa060f5c301e971553b120bf303a40a957c97604a3de6359196abf00 +ENTROPY 0f27414314ecac5ddc952d0bac572498b4518b7fdf1cacaeb25210ee8dc98ca2 +ENTROPY b1bf944fced563c0adbc45cb6d5f43a9cf3a5123987f251cbdf5a771bdb7c96d +ENTROPY d3100290747a155882b3736d5ef418587af4042369bf1452a7d24d33602aff7a +ENTROPY 18e9ec7320c6e3da3f614b7dbfcabfa88e8aad4853008f92a8bbd44e5218c360 +ENTROPY c35246ae9bf2e24aef55be033e29c09324580ef96f7b8aa8eea5d8390443b5e2 +ENTROPY 6e11ecc67d366853bacf01d435d2ff310a7ddd0d4e279a24a0d456e081ffda90 +ENTROPY 27f42ad9e67deca8edc42683626e34e3ea637b572531647c88f018cd504d24ff +ENTROPY 57038e62a309922bc0e000369861970e212dc17cef584cf26ed38b85e81502fe +ENTROPY f8930498197e8117737b4baf483b75d36a8765bf2695b2bbb8b1790701904192 +ENTROPY 13ca78e30a9b22552ac892e58cc071851cba478ad91283c79ce3f03ab9dec49b +ENTROPY d982f4479389f8f221935ed4dbcfe90470fe79335365a9daad0306eae43bf6d5 +ENTROPY 257cc7042c3081f4469b167ab1f228deebc74c43170f5ea7b58d448462fb84f3 +ENTROPY 742bcd24be1d97a0198f93ed18265a2664bb8b4c9c570c0392d61cf6e03d1643 +ENTROPY 98b1944f3a21989476893ad39c900b566ef3573b4f240d1f3d2833af431241dc +ENTROPY 21d9369149abf58cf8e8924d1c7d55057febfc51f3eb200479367873bc08b5a6 +ENTROPY 8c6d52f46a6fcb9972cec255a29a6862f1a1b7f59fbfd1c2c1da09364eec95c0 +ENTROPY 3e470fddaa0a7e5a926461bd1b3b7681936227995d34cea5ef1541113a38b6a7 +ENTROPY 425eae87f49d6032d88865e8cf7f0c9924ac7de6e5fb1426b1aedb9ca1a11380 +ENTROPY 970fc133e7e16fff85e22d47db7cc01d034222545ee8e4f439e1a7dc164560da +ENTROPY d8f2e05a6a02d162002a1ffd8aa2ba2020338c954e52bf552c46994344d17af0 +ENTROPY 98be32d6b3644958334327657e1f2efa07ea07acf321901a577c2fc8deae169d +ENTROPY 1e4cd345971edf68c3f3f7e457fadedcb3992bab6052a7a51e51384d500e0b21 +ENTROPY a07763d998d581b356a6521f36025795af00df9dfa95538a8f3d18f7aa9f3c99 +ENTROPY 35b1003cb7409f432dc75c67e9947e3a50334822041fba01d228235ceb35f752 +ENTROPY 77d42cf2414f907ed0b1394e8e3f68d17c93099d3995d0ba53f2ac67363bc295 +ENTROPY b3f73fbfb3bf7c450ace247da4afece9ee0746b503d6fa181bd3f7ff1828411c +ENTROPY c8259fd2037ada1cb356fae42a95b6bf6b3807f79aeca3fd638bc0460586a95e +ENTROPY 533af774bc7685c2bac2df7a945f056c0225c8b555016e101afade7e764f9b25 +ENTROPY 7428156033b8b5a95c0cf19a3e1685248fb260397df2a836357a3e9037afb235 +ENTROPY a02807155cee1291ad72dc0a386eda45448ed6ddbf2aa2647d9aea923fe53e65 +ENTROPY ab0f05004d25e379245e7d4e016f31134ed8fa4540ebd282c677201b854026c2 +ENTROPY 277bb1a01d3c4666ec8ad8d297a2be2f5c141312fe7a08a9c596aa74bcfcf10a +ENTROPY aacb65afcdcab5ffed09787c3ac3b2745e766cd8a2eb573845ac3c6ffcb726c4 +ENTROPY f8e943f43b0ea9a94a4ac104fcfc95cd5a8248bc96ad74cf3521501dd650c8c5 +ENTROPY 534e98fb9fd880c276a95a377d963a6d42c36b9cf05f32838a9d56eb28db1a8e +ENTROPY a904e3a54670fe60bf8c54b3f75b09a144505e867d39e2489de8018ae8f353f2 +ENTROPY a4e5f91747d1c7ff6142a0cd4be80a0d72ada23ebac82a0954fe23ed4f02fe9b +ENTROPY 9f705f031c1e99adca27356ef5af7229b94fa6e6c3e6642699404c28bc99c68c +ENTROPY 6088403e1c30d273e8311be1dd26fa833dbb0d39a46de202abc470135418c65b +ENTROPY 000b46bea5cf42b235923de6d8804abe06e7a14e95daeffa9398c44fa72b1b77 +ENTROPY 53db99fc48f09903ab7050de0cb13b5bfa28a56f0a46dc313946ff13c522ad65 +ENTROPY e61ecd52e4dddd5bd89ea764b9c5b4ea9fd76ebb2f70a7986d9d2b22087ba7cb +ENTROPY f0599ae31656158fdc5c99fddd6c58d4b01ec6b3e0d697d8918a98879e948777 +ENTROPY f1a2a92f62d63cab4edc198092fad00bacb4988c20554eaa948c2a5ea8c30ad3 +ENTROPY cf64a0a8eb932aea5625508e3498322167177f7f84d25b153e9a8d3f4474b10a +ENTROPY c1e636ef4a2f6229cffa483610cba122f650c0bb4cd8845d38af186707f13c1f +ENTROPY 59e5e7dd6d43763f5b69434156643afa2bbe3195dc96b44235e164dc2f4d7a95 +ENTROPY c65ace162c99ec77a95f01f1150bb475bed971a0b2784b99470e4e92c423a4ab +ENTROPY 9608d255eb58608f84b4d93c6c6744088c59223e79eb645c7d75b398940ed217 +ENTROPY 4e36b9a6b796a1dd5eef25c7bca05516c7123c4215a0182956ecdd5806a5cc5f +ENTROPY afcfb8702b960909fd723bde340fa2734e179b5155373e8ce5d2977981c0113f +ENTROPY 1e94b4711dad258399207679c7d2993fb46254f319837878144c88b975128b6a +ENTROPY b0b7d197d16a80c3475e81d7f68f85be1ce27499eb60c789a4d1392c32da8c6b +ENTROPY 020e4fe3e265beadf2df5715255c09495b06a4819fda8d6c77a1f70d0afbef45 +ENTROPY ad803aa34c0ba8adbe82af6f4d23a8eacaf092917a1e070a4c824d30f65229d0 +ENTROPY 2c2b8ab3cbb0fba809e83615c55595871a4fd2d2028f11c0875ba279e843d936 +ENTROPY 5229d5906287be53c604571af161ee90e26f2e6954ece2e124653f26ece96c49 +ENTROPY 26436d2daa90fe5da578b6f82d0485b9129ed95b427a783a79ff5643ede20fed +ENTROPY dcb6380438508b55f0560f005b3a1ff7b7c60e1d6067ea94f93a122c7e33ea3e +ENTROPY 6ee0765965e1092ccd2c93a6b83cdff2ba1016f245c4fbaf56c91da938c8533a +ENTROPY c1bae78380c627e28460c3ac339c8369fb1a6b1253632082a324a38c5bf81003 +ENTROPY 2750a68d7ca9753ee0e310b8d757d32400e07aa216e996c9d53605e1e04c90ab +ENTROPY 2294cca9a4d0d3905341470f7b2854f767d1c42e863288634ad6b54f4f90ff6a +ENTROPY 04adfdde463bc3e0e7c0ac13533bc6cd43e2e0eff0334ac83673f9ac751d9df6 +ENTROPY 2e4258d7578aa4bf04877bee32b418ceb87357dfef4d4994a5f2ed89993526e1 +ENTROPY 8a88ec6a4198cf0db3daf8bb9968aa0ed8749ab3baa0fdaf71ac140084c750a5 +ENTROPY ae0b922d1c46e0c3e2a16c25e7cfbc2171f11b8a2083b5fd7f86c4abc58611e5 +ENTROPY 755dcd4d15a74a2534dd69cdd14fe9976c3c9b38b5d4feae8389c089dbfba0ad +ENTROPY 7c1212c39c6cd8a870b79935756b7e52b50cc70015a470fdf5b152df23c259dd +ENTROPY 087780de42a4e2de85ec2b4cdd865b4d5a69e103329687da5b7f24018fa24314 +ENTROPY 463cc47d815394e4ed7ee9fa37a981918ee0e484d82726fcbcbb187eaf009eb3 +ENTROPY 443a3d146ba979c3e0041345a92d5f11a49f4f221058878fd1d106dce0a5b3d0 +ENTROPY a46f7cbac55f17bb4d71ac18c575632279be48d39b438ff72662f0cf805f284b +ENTROPY 4d3bfbf21ed418a2d74bb00cff91e77110978e4522cf3e34142d1db243bf60ae +ENTROPY a2709f0361d22c656f63596dc22bf950b9515d389d7e3a2a1debd7b459396c84 +ENTROPY 7411d5c2da16845fc7fb7e8319d731aae62f6f91470f89ffadf000674e07c670 +ENTROPY e7a3e993b7938cf785b92112e49746bf3e7ec643091d2409ed8123d45e6e461d +ENTROPY 40bbc2984e0e82b4f0f11382a79cb9644e62dca623d925a6ffc51000ba9d5b2c +ENTROPY 6b23f156329892640ba9b002c265abbd01479a8828f1194f69afd13ca4e3ff12 +ENTROPY 43a45ee31bf7434b40a12d8bbe564e8ee3c005b14a020f0cf6e31eb79baebac8 +ENTROPY 6d3e4d17635d6e02f471647eaab01530e7139db60cff5c3ea1725d22c36e85e3 +ENTROPY 4d806bab30665a59668d3536426d95d42bd44fa5535d364231d600be6734dcb7 +ENTROPY 4481c1f725db1fcf438a4f0bd598ad57378db760f760463a214fd4d9f2267dff +ENTROPY db6199f3aa1b76e59f1b8ab7d9971d84cba1d2ddf4214ebb476f5e7ee857dd4b +ENTROPY c201b940cae0fa3098f6f3d74ea98fe95f43974ef9db6ef0594aa06ca18dc63a +ENTROPY 7c638ffa82f54ca995ceace79bf2e8320ff31f35b974d9e42c9305f6f30ec801 +ENTROPY 635f3dbdade1ed0558eff1043166a1899b399728feebafee95d95101526dd62c +ENTROPY 5e899d5108e5c8012767b6165e6442bcbed594ba020d51ad916204681d18a437 +ENTROPY f3cf1e8ff69f00a2c0c3ea0427f33f20f9c534905e238ab9738ea4825dd49e0e +ENTROPY 0205f054e66504b2b6aefc3bcd60773892ee7a696e257fc872d2a8464c0c3019 +ENTROPY 8efa6ec191182cdc55d75d68592cb7cfa56aa625452768470452c21b000160b1 +ENTROPY dae95d1e10b1c8f1033a2695480296937ba2825de86973025ce1e7faae0b5c29 +ENTROPY c6dc0435989efceaedc5db841a06ea439c20813d611fb236e879b25b71793b62 +ENTROPY 63fe11fe170173d82f93ab4d3ecded5678f90ac156c59ee0df203c11df0fc9c1 +ENTROPY 0e58ecc17c1e3137f933517c1afb380bcb7b55c01a8c4c4d479413a2a68e4b96 +ENTROPY 5176622e2730e27b1b9df8d7f691094e09a2aa18df4b4bf23f256fca23c5e1fa +ENTROPY 7ca669c3b4d99a020e6151eacb22e8ecf79db8ac25b1775b0642443ab4991311 +ENTROPY f324382e328e20b2f0ce795321fd8cda953820c22dc5deef5fb23286ca2a0f05 +ENTROPY c50385a16faddc9c8c1dacbb0007df9113864fada5ad0905331c9f6952469a51 +ENTROPY b9796f6410484cad70682f8d61b78bd2b8557d81b0180b0481bdc985aa5897d2 +ENTROPY 44546dbbbc90b2e64aefd17fff7f4c210918b57a0705d26dac8c4f68a0f804e2 +ENTROPY 5b2f5b62b9c4b9b803a99b1c9845781c17643909faa7bd99b23a384315370759 +ENTROPY 93fade675fa07b8b6a773a1d4483926f1862d8b5cfcdeaacb03eb4ae3a125e08 +ENTROPY 1157edad8c6bb528ae4c6400effee6eab802c5cf727d16cc9ed3aac15748be90 +ENTROPY 375feb3b2e3364540255e491532ecc7e8a7f19f686e2b1c5ac575098ead4de92 +ENTROPY 1f6f9b0519e517fab103e7c288f8f8d42c745e67e8ee8ebce0da52a50b224e34 +ENTROPY 7c12eef8f4d2cb5c400818d6f79881a0c0efd3d137d52ea49b99a8aa9d8b3061 +ENTROPY a5e51ffeca3a8fe3c4ddeb7011f347cc25fc511ec5d7dc194dc56865ee9098d4 +ENTROPY 7ce141fa365d6bd50e572d486c0785c0fc08318d2d556451dc5166099ea21dbe +ENTROPY ed10ab29437ee1ff80da11f9b9903f35ec2f94cdfcc99893a853f8fbfbba1a13 +ENTROPY 1043d20bbfc291df4cbc94bbd7fccedef75e788600bbb3af50bbdd7c3434aa0f +ENTROPY dfe2b915dfb4ca580cdee8112d32117ef3308f87ead9ce3acf0648c210d8d219 +ENTROPY 95e20a90a38a88e52a53aa6f72ec51bdf1ee21351f454773ec67e02a66a824d7 +ENTROPY 3803b3994029144ff03396f06a364e7fb36b28d823d6bb454702b74f8694bede +ENTROPY 9f4c5c90e9ab5e09ae08aa5db1bb993056fde9020b95533e9d0288ee52b043fc +ENTROPY 1de6b3cf7d055bae29fdeac8fe1a75aadbced8186561c508c363f24e5de9cb3d +ENTROPY bb7b620a45403a4b8237b69389b749e87f68a978ee2d8858086016659f1236db +ENTROPY db2b10242f148e0a9e0c7fea54b0fff78143deffd0f88e1f705ca394572a36b3 +ENTROPY cf2b9558cf28a26809a363e861c5f69508ee4ee03b6d08d249236342c73f7f95 +ENTROPY d59de6442866248605aa54b9605426a8352c4f285dc252aef1448ebaede3b1e9 +ENTROPY 74d5cabe91e115b7734a984c9a89139211014c00f5d901a2bd789b71aa38e293 +ENTROPY 95a5de326bb2c2b172c0262418113d14e1ea3f76a8899dfe59ed1485ea04771c +ENTROPY 8934ca9cbc35ba0eb018d5016cc1ab0794fc53c33cef2160a5a585f80393eb3d +ENTROPY c73f6408cfbc1537f3d484876f9ec499d75b8473dd15844c6d826f1626dff0a8 +ENTROPY 7027fca14686e2bdf9427054af12341d551daa10493490264870b88a33d3186f +ENTROPY 4aecfcc4440c1e4333d579bd0ed3c23c9364954cdcc3cf1a9030cf3f1a4957fa +ENTROPY 6365189bc25ab9e7c071d21c68c35914c29b94465b987a91619675cd36dad265 +ENTROPY fa8988dcd614615e73704111dcaaaaafdca1255e6dd0cea9666240e4df8c3c32 +ENTROPY 5ad86ee802b023fccdd98c4b4aea2bb04a6d2c18031de92a29249f9c5d3ff290 +ENTROPY 4431966dd8797643b00719c67c2aa457db102e0d5bc8e94f7b9491667c8019fc +ENTROPY f921c4a624ce2ffd7e9e4b871689aad1cb74f2335d3b8a975c0fa167ff27c251 +ENTROPY b50e55c471dfa0416f1a797a5585b809847dbcd656151cda51644752ec835c6d +ENTROPY 059016d6b95491d47338b0f83acbf5dc2d4e111d958f3a407bf43c008cbcb521 +ENTROPY 9a8ee487ce885b9040892ab4c3e24bc405d0eff23548cabd19d6b3a4270ca6c2 +ENTROPY aaa6c094059cf0c7ebadf0c916bf9e847a7495f99e18d0537bf96e40420b6210 +ENTROPY 13576c570f34e6a38c345fada586dc8693dd6e21db6c731f58fba0ae9fb263ee +ENTROPY b3eca42ccd043bfd3879e47657e197f5824cebe2fc1649340c5f6fb1c5a3c4e3 +ENTROPY 3324044e062d31226abd5001900b12acb0b983626e757e91ed78fb44731747ce +ENTROPY 5df66cd7bdaba52f5ca46cff0d0c8034b0447ed1998b411c84eb1a6e5fc15cff +ENTROPY 86e703df04aabeb5e5f929954eab3fff2682b3660003dae0ef69853b8f1399f9 +ENTROPY 8920970133fbc3a1705c801e1160b3b3300dc12a742c67faddad3d5143ac0898 +ENTROPY 07750c71eddf1126312aca49a951413c73fb16487219543a47e882d4d758a335 +ENTROPY 37e409f9cc1c61e7ec9bf0635f39090ce75a5d57a908cee80f5b4a62c34b0ff6 +ENTROPY 0d853bfb9a617a2b18a95c937f031d6c3047cbf8c2756d1506086cb14de4723f +ENTROPY e28313e4758bbb27affc885550d664645bbdd1d134b3a4478a7d2bf565c218cf +ENTROPY 86881592829971a890c91d564898ed0eeca0fa3dc6b77eae6fcd726b66e5aaa2 +ENTROPY 2d4fd4044bac5aed6989bf2478dbb11005ce6865286d05f288d52d1ea7a38aa9 +ENTROPY 20f9577753b78fa593963b72db9cd1e92201710e04b794a3719fef2f0ae7b18c +ENTROPY e98ff2608f7559fca7132ba9c3751e855719f69943b039e119fa4dc05387837b +ENTROPY 0c75b02f31b17f4f92307c0ab924e5b42dd95ff488e26bb700a79b1994524a09 +ENTROPY b9f62b3e9c8214df47afcdc54d993b146421e161efc7fcb8e0c9ea2273280bab +ENTROPY 399378e056c63ed2193136d0aa8b59b42465d366f0790715622ad5d6b8cf08ca +ENTROPY d8a1bc16d33d016d5f6801c728d88fbfb4f5111ad904f198f90a3b3fe5d3cf40 +ENTROPY 3cd0f339fca61c19d110d14e3a0dbef96149a1fe26e580f0082dcc1a7a4390eb +ENTROPY d3595fb8c7984c938095fcffd2314c0ee8769fa8ecc601a22f80afd7c4fe8b41 +ENTROPY 472a8509fe9fdfee76f634d5ba90f276a53de95fe404bf93aef8a9e716b484af +ENTROPY b620e96f5391e66e38b45446a5fbe524776477b224df83bc8b28ba4ea2c91304 +ENTROPY 87ba57657b2415cd5bac3c19bc03573adb77210b0b61a97907c2852812f67e9f +ENTROPY bd004f93df2542a97240aefa48d0db99b53cb89623a9c5aedf2f4fd443c102d4 +ENTROPY bc48639043c6baf5b9fa908c2dc7db7fbc7008085403cf27fee9f5b9896a9562 +ENTROPY 2338e61832b9aea054ca1aae47c9bf43759401bd821347a2fc2c8de0d52b2d23 +ENTROPY 412626da6b17d262273deecf96d203f2014ce79bb4a643fd747ac5a345b91460 +ENTROPY 6a962f82306f2df91a88293747a22c551ff3187b2b82a748c5afc4957baa935d +ENTROPY 6afb1c484f5954c902ad0ac5d0f76293d4f4ae7373af14e5c3c029e56c48b8f9 +ENTROPY 75eea80f1dc5e8b4d13a35237a123a9d7e3b482622ebd5e04e7d9d8aec32773f +ENTROPY 00b05f90f5f62e6aec634f0454dd0b3f332a2cd8c8a1e6cb48dd887846c4e95b +ENTROPY 5b43b4937ef18eaf9811c2c62420fba049ed4f5e24a1a7eee98dbbcea325612e +ENTROPY b29a7535b8702f524f448dbfdc194c1031029c3d0a697fb57f95bcd265bf686a +ENTROPY 98feb01c49946f86cdcc8c1f1daafa13994d1450b51b0d6567adfaa6874f5838 +ENTROPY 725094d75cb28fd5d01e8be6f3befdc69fbf64cdd0f143ba5a44f929b2edf6a8 +ENTROPY dbd662a3b844393156015104582a8f752d2fbad5b3fa360955a057f7440697d3 +ENTROPY bbc1064d7805e54724453c2663200a4839083091e4ee98a669c34ff204c714f4 +ENTROPY 01f572c3aaf8775d5f3287895c2c455556791c06d7464453d91a7140df23b723 +ENTROPY c566a2289a9ff149ac3e5f1e55dd5dbd8ef88f09b3ea3c7ca63968c3fdc70eeb +ENTROPY d5ebbc81fca5c074744ae971e78465c33016481daa30daa184a077cade950674 +ENTROPY 147375a7875b54ae4bc3b0dcb8c66967fc2eae622b9464f1b19e32eb3e89020e +ENTROPY 2e81718fca1f973af57c058608cdc3a395b53ddb729968d65366531109ad0988 +ENTROPY 0b3de9c424b14b3b53fc63ccb4022d5b674506b3c456903242b4d5952d976388 +ENTROPY 73f44fb0b999c6035545929daae207589c4dcc6bb1db12be9b49247222f52e74 +ENTROPY 739f31e21a66a92ae683c981c83c77b8203efe06d912c244ca209abc1badc6b5 +ENTROPY be5206ac26a9db283bb88281b57c735476c0854afe0f78601d4254a37fec94b6 +ENTROPY a4741fe6f80858fe6572db3c168e1cf277903189cf58c89be90452c64819fa34 +ENTROPY 9beee028ae787f276828970927382f49d0cf9834f8d44f762d19dc47c25d2bde +ENTROPY 5291a0d64fd54c2fc37d31248e6ebf4c00101bf5bd591e99474ae04631d5b779 +ENTROPY 97fc65d85a836902d97fbd959c70f4360e491e46a0be257572482b16ce512386 +ENTROPY 1bb2645eab51dfdd1b9d6028d41c9c3d548e9df1bdddcfc7edb36345cc81b735 +ENTROPY 7f23cb7c5934461d704634d7bc1dde7d3f8897680b5dcc804a77ae0c7ac747cd +ENTROPY c204ce991f58f82da1add645b84c772f271091b834ec07aa15de26d0e9c4cf49 +ENTROPY caefffc88fc1a6b437a1104c6bce6fca46bf7382b4aced74c646912937b52cac +ENTROPY 0e8da1964c7fbd1750ab3521510527ebea0085e8026bcb4359d9fa572e8dd239 +ENTROPY 6d38a3ff1c5e08532b21a7707d673b344620dbaf8301bc8818602723a93cbaa8 +ENTROPY 2522104ce6cf9fd395390f20d1a599c1477752c00c3d0aed9251b197ffb9162d +ENTROPY 371131b97d1c353e5836feab49455d4e38c90d01d28e2199e98dab8d6e505baf +ENTROPY b1a4ee1e40f7f9a0532a68622fa555c294613ef730eb226011236f6cc3d43582 +ENTROPY f6e6601172ef1aa1892d230291dbd3266ff1f7f48b46df484fadd14743d23948 +ENTROPY 3f7bf4591df4f7973278c3e53b6709ae093fec76a755bcb402cc3af179995669 +ENTROPY 9f0856da45958f9ec9adc25fb420597df104c6c069a51bdf48e55c9bacb3a0cf +ENTROPY fa82b84fe24614e443ebd6a65e8682693ccfb99e8adc171e21c6cfa988856ba6 +ENTROPY 491dca562d64024cf4bcd7d645c81e91152cbcb2e1887adedaa3f3d7ad5c076b +ENTROPY 8b81eb9ed82a4d5d02a8920b60259911a46ca4ab04578a2d442ba2b8a5bce0d2 +ENTROPY 9399cae8a065ce5c9e02a422c4d88f109166f2faa7c3197bba93a4f525501307 +ENTROPY f385f319fc8cb34b31caff3b0931a1fbf339e3b033468236590683855e546549 +ENTROPY a896baf76304007e3321d3921f6adc466913c65cc180f70161b9ba6be8cfb85e +ENTROPY b5078e30ccdd48118326c6a4162c5cac474e336074272cb0e3ef742f7d503373 +ENTROPY 52ee968c8feed05ebe75f2f78377c74e733b2b1326391f2327b752319bfc65f6 +ENTROPY 2010ba502a0f9e5785a154d797e5fd78c2db1143dbcbc6d5b06b43b79db1df55 +ENTROPY 7a7fd34f8d421017ffcaa2218d126e017d91248a06eb5a5e424d3c0d2b73c404 +ENTROPY b187fb6a11c1eedb6abf30c5f92b48f06acc33c9fa3ba1cd1ea94474b13798fe +ENTROPY 0181d376bb51e628c2b2558862146da18f47db733ea43dd9281b76b7ee9b11df +ENTROPY 01fc479457a4b851466f0b0193d8cb2da19b1c53efd70824d6dcd17402e68036 +ENTROPY 963e5ffc1b5d0b4adb13b860828acb95beb7bed15ff5dfb3e34561441dfe5401 +ENTROPY 826f3077f01efb12906bb7e706bbf878194af0ccfbac963fcaff60268f7d19e9 +ENTROPY ca106a68b5ab56538336bd8e91dffce4fdcc50afc688886fc72658137623dcb1 +ENTROPY 4854caf42dcd1762250b2de17be0ec4fca4a8698c9348fbbec301302838b9862 +ENTROPY c531ce2c6257bd35857e272283328955b4a86949a194ca68d13e30d096a7f415 +ENTROPY 364bc016a37bc599b9850e2d23d107689d8583d463bc40aedaac8efa64afee05 +ENTROPY de3e0c96ddec143430c3d44645475822707df3dfc7a6544c3b1647f959f85f93 +ENTROPY e7f34896a727a381a8cbe334d0ed4c08a215a45adf5b0a747f0b4bf527db4284 +ENTROPY 1e0cb59b7da3d6be597c346b6abdd9e0f9194469e98f56f66e7b7ce5dd14ca56 +ENTROPY 641c9b7ba99361e24020bb8c08da597af1c2aa0f88697bf1ac97fa320877a9d8 +ENTROPY 5636c71b981e0957db4dbc238765b2f337ba3f5849a995eaff97ca4acb0392dd +ENTROPY c713c98c024d3932a1fb762545b398df128ac32a878fee52961ef37cec781e07 +ENTROPY 03536d507bbb835015ad8ca607cf511ce97b5daa2ea9b07fd9dbd387aa7ca830 +ENTROPY c8e78e53c4637df15e565a6f3f6d3f89f2551eb8b4c2c8018970affb2bb813cb +ENTROPY 71e13d5c81e84e5ce6b285544cd533e563593df5eb072f68d1dce49ea90d12e2 +ENTROPY f525f6829b8836cd88f52aad70d9ba5ab6786d37d4310b9df0af0d754dead11d +ENTROPY b3b7219a6485a68d4bb3709a9a4f65283ea71330ba8b4c06fead5aae358dcfd6 +ENTROPY b5715bf8c0b31953c9a3fbdf127b900204111b4d83e1ce5e18f06127e71da6b8 +ENTROPY d076b96d3eaa679fa7ede75d7de4cf7893dcc1a64d8d4f5525e3766acfccce39 +ENTROPY ce42a1454f5beaf0c11275a6ac8a77159c3c98b3db46c24538ba0bf7642e9fff +ENTROPY e73985ab14cf09af7818366b2fa2c4e91076090d8c3e01e1502ff9244897ec84 +ENTROPY 493428b637ceafbaf605d6faab408b3af5ba36f2fd0ace58b72ed7a132b469b1 +ENTROPY 9f192e9270e625b445d4acd178dc4a0777d24d6a1c0b5ac9426e3432819edf17 +ENTROPY b29b140fdb70c9db0f9dcc57252db21f1169e0dd38161f0f95010a05a67ada96 +ENTROPY 3444b09915211a127e3348f343b4f51b535159162005c3f2ca5a49ee9c240aa4 +ENTROPY 52a4d0086aecd86fa6830a8155df10a977ef3c63371070fb0f4e2d153d94d6a1 +ENTROPY df90d288a6537c83644cba4d14dc72c82f2f663f8099516ed154f1ad79a76db3 +ENTROPY b31e18e7f4b8cca7c08888fb68dcd6ace8df753740044121780297caf9d16e15 +ENTROPY d333c4b26a0edd83a0b7796dfbdf337380dc90b40b80b7ca67dac6de22e2b49f +ENTROPY 55a2e03b785b0d1be708475d98a14af53ea4c5bb61d41baf2bae268f2b0e7c3e +ENTROPY 39297fa02476552b0fe630049ae297269ad9ffd3b324bd1e90a9102507e8c4e4 +ENTROPY a94a70094f116ace6011a95bff35224800675d481236e9db571345faa0a62590 +ENTROPY 4e3092bc6919a9b22053e027ba6d9bda962d5b16ba413d70d57659fa292f3d57 +ENTROPY 0007f341372b78000fa475aaf84a4a1be917c3ce407f835c455496344949bb1e +ENTROPY cc85f215c0df098e55c2c3ef40afb1fa51eec9da615caa221a4bbea9f6027c20 +ENTROPY 2ac117604d2bb88df71923312fad75d21472518c98a4b3aaad8b1b5eba6b8a32 +ENTROPY 2fd9b3c94d6edad204574fc78ba61ddf9ae0ce1162939075f8e5fffb7dc35496 +ENTROPY 66131c731791a01bc4b227dced7d0781d36414bfa4f38d01195c81ebe58c3603 +ENTROPY 4e3b3d3f748476936c2f75e378b29bc15d89752b564066ec66bd4dd0a37889fc +ENTROPY 503fbeb1b16ed3d5b7a78071024c4724e5d76f5fa0840e86acbdb29384f14758 +ENTROPY e4e87a393cb338a778cc3eacd30c5bf08fe5b1054daba5b3fe3b683e431c571c +ENTROPY 4123c4efcac43877e08dffb0b6564ef7917591dddb1ac02e1efd0dbfbdcd368d +ENTROPY 44b714036256dc5645f0805146383df86f8a7bca301d431cfef6b894204092b3 +ENTROPY 3b539c774cf916bce0d6378893ecefe0bd42512f76708a8fc987908a6f777be7 +ENTROPY 94fcebe97054d0cfe65345f6703af671cfa8ea758402a5fba6b4b3449e5b2024 +ENTROPY df681a2e259b8967dc9362b6b2a3054be335f9e272f5702051d20b0644eaca01 +ENTROPY ae4c52c3090eef1f507e70dca2a680da286802557b2705b564dc6d2552f166d5 +ENTROPY bcfc6bbc766b234409f77e539f596e78c08dc69ca3e4c83d1b6a2fe762604c00 +ENTROPY b1111af2ab0a3a006f1e32381755c2fcdced2908249128ead94be53096ee97be +ENTROPY 7748c533039889a0ca0301dadb65e4d02924dd9a3a3d36998c6b79821ff3868b +ENTROPY 58aa2ed298f7db8321bd99c4a233b7ff6b7d9c2b1ee7cdc74a0caad44095f462 +ENTROPY a2b7ddd05c8d5f189bfe6d8390e8d994d18ecbd482473e31d9e38ada98ee67db +ENTROPY a43af9fd438b79a544289f418e6fce2d130eab86044e79b7366ad16955fa1ec5 +ENTROPY 4c5d42299581984bfd272ca66222d7e6f166fa9985b20e38a13871941d9a9d70 +ENTROPY 4be4dc6625faf4b1c9e0f4d7fe2f446a5c803d10d3e42690f71abacbab4a423f +ENTROPY 25e02fba76aa8b7dbcb2a717f5e194f71b0391ac4564549a192f18fe0cd3db06 +ENTROPY 559b5b5f9ecfa646a27f186537d2fc38a087d8b9efd3d81d44086c5e5e5a5d81 +ENTROPY abf0f47f25420998b030aea3202b2605e04b919c169d2edc1d35ffbdd40dd43c +ENTROPY 63601e0ce26a8b7c8485a96329675047e1d7c9693fbd9b99d1bc4b0534db2109 +ENTROPY 3306531c678983b7c755c0d255c5ae3bf133c30ca8bf39baf11ba6c8d93a1956 +ENTROPY c0ebc3fa07508cc3837c1eba52bf11d594471119275da078e60355293b177012 +ENTROPY ae4ce39e0849f8d2ee80061c525b91134f2c1cb4b6a02a8cf3147519f7cfd9c9 +ENTROPY 6778b170835be17bd30e5e7dd57d6058968d6676a6c442414fd5985773c2df04 +ENTROPY 36984918859c2ee2003d19ea2645912b7cc70f2adce4f9465aeb4d1347361ae3 +ENTROPY e2fbe5ffab82c8869403fb3c4df628616559957a045f19bdcf541c6ee369530c +ENTROPY 3e634b2d60b6cc62b222d0b8b429819d6965968cdfab14addb5f94070ab91675 +ENTROPY 8260ab83daad6d5e66fcf31532e2882ad4d999cbb82d8fe7064f36b640aa9d71 +ENTROPY d5d272d2efcaf3da6dc151a4132a94136b6c831a58bbdd3c68e027310789d832 +ENTROPY 55cb286e0015ac895440bd8fd039492aff5162fe0bd4a403b1f167de8041b410 +ENTROPY 414214e919dfcd3cdc845b70fdc1f7a32b90a68df729dc46f61a5fa4b32eb67c +ENTROPY c4f485a7b5c5b32b4c245c6aeb1fbc86a36e1b28f8ec85b7cd26c5fc40c60ff8 +ENTROPY 3ad5de9971c669603cec89ef61878b5a66e19f07f54ee2fdc3ee3255be5ee902 +ENTROPY 2d232413f409b478ba0cb80df88f6b808ee78f274a9e45bde309e41955fb9930 +ENTROPY 90327d7fee609a93ce7ded567faf60a303911010776bdcd8f242874d6f9fb6bd +ENTROPY bcae2921a1122664b223852889d1ac1948a2f8ce7e59f9588d744f3ea46ca630 +ENTROPY 1b1f71d33753263116d2d90a9b48772c2435f71579e09efdeb90fdca2afb426e +ENTROPY d3a1083f16ded2aeb6c8701a6063f47a2bafc15424069e2678a667c0d573f418 +ENTROPY c3605e30a95730c2caecb6bcb226fbfe23ed28cd9ef2459b02ae0ae3cc4b419d +ENTROPY 90f40fb6accf71bb2b131bf8ec6cb1ff64bff55b55799abc97241e355e8833a8 +ENTROPY 42c9c2eddfb9b4c19d2408ae00e3a8d1231cf2ffb5ae9f427eb70ff5f5f9ed71 +ENTROPY ad6dcf74a5ef6aa02576fcf6b221f4f0ac0e29c1b3917f81453c45b70215c009 +ENTROPY ac9b56a45ce68cb96b1afb2c4ee50abab5d7c77931c20e35261eaebaece3dae0 +ENTROPY f24586ca39bbae11d950f84dce2be083ebb100c7bd74e75a5d901e729770b459 +ENTROPY 45387f1239f066ce7766d29b1b4f7b4f1f3231c83131dd18148d39c838105989 +ENTROPY 2772e8371dfa07e9adb84e98e5a66f56a22742b6bde59f912b85f43f7863bc63 +ENTROPY 2876cab2cc0c3f4f5883c7a2d8b5bfff71b72ff5eefdb58a6f23bb34e3d03fbe +ENTROPY c626e74942ef464655777c5c80a6c59f51adfb829bb8c60914e52daf4cd27434 +ENTROPY 8beba41f4bb8038c499d97b7380c6e3655cb361084a76f5269e5eef827022759 +ENTROPY 2f80ed5f2c34c712e53b0ee2a963cec539f17860df6dfe9ea789321ef4829639 +ENTROPY 9424fbeced23a0b1b46473fa791b56f2db5ce562ca30da1664234a013d2b5543 +ENTROPY ab37290fbe3e9b7532f0d3141bae645f266b0abf853ff92c4f9f7202ed08f304 +ENTROPY 0a26ba869a1030d4d8a9931b9b6c4f18e4a290e06d06d81bc5841a5ace415dd9 +ENTROPY 1c71545ee8304335e9ee54a8fab19ee511b60ff45eddc872ec73a89a7dbe64da +ENTROPY 2f02e145b5a1a19c66c98335436ee76cf41967fe9f2401270db36b09d25dbffa +ENTROPY dbf8c672072c9c81288878b3c6aa0364f73c937e69f65c35477968c4a510235d +ENTROPY 923ffbf8328e61d1412d6ba3a7e43124cd1fc4ce4af14d890e78e9da88f022ea +ENTROPY 93dc9cc2eb2dde450a2fbc138f65e80af418f8c5a194ea1ec7509585b6cf86b5 +ENTROPY b22001a8229ed6200c0cc048f91ec0191837b6290a4033d117f6d652b827c43c +ENTROPY 9a3a50bd486c132399e7f3991babceb97c9cd0fbc5347ae09de56512d3c407d1 +ENTROPY 0f82dcbc4a9bb4e2d8ef6f70c7779c82bc55875e1f6189a2d851d3f7048af5ce +ENTROPY cfa82f927b33052f4ff02064f292e013ffb5be63368e9915543921012769bd56 +ENTROPY a09536949de48537c67fd2e12108c6c6f1efddec66b6f7ca80b56b5ecee7eba9 +ENTROPY 69a57ddde24201bdd541113021487e95661eeac5c1593f10f2aa6909478e98ef +ENTROPY 7a25eb7ed842e803a29d9a91f822f72f6fc6c27e9905836ee801cc4138cbada6 +ENTROPY 474619107729b8d07651f8a4d9a618939bad880d3a7d9c1a7bceba5ec7dbf7a1 +ENTROPY 8c62fc2a5d6805f8d35009c629cec4adb448fe28ad35daf202fc58536d79a550 +ENTROPY 1becfb7fe4bf2586093cb9fec45b8a48104675b55176c83fd929936971ee1869 +ENTROPY 536f8b4d5ab12dd6297088cacaa9f03c1e1d46d3bbfbe3c1072ffa21d34e2e7d +ENTROPY e0203423a3e928d5a4ea08fcbf59ce11d07c6e1a4252ce13c2188ccb1a0e2526 +ENTROPY 497931d6b9fb7e745df15b9ebaeb3173a803ab034dce13d47930e480c6c5f22e +ENTROPY 15a228a2abf21f150059b1bc458ebdb0f15c71e587b7b41d8b21d85abe0bdbd0 +ENTROPY 67695d554a2b793d93b22fd4dda6a25c84518239237212bda5c9fe65fff9c98c +ENTROPY d687725c24c0893913df1f1a5dafde30308ff5baa34f7df58e1d964ef6fa7330 +ENTROPY fa004a7394ad2ec26bbe733d81f9310b2aac0a6a1a9907e88cb073b090d2a712 +ENTROPY 44f965429eb9c32232bdb164f938b3bfa67993055520dfad47ce2b67e174fb79 +ENTROPY 821d2752f9938e80d30dedc4be57d881934766827b34ef2adb80c1a15175d8d2 +ENTROPY 3dd9e89e0e30afd1c7de626428a346b40a1ab9cc4330015f5045491eab42bcd7 +ENTROPY 5f7a101327ad735846750b8e779744b0d001c224dff4508646e8171464c1047f +ENTROPY a65ac40a2d6799eea0ed0dcfcf9a657d50e0cba74a78dcfd4991c71cc50b06fe +ENTROPY 3ee5904ed902b45970f8a261b1aa1b1fedbdd23c85089f3436565ac41fd0a399 +ENTROPY 8b3c35fb8460935b0c9f7f63558442e3a9ae530384ef31955a2fbe7cbe40fdb3 +ENTROPY ce869c83ae284ab2251c512d9ca2831aa7ed97180cb06df72e57ecf0ad24ed40 +ENTROPY 852706f9f6b7bc087bb5afd55aa59fcff27817e010ca94d25e95dc0af6e75c77 +ENTROPY 0412f87a794a42d6b6839d77821f2bd72a3f377ee89a69965f64014fea8d5567 +ENTROPY b1def0d89291b7a099766f94175fdfa827b31eb645b6917c73f48c4ba9c41fc3 +ENTROPY 1ac975d377df4e2fe46d11defb724abdfa0c72e0e02ce6badc6bd51da577c737 +ENTROPY 017681a8b8b48bca694ca7dac5a796f2d8ff00ae07892738c38ac9c08e005113 +ENTROPY 04f15e8c912771112eb41e9acd892edbe5aa741cb8c95921e5f43ac10e282cef +ENTROPY f7ad4e5ff988cc16926fc8589c04983d8ea637974cc2a1836ffc50c2fb9b77d9 +ENTROPY d701dad13249ecdc0cf3e935f077644c7aec590d1090377a05c5019f51202cdb +ENTROPY 5e29ed494ecbf89cb2529cdf1c321a3ba37306870bdd65b3ea329f068bdbc35e +ENTROPY a37fcc31032e972553b003f2a62eabf99ace6ddda42051ca08157f355343fdd3 +ENTROPY ef8b1a9bbc48e8831776fd2574823a1d50f11db8ae488e0effc3a0ed31e4af77 +ENTROPY 2f8e10b1ffe0991124c66734aa707689d74511cf59693cd19e9af6e44cbddbc3 +ENTROPY 31f39915f3e54c20b892bf8640a76ea857237ac1fde015bb21fe5760d5eb58c6 +ENTROPY 1dda19260cfb42dff7c1782b096d1fac8a013a185c895ca099aa8e7f183e4939 +ENTROPY 0da2fdc057253d5bb89b292d6c217eb2c91d7f4967c79d0f235d9074e78a8d7b +ENTROPY 52404704bc099820622da493d806338ad54cb3413f086cfb5774ab9983046499 +ENTROPY 87a5d3a227d198e5ff7b6135f3808fcd616f15a721abfc25abc7328a1fa36d8f +ENTROPY 7203cf3e126df3feadcd876171c8d624b37e160f5b2f5ddd4512a7fa46813abb +ENTROPY 13089199d3fac9b3c4064a108fd1e123aab0629cd74d71b508d9eda5f6a68210 +ENTROPY a280c7f4cfc3608846b8904dd23e5005c9443188ef6631dc0e44313e47f6701a +ENTROPY 36ed200a9176b57ec61dc3e73472900464e610a684abcfa29aac8044fc293216 +ENTROPY 48334c2dceb11c709715215106f27799dd28a02eb36219685899188f37cf188e +ENTROPY 0ab9574b5bd6fd888b9f849a7bb97322eee2629b6653b24cf1237d6ebdcce03b +ENTROPY 316df4537aa745d5afeaaa2c4d45b3cf2273f6cf0ae97de42121617622ed0525 +ENTROPY dcab92de5cad4247b97c4ded1bac6b8c0b568c3a62e0e24cd7e7de1ddcc1cdab +ENTROPY 4deb74b9372af45408511d87ef26d729cbf242112ad465f693b170cf3eaee7d1 +ENTROPY bded5c86e3151d94735b5de7508057c91cdf6a0000c718193a44242ed22df058 +ENTROPY a9aa34e09f547a9133c53b104fe1ca9b567c3c90e263f67f7aa388089528e024 +ENTROPY fb15429c0808a909c2274d3e3bd5606a51a5e60a662b0f4f15a012316fbe119e +ENTROPY 2135d12a663fcd3922b26ae09384b1055002a0bef328f5fe1c54f045df56d73e +ENTROPY 5431fc43ed58c47d5f144008fea3589bae00186ca907821fa8771610e467e977 +ENTROPY 87dc3e507a2202f8a194b31136d4be37f3e990540ac2bc7ce35c02c6cca620b6 +ENTROPY 6f53c1b5919bf1f1b0d9cb92d0134ed153d2cf069df00d065c19cf2d4d1f49c2 +ENTROPY 5a3032fed60750839c2390b02c26a081c2bc6682ac2ad3cb66357816964a4e03 +ENTROPY 7df84147741a28aa585395e28f159c4448e16bf64e2e485c4a10b1e4353bd4fc +ENTROPY 8b060ea6f879d3a63685fa76210253f00f9d9913171190d3a9e8a00f914fe845 +ENTROPY 9f4460f1380c6b4ae029ed715f2dd19269d2ea52c8d363f0d153c6684a782f38 +ENTROPY 3586be8468f0df1ebbdc4f35dd026907260a5aca14ec3d0adfa096b6ddbfb23c +ENTROPY 5c893e3fd024b37386c846dd3e0b7e82d7f0ccfa53b054250292c89af9c27cd4 +ENTROPY 46eec852708d6831494d90e1129f22005e801c3b0b329c7f194ee01f5b5a5a45 +ENTROPY df8c23b2922daa28a195f4eb7a38b9b0a9820340cc50e04230a3f10b174b5626 +ENTROPY 9ca92c524d1ef267f7bba109842546e4b3f2670fce02e5d6297f3504a8f0f806 +ENTROPY e60542b5b2dc993ce9ea00d5754df5114b6c87cecfd0957074ef95f6134dc512 +ENTROPY f3ac8d97069e13c1570df13c1e4369ac29e095df6953526e692ca030606ba463 +ENTROPY a97f7fb71604bd2ae8cae5824571a48e44020bc28530220d95f49ad2ebe20059 +ENTROPY 6dc46112a72fa5bcdebcdbf7538929141975c0fc40036831560b41d264c6bf27 +ENTROPY f13232efa0d68f6ea4b68096486ababe9fbe582c37980da4bb22e698af46d99e +ENTROPY 7a871b1c1d3d064cae1e887d05883a4ab753f70670bbdcd3a034d8667d0d91a7 +ENTROPY 1ca198bb659c175f2498e76dc968cde5640ca1dfe3de1bfad54a3467ed05ee79 +ENTROPY 3df13aba670bc0280254d640c18b4e35d5d03b512172ec13bb2531cd4781f42f +ENTROPY ee0a5f13655627b1018641cf839fbddcf99a720cfa8b1267c5aadab8e016018c +ENTROPY 78c86bb5520da88f76589b395e2345ae7031f620800c3bb2c39010786a040ea5 +ENTROPY ff6e6378041c2d49f1956354ed05709cc4b416da023a7fc64592fb61362690fa +ENTROPY 2569b3b14cc63ae0b7df1640ebdc197bd8649103abfff7af6f65d0653d19ccc5 +ENTROPY 773867e02378827e8313e4ddbd8330933fdfab8c63143ca4c5a1afcf24d75db6 +ENTROPY 25d75ba29627e710b0116d285ef47bc48411a83404d5aa0af835f972f8856a1d +ENTROPY f5d85a82a040ec139fa8928ea82101ae7293753c292943267bf8b82d7ec1a7b3 +ENTROPY 261ea2206e6f4b94c65c5603073e0726e760e9056e8c6b13d8b306e9272cf9a3 +ENTROPY ae6c71bf57323490e14c0701f5e918f4e46878afd0268517433b0304c7eaf1f8 +ENTROPY 1301f60fb91d15af039f2415ac943ea9ee31751f93dcf15677d7e0f09418d9cc +ENTROPY 1d5cfd59f746a965f656739e01b8d3e204b538e80f885f43a404d7ae272d183d +ENTROPY a22ed4bd42bdc2e884a084d3bc8e46fca742952bc3d77d7e776ef6aede45dabe +ENTROPY 4ba1c84873931e819403e604bb13ccb16aed344cfe5007e6118ea1595a8dbb0a +ENTROPY d087ba9a21ba942321583f4a13c31ab2ee6d7a9bbb77329b4e781445a45a3079 +ENTROPY a892f7ee97e286efcbd033bb3acc3975d90ce48a2cf605da1b2cbdfe35bb0c1d +ENTROPY 5b5c9bebc159f53576a44ee0bc34982f2798895b0ab416c5d8259230eaa8c5db +ENTROPY 99c8f26b8600d9d4ee4f1651443006202b8933de6e6716310dc1b44d3d72bc74 +ENTROPY aaa3dbf2bff2e696f02ab57ebc3c3e669d6fc2ad1e44fdefcd8b94e8963c5999 +ENTROPY 9d3b34c91bdfd193c1838ee24b4e71e6bbefbc32a101b1bb9ab813111a2ef973 +ENTROPY a75695981c590555a44ceffde8c31e4236618088083b486fb0f28aa03c3c23be +ENTROPY 1652fb223246f94f00c8d9eef46f632249888b537219547d4434cc1107019529 +ENTROPY 6174db930f69e6480e605a5625bc2dd33776e8ab50dbe42a40c2920aed567868 +ENTROPY c35a08e351946f940bbbe2fca7945a346599d5b9d82105e4465db5e064c9b774 +ENTROPY 402394e4634ff75eb2a168d5f03bcb5f5573c0830ee6c679a980b9e354eb0677 +ENTROPY 710220dee868ff76eef56ea6f41a70fc45f017f4342e712afc798713ac16f007 +ENTROPY 2b222c50f176d3c16e0ce44c04ee26c6f1df0dad31870efb15126270cc4d6b52 +ENTROPY fc39f6461dc79dc88c2e12424ea1a5a85b8e06d3aa08511858df2ac2da2a8f41 +ENTROPY 702288a20b48a9b3c8ea7892fc2c97b93aa2cac615b25c06a1c6d0386dbf072e +ENTROPY 0672fb61618d8fe85c8434278048afa58d84dfd023e5a7c05b82288f7fa0f6a1 +ENTROPY fd10ac317b510afa4f0b7ec2df7f0e73d293253c039d68b512936fcb1351dc68 +ENTROPY 8c91d69a077ee076d99326977588a4c9ab2e90d7d9b5f8d926e05671ae8d6962 +ENTROPY 783abb598991fef08203f321715661ffd6d75f2a8fa3007da4a11cbc14bcd084 +ENTROPY 77b82a74c4efd19e7c6ed176db4a33c76e3c0be68089209f8a9484ff5e2f1358 +ENTROPY 52eee4f531e4dd5ef21cc4fae6bbe3cd345c3562a08b2e344004b48fa6a222a9 +ENTROPY c3b9e236740b518abf669aa80976480d942852c3f35f6f3e9377fa74436d0ee0 +ENTROPY 801f2bd7f34f64b040ca5bb4c6c3e2f8bb21c11cae4da1bce32c80d5aa74e1fe +ENTROPY f85838257656e29b9e6a58e93f23e0f22cd75cf252f8c1891c09319d83b55fca +ENTROPY 0c007fb018769b76eb626967d0b720dedb975b7062b071a23a19f841a612fa28 +ENTROPY 5bed52f899f2bf1800c292fe58f92a7cb020d07b4c2e71ad81ef2cb3ab2cdf6a +ENTROPY 7631606cc2a3dcec644fd66e03a1aa3d1c017b89b66be8765f07607c64c53eee +ENTROPY b1da70b9c2d979d95db77995cb9f94e7111abdc4a523e494c203049770034936 +ENTROPY 61a9315f64151765f6ea41fa5d184d36ff201b909b2293906c88e5d5bd81c807 +ENTROPY 9bced9fa683b51c0cb2f9a1b6d97653645beb2e238ee2e915ad1e2b6bfd2d09c +ENTROPY 1447a3a8fbb6f55eda1eac8cef6cb8f76514de99fb690fd0d220fd4158e024c7 +ENTROPY 145da2edf63268f2b86f705f88941c704c1045250f6e480ac9f2b64df693ee1e +ENTROPY 4ff25a64413e54599206e36c915044b9eb9d6f429e5783857b174f24c36e9c15 +ENTROPY bf6753e1361540cacb7c58cb961285d3e2570a6082deed25f7042708c0392ffb +ENTROPY bdc0cd2da4af41fd4dd9d077b1588af7a0c6053682e30d256db67ad64eb28453 +ENTROPY c35eb7f9b9f13314e509ea063bd804ebe0279b5f61c1a0198d3de120d5ad95e5 +ENTROPY c4af47ab8c3f738d7eef93cc9ddaaa6636e860e87921748070c279a0e85bedf1 +ENTROPY 5e2111240201be69214d91f40b7181f8ba0ab5198fcf25d46002ff16dfbee7ca +ENTROPY 8e8d1f490656c8b354545ed17872b0e351f540c7fd506d15052cbaa80423e9d6 +ENTROPY 7d3b703e8a83fdd6ea4ac9ebfb5889e999da2c31cd3579d7573df5bbed8cb30c +ENTROPY 2de0450a93a4357603eda5c4849c4796b2e1da51e76fdcd0591c8c4fe1ec3d3a +ENTROPY bd3d48b50b6a6506d3f02928c671c7efaaf4a4ed78cd6d6817062527758b255a +ENTROPY d78a47b78ea36c12fdc8ab6d00f821af765e719a903d711e766d2e43a0e23f65 +ENTROPY 22628677f64cd6dbf400042ceda0d418075676fad351d5f49a76bf6b8f476378 +ENTROPY fd0b3cbbd5c4f1ea02ac8ea58aed9d903365f3254f9637df692a1bc9b2ae2e9e +ENTROPY ad9521725d0434629cbd84ba565dac79e58c8c8e3086c9cfe48a899e32384e24 +ENTROPY df5df8f445794fb54a3f45df0340762298a202c6d733cc27bea806aff44c63e9 +ENTROPY 6a3ba75bd2343cb45f381d0b060793c4a9781964fc51a06733bd205bc7a1c75c +ENTROPY c5679c71432857ad3ed01b5fb656af5198e0248e3effe473049514528adaa9ea +ENTROPY 4d13a90b1d5eb68bde1df6d0d297ae54f6451434a726c517445b42ecdcc03433 +ENTROPY a74ad0fa54a5efa2392b9c310733d49d5c2f4fbc5de2cc42588e6f36e4efdbed +ENTROPY c402447b3ee1f5a98ee5bc10612417e3ce4681b8f5b55001df1a4891da3f52ed +ENTROPY bf66f21a0da22d931b5bb2b19db6975d3192cc644731b5a2abba3f198c549b94 +ENTROPY 24a6a97654aaeb59268abaf023f429c1268885506f452e40b40e18d7ddaac4a5 +ENTROPY 42eb7516f3fce288306a55b0d9930a01a36d5e1419525a449587d5e298115837 +ENTROPY 655e6ff5bccb841e8dd02eefa477e88cacc17766784c530977e570e12f9c9391 +ENTROPY 449661d780787a768cc1486bb00a6d7d9490fb7b5a6a83f6de7ad7c21355880d +ENTROPY 602a8826c64055f1585d3f0d0ed5af70f17b03c0e6e8b6ab02cf7a77b707669c +ENTROPY a781c5285f68021bdaf4249588dca0ea650347ab1ddf901d88ee9e35de865465 +ENTROPY 7a30aa69b04bd65d02b9db88a59eaa558718b85595df6209f9da1c50e1f5933f +ENTROPY 0b73a47a0a78141c48a58aa3e7a0634f8bb04d0f8aa8556f475097ef007f5e12 +ENTROPY e0be83f2568948a679bf607f87cbc398de739bc3b0fedaad3c1b45e57136e333 +ENTROPY 8df844cdbf1d537da229e6ec36c5a43c02b7d2ccc1ef6660b9b8d2b3ba3fe74c +ENTROPY ba91cedc8bfa2c95a83f1787770838348af0a3dba4f28c8c44deebf6872931b4 +ENTROPY 766209907edb51d1adc6fca40963f9372708d5429b67f069bbf696fbb2a23db8 +ENTROPY 7b67cf7ee3a971b6f5cc92985d71c811309970158a6ac873c63004a51474cd92 +ENTROPY af06cfb8803de42eab934d037cc7d58b2ee40a29c7546a4d7fe00685a83bf529 +ENTROPY 840674bc505e3772779a54180642d74256d8feecda5bbb1dd966b5308e0107c6 +ENTROPY 8ab4edb99dd9d01a19bc2d0f2c71a27025fef4f0cbece865691214b7ec89a048 +ENTROPY 68f4825a93b84f543f60873944ffe371809ff98c74955560428288028344f38d +ENTROPY 39c6b300d9163cf6d420685b90f78b18656d1d4006c8beb224efae9352fe4b8f +ENTROPY 5dad17de6436ae238b4957da4bfcf2cd4830f382faaa7a7d67f33f0859073094 +ENTROPY 270d8ede95beb446e7c89719f1f25061068efea83bccb5c00d844702888a4c18 +ENTROPY a24551af7d046f1bf9bbd4bd545308091de9152b956ec18dbd6ccb7539479c41 +ENTROPY db2f074d27c3579a2c4815847f08880e86e5144df0adc1792b316956f691bdf8 +ENTROPY 20502efd2bd63a152edad1a687da429c8d024ec94fffa68d2f97f6fdfe2ed945 +ENTROPY e54e7054a4fb01add3ea20412a8574fd377fedc77d9e8df3d3f274402c9952ab +ENTROPY 0ea6dd352f93d076d2a8c7bdd50f43c63e24b5ef2aca12b5d20e1b4f44930cd4 +ENTROPY c89420235be604ddca0b799817d57f2dbcd6d6bfce7d3cd45026011039e0a916 +ENTROPY a0380ee013116b916f8761709ad0f9d1830c07a78a75cf7e043e0ec449fea4e7 +ENTROPY 21add2cfa3af5606f21ad7b87f87971c7b82d0bec26c4b42d8d006cbba80ffe5 +ENTROPY 8b35ef79248795f52659f4cfade35606535984dacdfe9c3b07e77eab1f579662 +ENTROPY 7091cd52bb63cd7cb879adab4d92ba5edd7580b9721ef19c94cc5a6ef681d76b +ENTROPY a52610fb20e8c99f021f8c9bcd4962d27ad34e9fcdd2807092a12c95827bc73f +ENTROPY c73d259f476b91faf77b0f9703c987e593ce2492765c8026f2f5b998450f25cb +ENTROPY cfa6174f623b01f85f9cf8d8aea21a5636bd12ee18eb11733e11e9a8d26a116d +ENTROPY 8d0843954021b155bf39ec09893f30c3072b8ce36814ec7e715de85be4ba5f64 +ENTROPY f1e504d4996bf7b5a08999e71bc87ac7a6bde8df5fbedd4407a98011f2c6fda0 +ENTROPY 2080a2632682c7ffa61b15d1630aaa53a65f755e20466db7527a763e029d71a1 +ENTROPY dbe6ca555a89e725edacc85eea2caba02adf4c39a5f44cf74f8ee5876c5524df +ENTROPY d0a81f6a3ea4c09dd0b847fb3b8ea71ad999959e59f2d89b5c15e953c3a12b2e +ENTROPY 7ba81f3b1d6e8b49e4053a88e282773ec577b0616758b5bd8b2b393b6eba727f +ENTROPY b2c2e53f808c3aa4f68b7fd6ee35bfd2dd654a4e19f5d925113dae4cd2a50847 +ENTROPY 2022f477c7601e34c986214116a189d9fdc02a3c6eef53ab64a1c6383009df7c +ENTROPY e58fef71f1b31f65a9ff58b040881c262b311109ad3f49477c52ddf09ecba254 +ENTROPY 0cefeea992ec29c06879fcbad32087ca6b5e9efde5fe8a84bc95a79fbe46989f +ENTROPY d1bf6e6b301a207f87018cf34b55b01fc50094e12716d5db1663db8ad5a93acc +ENTROPY 02b4d2080949dc4392797b48767bef666e2422cdb46d037cfe06cf3b0e974735 +ENTROPY 9ea8f5a9e4ce172d341d2946630dfb3c7dc816acc84f2634120fc5fee9824d2d +ENTROPY 0ac61206df85831a5a328f2bb36bbd52e57d650802cd877629761a5daca571d1 +ENTROPY 75b09644334b2dd5303b939d6418c01f87d5179f795712bed6c84dc96fe22b2e +ENTROPY e4debbd3e91841d5689e54f922b2d28902bd9bc0ee234f1b1a0e8c4a9905d293 +ENTROPY c91dee2e3242d78282bbb8ed40a67c3fb449cb01953ce74ee632e38303e45d77 +ENTROPY 5a4213c110f66b1ef0f42969fdb79be691488fbddfcf8268e1c0593afbd3c4b9 +ENTROPY 425f36bfd221a0b232dd6dbd5ad003be128e33fcadbf8d1763e35d618f461e0c +ENTROPY 870c7af20d99ad0f1ada709a2e11140ff74ed9de16f2e8b36d606db5ea7f3419 +ENTROPY 50d0ed8600c15360ea4b40b7ac6eba6561f19c97233c980731a5dd46c3070c53 +ENTROPY 4d3c31eebc34c166dd3e8b2f065fac526d6fd77aad0fefd8f7d4e2fbf24bcfba +ENTROPY 83a0fb140290b8802bff9e301da7415d2c05be92efe0d3bb5d52a5ab337151ed +ENTROPY 4de27456a7926800a717e372bcb6d08634c32d7f1f6884682c9b799ee1e9e8a4 +ENTROPY 4705c7b5251d08f0fe963f11e6d52dbfe5dd106437c7e4c76e30e48016fe9839 +ENTROPY b4c338596e856913ce499a0c3f403365a856bd55e2dc14ffc59ea85ce9e20c77 +ENTROPY 207ee546e41cf399c69ee21d4bdb0419084ede806dec8d131191e1dbb944b3d7 +ENTROPY afd971e227d31298639bff6aba5a21d5fc82a91433cebbe959fa05d9cdb169aa +ENTROPY a284e43c692a945290604cf4bb59284776f20c0a879bb061898dabfdf4682503 +ENTROPY 757880c7a9ee7c56cccf881f4153debcd6a871002cdae83daadc43c949eedb8f +ENTROPY b345bf03185ac6087b2b94da0402cf6acaa94bfbe1981043af4198af3a08f135 +ENTROPY d07b4e96858b7d0e0dc5e8e252a549a1902035b4f15ccb3dd518fcd9db799f54 +ENTROPY ee3cfd3b4bd5a7d6a6793380e4ffbba72b8db246a360d6e1da45a4c4c33cd669 +ENTROPY 4d215c9751f6d08861195efa850ba78562856edfeaeb4810ff2f72352227a4ab +ENTROPY 3c7f55da24f34f3c0a4bec51140cc92417155dc64f62dc5b43e0ec2e114410f6 +ENTROPY 4dd8cfe94b4e5a29ee83d2027d15ad803a306fe301a4ff15709d135ddc622021 +ENTROPY 17671d121515e9952e2012b317f6ea8f129e1d5f8b39a2f256b879440a0efad0 +ENTROPY 397a41cdeb1ae9a71923769b97e1e925a06554cb5b24abfb090875b2c4cc0889 +ENTROPY 8b50b81f1e5f98cc89a213cc021540f13f05951b678619a0891db714faa12abb +ENTROPY 1b1e0370f2c791d379cd26c751204f2491378f384f973bfecde9331045e928bf +ENTROPY cce0c099e734f3506446066eb10d48da2669149a2714740f4a08d69dc53ee16a +ENTROPY 6aac75e7e43ba65634cb897bdeac80e5d0b71a82b52d4d10945b4608ace8b6e8 +ENTROPY a486f229f53f7f9086c2469b13742f44810b978d04185a92a43031579971c528 +ENTROPY 6227261a7ac654296b7e5a0ceb9f71f6325b9ceb38dfddca7b4a2c5f1563555b +ENTROPY 376bd70cdd2d089d17dbfdaedb3621630d5a96d446306343b217cced20338e22 +ENTROPY beb182017c023dd1bf09ea8fe9502b29faad3eecff41e534d5aca9d2f60f9afb +ENTROPY df4fa073585dca63f4372498e18f33d4ab32148ea9940d22fea3247570399397 +ENTROPY 2efc3cc2d10922acb225ae4682e2da979e4aaef433d45265d35896325eb2e951 +ENTROPY 3a7e7e2dc4edddfd16db6eae5566e58173ba1b6d0fb553050d632f9add4c5439 +ENTROPY 36958c13977d95040c7ed6ffa97fae1c4585341ca0125be90b56260960333b3c +ENTROPY 992aa8311abace9ff48a668eab29ceebc11d3060294fbb0dec45579b66748da0 +ENTROPY fe3c6c069e76673e01bcb1b86e096b5c1115f8bcee01766be15aadad6e9f1314 +ENTROPY c005ae9834772cdf7b82da3ead4ff58d53e4058522a57c3365af22d67aa8302c +ENTROPY b43781649f0d0dd14f9692c5325a900c3977e34b6ebe8d23a94f034f24a47371 +ENTROPY 15b6bbb0226a450315c1df6183648826e4fa4b9ea5fccf5508c2da3625bcccaa +ENTROPY 2a2b1231396133e92e6f056cad02a06b98a658732c66c933e4c1601766ede941 +ENTROPY 99b7193ebdaa64345cd4c85acfcf0e3c6e9daea5372e98a73be63aa6e47e3975 +ENTROPY 3be398922e4e6909ff519e2537c120e4721d67b70ece8d5d8f2393090f648e2f +ENTROPY 012d72fd6a6acf12489e5bd403c56663acd439c412b7a3b8c7ff35090d10d201 +ENTROPY 81b4af61b36af1908d9a0d22ef1c28bac0bf0d304a7ed891877b850b1075cfe9 +ENTROPY eacf45c177ccee4c4494371678820eed03105c37f2f25f0f6d1018c712e649ef +ENTROPY 84e1bef623a4693174aeebabdf5987d1a2fd65578f912489c396cb522621e38e +ENTROPY f69942b91db71cd4282f4827a16a85e278575bebd86524c7d465b73f903425b5 +ENTROPY 1b01603b0c17ba2be1fbe4d608dae437f8b750cdd1620435b0ad76993af4d7d8 +ENTROPY 5ac76d77846c6bb3ab1df058165fd1ce63c6fcd69cf0bbf82028360e4014e311 +ENTROPY 393bc610cc398d648a0ea309f78add2179c3f8ae6780b49b7f53b6920aad461d +ENTROPY e02b2545c048b733dcaeec02bbb70e5dd97c8aa21f6ffc2cbaf9c6dde7afef39 +ENTROPY 0b69810ef7021869a0778efe0dfa48b46761686aaf93586a38a9140ea4523775 +ENTROPY fb2c87cb473792230c3b258b23dfbe5aab4cbeacab26140e7658f70afbac3013 +ENTROPY c956e62e914a91c7f581036b9f547333f4e32c5c67ef24e11d647cfe286fd2e7 +ENTROPY 808141c6cf9f09755e1bd22e3b98713f5e9fa6feb5f5cc7b42f39881cd4c2519 +ENTROPY db1cb3649bcbb50f72ed664c51200022b197ab377b48f62d68f809a7ea4ae4d5 +ENTROPY 1597b9589dfa29c7bc14c75f415736a82c4e92f591a64e5605eaf7420974c050 +ENTROPY d4010eddc6c8ff31abc37a79ae85bef1196f0a0053518b84f03ad83f5e450507 +ENTROPY ba65bdc1422d0f355be2fd07f2444e8b7659e06db59994c7291a48532b086d4f +ENTROPY ec375df5981167981d8c093de41aa085ea6220c5af6467dbd9503367906d1ec4 +ENTROPY 3da780c2b08f6e3f3e3ab7635ef3128ad54dd2593218f2dd0d7887724c7ae0be +ENTROPY 7a44213df4acc75eec5ec7fbd55db2429ca8b32296afea94002defe069b69ebc +ENTROPY cbf739e42d17710d7b8cd5454864a12273709761067d94b9146c3afb1ee42775 +ENTROPY eb64bad3f40685488582d96867c353b702deee7179c4691aa252d6fc29d9b09b +ENTROPY 2d1e70996446e08063bf9a774a41fb2b8976e65e27fd36bfcf87115d3871149c +ENTROPY b264ec255ca08ada03c9a78cd70b3ecb17a8d90302283c33cad253454fdd6200 +ENTROPY 3a4cf4ed3600698dc7f30407ec2f262326afeb703cc430cc59c1678beb1fc927 +ENTROPY 90fe11afb0d899b5562b34cce506a17476d5550d2811bbada4cedf444702ae23 +ENTROPY cbf5a9f4d4e9c6bd55b0698f600491798b75382ca18c60effed67b6926d94c79 +ENTROPY eed6e1de0af3dc409b8f6ded3b631868717182736da3f6270abbcd65e17379bd +ENTROPY 0bc646591763d5ecaa73acbe487a45034bcc443fc407a00ede56e3698cfd4a92 +ENTROPY 71c9d48d3e0a226cdde7a3389eccd03f035df74bca76e6ff2901cb73131a204f +ENTROPY 2d05057c72ab2f973ac73ac5823f2c80d30f2e6c0a695e0c76b9309c826eafee +ENTROPY e7f11aac5d6e594117e6008d49e5a3f883fde8706df20689c76eb5395ffa7c8c +ENTROPY abc240f1e6a0dfe597f2bad88781b87df4a800379be28cf3c7e960993683e2cb +ENTROPY 14a683c53fbc1d9e00e1845728b21c6e422b00e0dc34766acb327322a467f140 +ENTROPY e359f7b9e013637941e949ecd91e6fa22d97193fac5f6db5b60f0b186f9b85db +ENTROPY c31feaa8c8214a617cd5c72ec2cf73ae7f1466874af6d4d2f1982d8d332c1e95 +ENTROPY ec8f4dfc39f81079c0082bb243cb75f88f8db3e6b45645e8c437e0782f110b0f +ENTROPY 4ad5b2421e67dee331795434035f7b3a3a8f8ccfc51b1ce6441e7de68dfffc4a +ENTROPY dd362634ddd222377fc1a9dad8d2e19751d7bad2a00fda3be7e38f538ddfd2fb +ENTROPY a5312d00f2d1eb15c62b03dc5b4d1518f919f41cc325670516ffef6431e097ff +ENTROPY 237cf0f8378e1216648ba1fc9e1d7177fcc6d9f22c54bb155fdaee0f69741488 +ENTROPY ef727eea660e0191c0ac3bcc952a3a099cdf5e9fabcee5875acb62515e0c5008 +ENTROPY b3ce70944a82f9583755a4ef0daf9ffcb7a7794e84fa55ab2b5c09c43190b1ee +ENTROPY 8a3406cea36308a99ddc231cf852204ba4d184c446b4277efd122f6bcd38dabd +ENTROPY 2715e36e47515f41b7d6a702e949737a4b166dc887c228d2bbe94e6ecaac8958 +ENTROPY 19db77ecb10216cec38199ca626fa0980c69269350ec01fde44fdfa3ce758f2c +ENTROPY 509b5889b6e4c702665831687043495a69c05c0120c968b2bf477a62c02cc2b7 +ENTROPY 87273202e1be288fa315b0b8959489bac53f4a7311ae413f0d0b488f3123f19b +ENTROPY 5dd9625dcb110355f63779045e56cb9213eb0693aeb8b1228ec240e691f74448 +ENTROPY ea5c00bce65fa2c1452f8998a2711bf70af96556d75b5fa1118df843cdff0cee +ENTROPY 58c125ef0279cc70d250c139491f46a82a932b3e7a0d5e1a3ba8f29be2296b20 +ENTROPY d9e20d6cb856df4f005adb0faa6e76bb8612a52b98a6645a8fd5e7e99cd1e304 +ENTROPY 1ab3bf16f667d1d06363f748427c05802eccbd0b9fc43b2e752df4119dc54e7b +ENTROPY 7e3dd1690ac397616b7c89df27a3131e31c16dcd4bc0df6834fc4accac280f49 +ENTROPY f152fda4a7eb385e4e77ff95277f71ac30db9922ac250458cef643d11637cf71 +ENTROPY 6a258206a0b2d7caa3cd1989ab4f395eac918e9ddab2296dc91f2d71c8acfb0b +ENTROPY 4bfe2505866c413ab888908d487d49e5ab3e8acf7bb3198cce0d01dd87f0e892 +ENTROPY 0ab18600541c4e5e51fc882f1652d16c9e36005d1ade4913821058b5167f740e +ENTROPY 1bcde5bcc5d58a5080bc7a81e6bd1d3f861eea8213c681d44996eb31ecedace1 +ENTROPY d53cdff0f7820687d607ac5da56ced8f252c25a82c3a089d36a849a8cf55c760 +ENTROPY af6f2fc46b363ba77c144e20c57a65c368db372f9789e87dfafd913cde452b13 +ENTROPY 8bd08668ef86a7dc47911e960eb4f5af9c453369ff730553d2364efea5b67b6a +ENTROPY 73909d208fe74b76461069ea727cf8dafc8b0759d423dbc0e2bfb5dc59b09f54 +ENTROPY 3d6db94ed2e9862de8dcf1d8f5d55f704684fa7edd6a5d04a3e610ee87268a40 +ENTROPY 7aa0e505e84afc7cff5a1eb6c63468622c8172c31aa9f59f1293be3140bf9c69 +ENTROPY 8d2cb6999039013ce7a4d212168e7f1071b52675619eebddbf49c3c18a28947b +ENTROPY e758494da4cb2a04f34d4fc43664d83a97971adfc6bbde229c4b1bb52deb3539 +ENTROPY b7f73912dd5c16a52cbad49437f960ac056ffd44dfa31cded04e7c450a8ea315 +ENTROPY 33b911ba2f68966f7c59573f7862d7632769341c96b3907ef48ce924fc550d8f +ENTROPY 8d8d2ba30f19e2f9b02ba4e6dbf07e85779ca61bbdc5ab4df65ffeb1eacac102 +ENTROPY d98fbc540cd3c0c74c03e9d04800c3cd14a7d0c7144b30d995e8bb9361499d41 +ENTROPY f6ab55aedfc8bdea2f6f37ac0944e9927090f6109f0e6bb132ecd445b33fe065 +ENTROPY a27c88a8f9c94d2df7c12c2dc7fb5276bf20c6cdddac2537f8902818b769c94a +ENTROPY bb299890ba0c8a1405a0699ca17551c1260fffb1b3a3f2523fb4d42b3ff0ed1e +ENTROPY fbb5d6767b8843d46d28737b1e3764392042ddd3bc894e5aaf91d07f48da183f +ENTROPY d5ef8c2807fe20398712a238a094c8e19cd1567a38deec6f6f400583c5623595 +ENTROPY 15b51c2235fff35f14d00d3abf0e2d1a89528d0fc4a372cfbb52a3159bd23a25 +ENTROPY e19f97834f15855514e8bbc020ad67a8ff72c783f6f68e016a5d03551f793189 +ENTROPY a9175e32c4d2d2d1fc592aa451ef1af13cfd827cd4a66f83949ac7d7e9a523cf +ENTROPY 1fcd5920832c26b59d8a258f0fa851a6de24a2a099a596da7882bb10296c99ff +ENTROPY 137c4a6917cf951528e8c4a2ff45a424ec9bcbed96018668f5534c9da1653240 +ENTROPY c4ed6dc68d55b7c51e726129f4d947ca3ca315ad8e5354205d7191a671c14932 +ENTROPY 0cb476bb195249c7cf799044f49621fbf555fd64f8e8d2e72065baa897998d08 +ENTROPY 1fbfa6219f1a05c5eddd94a7a43ada847d9d962d57ca777748ff050dd244052e +ENTROPY 1ff43c00f7a70d9fa39626c439edd34064f0a4c06a7e78deeb5d655434cb9946 +ENTROPY 6344aed2a182f5ddbfd677265f9df03b225c125b38a652292add8f9b10280c16 +ENTROPY c2ecef0136021a49f2e7dc13cbfb89a2415e23787a8259633e78e17fd0f455ef +ENTROPY de5ef10a133a891f3f51471f7874be48e5003b0d837e9847a0d0738471f73b33 +ENTROPY 9ea4074c6ba199df18c9ce43c599176c0820976cc1f5cf0b70cbc4998bab5a9c +ENTROPY efeff195cca42ae527fbd1cebbd28a64d19baeec2dfde74488b8b38df18c63e6 +ENTROPY b633599afc36127fe4cef484be63fcee55711c0a319aed1c8d8039a9e661326d +ENTROPY d49d7a8ca46c0d7fb735a617fbd2f6ba0e299e89b62dd2f1998a35aa3a39da0b +ENTROPY ac236a17702ef63d4a275bddb4b80108614adc429bae5cb19699977ddcf2bf90 +ENTROPY df89ec9c9aaa051b9de415320935e8f65b5362771555171239a28791c7a7d760 +ENTROPY b32ddf3415a2de027bfd420199fa144cd127df55b09fb6fb5244514102e7958b +ENTROPY 8370ab747f12931dd914955ba4f93f32ce6bf1f5a5d818b0f21e6cd98055eabc +ENTROPY 377df8ffdd27d926d2544bccec2141b42af7c3fee40fd583d4b38532a96b2cbb +ENTROPY 376610400dfa7a418dc297dfae182c4e049ce3d0c17441eeac019fd141f36f88 +ENTROPY bdf257249b678b272fafaf50d3e67218b4601c1493af2c4632e14a268cf297f9 +ENTROPY 48ca0d33d255be1e644521de0f1e47d8ad48912c44dd2a3bbf0d7b55f8a08916 +ENTROPY 36c7b7fd75277cf45403303934707f1b9b6ef08e8894ddc830c56d712142b114 +ENTROPY c18c92f2d4089ed2a1d711d7df1c156e1f4d4887c79e077c8cfdd03f3e75a990 +ENTROPY 2b865c2afc860085cf39118e6ee91d06f59975cf5cf6813e24733a6c79ac1cc4 +ENTROPY f2423db6fb51642565fb51f64d1c944c25bd221be92f1c2e8fb3e0c0e7384f73 +ENTROPY d4360a12a6e9968bfc74125aaa81b2ab08808a703cdf5f862f98224bf0ed3f5e +ENTROPY a9ac82a7e30a1e2a4c6aa6dd3fbf9f1c4bf284d32d6f8e2562687b51f14e1c48 +ENTROPY e6ab1b7ec68c7c83d77a60e18dc4cc101ee0a519b5d8a9ff9ec6c70d3f899869 +ENTROPY e107d8d5a10d482757e7c7fc8ee79334133d6ee64335af50f8d083f4c8e00096 +ENTROPY c8abbddcc7afbd57d0c9b24f8f42721d50e2712d87320790598078cdb2698c46 +ENTROPY 5b628f5f1b331267da92ee6391489c39b1a061bdc26f1ee90887ece66cf747f5 +ENTROPY d1149fc17270709cc46234aa64ddedb6276d9e4174c565882e918b0914f7aa1d +ENTROPY f95718eb744a091897409f4bed955408f1a19841c41adb9b9db7249b17a276dd +ENTROPY 1f493470efabaaea56fa039fd9b0fccd7c92f10610bc1b5ae55f7217f0998e80 +ENTROPY dabc0f28e9af3c0197abe3bc96cbc51bfb20a007cf200b3f2aef66b095cceb5b +ENTROPY 0d528ee0d3a2d5a12c701b2d3d3ebe0b76ae1aa506eb8ac1c1486a8c0eb3cb4c +ENTROPY a4bf307b2618f99bc7a145dd177d379e2976c1e4302d0965ee3afa24e94b73da +ENTROPY 42e2232bc31a0ebacdf657362fcbd5a700fbcb30d86e5901104babff80c46927 +ENTROPY ae7997585df5c15d75a3bb948bb96c4e60b7284e010a641bd39570a8c240bba9 +ENTROPY 8b682650cfe2d6e478406f612a0ff2a31d597d5238740c62adf5d0d934ebf0e8 +ENTROPY 7f4f2b521e52de34aa923c6dc1ee979835d51fd86f5c260b029ddac4c60a8279 +ENTROPY 5de690a135a4c2f149890827f65827e110166d292f0f6a438140d59deb9a18b8 +ENTROPY 1428b379e132a9f06d63737170589766379466f97b5a1101d2db77780fe87390 +ENTROPY 7532d8a5a4383deb9cc4ec5322d3437b7ec82d825b6c6bd68d50686183672462 +ENTROPY 118c03d133ac8a684634a3bbfd6639a840ec4f49655c503a63f695269e7744b1 +ENTROPY 82e8d2be861ffe62462715f12da7954584bcabf8020bf8324875b5cd6226040e +ENTROPY 7cae33d3ece6e1e4af6470cdce3e5d3e7c5a17025851f24552e06a80115dc305 +ENTROPY ac0499ab12eb87fc1e6cc88dc7b64e67f74d0bcbc2d88e7b7e3e8dbf404fd773 +ENTROPY 0c638abe38205927acc3111c77578774d053c6585ba660c21da19f0afaef4f84 +ENTROPY f3c1ee620ae9ab32ea2e53a37ae2e24a07f21a061930e6e162ef3d52ad773a08 +ENTROPY 6370c40e520c0ce19b6326a9aecdf69273fe2afc47480c8c1d35e75cb043acfe +ENTROPY 584499252782ecd77f60f73a6d6e33ebd764713e70d840a9f23cf81adb50abff +ENTROPY b4247f0aa1b1fa548cbea1204d500b3c6fa663a3ec022aabb1be2de8b9f22ab8 +ENTROPY 784c3a6367cd544f08b53c26d432a4a18c8d079b7809640a7e605d945940cf43 +ENTROPY 1a5a1acab3bb2cb00c5a467479d8d3d14059dfffd87d631a880bfe4747078c3b +ENTROPY 0973bce594815630cceab4f3ec63443bbf3369f19d0bf7a88d7e90a05aa100dc +ENTROPY 3941ffa71171e0f6f60723f61706134874fd3b5a245191eaf45c6deff7a78495 +ENTROPY b78b93eb80431a5e78865ababa4996bd99457838ca4e0bc19d737777d22e235e +ENTROPY c484b4f854f136122aea6ce50512ec35e682e8a15560bd2c16ba6f544f5007d7 +ENTROPY 4d303f73cadea853dc7feedf0cb4c4fd97946fa5a060c7f8fe245e644fc616a2 +ENTROPY cbff48f010f18f493cf0dccde00a407b2e2d45a6b753672973f079e92093e6ce +ENTROPY debd05f5873eafa5db68cfa8c84cec1836472e325a6a0a3029d73f4a05b8534d +ENTROPY 997dbfff85c90cbdf9aabef2d162d4464964fce454559e455bb35a62c3ebd39c +ENTROPY b84ba6e748738704e5d8fb5c67c34af67dfc099ef92ac336a29648e4378ec0a6 +ENTROPY 3d830e865e752a346978ae722d45f2fa4af4021225155b1acf489a8de805ccf6 +ENTROPY 52d9623cc6e788244be6d72917c4afb18ce8e7e482adb633ef62faeaa6c79bfb +ENTROPY 728b5743ebc44f965bce2d2259a36add6d78e1e9ce34eb7b0a33eb3bcbf47ad0 +ENTROPY e1ed1c6e916c9029949f72a7bd49f4e80b49d3433e2a5657d62cb5e7693d59a5 + entropy: 1048576 bytes in 103513 ms, 18 health failures + entropy: chi-square x100 22538 (255 degrees), ones 4194770 of 8388608 bits, transitions 4194933, longest byte repetition 3 +ENTROPY sample 65536 bytes sha256 4e86176ccdbe941b1461a58152236256bbddd5bb01a91f9db2451071f47fedcc + entropy: the mebibyte's sha256 168217acc9e6f2ceaac069d5143120d790325c4ce0c234f921cfdd9f4a16d28b + -> ok + req SEC-012 DRV-001 +CASE entropy_board_a_mebibyte_passes_the_sanity_checks outcome=passed asserts=1039 skips=0 +TEST entropy_board_the_raw_source_has_the_entropy_conditioning_needs +ENTROPY raw 262144 bytes, most common value 1273 times, chi-square x100 114925, transitions 1066619 of 2097151, 3 health failur -> ok + req DRV-001 +CASE entropy_board_the_raw_source_has_the_entropy_conditioning_needs outcome=passed asserts=259 skips=0 +ISR_STACK size=2048 used=188 +2 tests, 0 failed, 0 skipped, 115183 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.json new file mode 100644 index 00000000..7ce069c8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.json @@ -0,0 +1,115 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 15, + "name": "event_any_all_and_clear", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_overlapping_clear_serves_waiters_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_set_wakes_every_satisfied_waiter_in_one_pass", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "event_set_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "event_wait_times_out_cancels_and_ignores_clear", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "event_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_wait_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "event_binding_fires_after_direct_waiters", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "event_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:26Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_event" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_event.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_event.uf2": "3b7701d9c5b6102ab2cb6b6ce0a2c9691a96255fd46e04242166f568dbccd03a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_event.elf", + "image_sha256": "7bd9ba6e0bd6f767cea8a6efef81c6310ec38764d80e6961f4d5d25e9217bf44", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:24Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.log new file mode 100644 index 00000000..dccaee99 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_event.log @@ -0,0 +1,52 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_event.elf sha256 7bd9ba6e0bd6f767cea8a6efef81c6310ec38764d80e6961f4d5d25e9217bf44 +EVIDENCE v1 suite=test_event config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST event_any_all_and_clear + -> ok + req KRN-SYNC-029 +CASE event_any_all_and_clear outcome=passed asserts=15 skips=0 +TEST event_overlapping_clear_serves_waiters_in_order + -> ok + req KRN-SYNC-029 KRN-WAIT-001 +CASE event_overlapping_clear_serves_waiters_in_order outcome=passed asserts=11 skips=0 +TEST event_set_wakes_every_satisfied_waiter_in_one_pass + -> ok + req KRN-SYNC-029 KRN-WAIT-013 +CASE event_set_wakes_every_satisfied_waiter_in_one_pass outcome=passed asserts=11 skips=0 +TEST event_set_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-029 KRN-SYNC-027 +CASE event_set_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST event_wait_times_out_cancels_and_ignores_clear + -> ok + req KRN-SYNC-029 KRN-WAIT-004 KRN-WAIT-017 +CASE event_wait_times_out_cancels_and_ignores_clear outcome=passed asserts=12 skips=0 +TEST event_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE event_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST event_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE event_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST event_wait_validates_arguments + fault checks that reset the board: 3 + -> ok + req KRN-SYNC-029 API-015 +CASE event_wait_validates_arguments outcome=passed asserts=5 skips=0 +TEST event_binding_fires_after_direct_waiters + -> ok + req KRN-SYNC-035 KRN-NOTIF-004 KRN-NOTIF-005 KRN-NOTIF-013 +CASE event_binding_fires_after_direct_waiters outcome=passed asserts=15 skips=0 +TEST event_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE event_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST event_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE event_define_constructs_in_init_table outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=188 +11 tests, 0 failed, 0 skipped, 26 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.json new file mode 100644 index 00000000..06e24ce6 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "fault_successful_check_preserves_status", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "fault_status_policy_is_preserved", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:59Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_fault" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_fault.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_fault.uf2": "6f562b8467f7451b71e69cdf18b9b598f61ea4c70142e9e26a6229d8325f56b2" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fault.elf", + "image_sha256": "f2f9cd113d2d8e6d5ad9cd733c7cb800174283aad132fd795df5dada9f4fa8cc", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:58Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.log new file mode 100644 index 00000000..b6dd94b5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fault.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_fault.elf sha256 f2f9cd113d2d8e6d5ad9cd733c7cb800174283aad132fd795df5dada9f4fa8cc +EVIDENCE v1 suite=test_fault config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST fault_successful_check_preserves_status + -> ok + req API-015 API-017 +CASE fault_successful_check_preserves_status outcome=passed asserts=3 skips=0 +TEST fault_status_policy_is_preserved + fault checks that reset the board: 2 + -> ok + req API-015 +CASE fault_status_policy_is_preserved outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=188 +2 tests, 0 failed, 0 skipped, 11 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.json new file mode 100644 index 00000000..a8fe65c1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 80415, + "name": "first_execution_sequence_repeats_reliably", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:24Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_first_execution" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_first_execution.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_first_execution.uf2": "f887b9afba507495ab94847033e92076053dfcf5ce11e21b443854e6883fe8d8" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_first_execution.elf", + "image_sha256": "d06acd9a2a7a874f9bf0dbdfb82cce73765eefef7a1e23d2c533b80a6db6f92a", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:22Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.log new file mode 100644 index 00000000..88217fb3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_first_execution.log @@ -0,0 +1,10 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_first_execution.elf sha256 d06acd9a2a7a874f9bf0dbdfb82cce73765eefef7a1e23d2c533b80a6db6f92a +EVIDENCE v1 suite=test_first_execution config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST first_execution_sequence_repeats_reliably + ticks seen 202, elapsed 203, timer start +1, late 0 + -> ok + req KRN-SCH-001 KRN-SCH-004 KRN-IRQ-010 KRN-TIM-010 KRN-NOTIF-003 +CASE first_execution_sequence_repeats_reliably outcome=passed asserts=80415 skips=0 +ISR_STACK size=2048 used=188 +1 tests, 0 failed, 0 skipped, 230 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.json new file mode 100644 index 00000000..961c1a47 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.json @@ -0,0 +1,85 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 10, + "name": "flash_geometry_and_sectors", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_program_read_erase", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "flash_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_area_stays_inside", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "flash_power_loss_tears_an_operation", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "flash_polled_calls", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:40:59Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_flash" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_flash.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_flash.uf2": "3d2d1fed47631933664cb7011d46f67bcb6ce61549d2dc842c8d082c76c4be92" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash.elf", + "image_sha256": "e8d2918bc5d792c63032b68ef229d9ab308fce70be0df09e0beab655180f7749", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:40:57Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.log new file mode 100644 index 00000000..b21c4d11 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash.log @@ -0,0 +1,30 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash.elf sha256 e8d2918bc5d792c63032b68ef229d9ab308fce70be0df09e0beab655180f7749 +EVIDENCE v1 suite=test_flash config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST flash_geometry_and_sectors + -> ok + req DRV-001 +CASE flash_geometry_and_sectors outcome=passed asserts=10 skips=0 +TEST flash_program_read_erase + -> ok + req DRV-001 DRV-003 +CASE flash_program_read_erase outcome=passed asserts=10 skips=0 +TEST flash_refusals + fault checks that reset the board: 4 + -> ok + req DRV-001 DRV-003 +CASE flash_refusals outcome=passed asserts=14 skips=0 +TEST flash_area_stays_inside + -> ok + req DRV-001 +CASE flash_area_stays_inside outcome=passed asserts=10 skips=0 +TEST flash_power_loss_tears_an_operation + -> ok + req DRV-001 +CASE flash_power_loss_tears_an_operation outcome=passed asserts=15 skips=0 +TEST flash_polled_calls + -> ok + req DRV-007 +CASE flash_polled_calls outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=188 +6 tests, 0 failed, 0 skipped, 41 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.json new file mode 100644 index 00000000..594cc3c0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 260, + "name": "flash_board_erase_keeps_the_clock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2312, + "name": "flash_board_program_and_read_back", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:04Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_flash_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_flash_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_flash_board.uf2": "bfff671dd79b57358a0c2cfb59cf10f713f5a36fd43b4121d0d25d2a407f27a3" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash_board.elf", + "image_sha256": "b46f69f4536a313a7d5353d07174ce97fcddeb2541b6dbe5a257fdae7c45300f", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:40:59Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.log new file mode 100644 index 00000000..467b889a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_flash_board.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash_board.elf sha256 b46f69f4536a313a7d5353d07174ce97fcddeb2541b6dbe5a257fdae7c45300f +EVIDENCE v1 suite=test_flash_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST flash_board_erase_keeps_the_clock + erase of 64 KiB: 546 ms by the cycles, 547 ms by the clock -> ok + req DRV-001 DRV-003 +CASE flash_board_erase_keeps_the_clock outcome=passed asserts=260 skips=0 +TEST flash_board_program_and_read_back + -> ok + req DRV-001 DRV-003 +CASE flash_board_program_and_read_back outcome=passed asserts=2312 skips=0 +ISR_STACK size=2048 used=188 +2 tests, 0 failed, 0 skipped, 3156 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.json new file mode 100644 index 00000000..0b636c56 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "fpu_callee_saved_registers_survive_a_switch", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "fpu_state_survives_preemption", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:35Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_fpu" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_fpu.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_fpu.uf2": "3303d710bcf76d4bb0fad6da841b987481f1c32b4467225fea5eb41250f78591" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fpu.elf", + "image_sha256": "4b7978ee891ea064c28b31ec845ffda1c372d0e595934f5eb5e013b0f73193d9", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:33Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.log new file mode 100644 index 00000000..4809596d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_fpu.log @@ -0,0 +1,11 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_fpu.elf sha256 4b7978ee891ea064c28b31ec845ffda1c372d0e595934f5eb5e013b0f73193d9 +EVIDENCE v1 suite=test_fpu config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST fpu_callee_saved_registers_survive_a_switch + -> ok +CASE fpu_callee_saved_registers_survive_a_switch outcome=passed asserts=6 skips=0 +TEST fpu_state_survives_preemption + -> ok +CASE fpu_state_survives_preemption outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +2 tests, 0 failed, 0 skipped, 34 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.json new file mode 100644 index 00000000..b80f5293 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 9, + "name": "frame_encoding_matches_the_host_tool", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 39, + "name": "frame_runs_at_the_cobs_boundary", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "frame_round_trip_through_the_decoder", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "frame_decoder_resynchronizes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "frame_decoder_drops_an_overrun", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "frame_misuse_is_refused", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 383, + "name": "frame_random_stream_with_damage", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 122, + "name": "frame_write_streams_the_encoders_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "frame_write_misuse_is_refused", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:37Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_frame" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_frame.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_frame.uf2": "7117f1ea327411bab56cd2a8ac4c41e450ce57d15ffff433f6b0b3814d6a0208" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_frame.elf", + "image_sha256": "3532d4475a86bb81bce919a444d8a6acf037c3634a9339685fa5e04501cee0cb", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:35Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.log new file mode 100644 index 00000000..b74d8d0d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_frame.log @@ -0,0 +1,41 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_frame.elf sha256 3532d4475a86bb81bce919a444d8a6acf037c3634a9339685fa5e04501cee0cb +EVIDENCE v1 suite=test_frame config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST frame_encoding_matches_the_host_tool + -> ok + req OBS-019 +CASE frame_encoding_matches_the_host_tool outcome=passed asserts=9 skips=0 +TEST frame_runs_at_the_cobs_boundary + -> ok + req OBS-019 +CASE frame_runs_at_the_cobs_boundary outcome=passed asserts=39 skips=0 +TEST frame_round_trip_through_the_decoder + -> ok + req OBS-019 +CASE frame_round_trip_through_the_decoder outcome=passed asserts=12 skips=0 +TEST frame_decoder_resynchronizes + -> ok + req OBS-019 +CASE frame_decoder_resynchronizes outcome=passed asserts=17 skips=0 +TEST frame_decoder_drops_an_overrun + -> ok + req OBS-019 +CASE frame_decoder_drops_an_overrun outcome=passed asserts=6 skips=0 +TEST frame_misuse_is_refused + -> ok + req OBS-019 +CASE frame_misuse_is_refused outcome=passed asserts=8 skips=0 +TEST frame_random_stream_with_damage + -> ok + req OBS-019 +CASE frame_random_stream_with_damage outcome=passed asserts=383 skips=0 +TEST frame_write_streams_the_encoders_bytes + -> ok + req OBS-019 +CASE frame_write_streams_the_encoders_bytes outcome=passed asserts=122 skips=0 +TEST frame_write_misuse_is_refused + -> ok + req OBS-019 +CASE frame_write_misuse_is_refused outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=188 +9 tests, 0 failed, 0 skipped, 120 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.json new file mode 100644 index 00000000..5469fb30 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.json @@ -0,0 +1,79 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 9, + "name": "gpio_output_drives_and_reads_back", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "gpio_input_reads_its_pull", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "gpio_named_line_follows_its_sense", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "gpio_driver_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "gpio_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:49Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_gpio" + }, + "exit": 0, + "fault_checks_by_reset": 10, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_gpio.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_gpio.uf2": "32dcb56e4ab71039510ac0a04f0496e467753cb4c64de0dae6f9df2faedbcc12" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_gpio.elf", + "image_sha256": "f0ff4fa601dbf0bf7bc3be5383f0595f29aa6173798eefdfbe55013e2e86eca4", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:47Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.log new file mode 100644 index 00000000..7582c6b2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_gpio.log @@ -0,0 +1,26 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_gpio.elf sha256 f0ff4fa601dbf0bf7bc3be5383f0595f29aa6173798eefdfbe55013e2e86eca4 +EVIDENCE v1 suite=test_gpio config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST gpio_output_drives_and_reads_back + -> ok + req DRV-004 +CASE gpio_output_drives_and_reads_back outcome=passed asserts=9 skips=0 +TEST gpio_input_reads_its_pull + -> ok + req DRV-004 +CASE gpio_input_reads_its_pull outcome=passed asserts=6 skips=0 +TEST gpio_named_line_follows_its_sense + -> ok + req DRV-004 +CASE gpio_named_line_follows_its_sense outcome=passed asserts=13 skips=0 +TEST gpio_driver_refusals + -> ok + req DRV-004 +CASE gpio_driver_refusals outcome=passed asserts=3 skips=0 +TEST gpio_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-004 +CASE gpio_misuse_faults outcome=passed asserts=11 skips=0 +ISR_STACK size=2048 used=188 +5 tests, 0 failed, 0 skipped, 10 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.json new file mode 100644 index 00000000..f722a98b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "i2c_write_then_read_a_register", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_segments_count_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "i2c_errors_and_timeout", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "i2c_target_answers_its_address", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "i2c_controller_and_target_at_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "i2c_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_held_bus_keeps_one_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_recover_clocks_a_stuck_bus_free", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_recover_waits_for_a_held_bus", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:15Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_i2c" + }, + "exit": 0, + "fault_checks_by_reset": 12, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_i2c.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_i2c.uf2": "7c8b1c5a4b91fb62164d9e8127097c12d935ce752d9b193e836cb5a330c4fa3d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c.elf", + "image_sha256": "22f658a7053025157eefd98b15e3d201b8c4fbb8ed53aa40b6d8b91fbcfc76c3", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:13Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.log new file mode 100644 index 00000000..51f2c67f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c.log @@ -0,0 +1,42 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c.elf sha256 22f658a7053025157eefd98b15e3d201b8c4fbb8ed53aa40b6d8b91fbcfc76c3 +EVIDENCE v1 suite=test_i2c config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST i2c_write_then_read_a_register + -> ok + req DRV-004 DRV-005 +CASE i2c_write_then_read_a_register outcome=passed asserts=7 skips=0 +TEST i2c_segments_count_bytes + -> ok + req DRV-005 +CASE i2c_segments_count_bytes outcome=passed asserts=6 skips=0 +TEST i2c_errors_and_timeout + -> ok + req DRV-006 +CASE i2c_errors_and_timeout outcome=passed asserts=7 skips=0 +TEST i2c_target_answers_its_address + -> ok + req DRV-004 DRV-005 +CASE i2c_target_answers_its_address outcome=passed asserts=10 skips=0 +TEST i2c_controller_and_target_at_once + -> ok + req DRV-004 +CASE i2c_controller_and_target_at_once outcome=passed asserts=9 skips=0 +TEST i2c_misuse_faults + fault checks that reset the board: 12 + -> ok + req DRV-004 +CASE i2c_misuse_faults outcome=passed asserts=13 skips=0 +TEST i2c_held_bus_keeps_one_target + -> ok + req DRV-004 +CASE i2c_held_bus_keeps_one_target outcome=passed asserts=11 skips=0 +TEST i2c_recover_clocks_a_stuck_bus_free + -> ok + req DRV-006 +CASE i2c_recover_clocks_a_stuck_bus_free outcome=passed asserts=11 skips=0 +TEST i2c_recover_waits_for_a_held_bus + -> ok + req DRV-006 +CASE i2c_recover_waits_for_a_held_bus outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +9 tests, 0 failed, 0 skipped, 44 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.json new file mode 100644 index 00000000..dcc3d203 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 8, + "name": "i2c_loop_write_to_the_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 32, + "name": "i2c_loop_register_reads_of_every_length", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_nobody_answers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_target_drops_beyond_its_buffer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "i2c_loop_fast_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "i2c_loop_listen_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 88, + "name": "i2c_loop_recovers_a_stuck_target", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:17Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_i2c_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_i2c_loop.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_i2c_loop.uf2": "d56bceeb85264e9dab8c479aef52f95443ebd004d11c3423cd29fbe2968f1f5f" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c_loop.elf", + "image_sha256": "5982edf3e236c5446b549c6cf706baa125a265a7204cb326a4e008e2fab61651", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:15Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.log new file mode 100644 index 00000000..19c0fb72 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_i2c_loop.log @@ -0,0 +1,33 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c_loop.elf sha256 5982edf3e236c5446b549c6cf706baa125a265a7204cb326a4e008e2fab61651 +EVIDENCE v1 suite=test_i2c_loop config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST i2c_loop_write_to_the_target + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_write_to_the_target outcome=passed asserts=8 skips=0 +TEST i2c_loop_register_reads_of_every_length + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_register_reads_of_every_length outcome=passed asserts=32 skips=0 +TEST i2c_loop_nobody_answers + -> ok + req DRV-006 +CASE i2c_loop_nobody_answers outcome=passed asserts=6 skips=0 +TEST i2c_loop_target_drops_beyond_its_buffer + -> ok + req DRV-006 +CASE i2c_loop_target_drops_beyond_its_buffer outcome=passed asserts=6 skips=0 +TEST i2c_loop_fast_mode + -> ok + req DRV-004 +CASE i2c_loop_fast_mode outcome=passed asserts=5 skips=0 +TEST i2c_loop_listen_times_out + -> ok + req DRV-006 +CASE i2c_loop_listen_times_out outcome=passed asserts=2 skips=0 +TEST i2c_loop_recovers_a_stuck_target + -> ok + req DRV-006 +CASE i2c_loop_recovers_a_stuck_target outcome=passed asserts=88 skips=0 +ISR_STACK size=2048 used=188 +7 tests, 0 failed, 0 skipped, 161 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.json new file mode 100644 index 00000000..625a4599 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "irq_lock_is_nestable_and_lifo", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "irq_isr_wake_switches_at_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_delivery_is_deferred_while_masked", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_scheduler_lock_defers_the_switch_not_the_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "irq_disabled_source_stays_pending", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_blocking_call_from_isr_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_connect_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_unlock_without_lock_is_misuse", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:03Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_irq" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_irq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_irq.uf2": "ae1e9cc9a12018c89946cf70755a85b8ab23f51f4243c2e84b5751b930d26db5" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq.elf", + "image_sha256": "22d2e76982fa0bed63a894efa90537af8b323df76fdde3867523de411fa94932", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:02Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.log new file mode 100644 index 00000000..b1176e14 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq.log @@ -0,0 +1,40 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq.elf sha256 22d2e76982fa0bed63a894efa90537af8b323df76fdde3867523de411fa94932 +EVIDENCE v1 suite=test_irq config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST irq_lock_is_nestable_and_lifo + -> ok + req KRN-IRQ-001 KRN-IRQ-002 +CASE irq_lock_is_nestable_and_lifo outcome=passed asserts=5 skips=0 +TEST irq_isr_wake_switches_at_outermost_exit + -> ok + req KRN-IRQ-010 KRN-IRQ-012 KRN-IRQ-013 KRN-SCH-021 +CASE irq_isr_wake_switches_at_outermost_exit outcome=passed asserts=7 skips=0 +TEST irq_delivery_is_deferred_while_masked + -> ok + req KRN-IRQ-001 KRN-IRQ-033 +CASE irq_delivery_is_deferred_while_masked outcome=passed asserts=4 skips=0 +TEST irq_scheduler_lock_defers_the_switch_not_the_handler + -> ok + req KRN-SCH-016 KRN-SCH-018 KRN-SCH-019 +CASE irq_scheduler_lock_defers_the_switch_not_the_handler outcome=passed asserts=4 skips=0 +TEST irq_disabled_source_stays_pending + -> ok + req KRN-IRQ-020 +CASE irq_disabled_source_stays_pending outcome=passed asserts=5 skips=0 +TEST irq_blocking_call_from_isr_is_misuse + fault checks that reset the board: 1 + -> ok + req API-013 KRN-IRQ-014 +CASE irq_blocking_call_from_isr_is_misuse outcome=passed asserts=1 skips=0 +TEST irq_connect_validates_arguments + fault checks that reset the board: 2 + -> ok + req KRN-IRQ-021 +CASE irq_connect_validates_arguments outcome=passed asserts=2 skips=0 +TEST irq_unlock_without_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-IRQ-002 +CASE irq_unlock_without_lock_is_misuse outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=188 +8 tests, 0 failed, 0 skipped, 11 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.json new file mode 100644 index 00000000..24df6140 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.json @@ -0,0 +1,109 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 2, + "name": "irq_priority_accepts_advertised_endpoints", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_rejects_out_of_range_level", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_priority_rejects_unknown_number", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_port_rejects_invalid_inputs", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 37, + "name": "irq_priority_encodings_and_invalid_write_guard", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "irq_priority_higher_generic_level_wins_pending_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_higher_generic_level_preempts_lower", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 25, + "name": "irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_equal_levels_do_not_preempt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "irq_priority_highest_kernel_level_is_masked", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:06Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_irq_priority" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_irq_priority.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_irq_priority.uf2": "3866422c4cbaab960b2f843922862222f4748c44643b24ad82cff84dab39875f" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq_priority.elf", + "image_sha256": "a4c1f89e90736c4e1c42ef7c635479cd773b38aabce747aa49e8b53b7780aa68", + "isr_stack": { + "size": 2048, + "used": 276 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:03Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.log new file mode 100644 index 00000000..51b787c2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_irq_priority.log @@ -0,0 +1,47 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq_priority.elf sha256 a4c1f89e90736c4e1c42ef7c635479cd773b38aabce747aa49e8b53b7780aa68 +EVIDENCE v1 suite=test_irq_priority config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST irq_priority_accepts_advertised_endpoints + -> ok + req KRN-IRQ-028 KRN-IRQ-029 +CASE irq_priority_accepts_advertised_endpoints outcome=passed asserts=2 skips=0 +TEST irq_priority_rejects_out_of_range_level + fault checks that reset the board: 2 + -> ok + req API-015 KRN-IRQ-028 +CASE irq_priority_rejects_out_of_range_level outcome=passed asserts=2 skips=0 +TEST irq_priority_rejects_unknown_number + fault checks that reset the board: 1 + -> ok + req API-015 KRN-IRQ-029 +CASE irq_priority_rejects_unknown_number outcome=passed asserts=1 skips=0 +TEST irq_priority_port_rejects_invalid_inputs + -> ok + req KRN-IRQ-028 +CASE irq_priority_port_rejects_invalid_inputs outcome=passed asserts=2 skips=0 +TEST irq_priority_encodings_and_invalid_write_guard + -> ok + req KRN-IRQ-028 KRN-IRQ-031 +CASE irq_priority_encodings_and_invalid_write_guard outcome=passed asserts=37 skips=0 +TEST irq_priority_higher_generic_level_wins_pending_order + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_wins_pending_order outcome=passed asserts=18 skips=0 +TEST irq_priority_higher_generic_level_preempts_lower + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_preempts_lower outcome=passed asserts=16 skips=0 +TEST irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback + -> ok + req KRN-WQ-007 KRN-TIM-025 KRN-IRQ-012 +CASE irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback outcome=passed asserts=25 skips=0 +TEST irq_priority_equal_levels_do_not_preempt + -> ok + req KRN-IRQ-028 +CASE irq_priority_equal_levels_do_not_preempt outcome=passed asserts=16 skips=0 +TEST irq_priority_highest_kernel_level_is_masked + -> ok + req KRN-IRQ-018 KRN-IRQ-028 +CASE irq_priority_highest_kernel_level_is_masked outcome=passed asserts=17 skips=0 +ISR_STACK size=2048 used=276 +10 tests, 0 failed, 0 skipped, 124 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.json new file mode 100644 index 00000000..220fe343 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "isr_stack_info_reports_size_and_use", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "isr_stack_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "thread_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "isr_stack_limit_stops_an_overflowing_interrupt", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:07Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_isr_stack" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_isr_stack.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_isr_stack.uf2": "f407d537ad3dd51dc8077a2477214c9139fce5e7b15e75ed8d8e93388f24df68" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_isr_stack.elf", + "image_sha256": "f19eb8775b333cb30477524d64579af70144f72ff0cfa5919200d2662668fdf0", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:06Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.log new file mode 100644 index 00000000..eb37f9e1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_isr_stack.log @@ -0,0 +1,24 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_isr_stack.elf sha256 f19eb8775b333cb30477524d64579af70144f72ff0cfa5919200d2662668fdf0 +EVIDENCE v1 suite=test_isr_stack config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST isr_stack_info_reports_size_and_use + -> ok + req PORT-016 KRN-MEM-009 +CASE isr_stack_info_reports_size_and_use outcome=passed asserts=6 skips=0 +TEST isr_stack_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req PORT-016 KRN-MEM-010 +CASE isr_stack_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +TEST thread_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req KRN-MEM-010 PORT-016 +CASE thread_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +TEST isr_stack_limit_stops_an_overflowing_interrupt + fault checks that reset the board: 1 + -> ok + req PORT-016 KRN-MEM-010 +CASE isr_stack_limit_stops_an_overflowing_interrupt outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=188 +4 tests, 0 failed, 0 skipped, 13 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.json new file mode 100644 index 00000000..e7d8e67a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "log_record_layout", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "log_text_formats", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "log_levels_compile_and_run_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 84, + "name": "log_overflow_drops_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "log_isr_record_waits_for_the_one_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "log_flush_sends_what_is_committed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2855, + "name": "log_producers_at_once_keep_their_order", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:39Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_log" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_log.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_log.uf2": "da37cc06f8129cb2106409a55c32c6f13650556d0cd62f05ca122969edc61d72" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_log.elf", + "image_sha256": "876beb8ce1fa273ff1679551726c1f039090b913bad71616d37adf8e3b8387b6", + "isr_stack": { + "size": 2048, + "used": 204 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:37Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.log new file mode 100644 index 00000000..624962a7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_log.log @@ -0,0 +1,35 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_log.elf sha256 876beb8ce1fa273ff1679551726c1f039090b913bad71616d37adf8e3b8387b6 +EVIDENCE v1 suite=test_log config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST log_record_layout + -> ok + req OBS-013 +CASE log_record_layout outcome=passed asserts=3 skips=0 +TEST log_text_formats + -> ok + req OBS-013 +CASE log_text_formats outcome=passed asserts=11 skips=0 +TEST log_levels_compile_and_run_time + -> ok + req OBS-002 +CASE log_levels_compile_and_run_time outcome=passed asserts=9 skips=0 +TEST log_overflow_drops_and_counts + -> ok + req OBS-003 +CASE log_overflow_drops_and_counts outcome=passed asserts=84 skips=0 +TEST log_isr_record_waits_for_the_one_before_it + -> ok + req OBS-003 +CASE log_isr_record_waits_for_the_one_before_it outcome=passed asserts=6 skips=0 +TEST log_flush_sends_what_is_committed +[0.060] I t: flushed 1 +[0.060] I t: flushed 2 + -> ok + req OBS-003 +CASE log_flush_sends_what_is_committed outcome=passed asserts=4 skips=0 +TEST log_producers_at_once_keep_their_order + -> ok + req OBS-003 +CASE log_producers_at_once_keep_their_order outcome=passed asserts=2855 skips=0 +ISR_STACK size=2048 used=204 +7 tests, 0 failed, 0 skipped, 103 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.json new file mode 100644 index 00000000..b9cffd8c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.json @@ -0,0 +1,121 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 25, + "name": "msgq_fifo_order_counts_and_peek", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "msgq_send_front_is_received_first_and_never_waits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_waiting_receivers_get_items_directly_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "msgq_receive_refills_the_freed_slot_from_a_waiting_sender", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_waits_time_out_and_cancel_without_storing", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "msgq_isr_send_and_receive_never_wait", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_destroy_aborts_receivers_and_senders", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "msgq_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "msgq_init_validates_the_ring", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_binding_fires_on_empty_to_nonempty_only", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "msgq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "msgq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:30Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_msgq" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_msgq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_msgq.uf2": "d0e985b5d8f34db45d04c62ffc8a75766c10216cd27a01a8c70ee70eeb42cb80" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_msgq.elf", + "image_sha256": "30ae1ac59152845f03d20b5ed78ad7d370ef4dbca5f0424353188820d4c90e9f", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:28Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.log new file mode 100644 index 00000000..14db07cf --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_msgq.log @@ -0,0 +1,56 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_msgq.elf sha256 30ae1ac59152845f03d20b5ed78ad7d370ef4dbca5f0424353188820d4c90e9f +EVIDENCE v1 suite=test_msgq config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST msgq_fifo_order_counts_and_peek + -> ok + req KRN-IPC-010 KRN-IPC-019 +CASE msgq_fifo_order_counts_and_peek outcome=passed asserts=25 skips=0 +TEST msgq_send_front_is_received_first_and_never_waits + -> ok + req KRN-IPC-012 +CASE msgq_send_front_is_received_first_and_never_waits outcome=passed asserts=9 skips=0 +TEST msgq_waiting_receivers_get_items_directly_in_priority_order + -> ok + req KRN-IPC-010 KRN-IPC-005 KRN-WAIT-001 +CASE msgq_waiting_receivers_get_items_directly_in_priority_order outcome=passed asserts=11 skips=0 +TEST msgq_receive_refills_the_freed_slot_from_a_waiting_sender + -> ok + req KRN-IPC-010 KRN-IPC-011 +CASE msgq_receive_refills_the_freed_slot_from_a_waiting_sender outcome=passed asserts=12 skips=0 +TEST msgq_waits_time_out_and_cancel_without_storing + -> ok + req KRN-IPC-010 KRN-WAIT-004 KRN-WAIT-017 +CASE msgq_waits_time_out_and_cancel_without_storing outcome=passed asserts=15 skips=0 +TEST msgq_isr_send_and_receive_never_wait + -> ok + req KRN-IPC-003 KRN-IPC-010 KRN-IRQ-010 +CASE msgq_isr_send_and_receive_never_wait outcome=passed asserts=13 skips=0 +TEST msgq_destroy_aborts_receivers_and_senders + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE msgq_destroy_aborts_receivers_and_senders outcome=passed asserts=11 skips=0 +TEST msgq_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE msgq_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST msgq_init_validates_the_ring + fault checks that reset the board: 6 + -> ok + req KRN-IPC-011 KRN-IPC-019 API-015 +CASE msgq_init_validates_the_ring outcome=passed asserts=6 skips=0 +TEST msgq_binding_fires_on_empty_to_nonempty_only + -> ok + req KRN-IPC-018 KRN-NOTIF-004 KRN-NOTIF-013 +CASE msgq_binding_fires_on_empty_to_nonempty_only outcome=passed asserts=15 skips=0 +TEST msgq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE msgq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST msgq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE msgq_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +12 tests, 0 failed, 0 skipped, 25 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.json new file mode 100644 index 00000000..d05fa641 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.json @@ -0,0 +1,139 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 8, + "name": "mutex_lock_unlock_and_ownership", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "mutex_recursive_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "mutex_contended_lock_inherits_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "mutex_timeout_removes_the_contribution", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 28, + "name": "mutex_inheritance_propagates_along_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_deadlock_is_detected_on_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "mutex_ceiling_raises_the_owner", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_ceiling_violation_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_ceiling_violation_when_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_owner_death_policy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "mutex_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "mutex_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "mutex_waiter_priority_change_reorders_and_propagates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "mutex_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:24Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_mutex" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_mutex.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_mutex.uf2": "d324cd971ec678a1c6088917970cfbadbc27e89cde1927cc5c31e6f2a8c3c871" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_mutex.elf", + "image_sha256": "b656a86d4f2712b05cc3f6034718aa337c558550ff9759c74f00b9cd9f9e2112", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:22Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 15 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.log new file mode 100644 index 00000000..4841197f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_mutex.log @@ -0,0 +1,73 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_mutex.elf sha256 b656a86d4f2712b05cc3f6034718aa337c558550ff9759c74f00b9cd9f9e2112 +EVIDENCE v1 suite=test_mutex config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST mutex_lock_unlock_and_ownership + fault checks that reset the board: 2 + -> ok + req KRN-SYNC-001 KRN-SYNC-008 +CASE mutex_lock_unlock_and_ownership outcome=passed asserts=8 skips=0 +TEST mutex_recursive_counts + -> ok + req KRN-SYNC-004 +CASE mutex_recursive_counts outcome=passed asserts=8 skips=0 +TEST mutex_contended_lock_inherits_and_hands_off + -> ok + req KRN-SYNC-003 KRN-SYNC-009 KRN-SYNC-010 KRN-WAIT-012 +CASE mutex_contended_lock_inherits_and_hands_off outcome=passed asserts=16 skips=0 +TEST mutex_timeout_removes_the_contribution + -> ok + req KRN-SYNC-014 KRN-WAIT-013 +CASE mutex_timeout_removes_the_contribution outcome=passed asserts=14 skips=0 +TEST mutex_inheritance_propagates_along_the_chain + -> ok + req KRN-SYNC-009 KRN-SYNC-010 KRN-SYNC-016 +CASE mutex_inheritance_propagates_along_the_chain outcome=passed asserts=28 skips=0 +TEST mutex_deadlock_is_detected_on_the_chain + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-015 +CASE mutex_deadlock_is_detected_on_the_chain outcome=passed asserts=5 skips=0 +TEST mutex_ceiling_raises_the_owner + -> ok + req KRN-SYNC-005 KRN-SYNC-006 +CASE mutex_ceiling_raises_the_owner outcome=passed asserts=7 skips=0 +TEST mutex_ceiling_violation_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_is_misuse outcome=passed asserts=3 skips=0 +TEST mutex_ceiling_violation_when_owned + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_when_owned outcome=passed asserts=5 skips=0 +TEST mutex_owner_death_policy + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-011 +CASE mutex_owner_death_policy outcome=passed asserts=3 skips=0 +TEST mutex_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 +CASE mutex_destroy_rules outcome=passed asserts=15 skips=0 +TEST mutex_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE mutex_storage_reuse_requires_destroy outcome=passed asserts=12 skips=0 +TEST mutex_waiter_priority_change_reorders_and_propagates + -> ok + req KRN-WAIT-003 KRN-SYNC-018 +CASE mutex_waiter_priority_change_reorders_and_propagates outcome=passed asserts=20 skips=0 +TEST mutex_init_validates_arguments + fault checks that reset the board: 3 + -> ok + req API-015 +CASE mutex_init_validates_arguments outcome=passed asserts=3 skips=0 +TEST mutex_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE mutex_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=188 +15 tests, 0 failed, 0 skipped, 24 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.json new file mode 100644 index 00000000..338ed61d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.json @@ -0,0 +1,109 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "notify_bits_are_level_sensitive", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "notify_any_and_all_modes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wake_from_thread_hands_off_bits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "notify_wake_from_isr", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wait_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "notify_rejects_kernel_bits_and_terminated_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "notify_semaphore_binding_signals_ready_transition", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "notify_unbind_stops_signals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "notify_bound_target_cannot_be_destroyed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "notify_bind_refuses_a_terminated_target", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:19Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_notify" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_notify.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_notify.uf2": "1e6a4a34d9eadf9ee3d2ec5c0b7d570f190419cd74f9ea26a5a2f26d1bd05ad8" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_notify.elf", + "image_sha256": "d2832c9296ef1a0842805a718ed96f4f65aeef0a2b577dcf460d676cdaa5b1b7", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:17Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.log new file mode 100644 index 00000000..fba4bbf8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_notify.log @@ -0,0 +1,47 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_notify.elf sha256 d2832c9296ef1a0842805a718ed96f4f65aeef0a2b577dcf460d676cdaa5b1b7 +EVIDENCE v1 suite=test_notify config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST notify_bits_are_level_sensitive + -> ok + req KRN-NOTIF-001 KRN-NOTIF-002 +CASE notify_bits_are_level_sensitive outcome=passed asserts=7 skips=0 +TEST notify_any_and_all_modes + -> ok + req KRN-NOTIF-001 +CASE notify_any_and_all_modes outcome=passed asserts=12 skips=0 +TEST notify_wake_from_thread_hands_off_bits + -> ok + req KRN-NOTIF-003 KRN-WAIT-012 +CASE notify_wake_from_thread_hands_off_bits outcome=passed asserts=5 skips=0 +TEST notify_wake_from_isr + -> ok + req KRN-NOTIF-002 KRN-IRQ-010 +CASE notify_wake_from_isr outcome=passed asserts=3 skips=0 +TEST notify_wait_times_out + -> ok + req KRN-NOTIF-001 KRN-WAIT-004 +CASE notify_wait_times_out outcome=passed asserts=5 skips=0 +TEST notify_rejects_kernel_bits_and_terminated_targets + fault checks that reset the board: 3 + -> ok + req KRN-NOTIF-002 KRN-NOTIF-006 +CASE notify_rejects_kernel_bits_and_terminated_targets outcome=passed asserts=6 skips=0 +TEST notify_semaphore_binding_signals_ready_transition + -> ok + req KRN-NOTIF-004 KRN-NOTIF-005 +CASE notify_semaphore_binding_signals_ready_transition outcome=passed asserts=10 skips=0 +TEST notify_unbind_stops_signals + -> ok + req KRN-NOTIF-009 KRN-NOTIF-013 +CASE notify_unbind_stops_signals outcome=passed asserts=14 skips=0 +TEST notify_bound_target_cannot_be_destroyed + fault checks that reset the board: 1 + -> ok + req KRN-NOTIF-014 KRN-NOTIF-009 +CASE notify_bound_target_cannot_be_destroyed outcome=passed asserts=11 skips=0 +TEST notify_bind_refuses_a_terminated_target + -> ok + req KRN-NOTIF-014 +CASE notify_bind_refuses_a_terminated_target outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +10 tests, 0 failed, 0 skipped, 26 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.json new file mode 100644 index 00000000..5dc4c384 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.json @@ -0,0 +1,79 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "rtc_get_set_and_not_set", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_once_and_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_canceled_and_set_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "rtc_backup_and_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "rtc_seeds_the_wall_clock", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:40:52Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_rtc" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_rtc.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_rtc.uf2": "96b32b20c094c1e737deee5b3028f42d2f5e4d0dc2f78991a658c195c73a7211" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc.elf", + "image_sha256": "fdd98d31cc64df055100511b15965085bdeaf41dd74aae0549888aff8e1a4ebd", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:40:50Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.log new file mode 100644 index 00000000..d4a2de46 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc.log @@ -0,0 +1,26 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc.elf sha256 fdd98d31cc64df055100511b15965085bdeaf41dd74aae0549888aff8e1a4ebd +EVIDENCE v1 suite=test_rtc config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST rtc_get_set_and_not_set + -> ok + req DRV-001 +CASE rtc_get_set_and_not_set outcome=passed asserts=7 skips=0 +TEST rtc_alarm_once_and_again + -> ok + req DRV-001 +CASE rtc_alarm_once_and_again outcome=passed asserts=10 skips=0 +TEST rtc_alarm_canceled_and_set_disarms + -> ok + req DRV-001 +CASE rtc_alarm_canceled_and_set_disarms outcome=passed asserts=10 skips=0 +TEST rtc_backup_and_misuse + fault checks that reset the board: 3 + -> ok + req DRV-001 +CASE rtc_backup_and_misuse outcome=passed asserts=8 skips=0 +TEST rtc_seeds_the_wall_clock + -> ok + req KRN-TIM-031 +CASE rtc_seeds_the_wall_clock outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=188 +5 tests, 0 failed, 0 skipped, 20 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.json new file mode 100644 index 00000000..b28f536b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 8, + "name": "rtc_board_set_read_and_keep_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 42, + "name": "rtc_board_alarm_on_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "rtc_board_backup_registers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "rtc_board_keeps_its_time_across_a_reset", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:40:56Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_rtc_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_rtc_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_rtc_board.uf2": "3f0eda624495f59a4cf68d72afde380e51f50d403bb4d660a8d6ae01083c4529" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc_board.elf", + "image_sha256": "dda6bb821795355a7e5bf8486f8d5875ad9a97482d2780f8395a5543c4eb3f3a", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:40:52Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.log new file mode 100644 index 00000000..70a442a3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_rtc_board.log @@ -0,0 +1,22 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc_board.elf sha256 dda6bb821795355a7e5bf8486f8d5875ad9a97482d2780f8395a5543c4eb3f3a +EVIDENCE v1 suite=test_rtc_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST rtc_board_set_read_and_keep_time + set and get took 0 ms; the RTC read 0 ms past the time set over 2005 ms of the kernel's clock the RTC moved 2004 ms -> ok + req DRV-001 +CASE rtc_board_set_read_and_keep_time outcome=passed asserts=8 skips=0 +TEST rtc_board_alarm_on_time + an alarm 300 ms ahead fired after 300 ms -> ok + req DRV-001 +CASE rtc_board_alarm_on_time outcome=passed asserts=42 skips=0 +TEST rtc_board_backup_registers + -> ok + req DRV-001 +CASE rtc_board_backup_registers outcome=passed asserts=1 skips=0 +TEST rtc_board_keeps_its_time_across_a_reset + after the reset the RTC read 4 ms past the time set fault checks that reset the board: 1 + -> ok + req DRV-001 KRN-TIM-031 +CASE rtc_board_keeps_its_time_across_a_reset outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=188 +4 tests, 0 failed, 0 skipped, 17 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.json new file mode 100644 index 00000000..d942d9bc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "sched_higher_priority_runs_first", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_lock_defers_preemption_until_unlock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "sched_yield_never_to_lower_priority", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sched_fifo_within_level_and_yield_rotates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "sched_preempted_thread_goes_ahead_of_its_peers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "sched_blocking_under_scheduler_lock_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sched_idle_runs_when_nothing_is_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_thread_self_and_priorities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sched_raising_a_ready_thread_above_the_caller_preempts", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:01Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_sched" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_sched.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_sched.uf2": "30a00297bbf3d33fb1659c88fa47684184c4e0771167eb861fd94eab2751a42e" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sched.elf", + "image_sha256": "c22f078b60b77560edd48ffe49572e7a9ccb51e5935d0f946401251bcdabecde", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:59Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.log new file mode 100644 index 00000000..5cb466e9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sched.log @@ -0,0 +1,42 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_sched.elf sha256 c22f078b60b77560edd48ffe49572e7a9ccb51e5935d0f946401251bcdabecde +EVIDENCE v1 suite=test_sched config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST sched_higher_priority_runs_first + -> ok + req KRN-SCH-001 KRN-SCH-002 +CASE sched_higher_priority_runs_first outcome=passed asserts=3 skips=0 +TEST sched_lock_defers_preemption_until_unlock + -> ok + req KRN-SCH-016 KRN-SCH-017 KRN-SCH-018 +CASE sched_lock_defers_preemption_until_unlock outcome=passed asserts=4 skips=0 +TEST sched_yield_never_to_lower_priority + -> ok + req KRN-SCH-008 +CASE sched_yield_never_to_lower_priority outcome=passed asserts=3 skips=0 +TEST sched_fifo_within_level_and_yield_rotates + -> ok + req KRN-SCH-003 KRN-SCH-008 +CASE sched_fifo_within_level_and_yield_rotates outcome=passed asserts=5 skips=0 +TEST sched_preempted_thread_goes_ahead_of_its_peers + -> ok + req KRN-SCH-041 KRN-IRQ-013 +CASE sched_preempted_thread_goes_ahead_of_its_peers outcome=passed asserts=8 skips=0 +TEST sched_blocking_under_scheduler_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SCH-019 API-013 +CASE sched_blocking_under_scheduler_lock_is_misuse outcome=passed asserts=1 skips=0 +TEST sched_idle_runs_when_nothing_is_ready + -> ok + req KRN-SCH-043 SIM-005 +CASE sched_idle_runs_when_nothing_is_ready outcome=passed asserts=2 skips=0 +TEST sched_thread_self_and_priorities + -> ok + req KRN-THR-002 KRN-SCH-009 +CASE sched_thread_self_and_priorities outcome=passed asserts=4 skips=0 +TEST sched_raising_a_ready_thread_above_the_caller_preempts + -> ok + req KRN-THR-022 KRN-SYNC-032 +CASE sched_raising_a_ready_thread_above_the_caller_preempts outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +9 tests, 0 failed, 0 skipped, 56 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.json new file mode 100644 index 00000000..caf1d8a7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.json @@ -0,0 +1,121 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 8, + "name": "sem_counts_and_nowait", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_give_hands_off_to_highest_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_fifo_option_orders_by_arrival", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_take_times_out_and_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sem_give_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_max_overflow_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sem_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sem_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "sem_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sem_blocking_take_from_prekernel_or_isr_rejected", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sem_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:22Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_sem" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_sem.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_sem.uf2": "6f18423fd668434c566bdede280ca2f6039bc045b048cbb1a2909da07648e393" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sem.elf", + "image_sha256": "5edab6a7fbcf716f93046980dcad6aea6f602815ec12d6aad3cfaf05e321a955", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:20Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.log new file mode 100644 index 00000000..97896e5e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_sem.log @@ -0,0 +1,56 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_sem.elf sha256 5edab6a7fbcf716f93046980dcad6aea6f602815ec12d6aad3cfaf05e321a955 +EVIDENCE v1 suite=test_sem config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST sem_counts_and_nowait + -> ok + req KRN-SYNC-020 KRN-SYNC-021 +CASE sem_counts_and_nowait outcome=passed asserts=8 skips=0 +TEST sem_give_hands_off_to_highest_waiter + -> ok + req KRN-WAIT-001 KRN-WAIT-012 KRN-SYNC-022 +CASE sem_give_hands_off_to_highest_waiter outcome=passed asserts=13 skips=0 +TEST sem_fifo_option_orders_by_arrival + -> ok + req KRN-WAIT-002 +CASE sem_fifo_option_orders_by_arrival outcome=passed asserts=9 skips=0 +TEST sem_take_times_out_and_disarms + -> ok + req KRN-WAIT-004 KRN-WAIT-013 +CASE sem_take_times_out_and_disarms outcome=passed asserts=9 skips=0 +TEST sem_give_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-022 KRN-IRQ-010 KRN-IRQ-033 +CASE sem_give_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST sem_max_overflow_and_saturate + -> ok + req KRN-SYNC-020 +CASE sem_max_overflow_and_saturate outcome=passed asserts=13 skips=0 +TEST sem_init_validates_arguments + fault checks that reset the board: 2 + -> ok + req API-015 +CASE sem_init_validates_arguments outcome=passed asserts=2 skips=0 +TEST sem_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE sem_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST sem_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE sem_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST sem_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE sem_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST sem_blocking_take_from_prekernel_or_isr_rejected + -> ok + req API-012 API-013 +CASE sem_blocking_take_from_prekernel_or_isr_rejected outcome=passed asserts=4 skips=0 +TEST sem_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE sem_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +12 tests, 0 failed, 0 skipped, 40 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.json new file mode 100644 index 00000000..d0d4f988 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.json @@ -0,0 +1,67 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "smoke_thread_runs_and_exits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "smoke_sleep_advances_virtual_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "smoke_libc_errno_from_a_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:58Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_smoke" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_smoke.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_smoke.uf2": "735d46644c563df5c13ab728f9563da7c017f8e9f3df9412bad2176a9b638fef" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_smoke.elf", + "image_sha256": "8b0a81b3c1504a50059003c2c628f5852c7523363f32099bac319687aad68add", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:56Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.log new file mode 100644 index 00000000..0efc30a5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_smoke.log @@ -0,0 +1,17 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_smoke.elf sha256 8b0a81b3c1504a50059003c2c628f5852c7523363f32099bac319687aad68add +EVIDENCE v1 suite=test_smoke config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST smoke_thread_runs_and_exits + -> ok + req KRN-THR-001 KRN-THR-005 KRN-THR-017 +CASE smoke_thread_runs_and_exits outcome=passed asserts=5 skips=0 +TEST smoke_sleep_advances_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 +CASE smoke_sleep_advances_virtual_time outcome=passed asserts=2 skips=0 +TEST smoke_libc_errno_from_a_thread + -> ok + req PORT-015 +CASE smoke_libc_errno_from_a_thread outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=188 +3 tests, 0 failed, 0 skipped, 51 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.json new file mode 100644 index 00000000..bc6f30c1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "spi_transfer_loops_back", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_without_buffers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_transfers_run_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_unsupported_and_stopped", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "spi_chip_select_around_each_transfer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "spi_held_bus_keeps_the_chip_select", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_held_bus_refuses_another_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "spi_other_threads_wait_for_a_held_bus", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:19Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_spi" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_spi.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_spi.uf2": "a9e4d4565425656201a9632ce5db9b88ea4f27587975013e316a0fda6261dbb7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi.elf", + "image_sha256": "b9afc02f37255def25d0c1816c2ae371ee78e465531158d7ceec544137d1f779", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:17Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.log new file mode 100644 index 00000000..aeeec390 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi.log @@ -0,0 +1,42 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi.elf sha256 b9afc02f37255def25d0c1816c2ae371ee78e465531158d7ceec544137d1f779 +EVIDENCE v1 suite=test_spi config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST spi_transfer_loops_back + -> ok + req DRV-004 DRV-005 +CASE spi_transfer_loops_back outcome=passed asserts=6 skips=0 +TEST spi_without_buffers + -> ok + req DRV-005 +CASE spi_without_buffers outcome=passed asserts=7 skips=0 +TEST spi_transfers_run_in_order + -> ok + req DRV-004 +CASE spi_transfers_run_in_order outcome=passed asserts=10 skips=0 +TEST spi_unsupported_and_stopped + -> ok + req DRV-006 +CASE spi_unsupported_and_stopped outcome=passed asserts=7 skips=0 +TEST spi_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE spi_misuse_faults outcome=passed asserts=7 skips=0 +TEST spi_chip_select_around_each_transfer + -> ok + req DRV-004 +CASE spi_chip_select_around_each_transfer outcome=passed asserts=11 skips=0 +TEST spi_held_bus_keeps_the_chip_select + -> ok + req DRV-004 +CASE spi_held_bus_keeps_the_chip_select outcome=passed asserts=15 skips=0 +TEST spi_held_bus_refuses_another_target + -> ok + req DRV-004 +CASE spi_held_bus_refuses_another_target outcome=passed asserts=10 skips=0 +TEST spi_other_threads_wait_for_a_held_bus + -> ok + req DRV-004 +CASE spi_other_threads_wait_for_a_held_bus outcome=passed asserts=16 skips=0 +ISR_STACK size=2048 used=188 +9 tests, 0 failed, 0 skipped, 69 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.json new file mode 100644 index 00000000..339ad700 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 4, + "name": "spi_loop_frames_come_back_intact", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "spi_loop_every_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_slow_and_fast_clocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_refuses_a_clock_too_slow", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "spi_loop_timeout_stops_after_whole_frames", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "spi_loop_no_transmit_buffer_sends_ones", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 21, + "name": "spi_loop_chip_select_at_the_pin", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "spi_loop_runs_by_dma", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:21Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_spi_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_spi_loop.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_spi_loop.uf2": "830d1f7e61e2b2157fc4829e8cd10f4d7b10e2b25f06fc046271773501115fb3" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi_loop.elf", + "image_sha256": "582dfcc611c3917daa31050895f8080cc4c93b0418d89362bbf6f1a15dfd5c67", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:19Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.log new file mode 100644 index 00000000..5fe72f67 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_spi_loop.log @@ -0,0 +1,37 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi_loop.elf sha256 582dfcc611c3917daa31050895f8080cc4c93b0418d89362bbf6f1a15dfd5c67 +EVIDENCE v1 suite=test_spi_loop config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST spi_loop_frames_come_back_intact + -> ok + req DRV-004 DRV-005 +CASE spi_loop_frames_come_back_intact outcome=passed asserts=4 skips=0 +TEST spi_loop_every_mode + -> ok + req DRV-004 +CASE spi_loop_every_mode outcome=passed asserts=8 skips=0 +TEST spi_loop_slow_and_fast_clocks + -> ok + req DRV-004 +CASE spi_loop_slow_and_fast_clocks outcome=passed asserts=4 skips=0 +TEST spi_loop_refuses_a_clock_too_slow + -> ok + req DRV-006 +CASE spi_loop_refuses_a_clock_too_slow outcome=passed asserts=4 skips=0 +TEST spi_loop_timeout_stops_after_whole_frames + -> ok + req DRV-006 +CASE spi_loop_timeout_stops_after_whole_frames outcome=passed asserts=5 skips=0 +TEST spi_loop_no_transmit_buffer_sends_ones + -> ok + req DRV-005 +CASE spi_loop_no_transmit_buffer_sends_ones outcome=passed asserts=17 skips=0 +TEST spi_loop_chip_select_at_the_pin + -> ok + req DRV-004 +CASE spi_loop_chip_select_at_the_pin outcome=passed asserts=21 skips=0 +TEST spi_loop_runs_by_dma + -> ok + req DRV-004 DRV-006 +CASE spi_loop_runs_by_dma outcome=passed asserts=14 skips=0 +ISR_STACK size=2048 used=188 +8 tests, 0 failed, 0 skipped, 198 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.json new file mode 100644 index 00000000..fdfa2d35 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "stack_limit_stops_an_overflowing_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:31Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_stack_limit" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_stack_limit.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_stack_limit.uf2": "b3cd2160ec9e328bbeb80ed7fd97e6d9b83bfc014af1adc52315dc20a03cd0a6" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_stack_limit.elf", + "image_sha256": "a58bb24b8bf9bd856545bafeba408e124024ff93d9030756b4b7c4d2ddef6bb6", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:29Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.log new file mode 100644 index 00000000..2b450b3f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_stack_limit.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_stack_limit.elf sha256 a58bb24b8bf9bd856545bafeba408e124024ff93d9030756b4b7c4d2ddef6bb6 +EVIDENCE v1 suite=test_stack_limit config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST stack_limit_stops_an_overflowing_thread +stack_limit_stops_an_overflowing_thread: first boot, overflowing +EVIDENCE v1 suite=test_stack_limit config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST stack_limit_stops_an_overflowing_thread +EMB_CRASH 454d424301006c005cdf07599a09c881e03a94f94c2d8c8389d12ee5302e322e300000000f0000000000000002000000070006000000000001000000000010000000000000000000e8150020000000000000000004000000000010000000000034ed00e038ed00e06254c1eb + -> ok + req KRN-MEM-010 OBS-016 +CASE stack_limit_stops_an_overflowing_thread outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=188 +1 tests, 0 failed, 0 skipped, 41 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.json new file mode 100644 index 00000000..80609446 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.json @@ -0,0 +1,115 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "thread_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_start_twice_is_estate_and_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "thread_suspend_resume_are_idempotent_overlays", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_wake_while_suspended_is_applied_at_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_cancel_wakes_a_sleeping_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_cancel_pending_delivered_at_next_point", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_cancel_point_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_priority_change_requeues_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_state_reports_lifecycle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_define_registers_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "thread_stack_info_reports_size", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:10Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_thread" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_thread.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_thread.uf2": "404df19542fa6543ea67f5243ac710e99d26677cf0004e85e06b8e74c9d359d7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread.elf", + "image_sha256": "07b382a911a01b3b2bcb84469194c1478ffdbb7c428560b747e03d1814fcf3a2", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:07Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.log new file mode 100644 index 00000000..4a150345 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread.log @@ -0,0 +1,52 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread.elf sha256 07b382a911a01b3b2bcb84469194c1478ffdbb7c428560b747e03d1814fcf3a2 +EVIDENCE v1 suite=test_thread config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST thread_init_validates_arguments + fault checks that reset the board: 6 + -> ok + req KRN-THR-001 API-015 +CASE thread_init_validates_arguments outcome=passed asserts=6 skips=0 +TEST thread_start_twice_is_estate_and_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-THR-016 KRN-THR-022 KRN-OBJ-001 +CASE thread_start_twice_is_estate_and_destroy_rules outcome=passed asserts=13 skips=0 +TEST thread_suspend_resume_are_idempotent_overlays + -> ok + req KRN-THR-010 KRN-THR-019 +CASE thread_suspend_resume_are_idempotent_overlays outcome=passed asserts=18 skips=0 +TEST thread_wake_while_suspended_is_applied_at_resume + -> ok + req KRN-WAIT-016 KRN-THR-010 +CASE thread_wake_while_suspended_is_applied_at_resume outcome=passed asserts=12 skips=0 +TEST thread_cancel_wakes_a_sleeping_thread + -> ok + req KRN-THR-011 KRN-WAIT-017 +CASE thread_cancel_wakes_a_sleeping_thread outcome=passed asserts=6 skips=0 +TEST thread_cancel_pending_delivered_at_next_point + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_pending_delivered_at_next_point outcome=passed asserts=11 skips=0 +TEST thread_cancel_point_and_counts + fault checks that reset the board: 1 + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_point_and_counts outcome=passed asserts=5 skips=0 +TEST thread_priority_change_requeues_waiter + -> ok + req KRN-WAIT-003 KRN-SCH-009 KRN-SYNC-018 +CASE thread_priority_change_requeues_waiter outcome=passed asserts=13 skips=0 +TEST thread_state_reports_lifecycle + -> ok + req KRN-THR-021 +CASE thread_state_reports_lifecycle outcome=passed asserts=11 skips=0 +TEST thread_define_registers_in_init_table + -> ok + req KRN-THR-015 API-017 +CASE thread_define_registers_in_init_table outcome=passed asserts=5 skips=0 +TEST thread_stack_info_reports_size + -> ok + req KRN-MEM-009 +CASE thread_stack_info_reports_size outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=188 +11 tests, 0 failed, 0 skipped, 63 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.json new file mode 100644 index 00000000..4526cf0d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.json @@ -0,0 +1,79 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 15, + "name": "thread_identity_survives_priority_and_termination", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1200, + "name": "thread_identity_repeated_construction_does_not_alias_live_object", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_identity_survives_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "thread_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "idle_context_is_not_an_application_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:13Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_thread_identity" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_thread_identity.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_thread_identity.uf2": "cbbd99283832ed2dd321dd564dedd1642d07c91a3c4eb089586f92422afcd7dc" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_identity.elf", + "image_sha256": "8420b49b1d3dbf774e32b1d57807cc179f7ada0806bbdb587f183afe1cbd44dd", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:12Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.log new file mode 100644 index 00000000..f7e12d08 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_identity.log @@ -0,0 +1,28 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_identity.elf sha256 8420b49b1d3dbf774e32b1d57807cc179f7ada0806bbdb587f183afe1cbd44dd +EVIDENCE v1 suite=test_thread_identity config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST thread_identity_survives_priority_and_termination + fault checks that reset the board: 1 + -> ok + req KRN-THR-025 +CASE thread_identity_survives_priority_and_termination outcome=passed asserts=15 skips=0 +TEST thread_identity_repeated_construction_does_not_alias_live_object + -> ok + req KRN-THR-025 +CASE thread_identity_repeated_construction_does_not_alias_live_object outcome=passed asserts=1200 skips=0 +TEST thread_identity_survives_suspend_and_resume + -> ok + req KRN-THR-025 +CASE thread_identity_survives_suspend_and_resume outcome=passed asserts=12 skips=0 +TEST thread_storage_reuse_requires_destroy + fault checks that reset the board: 2 + -> ok + req KRN-THR-015 KRN-THR-023 +CASE thread_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST idle_context_is_not_an_application_thread + fault checks that reset the board: 2 + -> ok + req KRN-THR-025 KRN-THR-026 +CASE idle_context_is_not_an_application_thread outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +5 tests, 0 failed, 0 skipped, 13 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.json new file mode 100644 index 00000000..3ea3f282 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.json @@ -0,0 +1,85 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 4, + "name": "thread_join_after_exit_returns_code", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_join_before_exit_blocks_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_timeout_then_success", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "thread_second_joiner_is_ebusy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_self_and_detached_are_errors", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_detach_after_exit_makes_reusable", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:12Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_thread_join" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_thread_join.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_thread_join.uf2": "db02d1cfcf824a9e83218e9afa881f1fed10bf251f5f7e84094dabe0a5583b2f" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_join.elf", + "image_sha256": "715695c9b7074b21f28345a89e3c71a0228f89e3903978aa4e05f2a6a091ef87", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:10Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.log new file mode 100644 index 00000000..c2c27fea --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_thread_join.log @@ -0,0 +1,31 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_join.elf sha256 715695c9b7074b21f28345a89e3c71a0228f89e3903978aa4e05f2a6a091ef87 +EVIDENCE v1 suite=test_thread_join config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST thread_join_after_exit_returns_code + -> ok + req KRN-THR-004 KRN-THR-006 KRN-THR-017 +CASE thread_join_after_exit_returns_code outcome=passed asserts=4 skips=0 +TEST thread_join_before_exit_blocks_and_hands_off + -> ok + req KRN-THR-017 KRN-WAIT-012 +CASE thread_join_before_exit_blocks_and_hands_off outcome=passed asserts=6 skips=0 +TEST thread_join_timeout_then_success + -> ok + req KRN-THR-017 KRN-WAIT-004 +CASE thread_join_timeout_then_success outcome=passed asserts=5 skips=0 +TEST thread_second_joiner_is_ebusy + -> ok + req KRN-THR-018 +CASE thread_second_joiner_is_ebusy outcome=passed asserts=10 skips=0 +TEST thread_join_self_and_detached_are_errors + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 +CASE thread_join_self_and_detached_are_errors outcome=passed asserts=5 skips=0 +TEST thread_detach_after_exit_makes_reusable + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 KRN-THR-022 +CASE thread_detach_after_exit_makes_reusable outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=188 +6 tests, 0 failed, 0 skipped, 13 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.json new file mode 100644 index 00000000..c80fcdad --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 4, + "name": "time_sleep_is_exact_in_virtual_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "time_sleep_until_does_not_drift", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "time_zero_sleep_and_past_deadline_yield", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "time_timeouts_expire_in_deadline_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "time_conversions_round_up_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_at_least_adds_one_tick", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_instant_helpers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 40, + "name": "time_now_is_monotonic_across_sleeps", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:15Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_time" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_time.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_time.uf2": "543238cb62a12be6c9ad0e069b36a20a80012ff9172707b209d2940af993709b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_time.elf", + "image_sha256": "cabd995e3c409e7e11c31ca63bc437364e3a2a5e8e58094e1443f0be47ab2bae", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:14Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.log new file mode 100644 index 00000000..7d8037c0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_time.log @@ -0,0 +1,37 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_time.elf sha256 cabd995e3c409e7e11c31ca63bc437364e3a2a5e8e58094e1443f0be47ab2bae +EVIDENCE v1 suite=test_time config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST time_sleep_is_exact_in_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 API-023 +CASE time_sleep_is_exact_in_virtual_time outcome=passed asserts=4 skips=0 +TEST time_sleep_until_does_not_drift + -> ok + req KRN-TIM-011 +CASE time_sleep_until_does_not_drift outcome=passed asserts=20 skips=0 +TEST time_zero_sleep_and_past_deadline_yield + -> ok + req KRN-TIM-010 API-024 +CASE time_zero_sleep_and_past_deadline_yield outcome=passed asserts=3 skips=0 +TEST time_timeouts_expire_in_deadline_order + -> ok + req KRN-TIM-020 KRN-TIM-021 +CASE time_timeouts_expire_in_deadline_order outcome=passed asserts=14 skips=0 +TEST time_conversions_round_up_and_saturate + -> ok + req API-021 API-022 +CASE time_conversions_round_up_and_saturate outcome=passed asserts=12 skips=0 +TEST time_at_least_adds_one_tick + -> ok + req KRN-TIM-024 +CASE time_at_least_adds_one_tick outcome=passed asserts=6 skips=0 +TEST time_instant_helpers + -> ok + req API-021 +CASE time_instant_helpers outcome=passed asserts=6 skips=0 +TEST time_now_is_monotonic_across_sleeps + -> ok + req KRN-TIM-001 +CASE time_now_is_monotonic_across_sleeps outcome=passed asserts=40 skips=0 +ISR_STACK size=2048 used=188 +8 tests, 0 failed, 0 skipped, 180 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.json new file mode 100644 index 00000000..3a034757 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 22, + "name": "timer_isr_context_one_shot_and_periodic_without_drift", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 22, + "name": "timer_restart_remaining_and_stop_states", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "timer_callback_runs_on_its_work_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_stop_sync_waits_for_a_running_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_expiries_during_a_long_callback_are_overruns", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "timer_init_needs_a_queue_or_isr_context", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "timer_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:35Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_timer" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_timer.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_timer.uf2": "5da7821af1ac0d4bcdd6b2f4b4d129fddde79354bccdafbcea33cd0c2117dab0" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_timer.elf", + "image_sha256": "30f47b94a231387d3c0c8e9342bc7533155d61e308d1381f6202ff7faa1c3390", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:33Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.log new file mode 100644 index 00000000..0d6955cc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_timer.log @@ -0,0 +1,36 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_timer.elf sha256 30f47b94a231387d3c0c8e9342bc7533155d61e308d1381f6202ff7faa1c3390 +EVIDENCE v1 suite=test_timer config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST timer_isr_context_one_shot_and_periodic_without_drift + -> ok + req KRN-TIM-025 KRN-TIM-005 KRN-TIM-014 KRN-TIM-015 +CASE timer_isr_context_one_shot_and_periodic_without_drift outcome=passed asserts=22 skips=0 +TEST timer_restart_remaining_and_stop_states + fault checks that reset the board: 2 + -> ok + req KRN-TIM-025 KRN-TIM-028 +CASE timer_restart_remaining_and_stop_states outcome=passed asserts=22 skips=0 +TEST timer_callback_runs_on_its_work_queue + fault checks that reset the board: 1 + -> ok + req KRN-TIM-013 KRN-TIM-005 KRN-TIM-026 +CASE timer_callback_runs_on_its_work_queue outcome=passed asserts=11 skips=0 +TEST timer_stop_sync_waits_for_a_running_callback + -> ok + req KRN-TIM-028 KRN-WAIT-012 +CASE timer_stop_sync_waits_for_a_running_callback outcome=passed asserts=13 skips=0 +TEST timer_expiries_during_a_long_callback_are_overruns + -> ok + req KRN-TIM-027 +CASE timer_expiries_during_a_long_callback_are_overruns outcome=passed asserts=13 skips=0 +TEST timer_init_needs_a_queue_or_isr_context + fault checks that reset the board: 2 + -> ok + req KRN-TIM-013 API-015 +CASE timer_init_needs_a_queue_or_isr_context outcome=passed asserts=3 skips=0 +TEST timer_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE timer_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=188 +7 tests, 0 failed, 0 skipped, 26 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.json new file mode 100644 index 00000000..fe5002f4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 8, + "name": "uart_read_and_write_run_at_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_ring_keeps_bytes_no_read_waits_for", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "uart_idle_ends_a_read_early", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "uart_overrun_and_damaged_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_read_times_out_with_what_it_got", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_polled_calls_and_capabilities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_break_runs_after_the_writes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_misuse_faults", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:43Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_uart" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_uart.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_uart.uf2": "13362e6d96d130667c0f57b1ebf726dc2fc48edc1d6d38ae3c6e51536f4f361b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart.elf", + "image_sha256": "b2dada8bc79f90e494200765166507529dce10257bbc4be1c635929cd1a482aa", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:41Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.log new file mode 100644 index 00000000..847d4174 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart.log @@ -0,0 +1,38 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart.elf sha256 b2dada8bc79f90e494200765166507529dce10257bbc4be1c635929cd1a482aa +EVIDENCE v1 suite=test_uart config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST uart_read_and_write_run_at_once + -> ok + req DRV-004 DRV-005 +CASE uart_read_and_write_run_at_once outcome=passed asserts=8 skips=0 +TEST uart_ring_keeps_bytes_no_read_waits_for + -> ok + req DRV-005 +CASE uart_ring_keeps_bytes_no_read_waits_for outcome=passed asserts=8 skips=0 +TEST uart_idle_ends_a_read_early + -> ok + req DRV-005 +CASE uart_idle_ends_a_read_early outcome=passed asserts=10 skips=0 +TEST uart_overrun_and_damaged_bytes + -> ok + req DRV-005 DRV-008 +CASE uart_overrun_and_damaged_bytes outcome=passed asserts=11 skips=0 +TEST uart_read_times_out_with_what_it_got + -> ok + req DRV-006 +CASE uart_read_times_out_with_what_it_got outcome=passed asserts=6 skips=0 +TEST uart_polled_calls_and_capabilities + -> ok + req DRV-007 +CASE uart_polled_calls_and_capabilities outcome=passed asserts=8 skips=0 +TEST uart_break_runs_after_the_writes + -> ok + req DRV-004 +CASE uart_break_runs_after_the_writes outcome=passed asserts=5 skips=0 +TEST uart_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE uart_misuse_faults outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=188 +8 tests, 0 failed, 0 skipped, 10 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.json new file mode 100644 index 00000000..6c05e833 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "uart_console_writes_by_request", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "uart_console_read_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "uart_console_break_or_not_supported", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "uart_console_polled_write", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:45Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_uart_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_uart_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_uart_board.uf2": "867f2872df9cc392c0367585c0e9a483bf3a8f16483f269938cdb4b8c0f683a6" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_board.elf", + "image_sha256": "7fcd495388a1bea7d9e4191a73b897c78e817a59ef3b833474bd5ec67149c3d8", + "isr_stack": { + "size": 2048, + "used": 200 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:43Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.log new file mode 100644 index 00000000..2b8314a9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_board.log @@ -0,0 +1,23 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart_board.elf sha256 7fcd495388a1bea7d9e4191a73b897c78e817a59ef3b833474bd5ec67149c3d8 +EVIDENCE v1 suite=test_uart_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST uart_console_writes_by_request +uart: a write by request, sent by the driver's interrupts + -> ok + req DRV-004 DRV-005 +CASE uart_console_writes_by_request outcome=passed asserts=5 skips=0 +TEST uart_console_read_times_out + -> ok + req DRV-006 +CASE uart_console_read_times_out outcome=passed asserts=2 skips=0 +TEST uart_console_break_or_not_supported + -> ok + req DRV-004 +CASE uart_console_break_or_not_supported outcome=passed asserts=1 skips=0 +TEST uart_console_polled_write +uart: a polled write + -> ok + req DRV-007 +CASE uart_console_polled_write outcome=passed asserts=1 skips=0 +ISR_STACK size=2048 used=200 +4 tests, 0 failed, 0 skipped, 77 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.json new file mode 100644 index 00000000..e4007fb9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "uart_loop_echo_full_duplex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_ring_keeps_what_arrives", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_loop_idle_line_ends_a_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_loop_a_kilobyte_intact", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_break_arrives_as_a_framing_error", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_overrun_is_reported", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "uart_loop_writes_by_dma", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:47Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_uart_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_uart_loop.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_uart_loop.uf2": "18b1a261b3cb04730df91d3b35d2a44b423836dbc63b0875dcdcf1d67f1fb672" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_loop.elf", + "image_sha256": "0cf27356bb71288911e8059becd07d40fd903ce0017809926ec903ce562bec82", + "isr_stack": { + "size": 2048, + "used": 200 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:45Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.log new file mode 100644 index 00000000..110b0ca8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_uart_loop.log @@ -0,0 +1,33 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart_loop.elf sha256 0cf27356bb71288911e8059becd07d40fd903ce0017809926ec903ce562bec82 +EVIDENCE v1 suite=test_uart_loop config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST uart_loop_echo_full_duplex + -> ok + req DRV-004 DRV-005 +CASE uart_loop_echo_full_duplex outcome=passed asserts=7 skips=0 +TEST uart_loop_ring_keeps_what_arrives + -> ok + req DRV-005 +CASE uart_loop_ring_keeps_what_arrives outcome=passed asserts=4 skips=0 +TEST uart_loop_idle_line_ends_a_read + -> ok + req DRV-005 +CASE uart_loop_idle_line_ends_a_read outcome=passed asserts=5 skips=0 +TEST uart_loop_a_kilobyte_intact + -> ok + req DRV-004 DRV-005 +CASE uart_loop_a_kilobyte_intact outcome=passed asserts=6 skips=0 +TEST uart_loop_break_arrives_as_a_framing_error + -> ok + req DRV-004 DRV-008 +CASE uart_loop_break_arrives_as_a_framing_error outcome=passed asserts=4 skips=0 +TEST uart_loop_overrun_is_reported + -> ok + req DRV-005 DRV-008 +CASE uart_loop_overrun_is_reported outcome=passed asserts=4 skips=0 +TEST uart_loop_writes_by_dma + -> ok + req DRV-004 DRV-006 +CASE uart_loop_writes_by_dma outcome=passed asserts=16 skips=0 +ISR_STACK size=2048 used=200 +7 tests, 0 failed, 0 skipped, 230 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.json new file mode 100644 index 00000000..2b13d57d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 8, + "name": "wallclock_set_and_get", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "wallclock_adjust_moves_no_deadline", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:17Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wallclock" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_wallclock.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wallclock.uf2": "3d222c1f93b851c0e83fcc0ef79c6febeb05e33ba73b480e01927fd3ff812d41" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wallclock.elf", + "image_sha256": "462dab3b90a75b5b48665efb2ebd42465d99b9e28705e7f7c108d102c005411a", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:16Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.log new file mode 100644 index 00000000..e407cdd4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wallclock.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wallclock.elf sha256 462dab3b90a75b5b48665efb2ebd42465d99b9e28705e7f7c108d102c005411a +EVIDENCE v1 suite=test_wallclock config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wallclock_set_and_get + fault checks that reset the board: 1 + -> ok + req KRN-TIM-031 +CASE wallclock_set_and_get outcome=passed asserts=8 skips=0 +TEST wallclock_adjust_moves_no_deadline + -> ok + req KRN-TIM-031 +CASE wallclock_adjust_moves_no_deadline outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=188 +2 tests, 0 failed, 0 skipped, 89 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.json new file mode 100644 index 00000000..3b389e10 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 13, + "name": "wdog_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 122, + "name": "wdog_feeds_until_a_party_misses", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:08Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdog" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_wdog.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdog.uf2": "5747cbf9eaddf8361958bad14ebf22a959831fc40b952e5072fb6a3b4c135d9b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog.elf", + "image_sha256": "393ada9ecb38140bdb660fe417959c3f471d3b05e4ea938f2e84fc19f9aa9e41", + "isr_stack": { + "size": 2048, + "used": 280 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:05Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.log new file mode 100644 index 00000000..568c3f84 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog.elf sha256 393ada9ecb38140bdb660fe417959c3f471d3b05e4ea938f2e84fc19f9aa9e41 +EVIDENCE v1 suite=test_wdog config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdog_refusals + fault checks that reset the board: 4 + -> ok + req FLT-004 +CASE wdog_refusals outcome=passed asserts=13 skips=0 +TEST wdog_feeds_until_a_party_misses + -> ok + req FLT-004 +CASE wdog_feeds_until_a_party_misses outcome=passed asserts=122 skips=0 +ISR_STACK size=2048 used=280 +2 tests, 0 failed, 0 skipped, 467 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.json new file mode 100644 index 00000000..e06e0026 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 10, + "name": "wdog_board_hung_thread_resets_the_board", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:13Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdog_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_wdog_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdog_board.uf2": "cc7b4b7f14e01cf6891f917b5f833bf56451176ce133ab6599ff03e543fa4ba8" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog_board.elf", + "image_sha256": "23eb667e7ebb15dbd42c8325ff23b28cc57986681335bd218fea910856dd8b17", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:10Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.log new file mode 100644 index 00000000..f003d584 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdog_board.log @@ -0,0 +1,10 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog_board.elf sha256 23eb667e7ebb15dbd42c8325ff23b28cc57986681335bd218fea910856dd8b17 +EVIDENCE v1 suite=test_wdog_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdog_board_hung_thread_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdog_board_hung_thread_resets_the_board outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=188 +1 tests, 0 failed, 0 skipped, 11 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.json new file mode 100644 index 00000000..d62a969a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 13, + "name": "wdt_start_feed_and_cause", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "wdt_not_ready_and_misuse", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:05Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdt" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_wdt.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdt.uf2": "710b0c04c3aa2deab11febc6c668161705888d5a9dad82b97ba383491d4698d9" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt.elf", + "image_sha256": "7716889f5d71a5728f172771aa45f012ac0db08e74427991ffeccafaf06a3c3c", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:04Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.log new file mode 100644 index 00000000..2f922dde --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt.elf sha256 7716889f5d71a5728f172771aa45f012ac0db08e74427991ffeccafaf06a3c3c +EVIDENCE v1 suite=test_wdt config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdt_start_feed_and_cause + -> ok + req FLT-004 +CASE wdt_start_feed_and_cause outcome=passed asserts=13 skips=0 +TEST wdt_not_ready_and_misuse + fault checks that reset the board: 3 + -> ok + req FLT-004 +CASE wdt_not_ready_and_misuse outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=188 +2 tests, 0 failed, 0 skipped, 10 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.json new file mode 100644 index 00000000..109ae89e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "wdt_board_refuses_what_it_cannot_count", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "wdt_board_starved_resets_the_board", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:41:10Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdt_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_wdt_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdt_board.uf2": "ad4e483f58339d9898dd941c57bc34f4cc6f855d5a5b80688d41628839f1a7fc" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt_board.elf", + "image_sha256": "11e7f1f3d94adad79c47e64922ba7996d2a5813a2159e054e489ffb166b4997e", + "isr_stack": { + "size": 2048, + "used": 188 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:41:08Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.log new file mode 100644 index 00000000..b71d634c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_wdt_board.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt_board.elf sha256 11e7f1f3d94adad79c47e64922ba7996d2a5813a2159e054e489ffb166b4997e +EVIDENCE v1 suite=test_wdt_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdt_board_refuses_what_it_cannot_count + -> ok + req FLT-004 +CASE wdt_board_refuses_what_it_cannot_count outcome=passed asserts=3 skips=0 +TEST wdt_board_starved_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdt_board_starved_resets_the_board outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=188 +2 tests, 0 failed, 0 skipped, 11 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.json new file mode 100644 index 00000000..ce8087d9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.json @@ -0,0 +1,145 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 9, + "name": "workq_runs_items_in_fifo_order_on_its_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_resubmit_while_running_runs_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "workq_item_belongs_to_one_queue_at_a_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "workq_cancel_reports_pending_running_and_idle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "workq_flush_waits_for_items_queued_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_submit_from_isr_runs_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_thread_is_a_kernel_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_destroy_refuses_a_busy_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_system_queue_runs_items", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_runs_after_its_delay_and_schedule_is_idempotent", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_reschedule_replaces_the_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "dwork_rescheduled_during_its_expiry_keeps_the_new_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 19, + "name": "dwork_cancel_reports_pending_for_a_delay_and_a_queued_item", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dwork_cancel_sync_waits_for_a_running_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "workq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:38:33Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_workq" + }, + "exit": 0, + "fault_checks_by_reset": 6, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-clang/tests/conformance/test_workq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_workq.uf2": "a34d0d70e96ee541d937ecc3dc418574c8f10ddbe868f03d8cea9ef17f6c9fc0" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_workq.elf", + "image_sha256": "1173072cd38f701efa119aee51555d35871b03a294c2e08bca225ba281934d3b", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:38:30Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.log new file mode 100644 index 00000000..4edfa3bb --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-clang/test_workq.log @@ -0,0 +1,73 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_workq.elf sha256 1173072cd38f701efa119aee51555d35871b03a294c2e08bca225ba281934d3b +EVIDENCE v1 suite=test_workq config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST workq_runs_items_in_fifo_order_on_its_thread + -> ok + req KRN-WQ-001 KRN-WQ-002 KRN-WQ-005 KRN-WQ-009 +CASE workq_runs_items_in_fifo_order_on_its_thread outcome=passed asserts=9 skips=0 +TEST workq_resubmit_while_running_runs_again + -> ok + req KRN-WQ-005 +CASE workq_resubmit_while_running_runs_again outcome=passed asserts=5 skips=0 +TEST workq_item_belongs_to_one_queue_at_a_time + -> ok + req KRN-WQ-005 +CASE workq_item_belongs_to_one_queue_at_a_time outcome=passed asserts=12 skips=0 +TEST workq_cancel_reports_pending_running_and_idle + -> ok + req KRN-WQ-004 KRN-WQ-006 +CASE workq_cancel_reports_pending_running_and_idle outcome=passed asserts=17 skips=0 +TEST workq_flush_waits_for_items_queued_before_it + -> ok + req KRN-WQ-006 KRN-WAIT-012 +CASE workq_flush_waits_for_items_queued_before_it outcome=passed asserts=9 skips=0 +TEST workq_submit_from_isr_runs_at_exit + -> ok + req KRN-WQ-001 KRN-IRQ-010 +CASE workq_submit_from_isr_runs_at_exit outcome=passed asserts=5 skips=0 +TEST workq_thread_is_a_kernel_thread + fault checks that reset the board: 2 + -> ok + req KRN-WQ-009 KRN-WQ-010 +CASE workq_thread_is_a_kernel_thread outcome=passed asserts=8 skips=0 +TEST workq_destroy_refuses_a_busy_queue + fault checks that reset the board: 2 + -> ok + req KRN-OBJ-001 KRN-WQ-010 API-013 +CASE workq_destroy_refuses_a_busy_queue outcome=passed asserts=8 skips=0 +TEST workq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE workq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST workq_system_queue_runs_items + -> ok + req KRN-WQ-008 +CASE workq_system_queue_runs_items outcome=passed asserts=3 skips=0 +TEST dwork_runs_after_its_delay_and_schedule_is_idempotent + -> ok + req KRN-WQ-003 KRN-WQ-007 +CASE dwork_runs_after_its_delay_and_schedule_is_idempotent outcome=passed asserts=7 skips=0 +TEST dwork_reschedule_replaces_the_delay + -> ok + req KRN-WQ-007 +CASE dwork_reschedule_replaces_the_delay outcome=passed asserts=7 skips=0 +TEST dwork_rescheduled_during_its_expiry_keeps_the_new_delay + -> ok + req KRN-WQ-007 KRN-TIM-024 +CASE dwork_rescheduled_during_its_expiry_keeps_the_new_delay outcome=passed asserts=9 skips=0 +TEST dwork_cancel_reports_pending_for_a_delay_and_a_queued_item + fault checks that reset the board: 1 + -> ok + req KRN-WQ-007 KRN-WQ-004 +CASE dwork_cancel_reports_pending_for_a_delay_and_a_queued_item outcome=passed asserts=19 skips=0 +TEST dwork_cancel_sync_waits_for_a_running_handler + -> ok + req KRN-WQ-007 KRN-WQ-006 +CASE dwork_cancel_sync_waits_for_a_running_handler outcome=passed asserts=10 skips=0 +TEST workq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE workq_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=228 +16 tests, 0 failed, 0 skipped, 47 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.json new file mode 100644 index 00000000..edc129aa --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.json @@ -0,0 +1,65 @@ +{ + "baud": 115200, + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 62736, + "unit_hz": 150000000, + "units": 12547292 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 60754, + "unit_hz": 150000000, + "units": 12150964 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 17846, + "unit_hz": 150000000, + "units": 1784606 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 133133, + "unit_hz": 150000000, + "units": 6656653 + } + ], + "board": "pico2_w", + "cases": [], + "ended": "2026-11-13T05:37:55Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/benchmarks/bench_compare.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "bench_compare.uf2": "31dcfb64d0ceeec26ae6fe3be32170b62395282a1f1f3c47ad36a16479a0706d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_compare.elf", + "image_sha256": "feaaf0665bfa2594a98a6f07829f5e9606e4e483f80fc9bb3d4da5652f484a8c", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:53Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.log new file mode 100644 index 00000000..f1bc265e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_compare.log @@ -0,0 +1,7 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image bench_compare.elf sha256 feaaf0665bfa2594a98a6f07829f5e9606e4e483f80fc9bb3d4da5652f484a8c +bench_compare: EmbLinkRTOS 0.2.0 +BENCH v1 name=notify_handover units=12547292 ops=20000 per_op_x100=62736 unit_hz=150000000 os=emblink +BENCH v1 name=sem_handover units=12150964 ops=20000 per_op_x100=60754 unit_hz=150000000 os=emblink +BENCH v1 name=sem_give_take units=1784606 ops=10000 per_op_x100=17846 unit_hz=150000000 os=emblink +BENCH v1 name=isr_wake units=6656653 ops=5000 per_op_x100=133133 unit_hz=150000000 os=emblink +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.json new file mode 100644 index 00000000..3955e1c7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.json @@ -0,0 +1,42 @@ +{ + "baud": 115200, + "bench": [ + { + "avg_x100": 14337, + "checked": 1, + "max": 2513, + "min": 141, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 150000000 + } + ], + "board": "pico2_w", + "cases": [], + "ended": "2026-11-13T05:37:53Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/benchmarks/bench_irq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "bench_irq.uf2": "f826044c5497e0d76a20e0410a28a446d4da7a06707ec32bbf8396886ec1ed65" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_irq.elf", + "image_sha256": "e064bba938127b0a0faae131ee65be3f48765863c24400daaa00717a2ec86ec6", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:52Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.log new file mode 100644 index 00000000..374f4e81 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_irq.log @@ -0,0 +1,5 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image bench_irq.elf sha256 e064bba938127b0a0faae131ee65be3f48765863c24400daaa00717a2ec86ec6 +bench irq pend to handler: min 141 max 2513 avg x100 14337 cycle-units over 1000 runs +BENCH v1 name=irq_pend_to_handler min=141 max=2513 avg_x100=14337 ops=1000 unit_hz=150000000 checked=1 +meta: board pico2_w, compiler gcc, profile base, checked 1, cycle unit hz 150000000 +BENCH_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.json new file mode 100644 index 00000000..8f08e6c9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.json @@ -0,0 +1,41 @@ +{ + "baud": 115200, + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 61998, + "unit_hz": 150000000, + "units": 12399610 + } + ], + "board": "pico2_w", + "cases": [], + "ended": "2026-11-13T05:37:52Z", + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/benchmarks/bench_switch.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "bench_switch.uf2": "19cebd1bf9d6eebfe849ffdde2e9c488c82d38ca429e807bdd9bea2fbfb1157d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "bench_switch.elf", + "image_sha256": "c2cbb624ae019228044752f5652fc57ea9ed7158605c283243d068db09a2a547", + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:50Z" +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.log new file mode 100644 index 00000000..abda7b27 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/bench_switch.log @@ -0,0 +1,5 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image bench_switch.elf sha256 c2cbb624ae019228044752f5652fc57ea9ed7158605c283243d068db09a2a547 +bench notify round trip (2 switches): total 12399610 cycle-units over 20000 ops; per op x100 = 61998 +BENCH v1 name=notify_handover units=12399610 ops=20000 per_op_x100=61998 unit_hz=150000000 checked=1 +meta: board pico2_w, compiler gcc, profile base, checked 1, cycle unit hz 150000000 +BENCH_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/index.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/index.json new file mode 100644 index 00000000..100c63aa --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/index.json @@ -0,0 +1,978 @@ +{ + "board": "pico2_w", + "build": "checked (GCC 14.2.1, 150 MHz)", + "configuration": "9461e3c42192b75e", + "date": "2026-11-13", + "format": "emb-hil-archive v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "images": [ + { + "bench": [ + { + "name": "notify_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 62736, + "unit_hz": 150000000, + "units": 12547292 + }, + { + "name": "sem_handover", + "ops": 20000, + "os": "emblink", + "per_op_x100": 60754, + "unit_hz": 150000000, + "units": 12150964 + }, + { + "name": "sem_give_take", + "ops": 10000, + "os": "emblink", + "per_op_x100": 17846, + "unit_hz": 150000000, + "units": 1784606 + }, + { + "name": "isr_wake", + "ops": 5000, + "os": "emblink", + "per_op_x100": 133133, + "unit_hz": 150000000, + "units": 6656653 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_compare.uf2": "31dcfb64d0ceeec26ae6fe3be32170b62395282a1f1f3c47ad36a16479a0706d" + }, + "image": "bench_compare.elf", + "image_sha256": "feaaf0665bfa2594a98a6f07829f5e9606e4e483f80fc9bb3d4da5652f484a8c", + "isr_stack": null, + "log": "bench_compare.log", + "outcome": "passed", + "started": "2026-11-13T05:37:53Z" + }, + { + "bench": [ + { + "avg_x100": 14337, + "checked": 1, + "max": 2513, + "min": 141, + "name": "irq_pend_to_handler", + "ops": 1000, + "unit_hz": 150000000 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_irq.uf2": "f826044c5497e0d76a20e0410a28a446d4da7a06707ec32bbf8396886ec1ed65" + }, + "image": "bench_irq.elf", + "image_sha256": "e064bba938127b0a0faae131ee65be3f48765863c24400daaa00717a2ec86ec6", + "isr_stack": null, + "log": "bench_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:37:52Z" + }, + { + "bench": [ + { + "checked": 1, + "name": "notify_handover", + "ops": 20000, + "per_op_x100": 61998, + "unit_hz": 150000000, + "units": 12399610 + } + ], + "cases": 0, + "cases_passed": 0, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "bench_switch.uf2": "19cebd1bf9d6eebfe849ffdde2e9c488c82d38ca429e807bdd9bea2fbfb1157d" + }, + "image": "bench_switch.elf", + "image_sha256": "c2cbb624ae019228044752f5652fc57ea9ed7158605c283243d068db09a2a547", + "isr_stack": null, + "log": "bench_switch.log", + "outcome": "passed", + "started": "2026-11-13T05:37:50Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_cond.uf2": "623cbe62c7a40fdfa77d99461ae9ee99bf79d9b68181748c1e995fc09a3e35d0" + }, + "image": "test_cond.elf", + "image_sha256": "3ff3fcf449190566d99ea099bb33e0a82943de697bb06b36b589b6a70b197330", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_cond.log", + "outcome": "passed", + "started": "2026-11-13T05:34:39Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_crash.uf2": "ac3098e9c5cbd3c70f9ded4d26d174d9c4c6602e7c65c8bf9168ea4bd112b46a" + }, + "image": "test_crash.elf", + "image_sha256": "837b98711c2ebcbce361b8c31ba64248adce0cc118310d024d1bbc342fc7d531", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_crash.log", + "outcome": "passed", + "started": "2026-11-13T05:37:39Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_hw.uf2": "0690398d66e84103bef7502297e191e092c5d731d6981932f4803c5fe09fcb45" + }, + "image": "test_crash_hw.elf", + "image_sha256": "26910b4c124c606821d994661652a18c38e1d98796d7155683e141a8bc2d5f1f", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_crash_hw.log", + "outcome": "passed", + "started": "2026-11-13T05:37:43Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_crash_reset.uf2": "e42ee316a82768432a07d6640c9a973860b04d30b55530f50c0bc6f2e9999a38" + }, + "image": "test_crash_reset.elf", + "image_sha256": "34cee9bfc881ea21ddc8b022b4b6a67e8d354d6fbbdbc09b000a7c3863d10abd", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_crash_reset.log", + "outcome": "passed", + "started": "2026-11-13T05:37:41Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_debug_descriptor.uf2": "2bfdab8fa633d3335793236a296ecc1c6a33426ae19d9b7faa201e9c3fd72787" + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "57a94e2d944dc64f694659df791f8ed63177c1b0e12ba89e70629e25e9e45d4a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_debug_descriptor.log", + "outcome": "passed", + "started": "2026-11-13T05:37:46Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_device.uf2": "22f18e0da11a8245dd16aeb0d6c7691298ad9b69adfb9e86877a43a51b2d24c7" + }, + "image": "test_device.elf", + "image_sha256": "cc0e9c0a5f977cb8522310ec82d28bd83721ea34114af04d6a817cd10869dd47", + "isr_stack": { + "size": 2048, + "used": 252 + }, + "log": "test_device.log", + "outcome": "passed", + "started": "2026-11-13T05:34:52Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_dma.uf2": "ecedba12a3da130b7bee70ff1ccfdcbe0b00e1396b9e7f6241c2909681fc1454" + }, + "image": "test_dma.elf", + "image_sha256": "258d82dd8dad0fc92a9f4f32e20162400a943045ec1ccd8a39f2cde68a7bcd8b", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_dma.log", + "outcome": "passed", + "started": "2026-11-13T05:35:02Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_entropy.uf2": "802253c60dcd8790a13a2c571168dd71da0edba2f47f5f9fd8f52daa5695a811" + }, + "image": "test_entropy.elf", + "image_sha256": "8db9e18ec7b211f02afc594e980017218198a1c96641a91b98bf61cebfd69d7f", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_entropy.log", + "outcome": "passed", + "started": "2026-11-13T05:35:03Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_entropy_board.uf2": "dc992791a79e91d9795c6ff0ea09b30f64ba706b58c9df3e68d839fd549a9f54" + }, + "image": "test_entropy_board.elf", + "image_sha256": "6e179cbd34048913ae96631a1747b78761777ab1aa6f793658e36fa36caa9f81", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_entropy_board.log", + "outcome": "passed", + "started": "2026-11-13T05:35:05Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_event.uf2": "ce01d07c2bbf268f556c8c1f78a1eb241b8652c7ecd741d547f30641d5359a4d" + }, + "image": "test_event.elf", + "image_sha256": "b8822df216607e7c6a8dfdef5fbd55a654ab83f4551b3d1177ce6b146c1a759e", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_event.log", + "outcome": "passed", + "started": "2026-11-13T05:34:37Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_fault.uf2": "2f6b7aa2cf018b2510b072c97e125cd93ea7ac39364fa1af6f31ed2db2fb43ec" + }, + "image": "test_fault.elf", + "image_sha256": "73bcdd6b28015408184019c6ebc30705567f1fa0c6a532c157130b9e0782feec", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_fault.log", + "outcome": "passed", + "started": "2026-11-13T05:34:11Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_first_execution.uf2": "5aa128fdafd8332b88d7556539db5614fc0fbed89ab4388ee2846b990823a54a" + }, + "image": "test_first_execution.elf", + "image_sha256": "73efab940255ae22dd0e29b63d15e2d0c814dfd903c4a0d06f6dbc9bcbcd8c2a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_first_execution.log", + "outcome": "passed", + "started": "2026-11-13T05:37:37Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_flash.uf2": "535830192363160496a2370a715b383929d51dd9eae1a706236087976ccae744" + }, + "image": "test_flash.elf", + "image_sha256": "53cd46054dd9f6b23b768c96bfcf4fb448ebd87bf3e80320fa60c081e195023a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_flash.log", + "outcome": "passed", + "started": "2026-11-13T05:37:12Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_flash_board.uf2": "a6496e398cee370bc3cb516b3222b65a5ed6d5256994ffbd9348b65e52804ebe" + }, + "image": "test_flash_board.elf", + "image_sha256": "8e7281f47efa2cab8a533ea95e0557b86a56b2a4d59b1cf4efc4023e1bfa864b", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_flash_board.log", + "outcome": "passed", + "started": "2026-11-13T05:37:14Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_fpu.uf2": "73ec908d80aab1a2895642a9c935994583df0ce2e96075f9c1ea4143fa7d901c" + }, + "image": "test_fpu.elf", + "image_sha256": "0e93e73f799df4e9164f76132840523513d4e68607f215a321d6ce89dd33d26d", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_fpu.log", + "outcome": "passed", + "started": "2026-11-13T05:37:48Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_frame.uf2": "ba8550e70f74aa113ae1e9e961948f072611e865838c31bfc9b736b92d68221b" + }, + "image": "test_frame.elf", + "image_sha256": "521a2431361b8dd9bf6caf607ac29b99a71ffbe7d4084f35fdd8d79812154d8a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_frame.log", + "outcome": "passed", + "started": "2026-11-13T05:34:48Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 10, + "flashed_sha256": { + "test_gpio.uf2": "6e163e3418e53f5db73940d3f560919a1a150f4174f80974a96854695f593c12" + }, + "image": "test_gpio.elf", + "image_sha256": "c2e1c23185ea206ead32645e145c57c83ade73e52b16efa01f2790721dbbd6cc", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_gpio.log", + "outcome": "passed", + "started": "2026-11-13T05:35:00Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 12, + "flashed_sha256": { + "test_i2c.uf2": "ba9dc3ac87bfb121576c4b94dca9336cf9664d03c96beab9c1265b8f8a32c68e" + }, + "image": "test_i2c.elf", + "image_sha256": "2137c6719cd35e3ca58d070b535edd801ce19198e7c8f9175d1b559ce58a7177", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_i2c.log", + "outcome": "passed", + "started": "2026-11-13T05:37:29Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_i2c_loop.uf2": "df6bea5851ee37f5b45d34397f4b8ac41803dbb92412dc1b2cd97d6d423b3e04" + }, + "image": "test_i2c_loop.elf", + "image_sha256": "a3048e7eeea96848307404ac10baad43ef4b71f4623b2ba8903f8f9aae2b7e57", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_i2c_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:37:31Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_irq.uf2": "4cde7f8eda2f981d9eb106b6caa9bcc8fca8fdff31760a155a3779d60fc4b7dd" + }, + "image": "test_irq.elf", + "image_sha256": "d6e0ea220c10ad98e1db9254d7e4555bbf71755605d68973713d03db5ae09dcc", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_irq.log", + "outcome": "passed", + "started": "2026-11-13T05:34:15Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_irq_priority.uf2": "0c5337271253300f4ea864c7e5dd03e1320636068bd1840626c898735c034fff" + }, + "image": "test_irq_priority.elf", + "image_sha256": "fb4eeefc2fce3cea4aebb48a089c66a0a942875fa3ab84d816e99c5580e6c89a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_irq_priority.log", + "outcome": "passed", + "started": "2026-11-13T05:34:17Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_isr_stack.uf2": "4204209e080214ee6f71126c8fc3da37bf40b5929ad86a97b8f2d1604fb48592" + }, + "image": "test_isr_stack.elf", + "image_sha256": "eaae1261fa14c9db0e19dd1cf6af7dcc6e55d9c41508ba5fa069cef3ffe77e63", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_isr_stack.log", + "outcome": "passed", + "started": "2026-11-13T05:34:19Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_log.uf2": "12fb134a25306c0cfaca693addf4969f393f282521f2118a4affb9389bb1ff0d" + }, + "image": "test_log.elf", + "image_sha256": "321c9394e101dcf44abd9ffb7c2a5682657fb57fe6d6448f9ded541be539045d", + "isr_stack": { + "size": 2048, + "used": 236 + }, + "log": "test_log.log", + "outcome": "passed", + "started": "2026-11-13T05:34:50Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_msgq.uf2": "d6ec32bb827ca93313da26564ad418ebca67661d285935878ec2f64e05552192" + }, + "image": "test_msgq.elf", + "image_sha256": "fd227a96bb8dcbfeedbbe0d11a42c8b8f259faf66cfd75b18f8cb733f24d1a30", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_msgq.log", + "outcome": "passed", + "started": "2026-11-13T05:34:41Z" + }, + { + "bench": [], + "cases": 15, + "cases_passed": 15, + "fault_checks_by_reset": 11, + "flashed_sha256": { + "test_mutex.uf2": "7f0e25d8581efa9997d6816b7a27d6fca4c939eb6727f19ba53b091e9c0c7393" + }, + "image": "test_mutex.elf", + "image_sha256": "b964ad83d3c0da0a1f0d46014c38f6ee60daf618a7ec7bbc84e6d719e61ac8be", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_mutex.log", + "outcome": "passed", + "started": "2026-11-13T05:34:35Z" + }, + { + "bench": [], + "cases": 10, + "cases_passed": 10, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_notify.uf2": "4b9a9a8a1a969c1b014e6cf8b0fb9a72c7c9d0d821ee4345aef75955a8e37972" + }, + "image": "test_notify.elf", + "image_sha256": "3e3685187f6494529e412850c342230f193719cd636627cdcee02ad6fd0af312", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_notify.log", + "outcome": "passed", + "started": "2026-11-13T05:34:31Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_rtc.uf2": "ffc229a6886489e416f70b882dd41f4b9302e06a516f91ebe0e88873a2536161" + }, + "image": "test_rtc.elf", + "image_sha256": "20262338845b494ac6337854e606ee1328a90fa43721ba03e77d1801c38b4199", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_rtc.log", + "outcome": "passed", + "started": "2026-11-13T05:37:06Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_rtc_board.uf2": "57f92dff34d962a76652b3d994218634e85818c7a7d729e717cd78ff2a5269e5" + }, + "image": "test_rtc_board.elf", + "image_sha256": "11136f33644b4b51d47c5007b30477efada1e71efd74a97198d1ba72ed425273", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_rtc_board.log", + "outcome": "passed", + "started": "2026-11-13T05:37:08Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_sched.uf2": "d3002d511d30ca3a775cd67aa71f8d1ecf02567143851519ad400457d6024e50" + }, + "image": "test_sched.elf", + "image_sha256": "12888c30cde6b0347610d32414aaf4b9a2e4d33e9a5dc20f4267fddd6286f5cc", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_sched.log", + "outcome": "passed", + "started": "2026-11-13T05:34:13Z" + }, + { + "bench": [], + "cases": 12, + "cases_passed": 12, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_sem.uf2": "c9ab3d5c4800521c29238bee9f218fc1639a604a7cbd8af08d26deb66f92a220" + }, + "image": "test_sem.elf", + "image_sha256": "615641c7d01eee19a95dc510a911be2a91442fb1d29048a98114d5a7febe3191", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_sem.log", + "outcome": "passed", + "started": "2026-11-13T05:34:33Z" + }, + { + "bench": [], + "cases": 3, + "cases_passed": 3, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_smoke.uf2": "1d9bb7e9af787a560779322b082d2672d2f125dec4a279b7e0f1b9f5d0e353d7" + }, + "image": "test_smoke.elf", + "image_sha256": "76b868b24fdd9a812f2322c0c58c68698a5cc4dc2b9beaa83484ae13307a8315", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_smoke.log", + "outcome": "passed", + "started": "2026-11-13T05:34:10Z" + }, + { + "bench": [], + "cases": 9, + "cases_passed": 9, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_spi.uf2": "bc80ce46f6cae889c8bddce89eff6028043600df01ea0c873e2a8fa88b554d83" + }, + "image": "test_spi.elf", + "image_sha256": "7914acc52a54102da1e4523769990671b68bb6c220b2a1e164c28342baa0e952", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_spi.log", + "outcome": "passed", + "started": "2026-11-13T05:37:33Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_spi_loop.uf2": "8ea8ca8d882e5e082c0604b10643dff4be8cfbd4a42cf2d8895bd0b8ac79799f" + }, + "image": "test_spi_loop.elf", + "image_sha256": "c36c23b16e0071391e21d71c88284b05117f6c456e969b7decc14f8ef28751ee", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_spi_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:37:35Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_stack_limit.uf2": "ac4034c9e1ff4822028bf7eb3f96745ab3dba2445d2201d4c089b70fd23ae488" + }, + "image": "test_stack_limit.elf", + "image_sha256": "ae205ba7916d95c2ebec2d273f453d4a68596b6489f54bc21cdad2afc1d36790", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_stack_limit.log", + "outcome": "passed", + "started": "2026-11-13T05:37:44Z" + }, + { + "bench": [], + "cases": 11, + "cases_passed": 11, + "fault_checks_by_reset": 8, + "flashed_sha256": { + "test_thread.uf2": "219ca6524fb2711f428fbf3b3c758debf3cb25206697c87d8766102a19712d92" + }, + "image": "test_thread.elf", + "image_sha256": "247b56c3614147b6bef72be3edc09b12fbaa361d3168d08f8aec6cad6547fe6d", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_thread.log", + "outcome": "passed", + "started": "2026-11-13T05:34:21Z" + }, + { + "bench": [], + "cases": 5, + "cases_passed": 5, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_thread_identity.uf2": "b2d7a2c5077804f070f44e81d8733230f1c4cff9d12c80b460cd8f14ec32b89c" + }, + "image": "test_thread_identity.elf", + "image_sha256": "0502e791217fca6824ebf47a589ec26e6de843e36d05aca08bac44bec60d8640", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_thread_identity.log", + "outcome": "passed", + "started": "2026-11-13T05:34:25Z" + }, + { + "bench": [], + "cases": 6, + "cases_passed": 6, + "fault_checks_by_reset": 2, + "flashed_sha256": { + "test_thread_join.uf2": "24f5d5498cbfaf98f3e0476328283b2ac2c794738af91ab77c0fb6edde124516" + }, + "image": "test_thread_join.elf", + "image_sha256": "c083f403fd004231612cf024db0b72bb110054042911998641969a860181f878", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_thread_join.log", + "outcome": "passed", + "started": "2026-11-13T05:34:23Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_time.uf2": "5224bfecaa7296107c36e1d87c7ff01ce6696a8d76fa1871d1fbe6529b5b7de8" + }, + "image": "test_time.elf", + "image_sha256": "ee7779030f24f40d42d23a497de5205e544e72579080885bc19a61d30c098141", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_time.log", + "outcome": "passed", + "started": "2026-11-13T05:34:27Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_timer.uf2": "e57be71de2b8d7ee67297a478a52e2a23b6f17793f11b215d39126bc7d2b61cb" + }, + "image": "test_timer.elf", + "image_sha256": "a655f7ea29efe85a1ba3f06972c1354a34c3fc5a58951fd553cecca209aa1861", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_timer.log", + "outcome": "passed", + "started": "2026-11-13T05:34:46Z" + }, + { + "bench": [], + "cases": 8, + "cases_passed": 8, + "fault_checks_by_reset": 5, + "flashed_sha256": { + "test_uart.uf2": "0a23680c0b2abb52d5cb07345305dbab92a3d7206038dc35f61ea46e9eeed181" + }, + "image": "test_uart.elf", + "image_sha256": "5480ac8614d8bb07b515391ab89640256a1ab8205739fd7b7bb4a85c4adcf823", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_uart.log", + "outcome": "passed", + "started": "2026-11-13T05:34:54Z" + }, + { + "bench": [], + "cases": 4, + "cases_passed": 4, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_board.uf2": "3313d307c3b3303b20ee4f896c674a76baef6eb2b974fcb0da46ab9c1798bf98" + }, + "image": "test_uart_board.elf", + "image_sha256": "70a5f250879615d3abe7eedad4e7e66ae5e26b80986be5f25b809821a8ea6ee0", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "log": "test_uart_board.log", + "outcome": "passed", + "started": "2026-11-13T05:34:56Z" + }, + { + "bench": [], + "cases": 7, + "cases_passed": 7, + "fault_checks_by_reset": 0, + "flashed_sha256": { + "test_uart_loop.uf2": "71667d147d23b2eb423226bb1c96741c3239bf39b7b455a263a0290f4329a2ec" + }, + "image": "test_uart_loop.elf", + "image_sha256": "594e29b279202bb07d90f07b94d45a1f78f73b8a7275a896fb139be63e59ed12", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "log": "test_uart_loop.log", + "outcome": "passed", + "started": "2026-11-13T05:34:58Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wallclock.uf2": "7c48af8d6a64e54e525926f1d1a1d6ccd8765d5929fa4654f17b269a0b8a52d7" + }, + "image": "test_wallclock.elf", + "image_sha256": "eaeb084952ff99c966dde01a1fe428e02f37e3e33dc34e7e13f4b85c78ea0e0b", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_wallclock.log", + "outcome": "passed", + "started": "2026-11-13T05:34:29Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 4, + "flashed_sha256": { + "test_wdog.uf2": "498f603a54c8683b0e67af3467ad688e010541a1f76459c089ea807617cac125" + }, + "image": "test_wdog.elf", + "image_sha256": "a3bccc0495356dba366b8d1463ab5a68079d78e6f3f59def15103b7bf399acb3", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_wdog.log", + "outcome": "passed", + "started": "2026-11-13T05:37:21Z" + }, + { + "bench": [], + "cases": 1, + "cases_passed": 1, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdog_board.uf2": "62d0f39b545953fe7ff485750815c58a43674e80b21c3215737cd32a6a59b767" + }, + "image": "test_wdog_board.elf", + "image_sha256": "2b35dbd13537b8f816da43f55e3ac0ef3257b8a734f8984668d1eeab616cd0c4", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_wdog_board.log", + "outcome": "passed", + "started": "2026-11-13T05:37:26Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 3, + "flashed_sha256": { + "test_wdt.uf2": "c24ea0912573c0d1b528a3e93cb87daef62704258acd881f5c4c8aee8768cf3d" + }, + "image": "test_wdt.elf", + "image_sha256": "c1aa435afe3aa53070e7510c7447c1630a078c8f77aeffa0543528e1d2413139", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_wdt.log", + "outcome": "passed", + "started": "2026-11-13T05:37:19Z" + }, + { + "bench": [], + "cases": 2, + "cases_passed": 2, + "fault_checks_by_reset": 1, + "flashed_sha256": { + "test_wdt_board.uf2": "57a77d4cc04b7444ff365c890c79dd72d5e2b631b5350323ae50b67723baee94" + }, + "image": "test_wdt_board.elf", + "image_sha256": "5edcbe909de54ac03b4a7cba8eb8fc732dc464dc66b5609469cb8470696f9823", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "log": "test_wdt_board.log", + "outcome": "passed", + "started": "2026-11-13T05:37:24Z" + }, + { + "bench": [], + "cases": 16, + "cases_passed": 16, + "fault_checks_by_reset": 6, + "flashed_sha256": { + "test_workq.uf2": "fb9741ac235e8e4ef05ae174065ef033f378ac12a7a1ab1e5a00198fd90654c3" + }, + "image": "test_workq.elf", + "image_sha256": "7e44aeba619d382de93805afc36c072159582b77d223c456a48d930059a328c5", + "isr_stack": { + "size": 2048, + "used": 252 + }, + "log": "test_workq.log", + "outcome": "passed", + "started": "2026-11-13T05:34:43Z" + } + ], + "isr_stack_max_used": 252, + "passed": 51, + "preset": "cm33-pico2w-hil", + "total": 51 +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.json new file mode 100644 index 00000000..d3319e48 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.json @@ -0,0 +1,109 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 2, + "name": "cond_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "cond_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_wait_requires_single_ownership", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "cond_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "cond_destroy_aborts_waiters_which_relock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "cond_cancel_returns_with_the_mutex_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "cond_relock_after_timeout_waits_for_the_mutex", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "cond_signal_is_not_stored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "cond_broadcast_wakes_all_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "cond_signal_wakes_one_waiter_which_owns_the_mutex", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:41Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_cond" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_cond.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_cond.uf2": "623cbe62c7a40fdfa77d99461ae9ee99bf79d9b68181748c1e995fc09a3e35d0" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_cond.elf", + "image_sha256": "3ff3fcf449190566d99ea099bb33e0a82943de697bb06b36b589b6a70b197330", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:39Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.log new file mode 100644 index 00000000..08002c8f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_cond.log @@ -0,0 +1,48 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_cond.elf sha256 3ff3fcf449190566d99ea099bb33e0a82943de697bb06b36b589b6a70b197330 +EVIDENCE v1 suite=test_cond config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST cond_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE cond_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +TEST cond_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE cond_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST cond_wait_requires_single_ownership + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-030 API-013 +CASE cond_wait_requires_single_ownership outcome=passed asserts=12 skips=0 +TEST cond_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE cond_destroy_with_waiters_is_misuse outcome=passed asserts=11 skips=0 +TEST cond_destroy_aborts_waiters_which_relock + -> ok + req KRN-OBJ-001 KRN-SYNC-030 +CASE cond_destroy_aborts_waiters_which_relock outcome=passed asserts=9 skips=0 +TEST cond_cancel_returns_with_the_mutex_owned + -> ok + req KRN-SYNC-030 KRN-WAIT-017 +CASE cond_cancel_returns_with_the_mutex_owned outcome=passed asserts=10 skips=0 +TEST cond_relock_after_timeout_waits_for_the_mutex + -> ok + req KRN-SYNC-030 +CASE cond_relock_after_timeout_waits_for_the_mutex outcome=passed asserts=12 skips=0 +TEST cond_signal_is_not_stored + -> ok + req KRN-SYNC-030 +CASE cond_signal_is_not_stored outcome=passed asserts=13 skips=0 +TEST cond_broadcast_wakes_all_in_priority_order + -> ok + req KRN-SYNC-030 KRN-WAIT-013 +CASE cond_broadcast_wakes_all_in_priority_order outcome=passed asserts=18 skips=0 +TEST cond_signal_wakes_one_waiter_which_owns_the_mutex + -> ok + req KRN-SYNC-030 KRN-WAIT-001 +CASE cond_signal_wakes_one_waiter_which_owns_the_mutex outcome=passed asserts=17 skips=0 +ISR_STACK size=2048 used=216 +10 tests, 0 failed, 0 skipped, 105 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.json new file mode 100644 index 00000000..6ec7673c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.json @@ -0,0 +1,67 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 1, + "name": "crash_record_get_refuses_null", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "crash_record_corruption_is_ignored", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 38, + "name": "crash_record_round_trip", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:41Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_crash" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_crash.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_crash.uf2": "ac3098e9c5cbd3c70f9ded4d26d174d9c4c6602e7c65c8bf9168ea4bd112b46a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash.elf", + "image_sha256": "837b98711c2ebcbce361b8c31ba64248adce0cc118310d024d1bbc342fc7d531", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:39Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.log new file mode 100644 index 00000000..cea2a8f2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash.log @@ -0,0 +1,19 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash.elf sha256 837b98711c2ebcbce361b8c31ba64248adce0cc118310d024d1bbc342fc7d531 +EVIDENCE v1 suite=test_crash config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_get_refuses_null + fault checks that reset the board: 1 + -> ok + req OBS-016 API-015 +CASE crash_record_get_refuses_null outcome=passed asserts=1 skips=0 +TEST crash_record_corruption_is_ignored + -> ok + req OBS-016 +CASE crash_record_corruption_is_ignored outcome=passed asserts=6 skips=0 +TEST crash_record_round_trip +EMB_CRASH 454d424301005c000e939c714439e2c4f5c4000320e5c8ac52f3c79f302e322e30000000170000000000000001000000050202012900000003000000341200007856000000000000bc7a00000000000000000000000000005f199d0b + -> ok + req OBS-016 API-017 +CASE crash_record_round_trip outcome=passed asserts=38 skips=0 +ISR_STACK size=2048 used=216 +3 tests, 0 failed, 0 skipped, 50 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.json new file mode 100644 index 00000000..77c8d870 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 9, + "name": "crash_record_keeps_a_hardware_fault", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:44Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_crash_hw" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_crash_hw.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_crash_hw.uf2": "0690398d66e84103bef7502297e191e092c5d731d6981932f4803c5fe09fcb45" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_hw.elf", + "image_sha256": "26910b4c124c606821d994661652a18c38e1d98796d7155683e141a8bc2d5f1f", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:43Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.log new file mode 100644 index 00000000..6a1534cc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_hw.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_hw.elf sha256 26910b4c124c606821d994661652a18c38e1d98796d7155683e141a8bc2d5f1f +EVIDENCE v1 suite=test_crash_hw config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_keeps_a_hardware_fault +crash_record_keeps_a_hardware_fault: first boot, trapping +EVIDENCE v1 suite=test_crash_hw config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_keeps_a_hardware_fault +EMB_CRASH 454d424301008c000e939c714439e2c4f5c4000320e5c8ac52f3c79f302e322e300000000d00000000000000020000000a0006000000000000000000000001008a0100108b010010f81b0020000000000000000004080000000001000000000034ed00e038ed00e0fd0200100a0000000000007c680b0020000000008b0100108a01001000000061ac9c01ae + -> ok + req OBS-016 KRN-IRQ-030 +CASE crash_record_keeps_a_hardware_fault outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=216 +1 tests, 0 failed, 0 skipped, 45 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.json new file mode 100644 index 00000000..caa04da9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "crash_record_survives_reset", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:42Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_crash_reset" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_crash_reset.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_crash_reset.uf2": "e42ee316a82768432a07d6640c9a973860b04d30b55530f50c0bc6f2e9999a38" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_crash_reset.elf", + "image_sha256": "34cee9bfc881ea21ddc8b022b4b6a67e8d354d6fbbdbc09b000a7c3863d10abd", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:41Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.log new file mode 100644 index 00000000..7619dd1c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_crash_reset.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_crash_reset.elf sha256 34cee9bfc881ea21ddc8b022b4b6a67e8d354d6fbbdbc09b000a7c3863d10abd +EVIDENCE v1 suite=test_crash_reset config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_survives_reset +crash_record_survives_reset: first boot, faulting +EVIDENCE v1 suite=test_crash_reset config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST crash_record_survives_reset +EMB_CRASH 454d424301005c000e939c714439e2c4f5c4000320e5c8ac52f3c79f302e322e300000000c00000000000000020000000b00ed5e000000000000000000000000a301001000000000000000000000000000000000000000007d4dc120 + -> ok + req OBS-016 KRN-IRQ-030 ARCH-AVR-008 +CASE crash_record_survives_reset outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=216 +1 tests, 0 failed, 0 skipped, 37 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.json new file mode 100644 index 00000000..951eb7c0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 82, + "name": "debug_descriptor_reads_thread_states", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "debug_descriptor_isr_stack", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "debug_descriptor_finds_the_running_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "debug_descriptor_header", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:48Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_debug_descriptor" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_debug_descriptor.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_debug_descriptor.uf2": "2bfdab8fa633d3335793236a296ecc1c6a33426ae19d9b7faa201e9c3fd72787" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_debug_descriptor.elf", + "image_sha256": "57a94e2d944dc64f694659df791f8ed63177c1b0e12ba89e70629e25e9e45d4a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:46Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.log new file mode 100644 index 00000000..f4a619ba --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_debug_descriptor.log @@ -0,0 +1,21 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_debug_descriptor.elf sha256 57a94e2d944dc64f694659df791f8ed63177c1b0e12ba89e70629e25e9e45d4a +EVIDENCE v1 suite=test_debug_descriptor config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST debug_descriptor_reads_thread_states + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_reads_thread_states outcome=passed asserts=82 skips=0 +TEST debug_descriptor_isr_stack + -> ok + req PORT-012 +CASE debug_descriptor_isr_stack outcome=passed asserts=2 skips=0 +TEST debug_descriptor_finds_the_running_thread + -> ok + req OBS-008 +CASE debug_descriptor_finds_the_running_thread outcome=passed asserts=7 skips=0 +TEST debug_descriptor_header + -> ok + req OBS-008 PORT-012 +CASE debug_descriptor_header outcome=passed asserts=12 skips=0 +ISR_STACK size=2048 used=216 +4 tests, 0 failed, 0 skipped, 58 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.json new file mode 100644 index 00000000..caaca41a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.json @@ -0,0 +1,145 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 47, + "name": "drv_status_codes_are_named_in_their_ranges", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "device_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "drv_setters_ignore_a_missing_request", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 23, + "name": "device_optional_operations", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 33, + "name": "device_board_devices_ready_in_dependency_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_wait_returns_the_result_or_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_cancel_queued_and_running_requests_complete_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "drv_lanes_run_independently", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "drv_queue_is_first_in_first_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "drv_completion_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "drv_request_completes_from_the_interrupt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "drv_submit_refused_unless_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "device_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "device_list_initializes_past_a_failure", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "device_on_a_failed_dependency_fails_without_its_driver", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "device_init_reaches_ready_or_failed", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:54Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_device" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_device.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_device.uf2": "22f18e0da11a8245dd16aeb0d6c7691298ad9b69adfb9e86877a43a51b2d24c7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_device.elf", + "image_sha256": "cc0e9c0a5f977cb8522310ec82d28bd83721ea34114af04d6a817cd10869dd47", + "isr_stack": { + "size": 2048, + "used": 252 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:52Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.log new file mode 100644 index 00000000..a8e48f0b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_device.log @@ -0,0 +1,71 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_device.elf sha256 cc0e9c0a5f977cb8522310ec82d28bd83721ea34114af04d6a817cd10869dd47 +EVIDENCE v1 suite=test_device config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST drv_status_codes_are_named_in_their_ranges + -> ok + req DRV-008 +CASE drv_status_codes_are_named_in_their_ranges outcome=passed asserts=47 skips=0 +TEST device_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-002 DRV-004 +CASE device_misuse_faults outcome=passed asserts=11 skips=0 +TEST drv_setters_ignore_a_missing_request + -> ok + req DRV-005 +CASE drv_setters_ignore_a_missing_request outcome=passed asserts=3 skips=0 +TEST device_optional_operations + -> ok + req DRV-002 DRV-006 PWR-002 +CASE device_optional_operations outcome=passed asserts=23 skips=0 +TEST device_board_devices_ready_in_dependency_order + -> ok + req DRV-001 DRV-002 +CASE device_board_devices_ready_in_dependency_order outcome=passed asserts=33 skips=0 +TEST drv_wait_returns_the_result_or_times_out + -> ok + req DRV-004 DRV-006 +CASE drv_wait_returns_the_result_or_times_out outcome=passed asserts=8 skips=0 +TEST drv_cancel_queued_and_running_requests_complete_once + -> ok + req DRV-006 +CASE drv_cancel_queued_and_running_requests_complete_once outcome=passed asserts=15 skips=0 +TEST drv_lanes_run_independently + fault checks that reset the board: 1 + -> ok + req DRV-004 DRV-006 +CASE drv_lanes_run_independently outcome=passed asserts=15 skips=0 +TEST drv_queue_is_first_in_first_out + -> ok + req DRV-004 +CASE drv_queue_is_first_in_first_out outcome=passed asserts=8 skips=0 +TEST drv_completion_targets + -> ok + req DRV-005 +CASE drv_completion_targets outcome=passed asserts=13 skips=0 +TEST drv_request_completes_from_the_interrupt + -> ok + req DRV-004 DRV-005 +CASE drv_request_completes_from_the_interrupt outcome=passed asserts=6 skips=0 +TEST drv_submit_refused_unless_ready + -> ok + req DRV-003 +CASE drv_submit_refused_unless_ready outcome=passed asserts=2 skips=0 +TEST device_suspend_and_resume + -> ok + req DRV-002 PWR-002 +CASE device_suspend_and_resume outcome=passed asserts=10 skips=0 +TEST device_list_initializes_past_a_failure + -> ok + req DRV-001 DRV-003 +CASE device_list_initializes_past_a_failure outcome=passed asserts=4 skips=0 +TEST device_on_a_failed_dependency_fails_without_its_driver + -> ok + req DRV-003 +CASE device_on_a_failed_dependency_fails_without_its_driver outcome=passed asserts=5 skips=0 +TEST device_init_reaches_ready_or_failed + -> ok + req DRV-002 DRV-003 +CASE device_init_reaches_ready_or_failed outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=252 +16 tests, 0 failed, 0 skipped, 109 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.json new file mode 100644 index 00000000..c90abff4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 10, + "name": "dma_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "dma_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dma_stop_gives_what_moved", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dma_job_starts_and_ends", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:35:03Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_dma" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_dma.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_dma.uf2": "ecedba12a3da130b7bee70ff1ccfdcbe0b00e1396b9e7f6241c2909681fc1454" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_dma.elf", + "image_sha256": "258d82dd8dad0fc92a9f4f32e20162400a943045ec1ccd8a39f2cde68a7bcd8b", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:35:02Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.log new file mode 100644 index 00000000..6286062b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_dma.log @@ -0,0 +1,22 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_dma.elf sha256 258d82dd8dad0fc92a9f4f32e20162400a943045ec1ccd8a39f2cde68a7bcd8b +EVIDENCE v1 suite=test_dma config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST dma_misuse_faults + fault checks that reset the board: 8 + -> ok + req DRV-004 +CASE dma_misuse_faults outcome=passed asserts=10 skips=0 +TEST dma_refusals + -> ok + req DRV-004 +CASE dma_refusals outcome=passed asserts=5 skips=0 +TEST dma_stop_gives_what_moved + -> ok + req DRV-006 +CASE dma_stop_gives_what_moved outcome=passed asserts=7 skips=0 +TEST dma_job_starts_and_ends + -> ok + req DRV-004 +CASE dma_job_starts_and_ends outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=216 +4 tests, 0 failed, 0 skipped, 38 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.json new file mode 100644 index 00000000..af219ae0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "entropy_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "entropy_board_source_or_its_absence", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "entropy_timeout_keeps_what_was_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "entropy_health_failure_delivers_none_of_its_block", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 54, + "name": "entropy_read_raw_assembles_blocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "entropy_read_conditions_twice_the_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "entropy_conditioning_is_sha256", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:35:05Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_entropy" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_entropy.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_entropy.uf2": "802253c60dcd8790a13a2c571168dd71da0edba2f47f5f9fd8f52daa5695a811" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_entropy.elf", + "image_sha256": "8db9e18ec7b211f02afc594e980017218198a1c96641a91b98bf61cebfd69d7f", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:35:03Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.log new file mode 100644 index 00000000..1c03fd40 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy.log @@ -0,0 +1,34 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_entropy.elf sha256 8db9e18ec7b211f02afc594e980017218198a1c96641a91b98bf61cebfd69d7f +EVIDENCE v1 suite=test_entropy config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST entropy_misuse_faults + fault checks that reset the board: 4 + -> ok + req DRV-001 +CASE entropy_misuse_faults outcome=passed asserts=5 skips=0 +TEST entropy_board_source_or_its_absence + -> ok + req SEC-012 +CASE entropy_board_source_or_its_absence outcome=passed asserts=4 skips=0 +TEST entropy_timeout_keeps_what_was_read + -> ok + req DRV-001 +CASE entropy_timeout_keeps_what_was_read outcome=passed asserts=4 skips=0 +TEST entropy_health_failure_delivers_none_of_its_block + -> ok + req DRV-001 +CASE entropy_health_failure_delivers_none_of_its_block outcome=passed asserts=7 skips=0 +TEST entropy_read_raw_assembles_blocks + -> ok + req DRV-001 +CASE entropy_read_raw_assembles_blocks outcome=passed asserts=54 skips=0 +TEST entropy_read_conditions_twice_the_bytes + -> ok + req DRV-001 +CASE entropy_read_conditions_twice_the_bytes outcome=passed asserts=5 skips=0 +TEST entropy_conditioning_is_sha256 + -> ok + req DRV-001 +CASE entropy_conditioning_is_sha256 outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=216 +7 tests, 0 failed, 0 skipped, 92 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.json new file mode 100644 index 00000000..9440d351 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 261, + "name": "entropy_board_the_raw_source_has_the_entropy_conditioning_needs", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1042, + "name": "entropy_board_a_mebibyte_passes_the_sanity_checks", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:06Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_entropy_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_entropy_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_entropy_board.uf2": "dc992791a79e91d9795c6ff0ea09b30f64ba706b58c9df3e68d839fd549a9f54" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_entropy_board.elf", + "image_sha256": "6e179cbd34048913ae96631a1747b78761777ab1aa6f793658e36fa36caa9f81", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:35:05Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.log new file mode 100644 index 00000000..f93630aa --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_entropy_board.log @@ -0,0 +1,2065 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_entropy_board.elf sha256 6e179cbd34048913ae96631a1747b78761777ab1aa6f793658e36fa36caa9f81 +EVIDENCE v1 suite=test_entropy_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST entropy_board_the_raw_source_has_the_entropy_conditioning_needs +ENTROPY raw 262144 bytes, most common value 1219 times, chi-square x100 88083, transitions 1061555 of 2097151, 4 health failure -> ok + req DRV-001 +CASE entropy_board_the_raw_source_has_the_entropy_conditioning_needs outcome=passed asserts=261 skips=0 +TEST entropy_board_a_mebibyte_passes_the_sanity_checks +ENTROPY c61e9b221efce7f5e99fd909673e240f46e6c189275d40a7e3a307b34fa36702 +ENTROPY ace3bfefb95a8becfd40b99fa699a8ea739bfd7efce953520e901d293e657e5e +ENTROPY 162e5234687105eb7bd8790038ba81ac2163139491b3d427b08d5d4d1f7ef1c5 +ENTROPY 34d097012f207adafeda80b2ba5b2f0a1acd6b460b3c49349229af9487339768 +ENTROPY 839eae9201d982189403dd466fd291a91f48cd54a7c6d8d37d67adeecb989cf4 +ENTROPY 4483dc62ac70a2f14d29bbe0e2d476094a7534667458ea340b20db0d77f42101 +ENTROPY 8a96bdcc41c2cb100287cd87534d676aad9f3e8dc21612401a249d960d09581c +ENTROPY 9a967d46bd33c509aea527350aedd6bca5c1cb5203b9a70a4078c1d6c18266b3 +ENTROPY 1f2f12b210511d5fdcd86374c13892eef1681ca023c16bb21cd809e9b8f262b5 +ENTROPY caeeb1ba4cfe02ac8d07cb8fc3ef73bb2854a7f08b4c0779e6c091bd17df04c4 +ENTROPY 2f30d6996770313a250d8a7691668dea9423e46c8e76efce28f7544223d829f5 +ENTROPY 3c4599dfb34dfac2ce8914e94f27ce5895d770e2cefc36ae0c9cbeafbabdc8f1 +ENTROPY ac9282691d27c6bc3c97a0ac93701631322cde5e1733f9212c675d5cd9466aed +ENTROPY da5b50fa0194f999708a7339dcacab40770882c3ebfdeaa6b7a348ee866c9a57 +ENTROPY 7c5992678cc567a25ff2b2997bb70033ede189d21472751a2d1717ebb9d57c91 +ENTROPY 709f35e6c9fcfb359434b359927d68356b6d970d8c9c30827b21c049426941d9 +ENTROPY 3809731c764424f4031ed884868fc4a6234edf9fcc3cda1d4381f132c1584302 +ENTROPY d7528bb49e3096e06973b4b857aa4d0f3df542920b4c990f4e11ebd58cd74691 +ENTROPY 11b7b98460415ac82b09913c61f16e7cde42a5498d1fe331e907a9879edf231d +ENTROPY e41ea93fd78893c1d8a11c313c03b81ac12f2a61fd4e7325ddfb8ad48c4b5a9a +ENTROPY 350e028ad35cc4f4c615258713033ac14009f9fb771c93deb54dce31107d2cd5 +ENTROPY f9d71f15be02ddddcb3b65685538df3517011e11367c2dbf4903ed3ff492a38f +ENTROPY f8d81e952acc827d77121929ae49f789045d82bc85876fc0a2d74baa60d6fd97 +ENTROPY 83d3ab0ab1a7064f199528095fb6512022f34b03e421aba46386b7cc118e44b6 +ENTROPY d8849dfe1c765c3463b32a6f61b604e5d4dfb30c47b5207501c0afb392d89d46 +ENTROPY a81c69fd1064e51a7252a98358fc3ac88b2a5c50f1476713de7894a87c59cb0b +ENTROPY a139e254c1542ee11f93d5041c4166c82066aba491bb8e23f4f583338282be3f +ENTROPY e9a7131cd6257aae964dc6e7646d0bffca939d504202a7e7604dc01fb5f0584f +ENTROPY 46a92c6ac395d0d00657a733a2f0da97ed49bf2746ee21d287cabd0121582af3 +ENTROPY ad9f954eb0a5064492fe4bd1d08448d746eb60ac179d634c85a68876df94df72 +ENTROPY 3b0776f2c74856e3ee1077ca4bb6137207dd67325fdd50e2e0e844e639c8642e +ENTROPY 8dd97a37ff2513f2f1199bbbed2cf1587d12117c8e46327b09ef2466b6f650c6 +ENTROPY 85a9968733a48ea425144d0e0eda694a85279725206703f925c1996f008c7598 +ENTROPY f062af3231cf5fa43778a9336c97972edce0cfa5d3cc70bcb45e554f70c61364 +ENTROPY 6879f8ac695c96f1cd440d7a8c2abcb97f91b667c2692c905005526717a48641 +ENTROPY 1d81d9dd534e1a0d7fac7f1c31af00db67bfa2d4ec2de0301bb0281980766095 +ENTROPY eb09aedd2de187b4b0f5c23f3608fe9cd65f4a228f672c3945cd77097e293bf3 +ENTROPY 036a02e60f4294b0a1dcc66e2f17f8c3dc2a0075bcfa129d2e73c439e6a261d9 +ENTROPY b1f49112c020ee71f7859856a39dfb074fc5024e0fb6305fb318cd3bb8a39077 +ENTROPY b059fc78132a70a78501022465ef2696e0f98c22ec3961d0bd1578ad0a87d7fc +ENTROPY de7da6c6c73e38ead098174d6cea3abb98acdd20922dea14cec716643a1e1145 +ENTROPY 1ee9c9663f7a9a2429e08de6ae06f95c54b946eac7b7a321475fad5e77013f27 +ENTROPY fcdb957c930869843775628713710a30836a3edf39d4a098ef68e516fafdc08b +ENTROPY cec03143abf8025a4dde8e8f65c912c0e829ccbe20ac0de08ad96a6e84ceb7d1 +ENTROPY de46abcb34e10e69b42550cb1cab90d8092a9d118a32de7b26e9ccf8b9655d1b +ENTROPY c245a5e4ab976091a37b57198df39f1456885985fda735df9c239b99d019c67d +ENTROPY f66efed6447f017689bfc5a8b19665cc449afd8ef436b4975a9376643148926c +ENTROPY a4ac21e5fc422ff518be27b600c6845354de1ae86eeeb29d203218e875ebc2f7 +ENTROPY 8798de5f968cde2c73db9fef63516fabe39c2f5d7b02e7baa0aea891ef2ed07e +ENTROPY 036410b5af89f0fdf893a65235694915e35448958fd3b4372953700f7a6cbbd2 +ENTROPY e51d53f7b7e0aa350e50f1bda249a3a1530b56d9956da9dc5629c937c9acaf0f +ENTROPY 5b643d6c7f712b64e65607692cfea2550443f53f1a75d6551dd6cf3c9a91d99a +ENTROPY 849b6e652d2deffec8fb065b8470806188f6c8188ddabbbb043c45025a67b584 +ENTROPY ff3ea4d9c6ede8cffd6c54df660574dab7966e57b1193fe3b6bb1f34bc6457f2 +ENTROPY 38d60b6d309ecc2df57d584a383e788d506ff5820642b855541b0f09b6662a17 +ENTROPY c0776b8d64f849066e7a32989cc95208ca4c603ebad68532142d6fc829dae6c7 +ENTROPY 0cda11febff77d4183b0bd757b97b6d605260e5d9f32cd788471732fe83903f5 +ENTROPY 47f8e79a151ffab4bf62c10068062301dbd51f32a6a10812193365c925076b7c +ENTROPY 7989b63f2e90ac12d9024334ce9866374e8f8d24d77dd65fe75bf30b2789edaa +ENTROPY 585933cee48624049a1e58dce43554d607953338fae9e15b09ac75aba3616260 +ENTROPY 398054d965a851957a9bb6e084235c2c9117a6c2fb3a95b39417f4221c968809 +ENTROPY 14f9e823372761487a9a3d459f09925b87f1ca943ae71d5c770c2b8446b46ea6 +ENTROPY c2bff905de8703db11e7cab639a095eb678060091d85ee7c7d561f50a3bb635f +ENTROPY 88e10834e6a2a08a5efd5e23750187e2790bf954f5dc0786312fb786b241727b +ENTROPY 20650477101aa14395ec3cf4a44df0f2115626ece0565dab7caed2f84def672f +ENTROPY 72740bd7edd29a6c27b9deb04ffae6116b802ae05a322cb649e4bf45baa2785c +ENTROPY 1b8c3995d3ecaf33547e083c12885713e3ef764e2d29cdb9121544988d2ccbbf +ENTROPY dc52b726a14874c125ccbed01ad4c0243524f0b6983e1531572e393127770ecf +ENTROPY b18c20a20a18f7776aae8af6c8a984d7fe20356f02a80c27107a39f2b4187886 +ENTROPY 4eef37852fbc14985a18495a7a78d7928d2018690d2213c44397b43f534ca3d5 +ENTROPY a24e30c4a5f1cfe82f759756d6179a021a5edc64ef5bb89432c11c0168225eca +ENTROPY 59d2261aaf6eb32ca4b33781b892ec8a900e14e29b3a1e3b644b15b3628141d8 +ENTROPY 701e2c21216cbbaf6e1d951c2381f916bd240371334899236c9006607e87405b +ENTROPY 877dc5bd6356b25b4345b2eec20d9b9a18972418615f98c574833c567e479489 +ENTROPY 199d915c5f66c14ed6a5fd6bd9a76440c558f9b1358a2de39ce2ef425f9af7f1 +ENTROPY c199435d9ef0da8359cf9bd8e5fd3e2ed966002334fa9f9f83fcdb1d0ea655a3 +ENTROPY c4ed32a3212370a7314d23d12d468ad281df0f8929fbf26ac247752889df4d09 +ENTROPY a6231bbac55fb1205ea37b3d7c52703c4d7ddddf4d3a85632fc597485fdabbf6 +ENTROPY 8cd6cc1975959c1e0f784d74a18c983cb69a8f334831004c4259dfb59b89ae7f +ENTROPY bdf2cfdad2a24ad548aaeb8417b562242eeb0446be1c6cbc19caa219a6bb74a9 +ENTROPY c239a9494b25a49f3ec083803106d22f138a523dc8e6918f4cc151a81062b630 +ENTROPY 539e3aa7730256a041445c20276aecc2785954b91949c41b599d87573e66d85c +ENTROPY fe32c72a129eb8045cb49be7a6b3b0e5aa24bfc582557864f5a7cd83be338f29 +ENTROPY 50f558f9880807b550f5e23196eb487c7f6356aa966b713e93f07d42701277af +ENTROPY 4564dcce776b792346e1258e7b1fa8ae187ad95fe30588d59ad07f09b829a3fe +ENTROPY 7ff06784e0e2eb67d4e7bdb5077628fa3be2769786534e8226c9a686904503f5 +ENTROPY 0804a943dd231bef57a54d059ac5739aeff9d75afcac7708f0900cbdf049cb66 +ENTROPY 63c844c17b1f0c590568d41feaa2301beb1837ccb6980ac09dd79cbd592b8aae +ENTROPY 37e9ceca1d3fed34da779a80f36e15c9bf01bea381e9147027966f866a12f781 +ENTROPY 2954d77775a19e68e2bda00115307a41c6d4a6bae9812c42861c12027cf8d5e0 +ENTROPY 445910bf08e00bcd4eed54ad6315e58f0e83df8bf4223eb6118dd3b1d8ffcdb9 +ENTROPY 4771401e024c811c6dbc9c04d986bdd8d0b16d915cfec30f398f9fa6ca9666dc +ENTROPY 2415df6df3978463dd8468a46b70b75e9e08cd120e5c987b024dc66846fe8618 +ENTROPY 6fd70fa3884da77dc8ebbe35579e96410dfbbbb0d6fce41529563b7971686afe +ENTROPY cd72e5ad2fec370fb027445c7e5598a07c558f129f5f2a3282f3557b54140f3b +ENTROPY ba2df62e2fcdf3408c058e3b5345d7bb1060e5e7b7a7eb30206272bf56ac6133 +ENTROPY ea6ec75ac61e0284d59d483e7c5e03ec2a424574b3953a070d5e8110dac58056 +ENTROPY 020da03c7e7ec50f22b13c6e9e827bd697bc3c31171e7b349cd730374340a594 +ENTROPY c7066975ac2a34206eac12c3f6bb5b470ad52dee90e10e896f17c1852b562531 +ENTROPY 9f44dec91381e15197bd12a078b3edbd9f9eca6c495b004ddba302f3cd50768c +ENTROPY 9173989a58b97e0ec071a705c1e65549aa1b919ef96f8cb5e25ca3412446d806 +ENTROPY 8398e3370f0dcfca320786e86b6d42e34a3f3aebdb62871f693cdd79320a916c +ENTROPY 30f5e7c714ee851eb4ec525bf8d05f4b4df685ad420cc66bbaad8f70f45de133 +ENTROPY 25b23f36369bfca02d257e0a0f4dea0042422672fd8c149455b0c9c158b13cfe +ENTROPY 3cb9d4fe8a23a1127dcb3b8af70bbc2af1590cbb0888b8ea74e3313041862862 +ENTROPY 233ecf981bc5258004e230cd36031e43b499810133231a6c93758b4fa90361bc +ENTROPY 6a715673161cf607b46ee0cc8b953d16a8b1789180266e091a06fc68270cdb8a +ENTROPY b1787fb891244c96f95c696a46c8e04dabb8eab34539e48f0ba258bdf9b5f43d +ENTROPY dd880ad613703185e4d19b5c11e582fe515da2b35b70f6bd557d75c6ce070033 +ENTROPY 07d3d55ed22f9d4e9294fe33180609bda2bf30fac9b64a1245656835ba8b926d +ENTROPY 4e8a8146634a836cec506f789a98a7d9622d5859c10aafbca63714127984c425 +ENTROPY 61769ff281d78cd8b0c553691f5dcbd2c884d78e8ddc792537d0ced249fcdf47 +ENTROPY e9970ae4287fef9bba1ac1754583523bf5ad1d81cf2837bcea9b123a93c6037d +ENTROPY aab91a65d119260c7e0d1ef2dd7fd05790d570e10bd73933546bea5341ebfdbf +ENTROPY 9cd5e9378ffa1eb2a8b2677c4bb76794ec4a333c521bbc118c11fd06f2bc65b5 +ENTROPY 46e40e78cf83a4e5cb4c7b242243e2c1df3d60347cad4febf833463d9873b61c +ENTROPY 1a2088a1fb650b6b3f3b56746633ce49c25b5c037cb7b2f6e8b96573fd571906 +ENTROPY 51ddb1e0fc535f7a894b5175ab109851fb354aaa9e8935244350a48956d7c68a +ENTROPY 5b9a0120da0e85ee7c82a754ec66f0cf260be89858e0b925d1a20fc98637adfc +ENTROPY 163c45e71581847c9a020c5689eaee98b305a92a25dd5a9c1ba33e3315b85fa0 +ENTROPY 455fe682b0e6c8930616386ef980a3d4837302bfeb73133f3f317c13aed55775 +ENTROPY 87e4ce538e06eeeb63c31e4417f578e73b032cbf042d8ccff7a4fa797b6f54b9 +ENTROPY 9e00b72eadbe414a72a7ad0c57971b646dd5bd960361225b718a5e9d6f16c640 +ENTROPY 075e87332ef6c0ec6dc2341de64b8e534556ab8721f1db5a09368106c3dd5ce0 +ENTROPY 92c4557278f5215d201af35f63ef621349f4e1355cb29ebe8cc2f700005c1175 +ENTROPY 10b4bae62d934e4e4bee678928b07e6a6b355c41510917a6fc95db1671a10112 +ENTROPY 353677b27eafa570818a6c5a1cb61256ddd919f50df2956da84d9ef95ee534d0 +ENTROPY 13a8b9874781a219ab31e3a7cdd7a8f47799e9e96906d95ca6dd447e817d719e +ENTROPY fe6aceccac9fb2474ab0c4a3a87197628ab16ec4625de910dace122302956933 +ENTROPY fa0700f414938407331b750c670469d815aea9cda7e5b12d14a224ed44063227 +ENTROPY 5c1f4eb586ca0942e84fb6dccbfcc874be9ab21f8d37bdf5382102c8216d13ef +ENTROPY 13837f8130f258276de5532a95f7b2d3140e1fae6942021a7c907a39904acd22 +ENTROPY 04e7861904805bcaa04e213fd8d4f4fc05ac10216677385b348e588457090e08 +ENTROPY 56a05696dc10bef3d96cc46b60e8a330bcfed26b587b82169cba3c042da14a89 +ENTROPY 4d9010403f8e29e986483fc44567e5ebe51a4d0b3535672ca4e53aed0bc6cad5 +ENTROPY f7e41f8c0167ce6e740e383b55abcf3a57830ba4750bcfede3f8aab8cbfa413f +ENTROPY 3ce92cf764248d301ddd70717800db003e4f94bf6aa83c41bd5365d4417ea5f1 +ENTROPY 4f7378d413c05d9842d6a65962d8b3c876e6d314c33d82e7f4f294fed2e38890 +ENTROPY eea3919051abd73a6d228c7805f19bb437309a68fb906e99d96746d90fe21bd8 +ENTROPY 7041262d21f7739bd9ee40bd0249623e42b5ec0b8139267351e4444dbb903f49 +ENTROPY 23e96234147b674f20109275bd520fc3bdae32e530087753d5b9eabfdba7f8c2 +ENTROPY 4c27f1edcfc0ed1c5e5c39238668f4009321512466aa4e9d1b7fb524877bcf5f +ENTROPY 86058e5c9701667173ae6fbb711504c67f059d9f33016441dae2eb5a77d3e84d +ENTROPY a7c3be130794cc1951c85c12d177af12b00e7c0d2e85dfdb422123df01e10c89 +ENTROPY f4ff47e6f371962cb8b63cb573fd63092b613cd9d1b47c8e0784b66abe62dbd1 +ENTROPY e5c8224b3a7dc2e868a300dd876a3b06b22e49338263293a85a55c62b31bd422 +ENTROPY 221d7a1a047f8b4d5a694bdc99426f938a1bdc0b5e57736e91b76a228de5fc3b +ENTROPY 8f987cc7ba275d9d3afb4b7dcbc6e5a7fe704432dab13c3165a44f4d8c0b613e +ENTROPY b42d727da2c464c9b5462ba38b1e41702dc5333e29ffddaa9bdc72d355f4ec22 +ENTROPY b8e2e763039946bc4aa16047f89f8ed5b16beab05791e0acca5a8b0e7712962e +ENTROPY 85bbe4c08dba509cb7b0f6ddcc0f6959c70bbd8c382387eff8c3d3f9c1d24698 +ENTROPY b203fcc0b90cd5b4fc236edeeae760ed6ffad212829de2918449966ac0e5aabe +ENTROPY 37f3522ccd672528608808b6d1f9094a00492942a07c352b5c8114f3fd50434b +ENTROPY 806d4c25f76757677a35fc28b1835b3a27d1b0b85f71792e6f995e74364110b0 +ENTROPY f8744e8326c2e3b6754195b5df7c2bbf15512a3c6ad70cab0c36cd51b6cbe5b9 +ENTROPY 2767b05da66b938d7c5de749d213635c11ba557497df683a58c414b43b53a31e +ENTROPY 7cb7c2eae4c58b2a71cfa8ee0dec56ec92cd3110134f8a3e26b55bb7e9d4aa6f +ENTROPY 6675bac8e54f9fa0b6967a61684744eb65804d7e677af0d07640c322aa72a046 +ENTROPY 073c75069e21e24284511e27d2a8cac54894fb57eb6cc19c052ec4225e1e701a +ENTROPY 2363eedbd09ffada976dbe334ae20933581229726953fc6cc832c64370014bf6 +ENTROPY 65646699069f8c3dba8f3527047dac6d671f6d5799a96a48cda08b8037d7b53b +ENTROPY 62435eb8a7754ccc37cb26e20dad1412d8b9c677479f7e351224c3d0e0a1a9c9 +ENTROPY 603a8c630bb6825817eb7cc4bca6e6a201828b23950f70cdd399162aa995a1ee +ENTROPY 1c0ef36b08cbd9fc6eee8d16fe48be195dab9ecf137cfead526d5ec968332a57 +ENTROPY bd1cf4aaf2dc9c865033be64a66bfde8932a382600d3974eaed2068c5e54171b +ENTROPY b289f87e1c0beb57315e649d0197df9f494d741bd50dd6e80f28221151eacdc3 +ENTROPY 0323557c49552d7a1168469bbb5fab8b2536ca63e7d69fa61c681098b034a86d +ENTROPY 25659ca1e70296874943dde64f157407fb18922dd6414ca4131ab9475b46a79b +ENTROPY ca24df9bda268530647b1be1259fb34c0057716211d7402e83ec2ad553f849b6 +ENTROPY 22be8b95951480b6812ed1250dabd21b2263a3c6b8d12250b057aa46d82b9e02 +ENTROPY 4fa55f40b34334990c4e9e5c49ed1a8cf695d53174a583c3e779b346de418a0c +ENTROPY 62da192309ed65d3b6b310e6e0d090cf24a30681d1e37b91d7107e0e71b81a1d +ENTROPY d59740f51114bc0a5f147da402def618bad6cdb175f12cdb5c3074019eafc454 +ENTROPY e8c96141086a8f2d113f1123be00bd64432bf4a9731553fd3df8b3eaedf1b523 +ENTROPY 0d3e7020d69474124ce67335bb06a282137c8da16aae71bbfc2aa4fd48834c35 +ENTROPY 5ac7f6eece25bcd255e32f2f3abd1a12d96b846ec2265928d1ad709940ef4903 +ENTROPY 5293d32e4f7da06f0130ec2b0c5a24d160507bb580285d4f25522e3218382528 +ENTROPY b0611322a2ca1f4601d8e30343b50dc32910fb7ad7340e44328a5c588e6a9c9d +ENTROPY c9c02bb23549eef84ba06591a2e2d8ca6093d8eb24ffd7e1cf1a4849c72a2ed7 +ENTROPY 1b5bab22b650231f3b42c61f554ce7f1302af9a31efedd4e88f272b9e8020845 +ENTROPY c06d4fad0ead9b68a6c24d85c37364eeaeb897a7b40fbd370c871c371a7896d3 +ENTROPY 28eeba8f3e2e0cd6e08735fefde8ba041f76b337377e59c99883dc7710f67a9b +ENTROPY 1df800293a06bdc2152aa5226887d908200659a53edf9f677f5365440b261cb5 +ENTROPY 72d6f3f4a7dbef31dd3dd60f87396c1918b84b26566a3e06f2f5fcc882e0e186 +ENTROPY 0181e41c28dd27ef2934ac9641abe8c9c6e4b50e6200d107bbf947b94106916a +ENTROPY 735211c92f5a99d86fc0f9318e5aabedeff5f1cefcbeab39e1d2dd6702e338cf +ENTROPY e9f48c6333734f9d984def7b3fc5f965b08edcdfb9a17d18bde75c8247e8996c +ENTROPY 9dc71756bba67a67446f0f2c56de262eca62d86fe0d325b3b9e7aa44e30efb9b +ENTROPY 0bfe0eaccde0f7f10f22b775e92712654edc12e888c7d18990a82b86abee5ff0 +ENTROPY c3b6d9c90e02b4e0ed001b5cd5b64738ac41bedccf78f6604fd93818d354ef5d +ENTROPY 5dace0985a3950282b89362a5999d679dd81385d1d54367a49e8a4e4a6b123a4 +ENTROPY 98f4d254dee42db36a444c63418a6976d4506f3fa3cba21beffa17ce0aaf84bb +ENTROPY 0a94e0712bfaa5ab123179a15269e08503bb207d880cf7dbd0ef383a436185e7 +ENTROPY db30f40ec4abfc438f52bf26d94a57673c5b78657107c36be04d50a8b4023862 +ENTROPY 5e19852b3e00dfe00f3947b6e993612c7b115f8276a44c0d8171e8a7729dc922 +ENTROPY 1060b8e0f012d9cdc1900669cbcbc87e24725eb1214060eb03451047d7120b24 +ENTROPY c94903fe6de32d8c8ab84cc94bbe81d76d6b5b290ad1f3250e4d7c3edfc3b10e +ENTROPY 368a0eade4ab5eaf09943bcf83fc3f8b264b71da2afecc31961825b342563a04 +ENTROPY 3e2c81dd488114564fddd42bd5b19bd6446c75c85d343eda366ba61552ac4079 +ENTROPY 25020e451d7b77a1ac6767ba9c43138145b61ac5ad84e69e50b0ede5366208fa +ENTROPY 7285b0d4f6abe82715bad1078d71f251f1da25573679a0172c38532994eb3764 +ENTROPY 04797121ad8f27e3a623bd6afe370df16749547e8f36591236a3afd92a4910cf +ENTROPY 50279fb2b2fda26ff9817747cd4da222cea86d3ce96e8708e82a36d9fd424c61 +ENTROPY 9a72562baa56d3d56cd1b7000781d73d91a804f8427b6d1829372eec4159d5f3 +ENTROPY 3fff50607cc74ba7f9d83ff80edce7c853bd5f10bafbb7b8a0b0fa0c3fc38432 +ENTROPY 86b1eec08b8119a85b9e702d78d9d48a2f9ce3b6b0a4ad8ed30cfd35328ae661 +ENTROPY 965909ce17459cd6f11d14ef3e9ec33243c8f535d7d9672e6d6b139e0bd415e8 +ENTROPY 65bfd7997d3be3a3939bc61d0a142fa3401ffd00493b13909309ac474495112b +ENTROPY c16f987863a6288bef21cc3af1fbb1e3c0df77fdc9683d2806d8022805b50abe +ENTROPY dba3d543673667c760218ff732216f666c46cdce87a2db361a66b60138f8df26 +ENTROPY 4c3f427bf7eb64010afc0d9a620eae3800378d4704fa5368740d8cb5bf7e7542 +ENTROPY 5b07d91ccd8a96793a05db382ea64939ed8574d28a57dfd0cd536dfc51ce5a81 +ENTROPY 18e23caf76fbea0666b6ea353c088c45ebe61da0295d248062069c55b36f01db +ENTROPY b8ce9facc1cd3e6a239051e771a215d2efeca7f5c65339ea6f4ef32585b02dcc +ENTROPY 864b3a1c7eba43315fb9d85a33974eaf2a5e9be66182875c1412f0b3ea792e61 +ENTROPY c44c8e74ada934b460a20936937a251364ab123b4ef05605150c0cccfa962b93 +ENTROPY faa5ea3558fc137a7365dc7fbdf65ad71fa0077112a1ac1c5ca8365086f6247f +ENTROPY 00df5338aebae20bb5e19e59315ffad537787c46f822a122a4dc4314dd3001fd +ENTROPY 86ae3cad8381274682d87a2c42c0811ccb956577193ab4ca68a99152ff3ac2f3 +ENTROPY 8dec57f7dba836b94269d9cde7b4f5613b7218105f7e974e7e0edc971bc48259 +ENTROPY a9e3d5d0c462abefa39badf4848b2e9b42f5635ccccd9f1c1e352c563a22ea4d +ENTROPY 5c123a0991a815f40ad2d45895abf3e57376e2df0566f0ba85808aeaa09746f1 +ENTROPY dc0863174f9f1978e3a899740be23bd4c7052ffd1dc07371e45723bc18e9f0eb +ENTROPY fe45800a8298a2534d8d0da968c1aa6d5e8ee2678c7a080f9b6aa567ca0046c5 +ENTROPY 678b04221e569cbc40faa4d96f87398eddbbcd885d2830809f02fe5d94f0704a +ENTROPY 8e147bd74fcf5d9e72870c1260d40e80e48dccd2ed0772a7dba3b764832b2867 +ENTROPY 6918fc1e33f9c3684f9bc8178e993553669ea3bc494029d858f268d634f06688 +ENTROPY 39af4f89be40ad939c203fb3c61451e59fa742001298b394b7b92b3ef05f031f +ENTROPY a32930d9e827c465a8bc3afa2fccff626376668b0d985e8015c3ecf225b00b7f +ENTROPY d72cdf3e17d1dbcd1880db025cf8f61af97260a42018f30476fddf38c57a7597 +ENTROPY 0fe7bcbc582bef309540a0d7f2687a48822df86d9fee977b3e2fe17f0c454182 +ENTROPY 86b1695dba723b4c2b7970acfe45f0261a39ba54a1c27cd4a8257da8abd35fa3 +ENTROPY dbfb413834602dea77915d68ec6dec89651b325b5839b989f78d4ed9daa408db +ENTROPY 4fb225e176911048039a7ff435010a097427558bf391b973a54e24b8713bad8e +ENTROPY f02d2bea07a192e98af9ab0ff91f7b8082a71f17cd2354b9cc7a99b4ca570f84 +ENTROPY 6e2cee8c3d34c5ee818229f3266019ad95623624aa3cf027978e0a18a178e526 +ENTROPY 72937ff9f865d9d99e1f0d941d5872ccb5d54ebc9360b663f440b22c6939f5e0 +ENTROPY b50b24c21df5489ccf9b7970c446337616430582ff853dc453b94c03bf31f81d +ENTROPY 1b1e83799d3d200d04e82a9ad73f8e40ce3ccc556b31a8c108ae0e7097d0d391 +ENTROPY a3de1bf120a397f141e22bd5a87f166953b8c74764064d53fc9f2b3b169339fd +ENTROPY 5442c13516afb0bf3c1a21c8c7e22b497f5b84fed39931fee06e07f3163157b7 +ENTROPY e61ecbfd2e69c09512da848938159be47054f73cf2e0f161be4ee390e6483965 +ENTROPY c3e79c94197f9c9782016d0636cf2cd98bd5af7751363ef68fcee2bdb60f76c5 +ENTROPY 7779b0cecffe0671c5167c035940d440736818ea2e50c7cf786cf70f65031674 +ENTROPY f90b6deed9f49cb0164ca13eb06ed89998e20da535551359d4c58246cc05cd1c +ENTROPY eb2efe3bf7939201a4a186f3e10cc4a324e30d2357e4e18d0f8e4ce4928d1377 +ENTROPY 469d643c0fcd8cdc3289f160a63721ef4749e400603c31d4ce846be18cee0937 +ENTROPY c3259f0601ae48e8b626f00724a3aff91e0286e461dba9309223c843cedf7558 +ENTROPY ede85138b2faf80225a646179b7a3ee0c767afb67f75a9ed57953f82ae0f209d +ENTROPY 3ad7010ba6a17cf880741af28a5a661ec2bfa36e4b959aaeb3a445d95cafdcc1 +ENTROPY 8772bf7c6d2ffcbf3ce6f62438f089653f967cb2253d05dcc959bdf61eb04705 +ENTROPY 9a0b0b51027031459d8239e43cbf62ca839b3a8b2c203313418ea0da967f91f5 +ENTROPY 3c4e6c86aa9a0f4546f450cc2557ec31a2f19f967b6fe069297c6d2e4b50f403 +ENTROPY f49371a47b1d212eaa23e4dc0e177196d2cbf8babf7f38945f1948607b6fcf79 +ENTROPY c16671e749b83a6abf66433f1075f883d3ffac323a0e8b3d18c16f6b2b8477f4 +ENTROPY cac3d2a5aa7e0d44681fa17d4b33b21e625082c258058b767bb51bf15ee60293 +ENTROPY 6751d17a6d4e876b500445135dc62dc0d644720c7b507cbdb005d4b2d05f32a2 +ENTROPY 038c8229aad73aa54ae84bc5306aa176704fe10fcb2d5b11ddf59cc7e99c2d2a +ENTROPY b1c4a33f4125df6b1e3534dbcef70db986cb87d77880b9f809292b885e407e0b +ENTROPY 2e130b699a201796ecdb5cc1db45512c99b8b08a2c44586be0254c8e86abfa00 +ENTROPY 93fbe39dea1f8c22c363a551c7319d40dd27d178ed965e304ec39aadc50195cc +ENTROPY 7b481f975f94e0e2c9a85dfdea068cb7a1fdbd86390298862f0fb337396371be +ENTROPY 340ecc6f99273183b51b2c17a44c79c49ac9aa546364327be821e4b76fb90f1b +ENTROPY 4a3cde15525f02718745982dd664750df28927f2fb8a0ebdf280046fc60db49f +ENTROPY ec7bbb7215856bc19717e94e910ed8296f155afddddeb1d2b965d68cb9b59b5a +ENTROPY 3c92bd5f3f2bca82646e807a6a5ffb87679e8c8814f399938399b2225bcdc934 +ENTROPY d7ecb9c5227b745b668dba1aea9169433ac8443c4a8d83733626536ba9539665 +ENTROPY 2f21a0289591df88d8b397585cf3fba6136306537ec69f25ffcc0dfdf338f019 +ENTROPY a744a6482f3815b5441f7185f05f509e59dc72b8a74d4f13766930ed00225d38 +ENTROPY 2b166c78fc4ab3605e949e996df6669d7cfeb6d897f0fc6ca8c7fbe2d43da66c +ENTROPY 8812f46c7783a0c32aa8c51b3d3008e38971ddd538c5fb40735b4ea446b13749 +ENTROPY b1f67d722abef02423abc627eb5aeb02c7c40a4737443cf9980a442fe7785279 +ENTROPY 671fef9250906fca00ae6fcef76a866c52bb3c3d8c2ef913b43b3bd39542869a +ENTROPY 04cdcc65aad97d54ad65be12970efbfb3278152ad3848fdbe6010029e749739f +ENTROPY 79287c52e7a717fb0471cfe54267e9e65f42f5b0ae16558b1760ee476ea9d454 +ENTROPY a22e2419dba40df18929956479f243276fff72ce71020fde0f7349433603bef9 +ENTROPY fa32eec2189c8c9bdccbbeebd3500f7071c85898d2007ae73187a5e3e5443722 +ENTROPY fe4d3adb23d93b9562d162da282d39c8a8bea380fda78bea628b339579f1a33c +ENTROPY 29b80fdfcf3263a91abe15ca187f779fc8dbf3806362630bfb7824f15e60f84a +ENTROPY 911bd4261899343c0f7c946dc07978c19a0b74a80296467227ac2738d8e7cf46 +ENTROPY 261a540a24fc359f777f0e99aa91b2905db05894d118d5b385fe3bfce21379cd +ENTROPY d802f052e69ffd924620b9a304895011fe36097663f9de92749d09dc99e38cb7 +ENTROPY fdd2d409b7f91ca2be6e7f5abc8521fbb29d3149ca8a428db44d6ca76c69bcaf +ENTROPY 24be949c8222a263461d5e2f1511166c1fb64219703ef63b60933c5f927b75d0 +ENTROPY a6d55f170730b09fcba02860b405c31b632be17a8207ede0cd3e72b5ea426e8d +ENTROPY 0765d9e143f99b2fdcac5bf731bfea768204c8c77892508d31d11b80f69c441d +ENTROPY a15f427729a566091d1304be97ae619ad64d5eb22de7ce425805dcd916418596 +ENTROPY 0dce1fff635543b99bcbb6095596dbfdcff2b1407e7b1b0b77bf36a89ad5ba25 +ENTROPY ee895f242714382c3097e0762e111e079c820cac27e0487077d7b792bf39b9bf +ENTROPY 2fbf1b918f07d4362131c7909315dc0cd694141cda4e06445795189823fd6f6c +ENTROPY 055ebf7df93004958d642cb39d85e4c63a0beee854af52fbb124969dbd5985ba +ENTROPY e4956ad4ed36bb3e1aa1700e3224de42086e85b6a36aba964efdbf83ab6251c4 +ENTROPY 22ff7839ebef1e400cd583c3b52b9351abe6275559257ce4283661b77430a7d7 +ENTROPY 5f9cc087777d1991d35d8ef50cda62a99780a6732ebfc27078a673cd8ccbb7e6 +ENTROPY 354caa45c5664771c305b3474e717f1af1a8be184b648e903ca6ba981d158321 +ENTROPY ccbcbd64c5d09de27027ea92bec9f72ad07d40f6d5e5f827cea8c6da9a1cf179 +ENTROPY ea24f0ed8a64259a7af52bbdfdf5e6df1fc294dc1c0f4e520245ed687793e9eb +ENTROPY c19329a59b7e24e0baafc5ac409f19eac14f038ca65bdf9b508fd4f1511e27e2 +ENTROPY a73d7ebec3555e2d7108dafa877c979104b409c3e635fb752879271611318fbd +ENTROPY 88b0d66e0bffa2bbc45c74038f4690d88c2cae0c73806001485f2a0aaa5ff418 +ENTROPY f8e724f01dd6203186a1b04ad57b1000b6e414ab57f0a1f6671b2bfa09478fca +ENTROPY bdf0a8f7093c0f55a335e9d15c7fbef7164e271559dd0f8a52e0ca03a97b58ad +ENTROPY 501338fe478789e57786694587a07e818f1d02677bfa89a2f6028fcb39ab64d0 +ENTROPY de7099443fd82306165ac6fec2ca1b498d1489ef78fd0d53ee0a4ecb62939aec +ENTROPY a96c283eefe7b421ec61082c9de1bd55e52b98b31234c4f796a46c29e0a3051c +ENTROPY c0d1b69fd8d5a2528146ec46a5920472e6c3332dff7a5a41714aecd57320171f +ENTROPY 603daec6f464a44e25581cbbe61488bbaf4539c0839b62987e1a1365eee3d1ee +ENTROPY cfef7a300b7cc8d7fc20972e331ee54b49d36658a8f8479a24c05b99bcbe2398 +ENTROPY 39a45c6252b987b9d7a2f139250c6ecf0e15effe0ff6a4c0704437868c1ed7a7 +ENTROPY 1561b89b334eaff70f3b2722a8fec19e47acad6b42b3f63114b39d62ca668581 +ENTROPY a44be474fd886dcbda65abaa3bd69fee0471d8b5695f1c5a5a4e7ba4e14339a1 +ENTROPY 4e610cf3554bad14a6e57411502733ad2fb14250a7157f697e4e0a62cd062baf +ENTROPY e8d5f6ea4432229d75aade73447b25ee61a9612fe9d86526a0eb7209ee03421c +ENTROPY 7986cfbaa9409cd3f3a785f5aba5a8fc7578dd8337d5bf1f79f2e675bb346ec6 +ENTROPY 27dfe8967aed3f1e616a0afd011a31313c519ad80c60c06971297ba92fe0e2a0 +ENTROPY 28ec70aae82fa37312d251991c3afb54ca57c9d69442e1e9d2e7638d2fb9e45c +ENTROPY 6f37bc9ccb52e2d69b1fa5eb69e55a9fcee1aff0e2b3119c5105e5464368ca0a +ENTROPY 343bbdaf08c9c48f41ac3eecc2c2660a36ddd176138617a0c35f4dc20b5de36e +ENTROPY cdf759091258a24ca45087909a3363338de7ef5b50440585c09a74a853dfb286 +ENTROPY cc909776ac8138c84d6f3bb85fce5a1dbabdc4e18cdce13ca1fcd00ccfd3bc85 +ENTROPY 6588cedd6dcc7f095261923d9312b52e78f84e91f1eb37c16b1d4f48bd5cddd1 +ENTROPY 698e6c69cfa4dc7f79a41e8a74143c861a84bad6021df76694f74dd1063ffda4 +ENTROPY 74f09c556d459ffda9a459d1ac7ada8a534a94f8636449ed6afc68c0e6e8023a +ENTROPY 6530c128d73f8bdbe85bd6047509b41faa433203df96402bac9abf4cb3ee1266 +ENTROPY bd0a0623eebbfe1ae7644460bffc5c9ca094e81af1605c693b41c4430820e50c +ENTROPY e4c2806054a36f1f16bb956c6c152a80f860c2cda294bd7c495e3b9adf775970 +ENTROPY 7460a82a0e0db9e5e37be9d5d0133efe79b193b01884f72ee34f388e9526d99c +ENTROPY ec55c47a0da9c848c6d5ab5f5a4449be4eae13ef1ad398e81101576fb145d702 +ENTROPY dadae80257fa5e2360d14eff1b27bb846cc03d9fc4938392cf56f55309b22455 +ENTROPY 98f4ba919c1ee3a8f37f93015785382002107e14389e1f4fd5c19d002f592cd4 +ENTROPY 17208ca459e8c786fad810497cc7ed537547d852d27c12c8b9dfb8c2baebc4bd +ENTROPY 9d1030a853d423c9ef3ccce3563d331d7b91cf505baf3e4ce0679a04a846baa3 +ENTROPY 0e6c068cc7e10a3bebf7bc02cf30d51ed65d9c041d925c76df2cc393f181b433 +ENTROPY 6e02f3cb393e2fac0158e7175d1edeedb5ecc8679b73d71e679e9889cd9bfc4b +ENTROPY 9600452a7a2e71e360b1f52e2abec323f4c31a7161599f57854758cd143c9f82 +ENTROPY 3e90941ce1f8ac50af0b7e9712a7d3f92b35404abd563b78d7904a378233db4c +ENTROPY 52d13007104b3eb3eca1b3855230bede5b22c5b4af11b03f810d666155bf7e5a +ENTROPY bf5d63877c47b38c0ad319405147201d825d07f3d2f3a357c449ea3ddb8d5d03 +ENTROPY cc7403c76f252a6bb80d796dc93fc43298ca20658e677aecfb5f6f069f3f343d +ENTROPY f058bc364b3777afaeced2611b799a14dec661c8c655942e4c7e8cf581266a9b +ENTROPY 42eb997c45d05363579de1dde5d0db2d02ac8a4251216e6f07e9a55ac55b1c11 +ENTROPY a109bfa549ffc14f294d5fc593cc1ee15b6bea41dc14c76f1f1228daf72818a4 +ENTROPY 1237bdf95e202f104e8e076d2aa90a89f8b03842f504462563eb324ac894c71b +ENTROPY f78c1857ace98aa89f7ae2f1c55c2acf5b61fd4de821987f6004fca5961eacb0 +ENTROPY c34042a257ed36156e5159e9564ea550649ddb8ae058004eea7048833f7bd860 +ENTROPY 68aecca52587a83ae925c6bc6ea1c5edb14e0bcd83c9227d9ceae651863e7413 +ENTROPY 8b400da7a7013fb564d485872d697c589f38cd8496247e68cd9db3d0bf375eb4 +ENTROPY 11c13610684d255b58cbdee718b030ab0d6186309f61fe3ba358491b90850db5 +ENTROPY 1d5fdb9c349f661ac0bf878eea0eff8ba586ec08c88531df7d657bccf80e1cb3 +ENTROPY 67cce768a7eeb88c4d60ab00e8c6ba74a0143f5e1ba29553474c3b61a8bc5a46 +ENTROPY 0cc8d7060bf940f291f0306b83920f97929b75dfed86a2d9030111e1700e6b7c +ENTROPY c2801db70f0a71459e95b3cf083518e72f319bc665bb779e563610bee62c8f74 +ENTROPY 385fac49f837f66363ccfc686906b629c80bcbdcbad24a7200dea460acf646a9 +ENTROPY 2248baf0ed355463828c9da0e25ccb88127b5d64c092ccfb943ce340eb89317b +ENTROPY e0ed6ef2196a7db396e1ada7c55eb1c337db9912bf8e0bff774181562bf034d0 +ENTROPY bc116c36fc46751e3675c79b3e0014b30f3dcaf9bc1debc47edbb08fc76a16b1 +ENTROPY 74bc79b571850b1eed3d68a5429750a2b4a60f9543821daa8fda3c78335f7206 +ENTROPY 6a7739fda3f485478d0aa577d17dfcdff2b9f0c20b9ff81396a675dab7b12285 +ENTROPY 2e0953f3aea94d3631a98b3626764e8446545c43d4eb8b2d66f41106d671d415 +ENTROPY cc66a44f3291b402d039d0bf48e015690c2f9e4a54bde3386806a3313a1b8464 +ENTROPY e4912c520a2ba4b0cb071b8ceed8af15a13d12724989df6dd67bd6694b8bbf75 +ENTROPY da8accc94b8966a187cd84e9023352666adfc6ef175776a07a007bc4c0ac460d +ENTROPY 38acf1b0828951d538af8606948620c41ffc3844d12b460b8e6cb11f40f26677 +ENTROPY 0ac20a2d7caec08dfc81af4243dd714c37e0332c741a84e49c737fbbbc975e82 +ENTROPY c2a2be8e89dc965bcd6dc13a7fb3f50c1aaddd1daf3edc0a74668e6dd54ef9fb +ENTROPY 8592cbee05e0b6eef14c55f8944fafe14f34dde451e1cdd025bec5f274bb2140 +ENTROPY 8798ac3acfa96b6932d9700fb88508a2bd033591f53ed61064b461ce4f877695 +ENTROPY 5e3beacbde65155890d79b8be3c9e2be0c4b27b8873f79291f0203b4fa7fa97f +ENTROPY 78a67340dba4df04f91b2f7b6aa702bc2d02a660d0a3c14964117eb7266a936e +ENTROPY a7030b2b713804041cc2848239a7d8d9a60de47ae8acdf94b8135107ae42914c +ENTROPY 5214005852502334cee78872000a0b3f972c1dee984c8eeadcb3cf95fee5579d +ENTROPY a03bd01b6e50b12413491a56636831f650c9e92b10233770a2cdc6444da23f38 +ENTROPY 2b82d2f2d6ce44daf45464bb8ec44504f0c8976c9b78c40801307aba4f9829cd +ENTROPY c9e8d713d7b7408506e95f99848e938623f65001eb77d19800b4e8e07c5423bc +ENTROPY a43ec089b39529651b027bd0b77178ef1269b4637162e4e3a965a141a2d23515 +ENTROPY 4f457086a1dddae1bc94aa973eb2f2bf05db26053124d7458f762ecdc4966ef5 +ENTROPY cc6016139c31c35d13f38fd6757b853e83d3fb0014703417fe0413cafd182005 +ENTROPY 60e6b40ae163630ec4c7675d1d18cf33110b1fd51d1fb247bf2b2d1353b29a86 +ENTROPY 98a9746e0e75c1b17388cf1b77906e0d910fe2bf27b0b039531f050912d431c7 +ENTROPY 3a957de46ebc10c0459f961e93432966cbe9828c8a9ec0b5a762a03fe8628680 +ENTROPY d1af568d19203bb80137d0fa1830d9dca95ff694d78a2cdcc3a1e5f1b817e4d1 +ENTROPY 100fe2de43322573b7d93eb327c7382f5bb71755cc4259c48a73e01a3985df0c +ENTROPY 4d655623b154d699080b8cec8d07510975d4512eace12f1fe4fafed282a38fa4 +ENTROPY c32e5ac50874687c8933e36affff9c5a89b5d62b3f5643ef28785a80df064b12 +ENTROPY 5a174b5461b2ba180dce939eb50ccc969e1adb72dc5fee93d72c67c8f2f3aef1 +ENTROPY 94db38c11cba06d37ac8d9aa0eb02df9c3f4df9b51b71b0bb49226068afebf43 +ENTROPY c0acf06ab726870b4b77ddbb01f73b9cbc395ab1af5344b6edbec0b979f55614 +ENTROPY 9a34757914d4ef0ad427e9730bca31f796166091297b8533011f3ec616e95652 +ENTROPY 4fdce0700fb5b40a4befdf090845a950ffdc503e4df66134680a4d1a11d95365 +ENTROPY bbf3c7640d19d8801819fa737117a4c48b8e87491abf73e062b21737577e3432 +ENTROPY 2a1185c551163fa9e543b031ff57e6ab159d7392378c740e9204f39866b5a117 +ENTROPY 12cae23085e5db126cedc8ea79b18184d807286d34fbdd3f149f024347b0fbd7 +ENTROPY 51cca26a541a858a93171994e6dd44f9cb3bc4d0d6c4211be87b966c55e040f4 +ENTROPY a70f8142f946c26c8c9173e5099963324bfa56f93f05da482b9a81055026ab1c +ENTROPY 40ee257154045f1f0e0697362c43e862ae9c6ad447aa2cb5fdab95cde6c15824 +ENTROPY e9c5772442b7c96b1659320be8d8610da6d723e594b2152364e0d5dc338f9201 +ENTROPY 385a49f587d0b41c06342352e60905a7e6888834af2dfb0e910b4294c1e03037 +ENTROPY 7bdd923c2df8c703d70c73214d98bbd83401b9e9df96262a5508d789630ebbd4 +ENTROPY 2add91d765c266a1dfb53d0db6f5fa1890b99590094c2986e4b358802a537b47 +ENTROPY 5975f020bbdb33000d4e37c8c6a5c0ecdbef94192b175f16c65a0ff6529e8f63 +ENTROPY bab0d7fca22df7ae32a023f7c4de7380da30f803dd7e179ae05e89844e2a53e2 +ENTROPY 5c37868b6b9db7e043e70ce1940d61adc4b32a04819f9268bbfe7275a2f8dc4d +ENTROPY 770ba37914fe34ce7563fe028b359a5ca0f812dcb9adc17af136b3640ac61952 +ENTROPY e1045a6a0378a96ac4d39b18c7546a6a6da3592706caebbdc03e335f55ceb2af +ENTROPY 126491c2793e7971a9ecaa7a7c92bc7d135570086b5219a79c10daa3f7b159f1 +ENTROPY 3f7b8a64d76b2d135abbcdef71723466195cc34658da04b40b102eb94fcd91ea +ENTROPY fa9569ebac4d0adb6793d83cc5ece4695f44fe8563c847dcfc3cdd1554103b4e +ENTROPY 495fc7a9fdb24b1a7db2932d3dee4c8a6f010728abefdbd49d5d0de699c56799 +ENTROPY 64635ae132a0c899c926800266d7fba3d96f6d0fe4eac915c83dbbd1fcbeec13 +ENTROPY d585ab9c120b2918f613f57900f9d7653492e97481713dce733f6fb917a08b8b +ENTROPY a3f79955de1bd99ecf942697a7eecad76487a42d47dc53505eca65541c3dc057 +ENTROPY dfb77c70111c82bcaef719ed708b15d329695c3ae8c6bb6562ba1d0fce5b89de +ENTROPY c6efdfe7ea12969a0c6b285f138255cb4533e6f294232faa243b27a8bbf36e5f +ENTROPY 489806afe5c9258a734ecce3fc15ab26348f341082982a69bf3bc5b8781a0869 +ENTROPY 62ad9a92c8d078397c056ac6bd57ba0d26cde440e53a785308c1d9fff6b19011 +ENTROPY ad44eddcf318750755cd7337349aa0056c195e59b692dae195373b29fa6aff9b +ENTROPY 4b986347cbd9c1cf968fdd51ccb4454e90130adea7e4332ad2d9da8b55531a86 +ENTROPY bcb940ca2f224ca4c95c1c217149a378276d7f6709a5ed02c4cac0d07e4393e8 +ENTROPY 62c9336302745f272cac55e11ee173cfc8c05e5b3f1cdf80001ad558cb7e4b3a +ENTROPY c1075b002364cc980695d4f43ca05c871b9b3be7da66a7ae3f23059b517e7324 +ENTROPY 508d94288b1c03b76a96f18b79437b18bb7c2b221731bddc5824d4b6f13bb948 +ENTROPY ea42689e35358c2dd6592df89e95ced3fa5f0a5f7cb5ee3a71724e666de13847 +ENTROPY 8ce2fffb6c6e13eb29d689e0c0b3710dd98921e4276937be1f95faf7e195da74 +ENTROPY e9945b0cceeca88282be0e87cfba75b52ef565f4ad674ad8d000bca51af600df +ENTROPY a3b36f6e75c7df0f0042c168cb017e91cf3c164cfcee4852dba1a38dd75c5dec +ENTROPY 70c5b6b873a2e84f09efe054c2e89d300f9ec94622401c75648a72b515e26b1b +ENTROPY d992c7e6a0d06ea53ad22b07a2cbbc5b109b90fb450bdb4e104792190be0fea0 +ENTROPY 8690624987a300e115bb58620b4c13febe445cef2ecb760a871b9622984ca986 +ENTROPY da82cd523d81995bc818a63cdcb96a6c798223782be3b6f290ebc03a13d14861 +ENTROPY f8295583741d66fd96ca8634dd70448109eb77b5fde52f15adcea76d09f73f70 +ENTROPY 70bcc259175fc2484ded03757c11645db3ffbc7476f07b22fa39de7616420166 +ENTROPY c07225754d1be599c1fbee42d956343f1f46076f071ed27fcac0312e4ff55832 +ENTROPY 44649bcc7da629053a8b812621acbba02012a4e9c4cb0c24632c186e857d2094 +ENTROPY a9b20d18def5522332bc38d29ec31c3f42ac255e719116df68dbf96486c232a2 +ENTROPY fadab54e97e58a25dd14833eaa81e824db12967fa7331a3fa20de0a35e8df636 +ENTROPY 8c63fa0a55e797cae44cd292510faef1bee89df6ced36c7aac8c2a20e164e183 +ENTROPY b08c92d27f375acf4949b8b1a188554fbe02925c970174db3fbe1ce8767c101b +ENTROPY f8156deee66b2a098f4fc4f4bcaf06ac409aad48cdbbdb4c48b9200a9d7440e0 +ENTROPY 8a38ee528172aea2b3d9af35906a465fb81f570871076a1ddd2979444fdaf693 +ENTROPY d9dcd3303455f30cb2a8bf97d19848003ddc77b218a613dfa177c5d1fa4903e0 +ENTROPY de359365e60e51199a72fd2903cc8a34c0307870687e7726dc81e0538f453c66 +ENTROPY e7d2d18c11b5b21c1c90b4d2ed616e23c9e2035c46d0b3539c8ddf5857dc52a5 +ENTROPY c78f8381a7898ec681d5ac92c2c00aa65a3ff6aabd6c386e28d25e9bcb2657cb +ENTROPY d3ab683f3e33609c20b690e81a4c24fe69bacf793ab2229501dc314959830283 +ENTROPY 01a418bb23bd0c2b99ed9784859e7a1ae98226b5afa33d72619621faf91b6c28 +ENTROPY 8fb370bb204bd6effc48ec98550d1ce4bbbc6844ebef7d48bf57d8c1598b0221 +ENTROPY 4ce98d3a700dfd1ab26dbde5e9511644320ca74d83a8866ad210b77f00208c29 +ENTROPY 03d1ec71195f4aa2635dd41b83f9495d01083d598236658753249d48a5fe25ee +ENTROPY 97744d6fe059380ac90cb5adde27625cbd219a8edc7d963d4616baf5ddbb2035 +ENTROPY b0eee9fbd647aa152e34fc41a6ac4c102a8b45cba5f6fd5e11600f67afec090e +ENTROPY 76cd1b6a57a1a9de3003a6b46203a3c16f05fb410bd09abc50108186f63186ca +ENTROPY ca867b200effc8ff4e29b64a1f530a428bef1a944215c6f847b09ae961bfc67d +ENTROPY ddf622cab46c04d4b8185911652713f40e99d49efa3caaf8e71dca52ab9a0c16 +ENTROPY d4c3cd3b7e0adb825b6c7c0aa480143953d80169d4480848c9bcf35502e59272 +ENTROPY be7fefb4ad0b82a042d6dbce2d730ec2d77f2b47262f787ba6f829fc2856a7b3 +ENTROPY f68b7be84b2e4142f9b012143a4f095a33c0692b2bf74de27345f423b0935e78 +ENTROPY 2e6140ca610daf126f3aab3d302754738c75cca8884ab918df80cd9e6dfc927d +ENTROPY a86e6f7bbbc90552f854d3f622236b2ea4d1549f36976206812ae8648646a946 +ENTROPY 965c60d3b4678b2e3e83b437dd6fe6b80ef2bfcdbb46614ecc0becb56b35fba7 +ENTROPY 61689fcab23ea0c481d01f878124944b298e8f282820fc69b32db873e2663cb8 +ENTROPY 5b1bdb7a50a21f949a86964b737b81f5957448909fa74824d4ed0bd7c78bb141 +ENTROPY b7f7bb4b1e36d42af2a8ae8994d3d705b91cd090e2ac0868945f1f193a61dbaa +ENTROPY 4343276becc44411f1f959123d5321c2c4aa1a18b7dc3a81605deb39ddfbd04d +ENTROPY b5020d9910e1ad01e02b4438cf1e259003162e2101be96d20114bdc4003bdba5 +ENTROPY 56f575d7c48670f4b889f1d8691bcd1e1d80f8368f7dcff364b6ab91cda9fd08 +ENTROPY 78affdc14d950f94069663e730004b8b2b65631ea7799df102e1bd91c41c82e4 +ENTROPY c8c3a2c29e6d84e3f4229925e32594a5d55e69985f78d08a4025c8db69754661 +ENTROPY 7facf4acb62b351736ea7aff622a49946b79994a00d6f5da91db71c8a5537357 +ENTROPY dcb84e08b89feba70c5b2f9784f4c9dc45db9f07392b1e076ae47829999ee4ef +ENTROPY a33fd92c9357015622e66d2fdd58d9e8f2ba56116afb841f45375106aa65184a +ENTROPY 54c985bd38c6c872ff3f8ef840943f7c9dc008dc480ff3f5368c7dd8e31a8951 +ENTROPY 6167c79617c9063155b399d12a755f13d59d3ca08702504ecc3ce0e6d47d949c +ENTROPY 07c38d6c786c8ee450465a6120fe27660b9ef930da77e502cb8b3d2fa4d3e09d +ENTROPY 3002258dffc9bca7eb7f88b3459983b147962069660837f4c61a003a7666ea9c +ENTROPY 468cb621324a60e09deb69451011d0842733a4b323a0d9589541fb79f3693a4e +ENTROPY 23b7c18de44cfb12f3599ca19b0f93b6d6e751e30b11f0af3983a9b30d92a8c7 +ENTROPY 76f387dbd2ce21fbe634af85532d2703de654af4701415cc1dd0ff547e3f13d0 +ENTROPY e020a4f58d69a6566d922fb9f43d396477873ee6c769418ad4d3be91788bd416 +ENTROPY de2d8821104aedc7c63116cec7489ba7b0133dcbfe38407e087acd60ed14f830 +ENTROPY 9bc31a69ae15137627f484b1e33dd166cc4cc61ee022e5f009eae4989ee01336 +ENTROPY 84da13ccfcd7c1c65090bc07ac77ce013ba85550805e6ee9202ad013c3ba4cfa +ENTROPY 5cbb24533b26ef19b32fa709a87e00f3f717adaef3633b3ba5ffffcb1c4d103e +ENTROPY 9c7de84d8d4a52c8a42697a22965586869ae295a88ca71d1b59ef5d6e7183f0b +ENTROPY 038db427b5f31149ea3fb929a3c6cfe11202a3ebcad39ea61ba8b34b86ac24db +ENTROPY e68b1e2407c2af02cb9fa204580a64650210bb934d1bf4d65c60111d6a82c659 +ENTROPY 17f7dde526ac37e7d71c1aa4e119a5d5b27ac9bc5986b9fe74435ae2565fa795 +ENTROPY 9c1a1dc74c0dbb0b82525c5d2776321ee30a344c745108d6d3f7bc0da35cc5cf +ENTROPY 6c019a9af7e2d816fde4cb24420e28ea7263494fedf3162f1720057b925642f1 +ENTROPY 22ca509d2a425efa9587edd5472b4fa07f181c7ef48efa65e72efe677c1af1fc +ENTROPY 2262489fde00ae892b79047af271dfd03f64636b0f584881acd16d99428015b5 +ENTROPY 669903b496b2e8c2b4191570dfcc9bb4675c517a6e0d83c33339eb054a5080f6 +ENTROPY 4d171f908a4a59e50d4ee435e3ad18e337bf6492c7b50c35508cb83d911d33b6 +ENTROPY a5627077d8f26b1b59c64311b78ac7177d9d998ffac665fbcbc375eec1d9cdd1 +ENTROPY 46eff43cd648b4e9a51b97de22cb00563f40729b0ddc9363837057218adad617 +ENTROPY aca49265c490b849300ac0b9e3ccb27299899b09649411747f8a96d72b039364 +ENTROPY 473b569a5419d8da1ff25f39360ded9f780b399704988b23fad254ecc1ea166a +ENTROPY a1a84a0736f2654d49ad7cb223bc6752fc3df87e06985afac75948ffd5262ce2 +ENTROPY de927716bda78d1d84bed15ff5786bcf9a919be3070234b6589c302fbb071e0e +ENTROPY ea38f935bed7dbcb1f17b69c48b4248f85035f8a8b45c022220acdc435a8b45c +ENTROPY 89724fd701979caa3cfb5232e1efab4c849791ac2225b53b495d47525ce5ffc3 +ENTROPY 7c6962f3d2511e27fab844da8defc23ca28d72456989e010fa6d29698cb54034 +ENTROPY 1d725dfeae903e95323044ee480b7ff047e74fc8673bec4626f8ca3f854d107b +ENTROPY 89144ce9d86e43082b0e057740b606221bbed95aba6597f8b33b5092c53e70fd +ENTROPY 841f27c9221e6da59eaf6d6514f44b17304dbbb248e2f48c263d11a29d10e86f +ENTROPY 88bcffbafa7c52e76e8f92da793575388a906a6ae9e775ded0e62b9e3a5586c8 +ENTROPY 660774e1db71d97c9ef50dbfd5cf8e450966053a671b2b15a93d7771f003c63a +ENTROPY 04a860b66b3f3d298e4ebe710c8dc632f15ff86406031f16e43515bc7732792b +ENTROPY abc9e4133b236f01b4afb26af4dd8909559546b141860fe810e4f8f416a30eb5 +ENTROPY fd522c00a4e03ebc9b87b685c2bfdeac266daa51df642e1573656bba034df215 +ENTROPY bb700cbfdfa07a7d987284e46e13f893695f2a0d42a0a7e8e72db6f42ffd739b +ENTROPY ff411deb38bbadae47223bc768a0b3af07e57126fb10f7870f785db249b39821 +ENTROPY 656169aca86264d83df849221bd4799b08ca277ea9b69d1fcabbe37f90b242e1 +ENTROPY 9c7a0d5da491c3ac25c28dc618e43396c0cc9e167bb701bd4e8c52cde69549f0 +ENTROPY 6a583f28febfc70ee05385cff9e1f16037349b7ea0b16792bfee02d7787f89f2 +ENTROPY b76aa35f163f3109505597e7703a437dd1eb88a1912a7f0221f4cd709e581d82 +ENTROPY 05355709c4c8d60dac176300b3e3843666f5ac0629b535a03473dd5615b9b0a5 +ENTROPY 5ebb69233e14e78b456bf8c91a14d5a9e6310af6f0769f504eee33dbb143c8d9 +ENTROPY 0a01206c5a539f048ae83e1a138d3c5607f7637a043af047727d6bbcba07e015 +ENTROPY fbd5fc1bb79397e8728335ce9e08ca43f1888615bb8759a08c1b1c98c3aefdc2 +ENTROPY bba57cc08124c8bba22bf666269d23ecceaa38c084e5861d24b556c6ba6a2ce4 +ENTROPY 3ba6f707b0cb3030bfff0f9bc26958521d09b9ec92ff62e6ce50be1714f8f310 +ENTROPY 2511c59bdbd81b9adcbb7915c266cdb4e487fb07a1290d77bf5ec9599ccfcc16 +ENTROPY 64832564fab853465dc8207d9977d802150e1b12cc56f8a48a3856fbe254de66 +ENTROPY 895f37e48b8fd45cca77e0b18cd749ec67cb1d3cd9dd2cb04734dd591d95d258 +ENTROPY 1379975d6f921a6e810a051871d86dfbc2d5fb4086811209f6a6471251accf8b +ENTROPY a4addd810660f30dfeea1ff9bf04042cece92876d609adc07c1fbe87e6847db5 +ENTROPY 2629e7ed7a7d870e835325ff49c763d486bb6cbced307ee339c861dd864add7d +ENTROPY 4d6950057df1a7bcd99c3ae142c6100070ddbed28ab4a757db680162b765e320 +ENTROPY 3747e98f034f351e0aac7548359a4e7ec52788d617219d79133a6087059df0d9 +ENTROPY 90962efdd25c959d88e4c873ea0ef150b53bd197ae88715c1bb4204bd21433ed +ENTROPY c58d44554a1c214bfb537abff4eab674a8b9cc2d36db73e3f008ebff0429d3f3 +ENTROPY 40e6c327917cae3d706731784d241c3a0cc40d2a238dd543f22b081007a3a042 +ENTROPY 67041fee0288e5ff345ecfc011b2bb87b168b05f65316fd8a36710b3133d8187 +ENTROPY 6fd22d0ab3b6d4a2340621f5f0f78f7107c9db98de4b72afc0e11993afff3cd3 +ENTROPY 4b47782f96e5b503f3ad516fcd3a9888ce43d7233891f6b09a35761712854a4d +ENTROPY 5c5afb914760e713157a5ca5a77ce2abf53703f2db762b0d4cc2137492f9d41f +ENTROPY b4563ca821af150c7b4d90015de74e70ef5b95f00b13b0a3d44455d78739c2f0 +ENTROPY 5c12f94d5d24c9126b34ec78a1a6131bd331b632626eb1eae9f46436938bab63 +ENTROPY dfae8aafa93a3f4a14cbf8387ea35ce1d0bd4888307ff30149b0321408653d38 +ENTROPY d692250bc51b400bba131776d585356b37f2ed6a88539a495815b3eb6d57ea57 +ENTROPY 78673cc686f780ca371542da8d455cd53befa4e91cd6ca45e9d981627b4e8137 +ENTROPY cd9cf241147df004ae94c09230a7d77183fd6a645ac8d96ca80e51382b7dcb7d +ENTROPY 866237d9ff53b797f7a49a3abc31b1b077649b689c00eced65495c3d8a1df701 +ENTROPY d4d7e944a77f424190e983cd8fd133e067730141d0e22138f56e6b9e992cb1b9 +ENTROPY 5962e95d8aca9fbf4858a6ea9467cca107316b7edaff7ebe4a13b3fa57d3e851 +ENTROPY 7f399d894fd82868e1eb6d6605b8248baa7bcd54fc4ce9e4e08708ac0c41b391 +ENTROPY e06793f8f5649c99457a86244570fb36dd89c6b73758a5f28fa98dcd9bb1bd1e +ENTROPY 5c2db6dc1cb77f0a3f3d12388e7274d870971ca356d59c24d56d07eeb1f00bc3 +ENTROPY 9964f57d7edeb9547ec5d84a0d0830d38e656920b7195a19d1aa236b697b0de5 +ENTROPY 18ec7e353deed6f85771118eec48a3925dd3d038904221526437a9df3cbb56bf +ENTROPY 67454db7be72c117037a4a08d523de89cd120a4aeb5d46ec2469ea4bda4f8819 +ENTROPY f2655a6ecdf807e2cae1a2d06db8ac236afa76e680259a8eabc1334ec6dea78e +ENTROPY 3efe60ef8d4dfeab466c9b751f344c8c115c1107f18b11568a3d53e4a7e983c2 +ENTROPY fea099c17b8df6362326a187afce156fcbf970d9fb0cc687dc215ca2e274823c +ENTROPY d9fc35705c23a6349f9f40203451c0d7026e109846e201a2ad8744dde2b704fd +ENTROPY 89e297760a097f0678e90259324ae2ff135bdc94e7867f9a8424284d36385390 +ENTROPY 6768c8817ffa98639a36757d65fc7ca545a89735c8d1ea6e3fcd21e45771816c +ENTROPY c617385c7614782c63bd1687df656208a0142272355ee1790cae820bf606ea33 +ENTROPY fb0c03a75000c4fb15f197f84786b2f8f0c70460bccc1585eecd237a29a5ab07 +ENTROPY 20533ec53afc7b7d7108d5cf31254b5398f836003bc45b1c9ffc7f7df776b231 +ENTROPY e904660da516492cdb563633d01f891ace23a9376719aa66424830377ea4abb1 +ENTROPY 0ed55855801a051a22a1da22e287a31b0863e3639a09ee0ca499912339a1b344 +ENTROPY 49aa9f86886ac7d19dda1fdb8a19f52566acb340717fa26e6ef7604eaa327052 +ENTROPY e9e3b5d529fb9f7c9628f0bc03abc9e5413a4588c4ce5e287969c930a8d5e96f +ENTROPY c390118a0ef0b6d812c722fd3cd83e166bd5eee64fb7d6cae44eca2ca2e1ed0c +ENTROPY d2daf70c7df28679c94d3eacf4a2bdb9c8b8f67926d3d903e8eda8f3830ef897 +ENTROPY 59b8372ac4d0282edfb76613cebf23bd8de7a825a4777d8c30ae116d63f66ef8 +ENTROPY 23152a32e1ff3a40feff0e8bca76563998cfb92e51d3ae9113cbccfe9aed7b04 +ENTROPY e163406bb1acd1373e7f3f8235dba1cab64b8f7ba8185b1c15b263620e792d22 +ENTROPY ca21b9848e27005a677944962fa93187747b523cb8dfb14170cb89e65e07c4ce +ENTROPY 58c6de3062a6fee922cc13791963f26ebda1c7f78bf5b1ef29f62aa81c2f345d +ENTROPY 9c7f21a8c24bee54bd56e18e65573ea016cd8bd9174b1f9975d492d91f703346 +ENTROPY 70039df0cb96c8a64254f89f7509bf3d34fd14acde59e95b403a4e01fc1a5299 +ENTROPY 23081f1310f8d497c4b362eb3d075f96467c3a3951be3f9927d448fe270748af +ENTROPY df7fe61759c195da2c8421ab2aae1365d78b507af3da47a3c3b353479da0a3c8 +ENTROPY ed6823923461b5813a82f0ad15831357436cf6d2cb03106d5ad8fd55ea714e87 +ENTROPY a1cc75241a29ee8ad4432fac81f65302df5e990f82caba03b52f629b1fa36ddb +ENTROPY ae0dcc7f55bca6e2df2d255562375f221fdca738ed8e788174fa52dca06d5176 +ENTROPY 70a2feb59c8b78691dd0aa76a0587945304bf9c226f83e84648a385859c25937 +ENTROPY 929fc72eecc87f419c66dc8ce5801186dbc8ccb1c29b801cfc2d833a4c249f9b +ENTROPY d4aa9e2cc420f2fa2b4f6e2f7c1c69f7547995b71d90ae05c0033040ff83dea4 +ENTROPY 0d7f16e995f3103a0268c4e8e2647465e7b63ddcb708a3d2d35828e7eaa323f1 +ENTROPY 4710208aa270f03663023cab66cfc3b4a96be2eb20c41ff2ad687a0d363be70d +ENTROPY 2ffe2a11c2f7e8278d7431a429c289412ed54c9cd030416c982eef18d17bbf50 +ENTROPY 28f13a6bfcba8b6bf09368ae4e86817198c87343ed38bcfce89c30e2178b4838 +ENTROPY 02e492a32e14e1cc4f4ae9ce617bbc6641b80701fd318dfa1633f4cad4bad877 +ENTROPY 470c74f950483b7465acae780e5c42997443bb9711bf6df89e7f6143893a5ead +ENTROPY 883c54a1402d280bec2971e892d1302425dd7655c1623154e58a2db85ccba420 +ENTROPY ac3fa361e16f7a209f7cdcaf884b9888f35d9d73181ec7a6197218f5aaf80bfa +ENTROPY 58845c386a17558c18bb850ebe4247ee9fc46cb748ce6610eeb49cd5229b8e44 +ENTROPY 45fa12164329018bc1397418c63a2fc346cbe064567bb326e335e28f7f79890d +ENTROPY 37804b83b10ff8f8c2e5702573a343f46b80575b799d7792715acfa7c9ac8e1e +ENTROPY e681fae2a927ee1e9fb20545a236c82cc3744a8b5ba4a6b43dcd44c4330dd6a4 +ENTROPY 0c630ec356f91122842790d05ebd60a04f44da68168bd2e61c2796487fdd7922 +ENTROPY 0bc6f33cf416cd73c29b1afc8e308a8c65b42734d36e0b7795117a7b48c2b926 +ENTROPY fc250ad56c625e5b21447e71280177eb1d8f8bb8dea5c5b55bd9e157fedc9782 +ENTROPY 31d8037fa19790121396826547a823a76ec1aa64242bba53ab4def9465eb45f0 +ENTROPY 2953098f99e18b18b883275b57b25017631219353cb42320901c0d7031987fdd +ENTROPY 93892cc9980d3c9ebb799e5b27f8d3f44063029c11f66acb433ba51f5a1f32ab +ENTROPY a9f5d7bed487e7a3a75d3089f1100fa553e4fc994a081984b0a7fa0035efffcf +ENTROPY a7e45cd325c590351d291b2a2b7c929508d77de3253ca3a751dccb697f2ad250 +ENTROPY e87ef34a4b262994a88f3b0ed004a2ad275a1f55c713a0cda5fe52d256e5f8f4 +ENTROPY ed23a682d87214404ec66c530eca98b07e51ef77f7afb2f3b75a34b899d48fcb +ENTROPY 880508daae8094ad9371922bcb071849f5eec499e6ff70947d3ac88fec4313c6 +ENTROPY a80a2c728d4137badb8e6fc8c0c98ec17773d27c8d5fd9e2cd437e5d8d366391 +ENTROPY 32744e95e92a3162d0b4d38fb659f25b15647b1a845d8ea1298889528eb4c4da +ENTROPY 71f564454fb6ba1ccdcf43a735f3de6cb97c7389eba613a2efbaf9d7a7e5b2f9 +ENTROPY 595694ccb9b8498908a71d2d18fc3617d0d22022785ef69c88beba11afb84e5c +ENTROPY d7eafc911c1bf4dc08cc064a2a0ee1f635af6f16c010ebc8b81733afb9408489 +ENTROPY 53de14049e83c5c083768ae1e6d95af23cdbab21deac996eb9920ee1c859ae96 +ENTROPY 7404c6a106d7451bdc6e1cbcd043ece1e2504be2bd3558b527147358caefce8a +ENTROPY d52d2c934e176d6655b6ebc00cbd470c294aef230b6df31ec8acada036ad558b +ENTROPY 5fc32da710da0cfcd974a5b6560ba9786fc713b7f86b9f7397ebd925689f6305 +ENTROPY 51c4ccfcc1459e1d4337eddc0eb2e40569bea627759360452c2d6c0648379c22 +ENTROPY 8918b90d083755eb4910d559f8bd4ade44720fd056ebd430bbb81f790b985d7c +ENTROPY 27f184196ad7075fd81fb7dcdd16d74491d3badeec0144dff22b05efe83efb0f +ENTROPY 609faa6f8754966b3e9c7ae92acbc1fcda34ce37066477173da69ae6a5201303 +ENTROPY 9022d1a5f1d0003c2fa3e6eb01bfb1a5f1e31dbf62bd16dfcd1a58ba8a7d4cf2 +ENTROPY 09a6db523b4d3ea5d87bffbcef5385fb13d0631c1b680dac0a155380ebe69eea +ENTROPY a666f82dc39b08610f9bab28adde7103fc98447b23a68a1417c79ea6e13d4fab +ENTROPY df2645773bc64ca952be58ad4047282f65381e311c928fcbe7678ab9078196ae +ENTROPY 902745dec3416ebe938ff79bc08b34ca597d38f677b2c3912ee5cf64d1392a3e +ENTROPY 603451cbd288b709761916a7d66f051059002aa62f865e100c74ad4dde4f394d +ENTROPY 28fe388fe1ce468629a3bc5331e8352f849dd4c36e08751c2d71401beacb66ba +ENTROPY 97e89b2d84040b6879d0eeaf289337db99d0cf6d4b3793a08ef17e94dc5020af +ENTROPY 565a7c0c148afa04e1a048a2648224333af76f56ce5e905b9f0d635607631163 +ENTROPY e55fbbfe4b5ab6cfb9b85c4268cb1e24863167d830bb8f03b87eded2e355dc0a +ENTROPY f131ad2cbfa41cd6673e79f5949191a93e1060d5dccd70527f61d4d54d29d10e +ENTROPY e58dbab0ccddd8b860f7afb6f1dd139c33f9d587a2e0ba3ea46226c5cac36e36 +ENTROPY 96954a5ac2521d3b390daeda188dd86cdcf9f712bb106c89e261949019d0cf73 +ENTROPY f6f919f082f505da6916cb504800f4ce87aa9286ba9045d822ff64116c0a2dbd +ENTROPY 915c977c222151474b0b6a97718f33fe77c7b100ac2eec2dc459d8ca82d39239 +ENTROPY 9f7ba213a4ee613acb44b58ab9906378966d733e6a3a334c9f99e6c62e5cfe69 +ENTROPY a46a9297781ec8b76723cce1c62ca6a4b48c13cb5c9fd69f3863ebee16dc8486 +ENTROPY 8443bad12428fcb2a7279123b995a6fe4b5028a912a2e227fd3d851db114aafb +ENTROPY 249e2494064263a6366a6d0977939b1b717268459e6036c7311ccdbc7fe4b960 +ENTROPY 128cc469a59a554cd94f1f7bc7542f736d115b4a3260eead3bcaefc4fd5bb6cb +ENTROPY 687a48943169548cb66ccbb1ef85a845f49fd898705c4dd5fe0491b67aba380e +ENTROPY 7c7f72a34364be1fa377684cb1604d8d8a1c7aaef387ccea32d25e69107e6813 +ENTROPY a4cfaf4fae81d120c285733bc5e162b182d85a5123ab8b9a39824dd7974f3085 +ENTROPY f476a5b6e945fd4274c1acbaf50544f6d99009d7b67d293ac02fb171eb3424b3 +ENTROPY c2ebda11564563ff984610eeab37bbc75778c2c8ef0245363ca11c1e290b8b3f +ENTROPY 6312d7def2faa007bb8c12c64bf89b8f6b964a8e0e8a20657be4428eaa3fe4f8 +ENTROPY e2bf343ed8647d1004e788a33d810b3b30031db4172b9c5095e6e82999fb180f +ENTROPY ff3251087945c14ecdee7d64f79d66549a2efc3352ad38017d3ce4ba8a6d2d37 +ENTROPY 920504e0d8741f09f990c079c9e5f8f986c1eee88445d0435e2fa90e89333675 +ENTROPY c44a5263f5a75b442355a0e1f9fe1e08c58bda4b040c0e5054fb9b7c91947419 +ENTROPY 640a83395ddf452d507cebf5e72939cf76118726342d99f0f888bdee19a39d60 +ENTROPY 1a3ced68dc7ec021ed5232ff0fd657a746170e44da82f7c0f7b7f3d13d1c9f1e +ENTROPY 2688c3f2cb0b406bce0a8f5352665abd3d51fa3013d08f95c454b498dac49713 +ENTROPY 28a98e3dd6fbdd325e7af3dee04965dff7c3eccefe74a782cc8ec576b23dbdb7 +ENTROPY 04e911655deca1c1572b561eabfde051c724486303d4fec7523427a15fb12dbb +ENTROPY 0ed3dd8aae22f660d8013f5f6b88763955d88e057de7c94ed4cec48f9a013f29 +ENTROPY 275e91059782bb17259f10c4e228756f673e0863ecc22a49d9f532321cfae9b0 +ENTROPY 5219868b88bcd5eb9d67b446313eb2397665c27eae80f3e9034e37c90b4f028a +ENTROPY d1a2db8507568b33e77e0ee79a1993b4a0fbcf0436f4a84dae734fddeb53f691 +ENTROPY 582c55635fdab968ebe0ffcfe66e6a49bd5de3b33deec0eb0228dbeabadbd749 +ENTROPY b0b36e69331640e5d095576418344935758e5e099af5a2a93b401c44ee0ad53d +ENTROPY b51920e82989d99b443f6722a4ecf5f41b6870b6e85f97e8ab052732dddb2d3b +ENTROPY 2c9764df7d7f3828852f46791a02d1f6cd09e37d41d0184ea667f21528e32ef5 +ENTROPY 5dbe04213c3f4eb9e8cefb4a954563f918003adb28b5124b7d14b5c88bba55f3 +ENTROPY 6d1fcdec97cf56822cd1cb0997e0e6ecd46e936b2c047ab89e99c37efdd772de +ENTROPY 24518822a41434821cbe8cd25454597b2f1b00165b9cefc15cf52850ce985005 +ENTROPY 7f52820821fce82456e5489d0838f2722c8090a2439bfa3fb7c1f1705b6083ce +ENTROPY e4a090f0710d35ffb48b3c957c36475dc350f82d5165a078d56ba2362c8a969a +ENTROPY eddbb309852dfed03ab4309c2c77f79b3e00b6f589b6ab9055379ffcd21cd31a +ENTROPY 0207334401633158c8dadf968dfd2d956ebbc567a0ed06f26997f59daecfa557 +ENTROPY f73d2976f1d1fb7f526e088f2cc9abf51453330352c08422aecd0ca98bdf5602 +ENTROPY 19216ec10cf031f6d89043594b8c96db8237179a5d85d88819b7f5a4fd4d19b6 +ENTROPY 35a1302621ee0467104581dfb44c0f1c44e2b12de79c61a2eae63fc395abd713 +ENTROPY 12810d41ebd9c4915d1232aeb801dd0db3c0e50048ebb2ef63ea15fe2ecfcbf7 +ENTROPY 62e50c2efd5ea7bc8480bb7720082733dfc73192aeef5b973195f2406fe9189a +ENTROPY b317c8aba4f697fe9e6261617a3491e89e4674ab7f86577fc691014991ff892c +ENTROPY be594f3cf64a557a1123693c05a9be423f97e50c808b310dfd8ba2e40ecb602f +ENTROPY a01b550c8bfd74c01b7a9c0c59c0c7eed45930d3daae9742d0fba2e2854c6e14 +ENTROPY 9b64234d72f3a8edbf7b5c62edf72be1a4fb0591688f5c949ebb875ea82caf26 +ENTROPY a30c75266e35e3f2cfbca9cd2e84ea9f75184cdc70e51bda42f1ba9fa0ff0191 +ENTROPY b675df66544fba5a38d990ba09c1fac8e40544242c126b9e2ce230894b84ecfc +ENTROPY 06826499283b3a4175bf99125a87be6968fb4f2d8378d72c16be34bce8c6ce69 +ENTROPY 2f1e5eb45c8a17688ce4b2048cbe93e28698987cdaf3e1f412d5e6e4a719ed22 +ENTROPY 02106aa2762c275e19d2e72bcb86f0ad7d1053b8239250e6640fc9e4939e98a1 +ENTROPY a0cb7f76b00e5b9c3806b4a7479e5f217d059a249ca145c41bf122ba71953f2a +ENTROPY 4beceabae22c618a3620861d919f4b4b920e3c9023e0e58722663d55b7b9f1d4 +ENTROPY 678fbcfcb262bff18ab6e6b54ab55cca549e9b349a077e8f103a2f36b5ffe2af +ENTROPY 9290ffd3dcfa20bdf6788b57c0dca2532a03872bb3e57f7ea95969e81ca9d188 +ENTROPY 095a1902ed6764c074254d1053bb0a080dfe9efc066ec546198f9e300cb67495 +ENTROPY 0ce6c5e34ad79e2e4191403963f1c3566493a19728b8d7c1feefbd47f6c5b6fb +ENTROPY 2a5fce63a0266e10c44bc72060da481f2180aacef81cf075babb4066a6c03002 +ENTROPY c01e33fec765e290f08c2366bc5aedb97fd5684ca63b839af46ee53c66351d01 +ENTROPY 1652e448325b40a53c155f33a7bd69f282166f032bd85743c3304034fbf21c05 +ENTROPY 5200b5c0897b948fb5708e12afa96622e02eb579d9fdb50f4c3b0a4bde8de56c +ENTROPY 04874a90b09a05d86ea2424069a184c5d08066f2e2769cda46f06b8d3160959d +ENTROPY cf38091add94a1a98a46cde9728a938262b939f9666537095d37a128ed8ffbd3 +ENTROPY 57a0712b45549864da8e9147ceefcc383428f30358b99a3fcebc34da25c077b5 +ENTROPY 24239acd30e5a84f698d27d37ccb244805d5cbf856f50f04bf59607f6ea72a7c +ENTROPY 8abbf964ffd67b2e68cbf047671652ca11a42b76d8454bd7ad88af71df8e6b96 +ENTROPY aab500205c7e0d0ae7b73c25f8099a317ed123a70a948d173ce423a736b02f3b +ENTROPY 571af298f83657ec8536b9ff7d0b37305762a4cc800602712cdf2f14421e3caf +ENTROPY e2a46966b59b098ae54365bb009a16a1dd83ac1c4f7826b7d5fdb1a5482a2352 +ENTROPY a3616d3e4288e668933cdada7de3d2716f3ec7eee8d2f0d94474fad1bb7e1fd8 +ENTROPY 2d9c837ff4bce9f3dcf6767f1cdbfbb1c05973d0f1713a31c73273b4069680ce +ENTROPY 4cd51b2f4424ae6ec466d8e481f5ca25afef46240ab752a3af80949c75eab532 +ENTROPY baf0d23f2c87d095b6283d03ef17bf5cd1358fe279da9387c6aa341f8fc001ac +ENTROPY 5ec2e4510a780dfce6fc5ab68cb3de755eeb6f352fcfaafd030de453a25829d5 +ENTROPY 25bc042e4ce81d91249a2125102b4f54c037b9bad1f0ee71cd251fe636f0d50c +ENTROPY c460898cdfc8f14f447cf340b7139700cdaca4f6873725be3ddb92f66eacecf2 +ENTROPY 77904b6ae679efbe2a7ceeab1c1682ebde07bd8611d8c657649f04022020c860 +ENTROPY 4f503a106e31e4ffd48f66abb3f38cfb931c413f6c737d7d4c124387d394475c +ENTROPY d3161d8ce0545f4ca1a4647cf1865daf47943991fa5c14ae96b0842028ff667a +ENTROPY c6669e8cda093f7c247feb0256dc64d1ccea833697be9dd38acf2596cb0d70df +ENTROPY 68f8b68a335de0edd33c3c50628e41f9e0ea18e58643073d42042f03c3efc314 +ENTROPY 0cf39ac6aaeefd9ecb4e45cc0ee33a111ae9af088c72ae91300a1c9608b343ed +ENTROPY d04cc7c0c10c31cfbac62575147dbac8e3a98beec7f4f07ccb711062f589694e +ENTROPY e83105283764c72326f08fde6f4a3575497ef904540297f440eec484022d8246 +ENTROPY 97ce3b8533a0b5cfd67952ea9cc06a0328715bccee971fc8b82de6b4035850d0 +ENTROPY 16418b3ddf6d982adb34bdaf57225d3f9d2b19a9ea989f75c432a5652fd29dc7 +ENTROPY a85e8fd8c958f7fc554f3d24926a953a9e011705d8ed651b6737556f45e292a2 +ENTROPY f94d4d974266f2a2ea7cf748d0f22d792a33083adbcd566138be4ad5e7f3aa76 +ENTROPY 7b005290ccd07b954734f47e62585e492b7d9aa72b8f8f8730c4b7c28526cfda +ENTROPY 377e06d3cc1eca4d71c7f9b53e99625f0addbd200f9ffbf54a7751c6437da20e +ENTROPY 2007542a791fc504da4c0be63be5f0fa21e94f39ffa02e167423a8385bb89841 +ENTROPY 9d56fe9c236e1c09b1be6de03f290d40ca71d63e61db3cf4e4d12de1922fdb4b +ENTROPY b035c2c80b8f92244a7d15b0dab9908575f95bf45d8dbd58c9075183e5e39463 +ENTROPY e835507e71b8a297b30dcdf0b0bae7481b57c09be9e19c3a025bfb828d3456da +ENTROPY e8f8f5aacad350ea5c6033d5162e34a2f84187d84768648d0ac637d4e8788847 +ENTROPY 21fe8ef33bb4af7652efb1c08adf3757eab666d8990b23d2e2e262de2c573686 +ENTROPY ee74ec576d6784ae1f9aec99882702969e3a362902780b6ac85c897bd3e68e6b +ENTROPY 8afe62f643c29a61bf953e5b661a686e00190c2c08ae88f8783280450f57910f +ENTROPY 9f8471162100a1ad733acde87164246bd11a5ae08089f544551a3fd9f3d85b30 +ENTROPY 2c34745a1b5365be80035a0a186213ed1d9cdf6859187e1c0dbcfa096694e664 +ENTROPY 7a33a61f987b3d0a6e276f870f3d6b6c41dc6e82a6c9b161446081d9f6192141 +ENTROPY cec1c548a91bb0418d5582e74d0f2b2044600ce5754220a3560bc05bd3a68187 +ENTROPY 63660df7873bd7b8c4033a240025da73b3b8fe187c6c50fee7e40cba48bce44e +ENTROPY 0c0cb86f1ff04e04d284276bfc7214f2b4055d6d178b92b5c3034b1e6dc70104 +ENTROPY 440ba11075867b7be3d4feb54183fcba2e9774b60b7875bf761d4efe5a093783 +ENTROPY 75ba2f44508d93d3c4aac55e91472a5d1da935cde6566916c2e708dbf79fb943 +ENTROPY 12a63387d8b111d5a2142a9c9a6df2a0e716b5fdcd5e2651f68b99654f750d65 +ENTROPY d1ef7dd399e801bccd4dfda4a51f0249e0f5fb10a72834697a076ca2ee284ce1 +ENTROPY eb4728b51f96ed3a18e09370d6f6735a5e053ba29c020b1af4799cf6d6a72a2f +ENTROPY 93bd29a3fe26fe4aef1abdb9b6821e0741731c8f7763f334ab227a2e0fcda893 +ENTROPY 0e8ef301e2808780882babf5d0a8d29dee51e630ce8c9ad29a46efa361c55424 +ENTROPY ace3fe3dfbd3ec70c4b0e859ba9323daa12041aad69d73d0e33a6595641f924b +ENTROPY f96d74e38e738af3a7fb75203700fd2082c4a95fde326199129093f4db163ab7 +ENTROPY d208c54a3f51c74578d03a0347e04099d37bccdbb17022ac1dfef2fe99a4e6f5 +ENTROPY be7e45b0f62b698bfad32e906326938733951c7bd74fc4a50326828cfb3d5ac6 +ENTROPY 949087e38f3decc77a0cb13d950ccba32fb19b6d4b044ab9dd338b3eaeb0c416 +ENTROPY 6cac95a75a65bd99e372cb331769e18e4d56e51f637f4d5c2bbd69a7a20e1d51 +ENTROPY f617ffb263f81007eae44bd1bc1dcffc9b3679e3f4fb7c0c4b01ecdc75b9e144 +ENTROPY 5914f60be9d3fc93e27e5dcc882917f38d2d44172fca3941fd366f71e86db5af +ENTROPY 1af34923fb296982656bc18f2ae9caee43755628b9cc930cd03245059166512a +ENTROPY 89e9f9c9a7f3025d269e2918fc44aedc910835b2d872d943bb317375553e90df +ENTROPY 4675c921741ef315027d620e77f772c0c25c2a29b6d8b875c72a9f29bb85ba07 +ENTROPY cdaec59aee3ec487f71770ec7d31431129e1915cb6abbc1a9a2484471cb413fc +ENTROPY 53b0991bca3164dcf1a6d57221f9eb7966ce9c05730def004b77876aa45dae51 +ENTROPY c471f5c3ca38f912c31a518e363828bd94ce9aef0e83d8c4f780caab12054004 +ENTROPY d7aa0d3881dfb9b01ffd7bdc15ec96006672648daad55eb7397127ca3f2120cc +ENTROPY ae125ba0484fd95ff73772ba85a6cd762ecf826c5d2af684f415e23da1ff3ead +ENTROPY 5f9c5ea4cb22983001b30293c78238b22470acf9b4f9904efa221079db3a92bc +ENTROPY 82b8fc804d46f52c116f323c7a681ad010ab29e20bf4a3875bb7eec8ce0a2cd5 +ENTROPY 64b2533917e7ea426c071b0388baa1223e33ceea57ac8bc6b98e66b7493ec585 +ENTROPY 3e69d705099a9386900d4f940d1a45c552a594d1a89ddbe2e2ea60701406ca2d +ENTROPY 600d6ade52addbc7c3e19686a780a899c6987270c3f6aa60cc1617e9cae8f0e0 +ENTROPY 170c6510d7abe3ef365ddb75b6f9d6045bd15260cb24ecc5a5ee1d00c1f770ab +ENTROPY 94a790b9615c6d8d22ea3d520b8be44513cee0325d3a7dbfd5070a388df218a9 +ENTROPY 0fefa5e48f2883fffd680567e7b2203d542ebfc73502eff1a6d219d7bb33bcf8 +ENTROPY 89083dd6c1cd5a0bc84ed2148858f0cc47e75dbe5ed9353af3a720b8a966af6c +ENTROPY dbf9a94c815006fec8414836b19034db60f5bae0991638c390276730fef07fc9 +ENTROPY a1b3f48d5838a981cc55ca25999b4240a1794d87fad17873ebf3aae12bc90324 +ENTROPY f8453f81b42adaea6acc31cc2e9a27ce92f775d6f5f35ad9f657ff513e71fd02 +ENTROPY 570b4a7d440b140787b243d6750ed2dceed43877a54efd3b35796ef949992e18 +ENTROPY ad196733e7f711e97819dc5d9b2b8c35e2735b512de92312d56e139648387d15 +ENTROPY 9e85b2bca3d9b152d1b7363e67ace284c7a8df1adc449c0ed4f9f754e2864432 +ENTROPY 5d88eadeaf551f352574f005e7e718dca28a60ba0447c84bfb4dcf5d81100e1e +ENTROPY 24341ed96fedaa24c8e7a34f63aee24a9f81b8a107668f56a355b01f6dd4a469 +ENTROPY eb932bf3c7a48752b6176c9d708dc494b7b5d5284ebb8eb82f73733a40ef1280 +ENTROPY c16d06ddaf65d18650460700eb16279323189d2ad22f6f02d77b8d20733f181a +ENTROPY c68c19e1a7fade304d1100cd8e395e4c1956de5c530bfe9446aa6b02599d0e26 +ENTROPY 1ecc6ea5f51aecd9b32122e3b960306814713291c0432513416cd5977730c3e4 +ENTROPY 9ed9a6111f81fed7eb492db266b5a1e1e36ea51499eb893bdf9133c0664f63d4 +ENTROPY caa6a209135cb73577509e8393553da0798b6909d8bd29323c899de9b7c35a71 +ENTROPY fd6f2d5fd1e97ca573c7b10f0a5a235d2691962428e2f131f6dbf39d68b885bc +ENTROPY 3731b64a7d4db8afda16202dfa7c1d005a77d4d354b2a23fd28998e5baea693e +ENTROPY 2d7ddcc7a10c8baddb6388cd485de47c19179b34af421851aea1b150f5afdb41 +ENTROPY 65818069be1ce4e734a82c6a339cf9bfcd343d04e42d0842c433b2b9104dec8f +ENTROPY 6103343a82bc1a3cd4bd3e22f254b2bbc2f69d9abd89b521918e60492ccc9cd8 +ENTROPY 19dda6ed47ac0aff12e22b9f76f3d045fd4af59ffefeb97a0fc437ad4b68c438 +ENTROPY 899312e4e5573ed9d6d9cce0357c991c0525190684750c242c632eff59313d75 +ENTROPY c0d8d826ceef00a322c660961e8dbdd9152f65944112beaa626dcc09c4fc63ef +ENTROPY 755afcdc44159186438366b796267d1f107363ae9797e3c057c09ae5e5880f2e +ENTROPY 92fb0ab8eaeefab304c34ff4d378b3625e08bff3d1d0e56b9477fc17225dfb40 +ENTROPY bd1e29af3e5c9cf12bd419edc9fa2493ffe0dfe974d346348aac4671ca56d0ae +ENTROPY 5df3c8635b2c180df915a96f8be991e3ae9a4ac87b052e0f07fec0dc0523a57c +ENTROPY e54b20b1e618f66df0ae413f0527bd46a19cc2c285b22811ac1cb6a1382d18c3 +ENTROPY 0cd676ac9ab83276c1f51570bc67d104c0c6dd3b6fb040cd968a59f7277bfc42 +ENTROPY 61a6af8f100467b9d715013879ef69ca64290f1feb97813d60edeb39ff07daab +ENTROPY edfd149f14ff21e401bf74f299311e0d8239c77077fe55b1e3e91b7fbee1ac2f +ENTROPY 2c55918d559a244139bb00f191f24686904666d2e6c906716384e1a0176fea34 +ENTROPY 4c753ddd6c975f1724e61f933814a1991a2c746ed52962ba73eb73727232b6e5 +ENTROPY 2f34b075955b34130b9c1845e178da89b56077bc1e047c72c4682137b0b149f6 +ENTROPY 4ed9679fcc59f73e8ee96acf88c4abc645ff4265a0d05f5d734eaec7157e1afe +ENTROPY e230abafbd9dbcafda0f6052f07d886c488007085f1b7c456da25a9a5e33480e +ENTROPY c4c1d50c30e4c88952aa66a4635447fdf9733164671f396ec08a96d0b75701b1 +ENTROPY 7bbbd828b34d84d8a7067f71faec6dda314a92accd98114c0459aef98eaacb15 +ENTROPY 9997a52b5ffe3b493377f6da82a210677837d85a4a670438b26888db6f165335 +ENTROPY 0888501159171e7f561437062362a54d3d5604ffe89327e821e6d05d0abb108a +ENTROPY ac20deb1f544a7d3c0fa9afda7371c9be7da43a00053cbbf8d9d553b6a6bda21 +ENTROPY b6fc97d7c66c451fc2f00d4f9d4dff557b30ef883154419adddbb8775e844dc3 +ENTROPY 91a63702069460bcba9671373d99e0d880a5b0988d8266e7ff8de22d8855bca8 +ENTROPY c27bfd7c6c7bc1af82d79030e2d6c8b2ba53cf64a737baab95e109ac9c65de15 +ENTROPY b120916d585cb0d61b2af3941af3b2caed8023936bd5682cccbe68c6a87ddbee +ENTROPY b7f9196c032ed2d2590d315cc17b16c0c52cec45a833c3d87f856310e594e3fa +ENTROPY 5ade8cab95591b3589198906ce00f31e8f35866cbfb99d8852d57030dbbe7473 +ENTROPY 11ce8dbdf026f77e9184ca6f1537fe7961af1c148d05cf8aa2ded5590e297490 +ENTROPY c81db6eb670686662c42d4ecf1a88af335b655bf610b41eae365fb1dcc5a6773 +ENTROPY 1daa360dde4f11c8c860d2be261b4f2dc6aabaa6ea4c6866a8643efc810e6d93 +ENTROPY 67933d7e9f5d7e09133327b0a83051705f9222326088c0b19987e90e91314897 +ENTROPY d38dbf01989018b89d4e990618e44a7817c72f0265b8f5c0b9e7c1fdc26583fc +ENTROPY 69136bd72eced941040dabcdbb145115c550758d2c3e3f0c2ff22264532a77b1 +ENTROPY 0b67dcfe5d606a902154a632793c1cbfd70bcf5c0a12ddb4b5a00a6973707b6a +ENTROPY bb031220819bc817a36a44863d15909926e01d6b6af2a49b7063eb3b829d1a80 +ENTROPY d1f6431dedb8303b97e182b70ddbf9b5b1dd9ecbcf2638b20ca6067709ebc70b +ENTROPY 33be750a171c5ddd2d47ddf6666db0eea0716f7c268af9c6290f91691e350419 +ENTROPY 321790751cb2737eefce140a3d8e5d2e3ac6a7ab3e2c1f3700caf13ac15c04ce +ENTROPY d8d75dc56275a174fd915055fb975d4cba343ad055212a5e7b266e474d9ec461 +ENTROPY 14c26247d8828cbb6980c9808b2d1c709edf32d121d8be9dcb4269765b20d6eb +ENTROPY 7b888f822ea38d24cff490025b7c107de0ab2c3387f229e2fd7f3f37d851dc4a +ENTROPY 2d6d7ccdca011b39ce4a6c24d10fb61cb4bc5cc82bbfe00850d46726df2177e6 +ENTROPY e58b4aa8110c71bac8180da29450960fc67961fef88063330efca90687b5b68c +ENTROPY f74ee565149cb99e5239be027ab12a0b7db4f136bf0d27b3b51d97b91f6bb164 +ENTROPY e0d92a0a670d89ac20b6e078a68db171dfac29c1bd8b8db486fa8b14133650eb +ENTROPY 7a1f93bf6036c45a5c64cbae6ba1358bfd1fedee13be3f383cb65c6a4c237a33 +ENTROPY 8eda7e5533c420774fcf15985f55df166cb909466a8ea2fa5866d0b6c6a953d2 +ENTROPY 8e92cb0759787f30259b731871c2dcf3fd3861767754d069858626c6fd959fc0 +ENTROPY f789a61695f5d1ef4b395b0afc3db3ada090f764e52a27d9e4b29c16ddae9e67 +ENTROPY 7f4abba77bdbff2e67a4d2c06ef913f357fe0af3721e3a22ee521f7bfa4b6202 +ENTROPY 5d6d05073d1309a8cd94c69fbced449735be595efb164d663011db8ff1bceccc +ENTROPY 9dec7bbff31fac8cdc87dd91c0b067240bbcb2123896ef507b790a4af8c2104a +ENTROPY 9066e08c1bf3c64a0991c1003ee65fe9bc3e3dfe592d3138679ad873ee06ae8c +ENTROPY 3ef813153ceb57a61b0da8a21e6bf8f3e173d553e32e110be810fed1444c967c +ENTROPY 65652108e97a2c233cbda432c70af230fd8f13fa8b321329cbc8d633a18c3993 +ENTROPY 8d7d7efc345be173e3f17a8712ce5b2116aea04c46990107edbaec6e77034af7 +ENTROPY 5cdfee0d68b16337f449cf30f5bc6e02dd6f3e2eb941cd5b5e7d694575f4f91f +ENTROPY e4cddff4b5193f2f1d79fce0c16e939b669e1124bd73942b897e3ad062b9b9d7 +ENTROPY fc23a96fa46db7b463cc62413938d414f2f798a4e203290a385f923e2c338eb6 +ENTROPY 5f7b6b0c9f1149091f81c7db1067bc7de101937d02c053f2da53c5c4c32da9cb +ENTROPY 4332a55a5f018dd44896135fc35769840c7d9ffb5241de33a9bff44a72e3a2fb +ENTROPY c9f5e9ac9f8d0c095b4cc2429d2885caac94137c693c18e9271095be4570742b +ENTROPY 25850f2278d8816fae266f665e86312602a955dc2d3ffed37ec3faa232eb2d9b +ENTROPY b430dd11784ab108546a96f7539d642d5115bbbfd7df453121eb18fa84556498 +ENTROPY 615d6134f65ee86452e6d905e2b4dc9fec9b781f91cc3d412a2469b877dffe72 +ENTROPY ce12708fe93cdc94f5d029cc661f2d0fd17f95ee70797470fe1a8abd7d7c7735 +ENTROPY 660da32f6559d46fa9d44f0898153c46e4f5a3bfe3fece5c797e038f44a9193b +ENTROPY f40e53c9763cc4e7132ad165af419ab5119033b3c44525eabeb98bb3a0ebd3c4 +ENTROPY dceb43ae4edc6ed1ed86fa604f3748d6739bc4ba9951c096de0f995381d5a5b9 +ENTROPY bde6230693bdff717613e1f870cca0518dd64d0b6d0c33ec0d2bb4ca2b5ec61b +ENTROPY 3dc733061484b9c1690fd565f8dd4665c26e1ece3cf9d03cf402d846e3319c37 +ENTROPY 8cd1c418bfb08d381b06864cd0bfcd740e6ae13fa4a0a73c3eaffa94f65cb219 +ENTROPY f5cb07b2133d322ab3ca9cf177f500924c1825ba4429e0eaf352f89220e0aea3 +ENTROPY d8f0be3e8d1366918ff170ff109f015339409b0355171e5a4230ff0f777f68cb +ENTROPY 63e592d65a4d61088bbfa1d9871bc6580fe1e8c31a309f987a5b97e2e1a37e0b +ENTROPY efbbb26ff98740aa07555089e7f22df574328e0c7439be76d53fc13b6abca4fd +ENTROPY fbb251283eba43d8c487b75f3b655e4f8c0695025a555a591f845a9a722c902c +ENTROPY 7169abc4dbbf182547c0ea424bde2b36ebaec2b8dbf5e1f8778b488eca808a96 +ENTROPY b14b1240782c5d068050c3d7c5600ba08b1c5619d8f16cb85bdb49b954f5da40 +ENTROPY 1ff786ccad2cbe69bc635864c33b564b03746e75ee81a0ae4a3cc9f75258194d +ENTROPY 22fa5fe29c3e01e868c1787d3a65430d2b402218f39775c7300d5257aa721a30 +ENTROPY 2e39c7c490ccceba80db62473309ca1fcf605adc24c002b71d4efdce087f5e4e +ENTROPY 232a9b61e17b21e3a7be37c5a52ed4c14bb2a8ef9f4f4b49549f2faf9f5a85d4 +ENTROPY 2c94f9f91aa602883f736a4bcedeaf79986117ad409cce2a435c830dc8a033dc +ENTROPY e461ec945659d15459a1d89a8a985eb6c4fb2b71674033385c46adc114e9ecad +ENTROPY 9adf065de41abbabd3d9207ce402539dd03d052262286ab90498f09d8ecaca62 +ENTROPY 0169096fa6d9d2c13e81a293753dbbef13b10c42dd5c003960e64310020ca778 +ENTROPY 3586b31036cacc1a08c0f87a5c59612ecdccaf6d17d2e29aac12b1a99a673e12 +ENTROPY 12415b8211d6c269376450e30eef0792a8cb993b52b0914abac838a42d0be6fe +ENTROPY a9cfa6dba4d121d88fd2f8e3f4cabf8f11718730c2ab8eb373dad7ada2ea2490 +ENTROPY ce387d3e52d642ab2b4612671f03d7fda1e9dffd68663a20c14a7dddd3fc52b8 +ENTROPY 65b7ed42d37b4600dd98d52a2141b3b659515cda6f6e8002b12f6dcbf62d8373 +ENTROPY 07f010a273911c8a088328e454c316b143290e4c82ec5fae56aea8c219009654 +ENTROPY 1f5c7fbf27af4d7d3ec5cd4040d871893453cd37ea33ac9fdef1661dc2ec3282 +ENTROPY 3960f53cfa8fc9e8484e60a243744fd46231388bb3f793d19b571b66fca497b8 +ENTROPY 714302835fd75a5517a535ad2067c3b0b19056445e6de090347a8198f64eaeb6 +ENTROPY 1b351224ff46f078b0c59a0210957d8ee7099c4c0ae0d21027d36808e2c740d9 +ENTROPY 3baa9e1975030e2a34ea5a461a35964661c00c1a9a5963c126a53c5144dfb589 +ENTROPY 8510b91b5150094e7f89b6f0c019a6afa31e1a03d27fe16aa7811e1bee0cc97e +ENTROPY b8adb6a90bd2a8cadfe33eeb0e86907e1766abc9ac6342f8e8dc94a41acbd6d9 +ENTROPY 8308b108ae76055d6f98264a2330600a2f07cbed3317855bae0401b48ac50777 +ENTROPY 88f22b551e00cd9959f63159f3a5da08a68e50fa6008e2b33c4e7e5e008e49a5 +ENTROPY 6819ee84d73a801752837e894e6316df7dd6ac8b72078d1ea1120be0e523327a +ENTROPY f68f4397d321859467f0f0354cf3a2fa51b07a1168b9b118ef06689286f68eb7 +ENTROPY b1b84fb8680b9eaaf97ac59a8e2df904cc138128aaf27c771ca359417a1b987e +ENTROPY 6b695a00363fc3675fa9f75b7ccf1c99ebde68fea7b899cfcaa3daf3fefe2a07 +ENTROPY 492c2097fda25384874dab5584dd93e91ce685044150d7d0402b2b553a6bcc5c +ENTROPY f92e939cc284722d0dbb30faa9480e2592fc5cfee7d8a70941bb6bc43839328b +ENTROPY 9cb67b4c19660d9a0e6bc3e401c03c674be6af9f3b1863e7eca467004a5f5d65 +ENTROPY 900e08f6204ead6ba6548ee1288964dbfec022c32c7117bc73684f4631d77992 +ENTROPY 320753696b5bdc90a2ee44930d788329bb431827f57dd0d3b35ebeddc43a0d0a +ENTROPY 6df16ff98fe6adcfaff3e8880dbb469a7aa8bb14debd0ad9e23cbe66c3b88556 +ENTROPY 37de2d7c362316c6ca7204fe1bd8a3818dc544429c9480f00b0aaa5a4180cdf7 +ENTROPY 854e8f7563665aaffd52691083605b850a7777c43cbef63be34a8320cac063d7 +ENTROPY 49af4b61667657dc7a816e00d732014e339dc3eda01c99ed98026368855fe71d +ENTROPY 914ef34b991614f52f0519cd1078fe8010014989624983dec50a8dbb174bf4fe +ENTROPY 4e2d5735926880d2fe10bfcd56162b707cd04ca813da8ca4b1ec6ea3839317b1 +ENTROPY 80c5f7a3c70a29477643a17be3b5680acf2e8ff91e9c879951496d5db0c17ae1 +ENTROPY e1cfb79df83718ee545ce99a9787e1c4e7be94e6b95d8be0cc2165f14c8428ff +ENTROPY ad72ec0957ca97a14359184a578e5b976dedd5049c3bd28b4d05a28a9511fe87 +ENTROPY 435ac26406cb759fb9f8f866af677fa42693c5c13f9a0f973244d394dc6045c3 +ENTROPY 6976b466ae9bb0543365199d063f9dff1cb08e3dcf7a3d4dbd156d4f32eb4bc9 +ENTROPY 4786252cbd00645af315ffcb87d16da4a8b158db71df1ad6a784c18543ca0b13 +ENTROPY 74bc38cb1d487c7506280a01a2852ea14b19acd0530ca64997f9617695b45f8f +ENTROPY 4cbf381b8453a48ce817eba38951c411c88c9e30bd43646c762d3e763443f65c +ENTROPY 8dddbf2339f6fc25d280f97198411fcce1932caee1bd86a3d1ec369c68abd1e7 +ENTROPY 6e2dc073e1a762af7ba6c046c6200da6ccd064c2a0ced35c830cb09dbaa20908 +ENTROPY f6914bc7bb14d1cf8187f42d62ef8fb9b9bf57b27401dbe1deb797c71b00e0f8 +ENTROPY 45958391b2c1e06def879fe902c7b05a8b2e989b0cae70bf013fe357020b2fcc +ENTROPY 566aa9d604b74eafba8be9adf0d3b6cbd7f5e1bf67d3437cd226d9e62c145d08 +ENTROPY d26224adf622d373912fb7bb07a5d6dca7acbfe0edcc17f74d284d4434809f0d +ENTROPY 23aff60473cf1c7fd002b9e344005bc608aa1e243df3b302934698984e0e2be1 +ENTROPY 5cf398c4352bee5f79bee82ce0fa6f610f17208bc8a06f9107986bf046ee151a +ENTROPY ffbcb30fe75ad711b129ce9dcdf11581b9ee22d7129cb1a076a6c078d34076a9 +ENTROPY 6e6083afaf240968bd90b69317552375906e54fb899ea8c52042fa5b3ec7c5a7 +ENTROPY 52b74100b6a15fdaafd0dfee34eccfb361a642c088cbf220024e3cd3bbac793c +ENTROPY c7dbd1c9035808a11b60f58f1229ccbcd7286cda3beee1c7b78259a21c585506 +ENTROPY d0cf3ecaf8c1cfc527a2739092fcad8fad5dbb5b547c91f7f479f1e56acb141e +ENTROPY 8d886597a5f81d688cf3a9c94e518ce2c227f11440727f58fe1e68edd7baef33 +ENTROPY b6327bd64b8bfd7b21923918d69e0aa51f44b1cb2505efaa2df8d703e7337a51 +ENTROPY c681ccf4294dd793ddba04af89e1dc1928d5fcbf53aaa5f2765de778a952eac2 +ENTROPY ecd2a8cd50f712e7f2fd704760137f547ece99f7d1cb0ccd43b8662dc54bd9ec +ENTROPY 795bb2cab153fae635e124a8bb05b3008ac274a80eb2404709bdc417811abe42 +ENTROPY 7ad627d0715b249d09ae5b492f6035632a7d60c0c54e0c1e71c986c3b4210977 +ENTROPY ab081a1ea8b8f35cd5888b5fede8bd758efee8ce502e2a1f8b15405b19ef32b3 +ENTROPY e5dc1c9a3b6b7f8d09626122b8a39d6c3a6e8ea3b13a2a8c2a995880a0472462 +ENTROPY e656a9de5b23b4d8b52690e78fad2a8bdf3298a883594fc1fa040bb03dd46d24 +ENTROPY 107757a0a54673594f95e6bb2c5874e0e7a959b14304ec8bfd46c58caa737e18 +ENTROPY 580c00e846b0250ddaaa3a2370900ad10232fab8e81216b3aba526eb0263a9d9 +ENTROPY ba46bf37d58820b7e40be9c53ca991d9ac12bc1545e0d292f19039ac98b711c5 +ENTROPY 7ce74b47eeb501d4d032f9c4e9d9ce047df51196ff59421e250f81b75adaf11a +ENTROPY c6630ee2e007f63e1837d723a5bafd217129f1586b7ee112ef7faacf2bd30f73 +ENTROPY 9a2e77a04586f49757240f90c1a71b529a164f608cacd70d6d8b593fc050e1bb +ENTROPY a526a75a7a6ae75c8d73a5bb7eeb9d13c510838615980fb52dc904d98304eeed +ENTROPY c186205f0dc6bf34fac584a60540e7c09fa2e2d40ddae38d2b7d5097f831a8ed +ENTROPY ff3be01ca3a1de130e63f6930249c447db9659a9808badce4b036f514edaea41 +ENTROPY 6ada5b6399026ff48011e7ebf6c21523a7f15d312448965597164661f5e1a9a7 +ENTROPY e1ba11c42d2859b89b267343c6d92b9341b6c263022c4d8632962e6728d90195 +ENTROPY e23a55712c32b2c1fc5edda1f4ae20af73e97ebdfb7bc939b3255003dcf0bf45 +ENTROPY a50e7ebb1fdcf731c1f12cf485b1171cf712284702a014c09e9044b2b96ffea1 +ENTROPY be5bc8fec50352fb528c673fa9857144757d14a14835ff9a79d8831c9cd9923c +ENTROPY 73b3f5e805fafbd0743009b5de9ef554b52284f8e96aef73c8f8129cc54ff91d +ENTROPY 23554810c575ea48a574a4434e950cfed381377c28c5fe1104c21d731366ad6c +ENTROPY 80231c592d6aa9b530c74c855d51b1b7e7f39a760bb69268f976c11e67eb729e +ENTROPY 644df7c4f2e6204ba0241c2c109172069101205fea4f7743109f572f61d807c2 +ENTROPY 46d80f2230fdbd3c5876111323194f6a950ab2502cb3b0fd7313c461ebd5e6ce +ENTROPY e610394e676f29c4eb5ea7b2288e0c1b6e9df26594815896187886368137c2df +ENTROPY 12a91076ca5489f66def692a3f571daa1a2616c6ca354f3f64cd4d63fef38ad4 +ENTROPY 7d766f514b6a7a1c05e481550601340492c5dc5f4e610f0eefe721de89dabef7 +ENTROPY 5fb2a9840ca1ce3e31239cab571a6dd5329b27da2ab1b5ceca908785162317c7 +ENTROPY 7ab22f25630a46d2b71341b9ac7e5e317d79ec5277724eb8f0e1960dc2517bb3 +ENTROPY f23ade289da3b1ef60b57b4ac1c3d281115e890455295bf2590b41dc88b4fa33 +ENTROPY 090cc5f008b773cda459352c6bfcb9414d9015f755437255693d0ca166227ced +ENTROPY 07fea95a88dc5722b97faa1652f153259f2c3d45f519cafde076cb2e7e489bdd +ENTROPY 1fa55903c61b98f4059b5ba1ef5b665ff6f64ad1a68034edfe7310985817f33a +ENTROPY 9ea2aaf093b1576a95dddd2dd205cf6b68a906cece052b93fae634a593c2ec15 +ENTROPY df4ce6ed6d1884178374c6b354e16d57933fa551bb2fd6883ccf6441b4b41030 +ENTROPY 7961f8a8b4d36b4c97232a6d79a1f6ba777a66f57e742185adbffd59d02918f7 +ENTROPY 06080436f139829b05242ecd4482707b761b6f43a33f582154eea9d886d9ca6e +ENTROPY 66150349c691f35e8ff14fe29978142805bad9d2a70dec5cd15288488db5f5db +ENTROPY 33e77252bbca7096e7c6cd9b8419448196000029eb85555d5473cc9afce17618 +ENTROPY 2f8aacb0b73891e75fab9a0768b6d33e3486d5011d022c23595f1b8b4e73a878 +ENTROPY 44ef00a3413d2e6a5028e962e281ae39dd80b04c7cb6d404d75088efae370574 +ENTROPY 2bc46cda15ed15d0e8b2584e14f34f262475c5173649ad423a466a65636cb225 +ENTROPY d6f00a6b6d0fb288ca3124b3286263fd6db49d370a2dd0e589a9ff60b6db1b83 +ENTROPY bafff2acbf7e68e4228bf575a23355ace9e307bc9eeb33c3b1164d979e5d1e8c +ENTROPY f6a87699d2e00e14c1096b5e1afe8978cf8517d8fc193c918d325842e836de7c +ENTROPY a59a8c2e485356e6a31ca74aed3338e17fe35ac32100a0435ef5d1a8da4293ea +ENTROPY 39ce0097e31670d59cdb16b56a0e0f0881507539ae0414601e4e982b7dbb66ca +ENTROPY 755f33de806084b6d8410101a96ff31e369d493d7a579dbdf6934e644c349ce1 +ENTROPY 866909b694bb7191e09df7b5c985ccfe2695719744566ea599deff908dd659a6 +ENTROPY 746654251d3a4c95b657226c97ec2232893d530175bde51bfd90a1d6f749952b +ENTROPY 939432bbc13ddb116d2f6c5d30fe7d3b3c4e4ea696a42aa84c0ac313d7368832 +ENTROPY ec8eac3327f70644a0b6e843775897b65c65b56813c836b7d0a5d04509af9d96 +ENTROPY 5238b824344af0eaf5c03fe57a8d914a1642ec2b56807fc04970ff8bdca9cc5e +ENTROPY 78159f8cd4bc88e303ee3af7391a735c262eafe7f20d3eb1a32718b817c12339 +ENTROPY 0131803eea066320bf5af3611fc1310d46d1a77a288a943697d64fa7da1a856e +ENTROPY e41c765bd1e65a465189cbf11916ba48a0d061736b0fd0c1f7a3703547a60e99 +ENTROPY 17a76f664ac346a6bfbc7db014ba5e217dc82d0c4203e58d5ace72bbb8483237 +ENTROPY e9e9c88354ec29dae85c71ab067314dd906610cfb3059809603f0888b741171e +ENTROPY 3e1a19a21a6c454c089de35e1fb22705ead1706ea8a759f422ac65f540f6a682 +ENTROPY f3c20374fa39c3a5d7310fbd34841c434a1a5d37a5bfefbd65e1c2cc2344b012 +ENTROPY 78530a0fe9e24384e5c75c0857b834e936ca6a847b499119ffe1994eab8bfba7 +ENTROPY 3791e5f39511beee93e1770e8ab344a0afe9e2b91459a547276e47a22e91a103 +ENTROPY 748192520a515251d4c47713d0e9fb3be73f59f3899ed138c19718472733fc01 +ENTROPY 61a5c0a551d715b74a304d51cd763ef1a4505af66087b41de35935655b38328b +ENTROPY 30796594f9c746875cbe933632f88191a6e7611a20e43228ec4a219a2a72f2d3 +ENTROPY 5bad75701c57d45995d44f1ded52762eef5ded071957ad5ee3b478b546005812 +ENTROPY 517ee3d44e077e11ecf046f1931e50f6407248802c180245dd38066f4833c452 +ENTROPY c1cc75519e82b01cdc6fae5b96d6f013e93ab4bdefd88f83b3eda481088bfff0 +ENTROPY c2297f30c8cfad8ef64b2bcff5bba40043d1c1881dfa9a21e8ccf4a9d82b8e71 +ENTROPY 129cefcbb1586e91c93ed36c72b42c8742bfb4d94efa8ccf12d01a249ddc085d +ENTROPY 38970b2eb3f78713446fd3cd3d4860059406a2d5707b85cccfb87595ad3d45a2 +ENTROPY b98157bb785ce742ad80a570a150e75b74ee89f97093d7ad22bf0cc2c7ccadfb +ENTROPY e05e21b250718633c32b12628d5fd3f3cac0de87e2b2499ffb2d7c63ee2d781b +ENTROPY 8cc684b862b517616b809e04588da2583e1cd8c8c954ba1dd5e9344cb09fa845 +ENTROPY daf7d0efe6d0be58e629f0e3464ae44bb4d749db44052d187c54d3e4a5baae17 +ENTROPY b3765abfad67f3ad58435f0840d7c5cf53e560899f08365368664ca50ad4e660 +ENTROPY 537b9ef2d1f8fb6e27725479622a6516684aad313e4dbbbf47cda3704c17f706 +ENTROPY 1dbd839c875cb15263887abcf9047da6f526738f4cb15d44b46f9e68b3d1cd6c +ENTROPY 66b796ff9d9afc42656e75063e7168e8057e53ef229a7010718e40a79ceb1fd0 +ENTROPY 58f2835fa533c161b853ffa6a2777ea0b9c90d7042b04d84f57fffbe82c35816 +ENTROPY 756d9fd4961c14dd1e9289e40599524d68b66721fe64d6eb25acf6deb7c85783 +ENTROPY 2f18d110717a3e80f4b68c44c83cafa4be60af66d19ac244cf263feb24b452ed +ENTROPY da055699c4036750129b0515df2ed2929857f4a093f3973442506ce1718811ef +ENTROPY 364fb411104ad68da8d684e3f64f551866ef333ac9b2f91879d1263411b3ba54 +ENTROPY b60c9b8fadbd16b1641b3210efb86b5f26e58f6ca49d742f44dded479b77015d +ENTROPY f6e97d55188b4bbb5144baba0cab14b233354eb0933e8e8ae08dddc1664545fb +ENTROPY cbcdef292505f69fcc48de632e6079396f3598f8427979a158540a161d67bee5 +ENTROPY 24ccf2df5c255d0653d522b74cdca786613400b5f14ad7d64e50ac7a45496bc2 +ENTROPY 979ab568641c67792199cbc6242207b81908f2cfd6c6e067d1709f5686b3e722 +ENTROPY 9ca48546d13c0904267dfd0c9b60b1955b1c8335f1f6561fbf2af180e4408e05 +ENTROPY a2b59048b677edca0811bf8e6d2f0139dbfa1197e74783f63c2de3b03e7245e8 +ENTROPY d39937575792fb1a1d9258d9a8b1c4e7af242fec8542866d1140c58da7013027 +ENTROPY 8a9d2c96c11d8471c18d2c9f256efc25cf959e13c58531a60538e7dec1c420d0 +ENTROPY 0b97fc34773e1729fa1072538143dc99c838a96fae9fd246388dc184b09a6a2e +ENTROPY 7ba28d45390a102ee23e54da48325e4d0b3ed0d5a1f663dbbc7b6ef9f7e9a7b0 +ENTROPY 1bfe12cd21e6b3caf4d1c2d39977dc15af46b96d2f09e51b49b89d8ca9605230 +ENTROPY d63b03a262529541b5fe2d56f304b22e4dd2a3aa73a68cbb980a0722fc5840f9 +ENTROPY abb189f2ebdaafa1e02972073d8be46bb09902b4c35d98d4459cf82ae479f8a4 +ENTROPY e250a909d424be77dcae87ed5158589cc3cd79f1332bb80543cd137268d37c86 +ENTROPY b7ad55d958e2e1e0b3fb967973e5ec8fdaab376f25f07f596677550d037e9a6d +ENTROPY a43d5d431cb6338b88c89ef92f49e18389b594d97a155e8e566b66a267092a91 +ENTROPY 9cffb12bddc54687abff4eeaa3590a48129d88f2127e94ce9d31d5a0d3b50d1a +ENTROPY 5cf9fe8eb0fde8b72e1ed0b2fe6ab227a7a4a2a8113d542b5ca69e0957528626 +ENTROPY f07365b7f39c01fa581397c362df457fb4b4446a3e720783b13e15823dbfa378 +ENTROPY 5365ebfebb9b5ad4141c221fa674f34b3fe06fff7f3fa4438ec098b680456a00 +ENTROPY 79e6881c81f4cb8ea573ba57da11828c1b643cd6c24a4f23aae1535232f0a2a2 +ENTROPY 3e3521c59bacae48cddcffd0b1a3ae2de0e4b27e822e430a6926cd75ca637a19 +ENTROPY 1bfdf085f2826a36d03955ea61f279c46a3afc44722408dc0aeb7dc2b2a089cf +ENTROPY d5e571f4178998c8bef5b2753491d533e71feb41f795e24104efefcdd9846d19 +ENTROPY a96aa1214acd612a6b6b8a24c80fd2abffb655d91d609c0df52e6eb92e0cdc70 +ENTROPY b6a8c71fea47f79f77a52cd9d2effc9943e890fd78a38bfcdba9f3a26c78db70 +ENTROPY 5b63e60ebfa9e4f66c27c2cea6342db7ede573ee0fab9cf7f8792b9a3af55256 +ENTROPY 3cd1ea88bd05ca62f66fc7a4db7e6f36fa98760e207791983a99972b4128e9bd +ENTROPY dc9c59030b40eef1f0023a958044b04b76eb9f7176757f04bfecd5c0a3b6cec8 +ENTROPY 94b07253b192851882d99259df370deaa0c7ec7e49d5b36c8cb0d54e6b69bbb6 +ENTROPY dac8e60ea1ea7052bfe806160aa08e86e3ce100f362f69813029db6bdcb7eb3a +ENTROPY 4fb18c1ba12ca1d6dda172b642e50ac924677ca0ee5ba2174d8c52508127f1b9 +ENTROPY ab109bee67aa78500e26919f87efe62af578a713711635f2f423b68272e61226 +ENTROPY 1fadbd5eeb312abd5d7ce5ebfaffa96c7ff6d6973046fd7463f79191a1c35e20 +ENTROPY 1af9e07188b9316e8ec6de2392a084bcb7f83de45cbb711391c71c3b13be925e +ENTROPY 93b79f72eea5e3e3490c1f73dcb8992ab304de4f3538a8e2ac77761099bb4963 +ENTROPY 296055485777ae24894d2b20dcb490c76d8fecd018ba8ef9dd0277e4b65a9533 +ENTROPY c2d535885e2765d9ba640fbbe63ce414250197b4dd2f5ebfc344ed22c137a4fa +ENTROPY e60d79dec6e3396ec447643d7dcc8d7c3b88404a202ae8399d104a6dac39ee34 +ENTROPY 86a57a863d114696c6fdab8e7eb685d6452719d0c304062216b81b6edb152aa1 +ENTROPY 59b7d8452b28fe1e785e48b3a0a24414ada4eec2663373ffb7b60821c8a14e50 +ENTROPY 31b2c904337cfa7cc5b4df93d0540d5adce82f7096f08f84c09951da89a7e92e +ENTROPY 366f49874ee4dddc2c9c5ccae0a08a0407a2ac707c54760d26ca4d88360fd94e +ENTROPY 35586ef2d1bf57361b07f10021337315d764ca3d23ff96cbcc8b59f1045366a7 +ENTROPY b228a52947f8d0e93b54aa9b68edeceb424b90ae72369b9d70301c1b61ba71d9 +ENTROPY 1b7490a627730f0abd1ad058ee200c878d6b20f97d752db26488736984f1a5d0 +ENTROPY e9ab4d86e44eecd7cd6c7272ec7239c96c1ee0d7feb646f4b44539d1352804d5 +ENTROPY 73175773184e2e477f0e3f5559c991ed6617aff51ce4573c7cd0f4edc1649067 +ENTROPY da6285f9b7f16fde25e68961819c9987feefccc670e571e8ac7a929945705a4f +ENTROPY 6125027c90de5070717a0b37d8d6401f06cfe6a279e2f0f47d52564d964dbe05 +ENTROPY 4b56bba600c1a4a31510cf3f6188a76161476e541b942ab75c301cc9a599676f +ENTROPY 3b0e73532ac1bf2f62f525467c6d01d3546d9f82af822f407563ef732b35d72b +ENTROPY c04b7d6b6451cba33637b8217f614be5524165572a6e39d02a254fe148c6106a +ENTROPY ee06e128eca0d5a28270a53f4d07f2b395c5d43d2aa58266d9fb84291415c4f4 +ENTROPY d6409df079e15dd752894082046625eb82a04d64bdc6885afcb638e0d3555d08 +ENTROPY a4ee6cf94497feb69d34c9dd57e2d696a13829323490dbd1df6272d18f88291d +ENTROPY 8e3f3dcfdbaa654b574155a1e05df945ed88a7202ea6ae6f446b232310b27356 +ENTROPY fdc6f47211635cf9b103e543236c309df17a30990aab6093b6dbc66bcedd6367 +ENTROPY 72db97fe7fd8eeefb7e9f301e536c02b716290233b9c08040fb62b21216de309 +ENTROPY 65cc01dd48448cdbbb73d8ce5aa6fbcf17d6cf735b6872c7a1e8a948f4421618 +ENTROPY 1ab6e07bac5d98b2d99cdf6fd6e2688605c4854469f2f5d8017c9fbd2627b24a +ENTROPY 9c5769d7fc38e15d00cdb478294eb7741e151ea50f5254249ada512ce6914c88 +ENTROPY c03f96a860ef74a40764d3487fe857fbe53b36390dc0f145c8c137e55d221900 +ENTROPY 2e5e246c205e6a2065cf1dfcd3bda9d85e843ce5f9cc521017fd5d6dffac90ca +ENTROPY 85675b8ba84c9120f66bd8ab6f1e39c0bc6b8e64b8ded61c253a52b04e4a0949 +ENTROPY afc9bff2877a2771fd21ac00a49b1ebd16258f3f1365e1225650f731cf8cec1a +ENTROPY 673960893aa478ae822de8c88c16a6f8a3a363a5191da55e73426ff90b2d828a +ENTROPY d778cc96dbf50e0a3de04c7e8ed61ac1d67010df382a51244223d9e42f2e24ad +ENTROPY 2c0b2505948687e32c1cbdf0b5aeb4ebda612fc394e7ad93fea2a7a4da2fbe2e +ENTROPY 0ac4569b190a827138616c2171fe86d003a8a36524843fe7b7dab626d41296b7 +ENTROPY e1e15eded8b9b00690fbffe2b144e3ec6d546b4f5a5835ace4908139fa6acd3b +ENTROPY 443bf715b7751474da255c5fa6a24345edb3d3004477b20aceb3134801e4b4d8 +ENTROPY eaa344a8c39a547abe6e60c195707f2f34b9fac40ce7a5273cd0204b987c7dab +ENTROPY eb00f5135ddd020363e724fe113133b180c721fbcae6d7f4147cdd0226657348 +ENTROPY cb8f2b46bca2e18c7383b8ad3c6765d89a030dfd6eeb27e9adfd64f541b5a1ee +ENTROPY 31193da4d784a7e1c5185957d07f356c25e0eff023389639e8aef4bf28087047 +ENTROPY cfd502d957b8a09e20a6aa422cefcfb05a306abbe72aa8f9ce30116b6299689c +ENTROPY e99f77c220a2d0a6cd39ded3e9b933f15430db6745225be048e4fc951a1db4d6 +ENTROPY 96b07269d35a40314f8557126893974acaee99efa79da1d8e843958d4ca080c3 +ENTROPY de9cbf5740341eb7d968553609c5d8ea141f06f7fc08e7e182b9871fa6e7431c +ENTROPY f479ad350e17414b16b676c95a17d4d7ba07263b39f30e40bc5d82faa9f57759 +ENTROPY 67428685f24d6bb6e618e14329670724e8eb9b4f6c47fc946b4d38bba2486348 +ENTROPY 86d0338a986780a3f55be9025f7f3628d8b082b3ced13f04318478e67033ef20 +ENTROPY 59d410aec8b728397d38a2bc71cd3062faf9253abb98ea1ab3c3753735511a49 +ENTROPY f144852ba5fa96cfbaaf8b8856e0aabdc18b9b55c541945c929db2f95da68d99 +ENTROPY f70ed04df0c8339f371ad73da70a9989a44695f00bec95f5b9ab138a8b187c1f +ENTROPY cbdea607abc122c7f343dbb7046e7486910245eadabaea373e88db14bfa2a4e4 +ENTROPY e0e19f58918d6075425d486bdf3a67853c4594ce4916c22edbc3f03f2effba67 +ENTROPY 1b10329d78fa03b622479ccb6792415ae11cddfdd0138ff3932f242a43cef45c +ENTROPY 58ec68ff5de9b843ecae12e353995e084b0c44fe77b823391d89ae67203adb6e +ENTROPY 6a33c503137f9af06a99ba4dc2a0e8b0183416983ca2ee28f6b618dd0c48cc21 +ENTROPY 1bd3950ca6974bed04c62645e3dd4071d8ff0f21ac2c3082bc623c9e504ccb59 +ENTROPY daf33427073505fd1dfe481922413c2bb8b5ec7fe63361a4403aa0110e3ebe4d +ENTROPY a20b4e517bf4cfb3ad9d8628c7f58d2b35c6fd5bb239b555592e6f724bfcb71c +ENTROPY 8fcf5457c730f0a606043139ab917269cbe515a5dfed661ed9cc56304693c937 +ENTROPY 20048260ca9fe566c28245428b1798ab60669c0c56e41424f1f2d4a1fd07bb62 +ENTROPY 1ce61d992aceca8d38236c2650bcf5b63c1cb2c73324d66a1b73c0bf04ae1306 +ENTROPY 68c4aefb4e0d4659f1c5fabe0ccbb8bf9d13df78eebd276d698ccf1fcb61ca54 +ENTROPY 28c89f96501ea9ea6af7e42874d7d0c916c9f893a660baca922c27773be4eb73 +ENTROPY 924b1fa206fac5790d635442afdb6300c5effe3b7756b79e7111b7c1581aa965 +ENTROPY 18f28c1f5e6d2f86b76aa8644151942094434e1c5bb92ad5581d91d1efac013b +ENTROPY 63e95dd02107f9d56820301590eb7b699da1bcaa72b9ae7bdc49720dfeda5b3b +ENTROPY 976a33a15a6e429eb27810ce8623bc978a73b172793a5c200179022235ae4188 +ENTROPY a986896a10face9495c26f0c4298635cf58f013a9ffe5610138fa49e0917f390 +ENTROPY 0badf98cf016a448e54cd54ab126a754b895d75fcea563fda5e684a6a471ef68 +ENTROPY eedaeea221c0f022d46ab400ac9958df8b103b047f4f1df924dd59b629bf66d7 +ENTROPY 96dffba58e932e7da71e24b96da385afe8b4aef91b086bd9e7aeb1763434735a +ENTROPY 40c7a306f54a6f175eb68e248858e16d2c37b28152d7b3e6760d9218b6f0c2b5 +ENTROPY 3e6927fa4fdb732101fe8b46e550308ea945b8087e947610cd72144f7dcdfe15 +ENTROPY c0d60a9380a091490ee788d68fc4a1f71ba7b33aeb9123d56d357485ab124646 +ENTROPY 873c0f2d239220b632827a17b7fe0b24e83301f7635c92376824f4acfacc2a13 +ENTROPY 2d16f322a07d0b99060a8a9cdff3fc1f4b4f94cf4862713393d4112377800919 +ENTROPY e22483618a8f8d617bd3cf95bb5a1e55f45c3a2f63d05928ae0b7f33b4539d99 +ENTROPY 3ee45d750bdcf9522a9bc3f7a66d4773d44be0559778441fb875fe9bf57d42d0 +ENTROPY 93f11664edd73d3df6a850d3887af7c2b9dfc946d662c22873e96cd274b35684 +ENTROPY 3ed8384eaa6e1471ac41986aa79ef68b3b4521eae7bc0f9771b9dd107498ad11 +ENTROPY b44da5e6fec1698ae7fadb9d07ff1534911f255d130d035d3a69ad9b14104390 +ENTROPY 1cd951729e1f7435345ae558b2d4c2880062c440f622069a0e90f3219ad0f498 +ENTROPY 24271686d657a0737b6ef9dae4e47230639a808982130c272637699001e2e2a5 +ENTROPY 9e183c0d907cfa657d4854c88186e20e24faeb04eb66d6b64c66a2fba088eb9f +ENTROPY a674870bde892514067ea0ca12479ea2f58964d5a8564f70376127342a5b3ac0 +ENTROPY ad5665a7950d03ed4830a7c1f8a2a527c25571ef772a5198a1d768547046ebf5 +ENTROPY f6ce113c8a33b99d1968cb2ff6a481572d7f425d466cfb6b32f5011c665c0247 +ENTROPY 09edbe8bf8cef709e2cfab64e80f9e40e2aa4288b84e02fedc0d4d3478552f81 +ENTROPY b117832b1837a97f52652655286d4334ec0fbf6a86c9c2edddc3fce19b22bd7c +ENTROPY a78098c533bca88f7e3fd0180b850ef6d124cc0ca2461d7becee421355205ff7 +ENTROPY e14f5298a05b4006a62a6f6b290dda8968169a09a460a690bee1949e39772171 +ENTROPY 6061d81d36d4bdaf29dd006b160c7e4c2fc08a29f1b913226a637d3326fe1b0d +ENTROPY a4568244bbce15b2622c3da933c2c7440be32dae1e7e1613f034dcfb1de63edc +ENTROPY 1fff1a23a039c855934ef4d095fdb7afec2c10f2bef747949e1d5abc55fc6914 +ENTROPY 38cf2a72df1ab36b1d688d68d921e534eddc449ee8da53d6a77b4a89f4e44db2 +ENTROPY 9c51fb6b6ec9e5c75f2650842b6027dc6a93d661890e93fb08d6b05d03e738df +ENTROPY d2d756820ce0c03be4654b864110a3230c72075903c882900b7ee5ef1b8a20a6 +ENTROPY b29f77379ce252a88b66ef06bc1af2cf2932a125bf900a62afe2df568ed6866c +ENTROPY 2dd6a7f7aa7de77979445ed78560b5cdf0298a66a10a6acb8245d72af572fa86 +ENTROPY 2e845e93f16d0598077f894154cc9d0b7656f8c43cba1f9bce5e430af6644d48 +ENTROPY b69e93d87b6b307d35cd917469b07ff85b35f6c4c9e6517f29b95292ea48b904 +ENTROPY 14401edf38dab0067110035da54207ca4e2e1100dc984183840f7e6370a2986a +ENTROPY 4725a0822b689e6757aa939385b12b62b709837e0eced2dd29cb3b24f9130043 +ENTROPY fa7638f645f38c1f0c129dae8b89520b7471e479d8ef159f1368333fa9d0a072 +ENTROPY 9317beae658f3815a69ba3995aef554e15281308c9342306a59ff7ea0072223d +ENTROPY f1aaaa5c62c8c9fa803003e61211836ceea7912f2a439a7dc833e3b570b8ff1c +ENTROPY 19950afc07a1de87da528d245eab661e31cd6eb3c44c244725af5cd0bd427a20 +ENTROPY a63c99c525b0c25f78a55cbec4a8361c2d781f8df3ac64755a473947623a7d87 +ENTROPY 7a876beefcd38d4dfd6597e9898fbdd32cbf9212df813b1d59c31facad13caeb +ENTROPY 63a24f199f907084e0e94fa35e0db8dd4d2b68df28aa4606649a1d76951286d9 +ENTROPY faf952f3f9cc1a67db96ea2c2b134e0ccfc856a9b780ac3b2d37aca54c8adf85 +ENTROPY c2bcab803cc7de0e47673471380865dfa93451bb5862615a6ea4dbc8a54118d1 +ENTROPY 275972b21a3eac721f1bd57923b2d558b61bc5cd9a0352ec73977e77c86d0512 +ENTROPY 01be2adc561b832ea4fb6a1eb84255616871de70509c7a6f06ef193fedd33283 +ENTROPY 10b5a66fb3409c06a9c2e5c40e294b2a620a7b374661536059987554efff3111 +ENTROPY f6d2a7d69855aabc39d701a0c367e5a87fac70b4288fab73cd8cfc74c6fdb2da +ENTROPY 53a673fef1694aca5c6b309d820c97c132059058c12022fb4ebe6c533d463a64 +ENTROPY df0c04953baedfa52f64c880535851c6a9572e5cadd4251079b4df5bcc407faa +ENTROPY 3a94746a59e37ac231ff8548c001a5e372ad6d5355282b9a711560bbda01515f +ENTROPY 0817f215d765c3f03afb821880717f40fb7e36cb24b86aba1134071c49271c7c +ENTROPY 0669bc8bfc438cd0948d876779d6cee4555c16021635cfd003d41d723da48cb0 +ENTROPY e18ba5a1e5f5ce993685c88ae8d9fb56a2cadd35dbe3f3e2626bb9fb028a77d6 +ENTROPY e512f1bbe0dc3630391a710aa7e2e3389a2f6b6defb188f7b64ca129febfd3d7 +ENTROPY 7fe2878cf6fd5663c694f13d7f78981322f29df9ea0615f28f60ff8d08ed714c +ENTROPY 83fcd1372b61dc2766f73a2fb8248264c18d9161ae9bc04091585b38cf028ce1 +ENTROPY 70467c781eb0f17a8977b72458b7a03f817c157b50c08c2f7ba9f96536c2c0b9 +ENTROPY 72e9488fdd6ddea7ec3e05cce9c271416a8945fea09ee0230d97e53113fe11b4 +ENTROPY 063e336cb87a394656240b9182527a6664c2c4ba26eb3f01ed0037f00b7598d8 +ENTROPY 2b4517dd3a1afa3912af08cb80de669268373dd6badb84510c69f88c9e4f377d +ENTROPY 9d6f4c26eeb2a8f5206c3a191fbea9ae5098c6e65aa640f4d7c44ae0fc5980dc +ENTROPY 38c25ae0b00f3cd74d572796d6e54932b9e2fddf798515b5ff7d0c7d8308aaea +ENTROPY 8e379c93b9399402d6a0f46a8c124c27f949f2156dab892ea4c9e5458384fe7d +ENTROPY 780f72560224b60ba8ef866a95a45d27ce8d687b7146f70e8ed4bbfe0b687683 +ENTROPY 4de8cebf11466e5ad84bf95736b9a88d55c7ed904230fe98b56df6f852265b58 +ENTROPY 6749ba25031ae09ce1b5bf69b0fa5eedaa4af038a48e7a84af8cccaed2a03dfb +ENTROPY b405f29bc95137c832a17b3d44e376f797377a35326fc2c1452f6d235c6dbcfe +ENTROPY 838fd3d0e81a9823a4af09e9f3eb841e5652f6b18d5eaaa4a67627fb5d51c670 +ENTROPY 39425991ba737ec137bae02ee8b45f23e74c49cf2de4afa2b98630dbbc461077 +ENTROPY 32e1df14467dafd98cb36ed216a7d341f68b2b59eb806f765f6f5ff9dd87dfda +ENTROPY b09ff2f79fc3af77e4777c41baa6942fe36d1383967297b5ef47482da8123e50 +ENTROPY 5e09d844905303c6d8727e0e381b3dcf7ed53cf7c538756a81e7a1b374db38a3 +ENTROPY 96c12b97603b728290863f73931e2f55732e4e4f3718f65d859ac4244deb523f +ENTROPY 4ab4c593a6471ed3b634560eaa145f5ef3556752211e6d79f8ba73f632da1235 +ENTROPY 67ecbd7152b7b89f13b8589ff2867b5b28b21277b3c51b4e95b2cc772e300396 +ENTROPY 1e493e56f74d4f22cc8ccf77caf2d36e9b1d175ea33ba3162a2adecb4a6f1a4d +ENTROPY 761b5d377002c3163f4156b74b8328fe1399d0dc8452d8703622558b946ba41e +ENTROPY 6598b1dc3e499ff2dd776308fcb2ade4b55a7edc944a8e241a78597d50d41dcf +ENTROPY 969ec3b0765923c1a2fec7810566c7233f18e89ed033438c250b16f8a98dde0e +ENTROPY 6f1c3831643e314578d4decf286b09d89163262e4627b0d29cce4cd1b3bf9387 +ENTROPY 27e295b18feb89217121360008a3d19db8bf7ce343074522fa4ec5d31c2d9126 +ENTROPY e711a96014425d3e72ce827022cd3ba6ab7fec3eb346e1ef61b71fded84cfd6f +ENTROPY 5a723fa24bc16111bc9fb68fd0a910b07c77a33df52042f02628d9d3a4203063 +ENTROPY 07f989524ee67654894e8ed9f97cf8a7661d656b8cc105eeffc8e8aa07888a60 +ENTROPY 7dec784d274068bf1daa6a16d9153e9cb21d34551f15d4a3ee10d572cd325e19 +ENTROPY 28cb3831a54fd2df03a0f63ac9e28e40aadb7a63937a9933f161e039660f96b3 +ENTROPY ba674d9b406f0bb5619c5aa47aad71617564feaf6806d97dfed9ad9202ae3fea +ENTROPY 7cbc75d8be2e16468e876c6a31759160871f9ec697786c7776dfc776fc990dc2 +ENTROPY 68fa067f1827ca2ce5072f5d50b734b8e5e5cf8bb553ef6c8cbf15594824aa51 +ENTROPY a3c7c999b0cb525d4646e3df2e1038edc592d1e265879cf15b68c49ade31b57b +ENTROPY f2cef30706a84c07325d83985a27b413120784c06abdbe1e68bf03b3c009a9fd +ENTROPY a13441aa42d6c48f49dcc02fb05fc1189b09d091608ba6c0d1358f8ff2c6714f +ENTROPY 1d11cefbf6f2acd7d51c3f41ab8109716082306e1a4789009d71327a4bde9e19 +ENTROPY 3255c5f3d2c03c76bfafdb40342d683ac2af0c7159a0dcfbd8ecad09425a590b +ENTROPY c49e972e5c1f31363533746493133e0f24461b1e6d8c7ac21d22e81da4da97f9 +ENTROPY 74e4312df023b144913a32bc35cdd14e8ac15894226d10295a44ddd4d749c86d +ENTROPY 328c56a00864b58f235d5782df836317fbb711156294c667383851d9c8672465 +ENTROPY 16d26d1f861d6fd4e70a718e2e9541c8f04e9e30235ce02f7b43207e402fc0aa +ENTROPY 7b63b922eecfb8c1322ab86de53c3925e05fcc158688835fc6310d5eb1658b8d +ENTROPY 1ada0a0866f6c40b73c3157cdfe1d2602c874408e8f37041822a1f0ba3c2a926 +ENTROPY 2670a441dd47437b4b2632ea0338c95c27d2bffe92b6a4814a6721a113de76c5 +ENTROPY a86988bac22570ebda0e6fbac46055a3a600e0e9ef0e10af37c94bddedc46414 +ENTROPY f65c253594620b137554a51ac58ca45e2949f893b04468d9ded22642f5802109 +ENTROPY bac140551c530db196ef8e7c9e8570c40eb198a3e5be903561be358e5ea5939f +ENTROPY bd6a454110d4e8e1ccf19463dfa0b6ee75ad42e7652ab8bbc14ea912ec0403c7 +ENTROPY a155fcd868e2aff08aea81a21cbad79edaa4e63dc1113204b4506eedb836ae1e +ENTROPY adf80cc04c7847aba1c0cfabc64b045940c24b584bf45fc306be95bf2471486e +ENTROPY 3a597d4c192109810ef9b97715c738505b61e2ac1a88923b937cca18820f9036 +ENTROPY ffa15a95855501d38ac885292a604a69e3fa8fd025e5046048e3e1c1e6c40b05 +ENTROPY 421133f981eadf6c3b625926c233e9aa98d2666bf3029ffb17670cb2d8d1dfd5 +ENTROPY 7267751f014ef1d36269ffab45a4c113e4a8d0cd7286a326cdfef194d2e62738 +ENTROPY 017765ddb43130b91495012306f88f695f71917d17e5292120ef37bb6353fce3 +ENTROPY 884aa348362e9a4bc50e1bc500734b0a671544efa2100b3497e80384df383969 +ENTROPY c9d9da868160d5d9788cfffe2df389a2217c029298b17b3eeca60378d7c56dd4 +ENTROPY 502955c5ac30e18adc0addbe499a2d1a027ca412c0c1982f6ca6caef77b31c6f +ENTROPY 625c141102709bb35d36597d3e632f6c54b2c31562bc0d1b7e268c300d62c7ec +ENTROPY f8e41a3a370877cd34c0191bb82b296bae38f6a66fc138e4ca1b4d0d806f65a6 +ENTROPY a8f0d369b3bd6a5918e0d9fb8f32c09b3029b34cc69792da4e45c08d85a51e23 +ENTROPY f6f91fbb144b56f0ace28a92fc934350e093a6a602c6f6cd4817116f558dcbad +ENTROPY 95aa258c2ebbd17c05aaf30c6d60494a6525cdb0e50890b2b0990ff167afe475 +ENTROPY acd6bb98bc5c1287e51c355cce1cf1ebab324bd6128e4de2c262693deb4b96d9 +ENTROPY 4f55d0ef668f4893086d95c0a7f46db4c7aa6ea4ddb6b2409d1410c2a8af5486 +ENTROPY c17265a9bb309c6727f9b1e8a8b387b0052fed3b91e2a49f6d1b19148f63251b +ENTROPY e7c8ba4d1030ab93ff88350aacf6d4b3f5179b1314c5a9b470ef48f5ba6c4ed7 +ENTROPY 7d2ae799dc13eeffd8f6a9e0d6fb525818398b29f988199aecae9ad3e6dcc5ec +ENTROPY 33b1372d53e541fddccb93c3d2ddcbdb3fc3e08667b0e3307395332fac5f10f6 +ENTROPY 2e4231d0027702a70ceb5ebaa8c55daba97cae3d25c20892c5db0a10467b47fb +ENTROPY 2629ccfab1e4c5a2a9d3d36e5c9316766315ca3be5438b326ac959039ea938cd +ENTROPY 41db700af8d0ec1a1864cf107a14919bac9909143f10e6116eaf5690506d4590 +ENTROPY 85a9a374c84447031ebe2597923fd01d1ad17b4103ba0179fc54d88681b6d8a6 +ENTROPY 08edd819e10ecba7f14d14a3db4a7cb025301f71a844298f82cb06e48ebd1a94 +ENTROPY 2d6e49716ce46c61fd84a37861de2310cf10cde6ab0a70b25c0ac50fbad695c1 +ENTROPY 41acb40758db132ccdc51b1d725cf2a533087b0e1e3c4700827b75c072b00816 +ENTROPY 4a8e29920ea3cf925bff9da1e50de13a351ddbb51ea6057b246158119169d8f8 +ENTROPY 46d63bac7eafe8fcc048f07ad131db3ee64403e445a6ff9be79a5689c4946e47 +ENTROPY 7e4c8393e43611da4c1cfae1c084f1f2d370643385b82badb1dbd0ecb6c3de8e +ENTROPY 03aa3477beed5b4c75f0c7c0528299f5c6a26d12d4411e73adb98cae2a63494c +ENTROPY 9d269838732989d51f27cd2431dacefe983cc919bfe0fe8e2d3aed11a23357b4 +ENTROPY b1427b4f143f7e7ae42523b5c973d7cd8561512dc750b4a6941774cf4b037e35 +ENTROPY f9c041db3ce9119acbd4dd08df491ddb7667bd6c0e3a1dfac1bfa12c85e11985 +ENTROPY 17f2b7ca03a4216d4bf7a6cc527571875212ab13002176692a95e5b53062e1fc +ENTROPY 616a56f9052c2895e672e593452c75433d31cfdf6b918fe08a1248a9a6dcd7c8 +ENTROPY 225263700b313af64ea954ef70a6fb5022c64c5c561c0b0033de570722489598 +ENTROPY 90ef7b66bf3080bd4c30f1c790c9c6946b233708d0e4f040713a6125bf9735ec +ENTROPY 62aa91da0590c486ee138b087709e0be51a8888e9ee22358e3447c60f291d599 +ENTROPY 23e212944e69173e25ae44b0bb47571f489978f3cd57ad4d57854f96d37ab70d +ENTROPY a32ee89964230423d60afce84de2e0528dbf657ad0383525c5ba64e7699c43a3 +ENTROPY 81f8cf629e957d1fcbc05179fc9fa60c40e29ddeed7d8a13fba14654d90407c4 +ENTROPY 623bb8e215d5ee701a42ad2cf8690336a629fc23befb7739d975d4f6f15142ff +ENTROPY 944243c34439e3a5916ec2e2cc6d7e628255c9517a565129e6b778e6f7d2b3e7 +ENTROPY e6bf7a8191349e683dcf9a0fc1352fcdbbd4427150c7bdf276679f6462f4fd7b +ENTROPY f1e4ea655b4675ce782ffb4b569c9f699a3c3b16ebbcbf21d17ce9236c7500da +ENTROPY bebf592c927791e434db19a68865d6c8c6b22f8624df1e724ea5fbca6ed54026 +ENTROPY d696f6de32794b4916dc0f099768540ee4d3313001f159272a876dda77b36a13 +ENTROPY 1628bd7952ff88997c0ad7a96f0bab2bb1dbac9109b639b5d3e4fe8df5d4e907 +ENTROPY 0f50eb4f30d67e8b94693ac8e89a93677d05aba89a93508e2aad13183c2fc89c +ENTROPY 8424a30e282d177601efe90fd00ce81e565be4cfff39e573a91faed4a2bdfb55 +ENTROPY 83a59964c198a7bb71ca54ea8d4bb30779bf50b51c81644cab70fbc58a8ce157 +ENTROPY 076a15466a1a83cb74557789c04bfa98aab9d552d4f448642ea110bcc939cdd5 +ENTROPY 053b2dabc04f9e02213acd90369738722745a88b17ec1f58b667cc0fc555ff10 +ENTROPY b3d489771077ca6b8d2c8c62515803fc4b78a0e55a86ef9ce13da0f63a1fd844 +ENTROPY a14ae510219d0a159851360db4f1aac4ccc257c7b23ff5d52dadb968692e4399 +ENTROPY 02fee15a201f705fdbf57ce904ec97fe677c1efb5bce3ed95514ea30fac192f6 +ENTROPY b7ac1995dc39ee638e7c40015c11046122a9105fc8ffedfc73ab0045d395b97d +ENTROPY a7488b42edf291ceb220b6005f7b9a397e1854bec098215e63aa24f5229c3065 +ENTROPY ecc1993f509d47c9bba19a1c0255f84840e72d262c1e27aa34f18c97900bea6c +ENTROPY f7ae032fc9501d19eb1e1c91f625f03932e514863a655fa42025f72eaee7a864 +ENTROPY 1a7ad580890c16959a83787c5b8426be6597db96ccb4a6daf22925a09e309a25 +ENTROPY aef396ff1439aa55eb92de9919d3afd3f23fa2028e810b4af2bc3dfc58e45347 +ENTROPY dadef5a279a81d9278705eaacb39c0a0c523dd53b9ad56efe8600bdc9867b02d +ENTROPY 0c1d5b4e8c197146ad6634e7c42ab3f13992c63997d381dade4fbd0e0acaa582 +ENTROPY f6f14723a66123bb75e4bf3b7ba8fa0c4c2ae332ae77b9c52e9997a7f5ac1cad +ENTROPY e756cbc57eb8c98c416173428216c8761cef300aa830cf516fed3e4c14543dc3 +ENTROPY 256a01470304b0060b7637784ae0e01feeba9a438e10f34d3c536d9dbae0c280 +ENTROPY 5724127fb86513a67158819c456c6dff4fad5febe5273e1bff801069d416a230 +ENTROPY d9d581d67275053722321a1bc895b489e52f8c9dd232ce25f3dbb8aa10723352 +ENTROPY 406ddcc082712dc552a8c8ce86544208155436cd5d394ee7830a164bb9cbf7ff +ENTROPY a3021b5b68994707b64474beab680a864d1a407a679c7b2786fadeae9d99f53a +ENTROPY 6ae7292fbbef75df4853a41df68468ac50c63244bf8d058621f8901011a0fd68 +ENTROPY d84a90f337b1c8451a5fc5361cb1fa2794f85a896e1a8f81f5147fe72c51a1f8 +ENTROPY abbcab1c5c38adf6475ab78a5fc0fa4bc607d34fa7a838b28f6a1f7e78ea04c5 +ENTROPY 9cf9276b2f090f0121e5840ec430fa0444c7f5dca1845841be2f41e9c2edc059 +ENTROPY 1489b77b8c064163a53e70fb86907595d699dd699a33539d4094a4c379d6bc1c +ENTROPY 481c8c3e88d51bc9c3f4a941da273be25167296cec686f1005962ba6b474b9a7 +ENTROPY 09dae384eae46c2ae629e42186ff4ac3d6843d6d2fa9cbe37c0f2ed2f0511c24 +ENTROPY 3ece08c70b4cd5e498bf71bf12ca58f141cb637dfe7ee3eab46113583472e789 +ENTROPY 43a8616a521054d360cc7e4f41d4b39b3a2d3baaa339a1c56452ecb85d3bda7a +ENTROPY 4f433ff488977003c407aead12d1e52487cbddada058b71032f726a38bb7307b +ENTROPY be40a91254002ad654f6af1ffec5ea26f5a0b4fa976ff304ab524bf9b95b793b +ENTROPY 3b8b46601a5176ff5af1ff34fc350b9730b83bc676adb7be4dee1c4660b44c17 +ENTROPY 0c397da49b0dd77446d63e00b4e0df8b51c96ed301b22eda02d21ecc000f3a12 +ENTROPY 15a084738a8aafe52afabe0087ac5bec0d2e44491ab41135c3067b1c78df5e90 +ENTROPY 6f4217a5c139db2a80d1beee8cff6ad6fc15f374f97203e972d1d3aeb3109311 +ENTROPY 216b73131230094e4dd14de3c685cdd293060c75c482f74c606f01a1818b4ac4 +ENTROPY f481dd6e3ba27053c2bae1e962f50abb632289509ccbb8bfce35e3e3c1da5a06 +ENTROPY 3a688bd59ac5c308334edc23902baa5c486e72b482c54fb1c36719823536b8d3 +ENTROPY d1845d718f51a9815c851f792cc776d88d15ca851eb7c2d70db1ee16ec5b41e2 +ENTROPY e01f9a4ac3a131d5ffa34c9dd9c5f4f012f30bc3ad9435b69dfce76b5218d710 +ENTROPY 945718acaff87166a3ec5c6ea6e2e69230788cb9c6d4fa0ea250daa238e4f9b6 +ENTROPY 61156d340a1f8858bb4c10f78c71c470c3a1d1b6af422fd2cf7ecb5f38bb7ca1 +ENTROPY f2eab68972205a724decb9840a63afc5f26e0d0eb249c9b2de3e0491b3d53c70 +ENTROPY d30038570205ee45ad4ccf966dde0715474ef23f4e0ecf04d37499719ebd0cc7 +ENTROPY 01e11f0859b46eb1ce523318456e3a43ac533f37116cfd08ba32011bbe956d49 +ENTROPY ee47fc38bbe6b70582d0f6d2fddc42517adffc159c7481c4d1cc3b97259dffad +ENTROPY 3ec8c60025003863d3478c94167746a7edaab80c7fc16e51329a8bda0d63dbc9 +ENTROPY fcfb47768809ace69b148d987bb6a96d5bda33de0f585cd68b1fb7d3e4cf5b5d +ENTROPY 552a108a96b4ee655e0741a8953580cc205d6dd63a203f858198e06015fbcc53 +ENTROPY 6afd88a2fed8301a4367150e48b881dd01afe4b75ef8c67e7f967994d1f58f2e +ENTROPY 6db9aa712397450311fc803dcba1ef05224fb1ac5375e18f9a5e45f27b42265d +ENTROPY 7866c9e4e39d2d0b1387c871ba4b198c4fe7814093667dfe4b9126e1aa23783f +ENTROPY 95f3992a67b721153380c1a9780bf2ae0e593cf17187c6a3042faa7bd2801afc +ENTROPY e348a608528bd88da97e47e5a53e4e2bec2e137c89e08b14b8c8203a8ad35a67 +ENTROPY 4f077e53035d677f3e1d92701895bc2c717b5b3e37bbe00049d5b45e9011c96d +ENTROPY d47a87630bbbf8967bd1be6ec91cd3b45e6ecae3def2070efa9570e4142031c8 +ENTROPY fa10ca9bc0b53e543c923737bf3dc7f58e549c5b04783e050bea9ff862ae7d82 +ENTROPY 16a1128336c760189364d10972127326bef9d86a5106dd1c7dc875dcb4a0f87a +ENTROPY 0993dfa70f8ef8bfca267aef57fee0d6578f92942fdaf9a4e8630dbba31df48c +ENTROPY c0d435ad74a64face5523cf9cc62ca0dd8fb8029cadbf261e93c677c42e094ca +ENTROPY 983ded48f0e70022474c68a7349ae4bb5c4a39af92f0fc46c0f8b9276dfeb92a +ENTROPY 02f91045926555e145ee2c5b08c919f7e7df879768fbb99f0db2ab1c55dc84c4 +ENTROPY f9e5f2d98d69a9a5717c122e188bc8a2920d46339edc9b91b893f0775ad9aeec +ENTROPY df487d8a550f0f3dc09a407d986651caf2282597df634ab881a47ef1b31ce5bd +ENTROPY 486e95ac1738d00f9595edf0ad1898dc08a33b270a56884ed4b0e6898470448a +ENTROPY fe23f70c7a9a2eff26412721258bbd306489c208daab62f2dbf4b1fe59eb1972 +ENTROPY ec81da25c1cbf0e7db17f6886526d636e8866076575f41f844402605f23ad86a +ENTROPY 06e01929f4f96619ac64a3856265040f80d8af2efdaeae43f4ce376682381936 +ENTROPY 193a4d98d375fae22916b78bbd31ff5c8d736823bdc4a0332e7bec3ea92b3cdc +ENTROPY 489bc188f12a4c6bbd56884a68b40356978d5586b1894fea8d3f94cc0e26f557 +ENTROPY 64f026cd101439c88f162e02195550d1e4e8e15b320d93f53e2e7352bba91fd0 +ENTROPY 7c916c17c77814b1140a6e4a146cfe434022d7f79685014133b53bfcf6f26099 +ENTROPY 7de1cfa8d4012595619c14a7da21770b91d008a0aaae16855cebf162bac60c47 +ENTROPY c1d5867d26764687afff1e3a5581b80cfdffb0ae5311b932433719a4be4cb5b5 +ENTROPY 1b2cea35738c368c72882bc5764ea55d4aa8cbbb682560770d4cff36d7a0daed +ENTROPY ac75e710816a97fb250c91e75f2945b94eaaeacf1155c1f4ad76d119db0c8b7e +ENTROPY 7a4e93bcb83d64a5cf64388cfa76d0ced37afb243a744887f3808edb041ac043 +ENTROPY e3db477bd81b6bedf5618f9400121f9326315c05768650f7c62d4cea1fcfd2cd +ENTROPY b1c3d7e8f5089991fc29a71a068f41535cbc27eb6ab6e89b6b1301fb6a73f263 +ENTROPY 8a3bc02372592debb0970a512d67606f047bce4ea95c943b9f1191079d5c6297 +ENTROPY 8cba1a0d261245ce6528bf1cd6e5a846e5f3c170bbf9014d42cf86940b4b03c0 +ENTROPY 979b54ddd8591ae71f887a13b3f9de238c41bf99542d76ec92a6bd24d9035a2e +ENTROPY 3d713a60f1b3b0e61bdb49629f1877ff16098817afaa72a67dd7a58fde630d30 +ENTROPY 7b81d294440d54e555497c5cf96417fd144aeebade9447cba634e550caa467b6 +ENTROPY 33c06b062ca3c09505dc2668f84983baf98b46e7af740f56d977352679771067 +ENTROPY 4bb59a909f48dda0155345c017cb99be5c6a813dbee538bcd20275aa1c46d234 +ENTROPY 11b3293ae72a77781ba3a6fd97e2465ff61b8b65a4f9420e5bd5d27341a88f95 +ENTROPY b0b36db124d3d976c892811558b752af454ef476f9d2e0f913c6feb36c23fca4 +ENTROPY 81cade5be2bb80a64933e8ebfe9ce703518a9b3d1c6141107d8d2a32dd59f42d +ENTROPY 2cd75f6ff48ef4492785e519229ac96dd75b178eafbca2bf65b4a10d3d7747ef +ENTROPY a6a246d65ae3027e46bdd365aa1503292f59a520a87f65abeb1bee46714eca70 +ENTROPY 07a362375f1f0b56ac4b51249cead9484270e8572d6358995b6b3e1fe2232bbf +ENTROPY 8963a39d4d39cfbe5dc1143d25b4441383d90643719daa76c184499f8acbd67f +ENTROPY 8c3c5e5021fe9a2c272e74051a86685eb97ec9407c855943a78d892167a56119 +ENTROPY ab08b3bbf8b0033dc7c53e82b4681f087e5efeb7f8c271b8e484226cad1ecc40 +ENTROPY de823045579c10e2cb94357023e7b4511295fd67396f7d79f7927ca5d2c8cb27 +ENTROPY 5fa10eda4e6a00d1e9d4cd2a8cf57f863a0898b89bc036a0abb8fc82a2500c4b +ENTROPY 7e558a865158e48d77e26cde7d246b3e5b34e0d4f0f3f3ff9d371740eeba4a7a +ENTROPY a31e302893992f996b947489c7c853b11bad88d143bdd0ab3fc27a7629a193f5 +ENTROPY 4f05818df34b3dc2a73f9fa075c2d7e143f10268002e3d26647088edf5daa643 +ENTROPY 620c589226df2c5960197c34f5cf07b0f53ab8e0aba5b249a3fc2adcb3634870 +ENTROPY 415d52d9d3af565690bd08d3d18d0785f2e017907440d2f0029f39755c646fc7 +ENTROPY afa8663c6b58b8c6c6be3308d17cd70f98a5786cdea0d5a2b29577c464e4cfd7 +ENTROPY ffb3198054d6ded69d7183da1fc8f109196585c3f287ff1279bc3fa2fdf71ec7 +ENTROPY a279106ef99ce1a18f382405243159cbc0e53029e515a74bf8edd600e73fa93b +ENTROPY 8b54ab6d2c2eed43614c6631796db494c91421e9d8a2d5b2c28817feb2d72e0c +ENTROPY 4a9a416eee57411394ed11b672626a021d4351cec16ebc68a449888df8a07d2d +ENTROPY 09ec0ff271452a097bb96bfa7d091bcedbb94261f8d4cbdd4779a2fe7b8a3dca +ENTROPY c84a49f419a818cb47509c56bdeb9f468483e7e4ec229ee8785a07f4280c9632 +ENTROPY 52c93a6edb16b42074c0c833fc8f9576c0576b3526f2b92fb56032b1e4e01d02 +ENTROPY 7818c10734460fef2dd3eeef8dc2dc69ca638f9598610f4d45a42b4fcc51d654 +ENTROPY 67257b28a8b4637ee3d5ecb1b5f7a5486e1ebff479438cfd6d5869788a61fea5 +ENTROPY 4c9bb15b73a85134261868c186573d84ca2876e179d546434e89d21d9a212e85 +ENTROPY 1f47eab5f480daf5bd69e58f4eebe09c2d1eb27c33b76565b7c093dacd8e461f +ENTROPY 842fc1255713bfddd70f1718cdb6571a51404bd6170b13b69b6a6136afd99f30 +ENTROPY 6ad8eceaf6cc9d6eccb1df773d1d245ed0515b814c7b053fb3d4ee9276c1b1f1 +ENTROPY 53a7e5b3578cfb5b08a4f7ad7e89a4171a76d458df6b4d7ac2fe7bbad73e9f36 +ENTROPY 7c7758cd638b5f39682474e1c24aa90c63766ee5e7ba50bdc95c2fe39bd07e67 +ENTROPY bf65ff01d08a581c91490894783a71df57df80fb0a9e1ca37c5e36f551458f49 +ENTROPY efeae0389b8b740e9d5ee857f9067360ebc78934cec7146c44c6dd9039b814a1 +ENTROPY 8a2c79ddd769164803550d2b78098a6871541491a40d3cd453defa3e08565b51 +ENTROPY 57d435e0e380f0095cb33592d6f01818a0e2863c7733a7d27b1948cc2c10df80 +ENTROPY 447993241ccfc8a770165101ea4900f794f87895a0cdce0ba5424b03595b67bf +ENTROPY 039bd630e3a6b9d1fc11bb582351a68ebcae08f800bd7d3c71da7b048dc4a850 +ENTROPY e20a562e6a668f78d98d8376bdecfe23cfa8a85a3a658ef0d8ef9fd71c4c8585 +ENTROPY 0880dc6a9557a3afdb9f24b6c8583813d69ed5f657c4f26e5cdccb5503390f1a +ENTROPY a0e11c863fbbc2b9e22e3fa101fb337415c5b13f9b4ae52a8115a0e98c2e8f8a +ENTROPY 1fe8ac7fadd83715dcdb27e8f793ee3f66ff6ec654d28faf537351454e7c5f5d +ENTROPY 304fcbe6db4bc8ad416db6187b052f3fdc77b6c75a8131abed47b537d72b5f28 +ENTROPY dd492ecc0c628e889e67efed34a5da4a0831ef88f85b05b79361e2e65ef8bff2 +ENTROPY a15fe5eaa09c95bb8fd553d21e4ec1ae987bc9804fa8f343344a396f1d1ad13f +ENTROPY cee8ee15ddd668a56565ed0067b2fd56ced357f6c5174d5382d30241f22f5b5a +ENTROPY ad4e31ac2e283c4de8e1861b55c24a23c0f13cc4bc868c566ab739d6ce8fed19 +ENTROPY f5900ece4ce685bdf4927617e68181b7d0c4161ac6ffde78a0493a2903d6f76c +ENTROPY 8912280b574be3588712f2016d8dadc44c3b6625b5b4ac9b499fdae7dbdbe8c9 +ENTROPY e3643abb70d9209d561090112e598330f70747260c59c663e3a076c001c9917b +ENTROPY 73380be5048e279292ca4a2c02c02d103696909a4b7b89652b7131196180b191 +ENTROPY 0ca929ceb105a3a6d2869d286dbc1f4ed8cf7dd56f9cb4bfaa4e7c352525da05 +ENTROPY 240e43df1f3461e16393d38904bab4af9829b5b1f6aeca7de1e60707f28e1059 +ENTROPY 136bfff690c3cace98b92b105f97b99a772d947a49e155e80ec68670188a35f3 +ENTROPY 748ce70037cfe180bef77a5f99d8778428936986c20941d1bfeb142a2068f1c6 +ENTROPY cee03ab8602053bc1381cc04ce6d102b38d04e788c3938706789a1d6246f543a +ENTROPY a18853614fdbc6f103067448246070c7c81808b62329db8063e7ae4d5ceea843 +ENTROPY 4169f5b12cffe8e432c8acfa4fe48f794d88a2f0af86125e7b86e28dfcd49b5c +ENTROPY 6cc779c319eae57da5412185f368fe405444ff8d4846d271f98333b39e56957e +ENTROPY 2954f6d003d2cd345accdb8b78cd4e289e8b55e3c2d1b832a1fce47c60230719 +ENTROPY ed7b5bd24bc88a68be8ca2266b85f6e75a2706234870c9bab287f7f35f1b643d +ENTROPY a86fdfa8009f07c136236c6742f2d15cfe058ade70db56cf933535b17e76d9fe +ENTROPY febd426ab5f190b21f830098c1a4d268f87015279dc7c6ef33314a317e559ea1 +ENTROPY dddbb8b9f0707acbad7596fdf5205e4b49a71008134ed8716b9d5774616f6701 +ENTROPY 7dd6399c8691da5d04180ce5fb9a4d378903920b938bad99d58c61fe07959885 +ENTROPY bc221e90a22362ddc2db6b1c84db462f3d6e585f28da56f597fb27cc616506dd +ENTROPY 1afbec9e7e153c935be9d838f970820fc21ef927adda53d73593c0bd914d94df +ENTROPY d2186fb8c2e2a47f21c86af6740cc11c3c22b76ef8709a7ce34a3e3c8d635a23 +ENTROPY e667c574c638161a2522ca81c8172a6f645576629023142ac95040d1db410df2 +ENTROPY 9d9bbc5f79dbd582f552d7e667bff48ac90af71d4c1e7eb3f0cf409b875d9d04 +ENTROPY f34cb090f8ac0472f1db577ba9fa6ec599b448157361e911bcd4cdbb8fb0ff6b +ENTROPY 076b0f4f90369e043739a9e2a999939ebd7caf33364b070e24ee536319485759 +ENTROPY fd3f0f6147c5e7706cb97bb860954f7165882caf0e5afa4bdc2e9de84de277e6 +ENTROPY 8cb6a4f4918464855872e89ff8f0d05445546799c0d993a5fd6258e5658e1d61 +ENTROPY 6a6f3193d4f3c1ca9f52caf1eefa2c87b5c4d03c9ee8ac672231d49a765c3da0 +ENTROPY 415ce06afa71799f87a3864348001705f417a5b8529459f0fdd48ce8108a3cd1 +ENTROPY 5147b7fa7d3adac57e9839cb5367c7e178a14f587edb9a7718869f919f25324b +ENTROPY 588a37bc8d65f412f20dd496bbca50f04735ca98413fe9f4c21eb2d5e912b2f5 +ENTROPY f3ac9c0365c36d37367846d9c7d463c674eb468926086aef8e36d8345fb07ab3 +ENTROPY 739251146fe3f72bdc78e753d6d3e338c8a930cb2c4975a36684154a244ce5a7 +ENTROPY 8c3d3165296445ec4c38d9c39603cdfc6c8c258560a355dea8d569c79b543587 +ENTROPY b29d5b7d4e830ef0bbab4cc4d74d12bbd7eec3eaa77cf095e8732e25183ff8f6 +ENTROPY e190da444fbf60e67faf939e9ce8c1a0dc13f2a36f5cdbd7d573cf1f1aa9ddc1 +ENTROPY cda9e933817104eb0d5c84b3cab934891dd670808167223a1d3af371c9e3fd79 +ENTROPY 95bd1ab5d166eee4041323e2286a09083bc486ebb75b396352f15d662c06d414 +ENTROPY 893a3b0b64448722e80ef894f385e77a7c7ca9026c83d8b5afb40fde087d1bbf +ENTROPY 519d6efe9afa303e4eaa71def4f3fb425d3ac7eb17ce22014804c3e64440a2f0 +ENTROPY 7acdfc4d0633caa06ce48e76cb95147813b739e7557c0591a12e810fa31b8159 +ENTROPY bf37b7a029c9839c38e7120dfe83eb3e794ccbd4aedfd5f7da2b450e3551e5c2 +ENTROPY 7807722832748951ea9353d15180ff0cc3aaabc53f7233936d7489b3a1e18d31 +ENTROPY e4b3c35cd413afb76fa252a3b1f88a840b70eb1246af0f209d0d8cf6413a0b23 +ENTROPY 60f5b8f5a9d8fc8f3141b6f1b48d8fabb6bcd74d177864ba9aae2461b1497030 +ENTROPY a4872c7b2198e736efa1c2b3bc101a5e5bdd899ec8bdd5986804404ee20a05fe +ENTROPY 40030abedc5528d635caf22d9f130e0a457f439d3f75a0f3bb75e6051300b183 +ENTROPY c739e7f799d3f57521fc959732b54e6b8122a375b401db2cd891359fda12b3b2 +ENTROPY 576134d90066413768a6e21cb89b717519f4b29ddba8a73dc46a6938a67c946a +ENTROPY 3246ff0e041c80dd535ec029087a9b117db166874f4857d2df07ee46e31c29bc +ENTROPY 049b2851f72471bfc064dbfae8902c5bef288dd477ae6899a61edd4dc6bf4e2d +ENTROPY 1183d23c6a40901473f1810a77b09bb0ae3c337329532250cd17d17fec6549ff +ENTROPY a436eae5823bbb491ff75b49d98b7b18b823f010636533dcc8f89054dac15a3f +ENTROPY ce9d8d279669fb358ce9550636b758ef3cfd7d9bdd1a1c3a63d864b3e7117311 +ENTROPY 3eb1094ba95c0de90ff4bf4769a7c7bb658d73f7a2c299bfe01c156db06aa6b6 +ENTROPY 0a9364ebc87ed3b49b34ed1b3defd99cfc66d88e0182467aaa60b0e99113c004 +ENTROPY 37bba155d9fb6f522eb63490112b92308590a9041eca5275721e61c1fa2a6cf5 +ENTROPY 842faacf84f7035a26479056f2b434e46bcaed14b07057be398c8a2104cfbde1 +ENTROPY 5254dad886bafd62460afd62149a55a8a2a4aff8721d1227f473f3c377d09694 +ENTROPY e962567f66f92b2ebf9c17af492719bdfb4ce2bfe004a366808821fcce56c560 +ENTROPY 597bc56d2bdd526216cc58d3c2c7014b058b156c901ecbd52c5cc0138335dde6 +ENTROPY d1ea7ec794b1417142478748ab546aec216d7b582a0fa93375fe615544c9bb07 +ENTROPY a09a2e6d2fd53c8831d8389f3f58f8ed6197566d0b389db30c5effe76dba3ed2 +ENTROPY d8d2b03739b1743b394b73bb8e0d88e060d9b1eb0992b9e9f85444d27e4056d2 +ENTROPY 93b3b6adcc2c06049e5cf4146aec0e8d56dd97c589a1769346b8e56139c6f250 +ENTROPY 43cb474a4caac2403c1704956a58ba04d0d3c97811fc137ca0154fa832a4bedb +ENTROPY 7ba858e1502ace4b14938e83305d7b99d7d9bbd862bda6abccd1a8977d4141fa +ENTROPY caa2ca4c1b89c5cae06f9950a8c61dd5d15ca5e8ba3ede82be934761f3cc5708 +ENTROPY 377607b761f2f9b4e681f27b56526b8191aa67fc410c5ae466b52a8fd909ad16 +ENTROPY 8454fc10bd6f54a9dc90b1dddf49bd001613dfbd1ecb8813bef78ddeb0747d6f +ENTROPY 8b33402558875fcc28941235febeffcf1f9bf6047acbb8531b882735f9c7e2b6 +ENTROPY 9370a98732a59ea4af56ee7a5fc73dfab1f61ee20e1884635a6bc98b9eae4788 +ENTROPY b59af665db60f9849506af97fd2d7b93c8f0f513ff1342bef8e874631269c139 +ENTROPY c60206243041ba06ba9b9022783b2dc32a8a4d97f4c76e9c764911b2ac37e076 +ENTROPY 2a738a3d89337ed12d2cc014dbf90519c9ca5b11f0413964da6bd6fd6d8bf921 +ENTROPY 8f6bd5f53b31c24157f51fe3b182c488ed1976836a05d8838b561efa0aee5ec7 +ENTROPY ac7dd69fea294764251023994fe1cf1a9ee3509fefa36f494c597344344dbdc3 +ENTROPY a7640c0433179b9f212c66bcaf8aa53f15c9a882aa9723fa10d9064dccd4cbaa +ENTROPY f59db2eac00f1a02f4e1269c9785f0cd7fc6f2554852f1601b7aeebcb28f6ae8 +ENTROPY 11e1a5369fa2c857942a9017958fae9a6c566798112463d777804f6127d697b6 +ENTROPY ef7e644809f589e5d083f5dc9e57076792fd6407043ea448eb5d6ae3b5fd2ed1 +ENTROPY 6744c67a80e5aa52be3141c3c53092c2df16d70e3baf26f75fd6c56bb4222805 +ENTROPY 22b89e1bf2eb4d588175f5312baa2acdcf8307c82d37d3cb8eedb0a46d904a17 +ENTROPY c6f5758868f9783213b888737214671ddc3a6c29dd3c28ff64e64d1c665ce68f +ENTROPY eca3999063a9e5548aa3b13751798b6802db97fb8d545c23535f058ff082fbac +ENTROPY c510654b04cc8d4102a59445c4d2f513f7beb431606ca34c7e3ec5e57bac8183 +ENTROPY 4cd07598bd007070e5cc47f240d6f73b484aa8b1d01e6070fbcab86b6c08a684 +ENTROPY edb579337fe19132c48141bb70fc130991d25ae799fd631b17c2dfd66c311d6e +ENTROPY 5adf039a48f5ae02994a43c6a3caee0a21450c984f4a48d780fcdea36111f5d7 +ENTROPY 6e740eb5678ad990427b87bc7ac2def58561e6f85654b31ddddacc906eae0cf8 +ENTROPY 5da857691fccb3ab38fc1c17fed5f1f7e4ee23d51b60efa216d99c324ab928b0 +ENTROPY d6ba490f23e65af2ece453e47d9be32d9a0b6bc26cafa2ea00e4ec9559a3f5e7 +ENTROPY b3fb09b9c105876c61a218b81393b010d7f1fd2f390ee0cbea1b81493b12b018 +ENTROPY 005d397e6f201bab3c033a2cceef702fa7d1c2f55e6835f38d06605766e10ae8 +ENTROPY b2435ab94e6b131f2e203db249916d89c2441ec7823abcfa27e9923120318af8 +ENTROPY 186f7e92dbdc47d4b5640dad8993bc6ddadb1a479f043f833382c4fcb062c8f5 +ENTROPY 17e73d67ec8d6b44fb83e4ebf5f854ce9a1ff49ce2ce8052a776d51ffd55c368 +ENTROPY fbe8463deeac362b4a966ccbe30bf8887f18369389aef64bbb0a5b243f74db6c +ENTROPY 1a53c95b868ea37155801196c6a81dad2380f7e14fe8841976b465b99085ec2d +ENTROPY 7b759d26256fcc56b86b01bba72b6cf38b8bc4e05543ee5a454c0e59c450ff30 +ENTROPY ad88cb8866a4d27b3c2836b5cd7bc2a614112ff35cea22ea9b884b81bec240d9 +ENTROPY c888b32a829e2dfa9d50a5ef14e986fee89412f2a460576bf566a36deb3e6f4b +ENTROPY 17e9dd5d219266b52849e6b938202c55a898e0f94a1b823d882589ad6f7980b3 +ENTROPY d33e2cb49c7104b039f7f03570d808ec5831e8ede956bcb62a1e870a3186e5e7 +ENTROPY ff1838af9707d670ac59e8a3dfd86b383d3049a61c0a566bd3fdafc33f2c666a +ENTROPY 2befdb153e5bb7d83d35ba264f24152270833a0bed7ac36449ae80d0bbaec87d +ENTROPY 77cee863a2ef8ec6fbbe085a67112dc871c4b09554dfe91124d1f7bebc73f7ed +ENTROPY 54ef7c57cef1de609fc374f93ea95384dd50510a2e2c6a03b19b87210d552898 +ENTROPY 7fcae33b230c220b7f1379190cec2a99c04a55deaac431fd844ce01fdf0e76c0 +ENTROPY 6a2f35678013705e00b70f549d9591111a591182659a07c69eeceb10c83a13ef +ENTROPY 9dbc00395d012ff580dcedf2b470bfca74c640fde0bf461bdfd04c63bae0246a +ENTROPY f92a5672877282e414017151ace8a45c56e4247e130bc235e22bae1b90da17d4 +ENTROPY 2576977fffe37968cc6da794302a3f052ccae2f21674fae8ccc548d6bc77a2c0 +ENTROPY ae8c16713e10e313302011fc19d2c6aefaa86397daa5805260dabbbd8f939f7a +ENTROPY ed9be82a038b224a10cdf5bfc4ffedbbb1f54358c28c6c9bff868b42668268cf +ENTROPY 891af951a593d30f773e661229634c1dbba3c85f7d6b9a6fa717377f34051206 +ENTROPY de19ce216f126a9089be4ff70313338ae8919269cab55e8c047e31421d286a1e +ENTROPY e22b71efb16556d08c4aa0270c32ea35329477c85970125101e3f9944f9e3dfe +ENTROPY f0f80486f7ef16dc3d65b4d1ffd22f292d12fc074da0644b38f4215142a948a7 +ENTROPY 83d42cfffc893c6a159fe6694da10f08a3d7d426e066b3c574e61205e63909c3 +ENTROPY 6f5cc060aed8907b4ee43b42ea58929fad509d386cc7b060f99cdf252d6ff5fa +ENTROPY d55709985900414e32ac32c9080beb829cdc8aa9c3dd2507741a78d519b27d7f +ENTROPY cd7e6971514f74f2b6502f36c3e7e82af7de053f6659dd1f4b27b7d0b54d1d7a +ENTROPY d75608abcbad3ce43a6fee9d87d660397c851fda9d2f8433627fced01bd2ae1f +ENTROPY fbce6fa41589b799759fc495c3fec999d14fd1751e8df4bb083d212332ae3f95 +ENTROPY ecb03c22137ff7952f5b8175ace6faf196be406989bd56c190c18924914618af +ENTROPY a932493ea61f63c2173fcd756b68bff108c0e581dfaad3b2e8df4cb40242aed4 +ENTROPY 5c0f466864688a03129c593b40395396781119277b15ca3d499f19be94327b2d +ENTROPY 481ccb8c2fa8fbb53312e8d3a1f3f4e933f360e17297d219e22edf8ab316f0bb +ENTROPY e606c9adeff86910103a0c62fd431e24d365075c36ea1ff43ab6d48025c1cfbf +ENTROPY f882ac877ac60e52e44ae15498255f0042036b187e00265fb32802736ea1a7f9 +ENTROPY f52e32997d1ef283258a1d3044da95a87be2e15d8af271534e91fbb42ac00a7c +ENTROPY 380612f7926da541dd212f255fdf4ac12462def5086c57d2af21df2c0e642efc +ENTROPY 794ff548161861dec45e8c9fea36695e0b1d44dcd24a2ad5ccc9e1c464cc8c87 +ENTROPY 9ce2ace9f87f6a9be2074334cdaab0135ae3d3615935b980fb3ccb78d821e6f4 +ENTROPY e33ff04a178cebc8cc98751028c6e791838372cb20f996b19261d3bf3b7c16f1 +ENTROPY f924a4514fdf7c3cff0ac6753f0c06ed4701464ec8fa6adac2f8d723836e6fea +ENTROPY dfe15116ff3d0569bf5b4b3e1a308c487ec917e8d7a7bd8ea1a810da6efde405 +ENTROPY a0ea2b17e90d58826e48b7bb44f243ff03db6740968a23f610621bb76d8dd27b +ENTROPY fbf93a221410be8bdc59401fb21a99d9c0c0447a72e8059aa01c75d057b8fd41 +ENTROPY b44ab5a831092311e73684dc03b557bb8723eb859ba713264062219ed51e4959 +ENTROPY 9bdc516509596bf5a18e3a6bf06007b5f1a01faee7a9b1e23dfbea48b03eda2f +ENTROPY a30e3ccccf7d0ed148a54076edd79aa5cad45f22ed4cf561d822f119b9bebc0f +ENTROPY 0fff6aa240b393bcd77d3e356c3f388c3bd82d95db3b816b57a802bfc748da77 +ENTROPY a26c53d6864e2c0a692a434b01ac9fc7f1d3a7e877ab203359a226db1fd2e1bf +ENTROPY f41058cd2f5f1ed1df506f5a99667d26e88dd53aa1ddf5defdc4a036eb8d399c +ENTROPY d235798762b43e06fdabbcac76d6f889fcf6257dcd700984a29b2121d94babdf +ENTROPY 5d1dc2c557c6e6b1d4cb914e693bcb4ed1b4633ecdb0cf1cd28975622939bd57 +ENTROPY 13f6e644735c6b00cca9bbf096df8210842317ec7a400a8ea80ab268ca9de37a +ENTROPY 1905a0b3dfa30622a980e705d928e1a9d73bfb20fdff29eb99de7f38f87c6bee +ENTROPY bc80f27dffa8e7bf9b8ec9091dc0e4f6c7c0b7486f08a64fe1ed4567faac2707 +ENTROPY ca8e70d6afa8678c3d1127d95c0e8937947447016fa782096e8022f2a1230630 +ENTROPY 1fe7f9e6f1353de66098e368a5b2ddda6dc9a3b60922030d7ee797648bdf4517 +ENTROPY bd634f4b7533899c1b7472c9442fec863d90d62b838333c5a01aced5dd4f0d19 +ENTROPY a115cd8b015fa6e6bbb4eda9c2270ea770eb12cefa11811cd4ba1295b0743852 +ENTROPY a8b78fc2964236008de5b6e9b0a10b6bc33ee477205534a039656cc50c0951fc +ENTROPY b8198fecca57d2ab6bfe4ded4d1db517a14ef552e46a69a95eee6df65380b85c +ENTROPY 47517318cefa835042da26470708de046acf5d342c1b07a260ce1e9ad059b393 +ENTROPY b00813770e20adb9282b281aae2283bccf026ecabb25d3a46481615fb6d6c7a6 +ENTROPY 9835e2159d3b62e2ecb900ac849f0b23e18f01150d363cdb69b365ae3ebdc403 +ENTROPY 2bc8adc57e248902651d631845f1b061abcbe0d048012507647eb7a562c23a48 +ENTROPY 5511a1ad1b4e836088d786463ec69c120ad90620305d2b36526fb4004dfbee44 +ENTROPY 4899b804e740ee8d154a9cc5890b8afe73b50e8090a14914ad2eaa1c8d6f354c +ENTROPY af239e2c1ca30ee7c4668b285030a41744ecec0b04b122df81e17807b58241ee +ENTROPY 92d079a76b6dcbc1e00cf0629968a9962464e9233e2fc6cac62eb6f0509ddeeb +ENTROPY 0c70e688c9e72d10009f0658e649cc77b87b5e7cffa49d03f79fd7643a290a63 +ENTROPY c5faf64c82de8b7519fb2ed42765c19e2fe61b72d1a61789652bbe96e8c83b39 +ENTROPY 932404ce20e76c2ec13685409f99e13b260d7aa5054fa0bb5b8958c683a83f00 +ENTROPY 8a1ade5f63bd79a80c185a4edd9f1617d1cad970a2f0540b951e7c8342c6c937 +ENTROPY 68a85630767b44aef1bef14f3501b02f81326bc8b37b9ae806ac0ff3db1a89db +ENTROPY 6ad0e4610f088db1d773b97cdf2d2587ea4aa7a2b98748949b66e2216b4a361f +ENTROPY 13e59e325c070f1f9a75b932045e548cc9c065011ef8ce375478134a83d22543 +ENTROPY 64ed24ff2ed31e1eb3730313ee5616c339e6c3b3a78dd7c1761f3a4754651f8b +ENTROPY 6e47989ef8d7e3dd5f8150fae18b366c36b891033e216eb385717e70632f4741 +ENTROPY ac6490afa89c2b04c7151ca5ca4a863ab372e7f90d8204f6199f8d87ca0b450b +ENTROPY e160975be91a28771fe0a079bfd53325722ee6ce699d2ea5c4d9eef9d0fb148f +ENTROPY 4d59a85fbd45b47e0260405169758d30552b4a45f858d3ab2073711811a834f1 +ENTROPY 2dd79fe787e2dd7afdbc0e5b8aaad44e9766f7333f944c818d5a20c112d7dab4 +ENTROPY 959a8e2563292cc89a9c7164718595eeed74e4faae0a8ba158788b4eb72f63e9 +ENTROPY 0a6bbd30b90adf5c1310c2b2d7a5208f080d52e7e0a48b2f64230d647cda6f4e +ENTROPY 3bbc1c7f59f963f585ac97c8025411d086e3db7c24822c527e7db6d08a1f3392 +ENTROPY 750968f8c03d64fc7f696b546c22fa1695583cca13e68479a9191269a0d80fde +ENTROPY 029eeb34b1e815c45a457e1eefafab3b692f3260ae1a5d8ffc17eb98856cb06e +ENTROPY d2f5f7d680680cd65669203939af62e415e65ed4f36c2c423504d87538271304 +ENTROPY 64e6efe3a3836c0786156fcf838c7669e32c1d51f7ab8c78cfa5aad23c9959aa +ENTROPY f6863115de4a732b65c0cd51ba08aa416f4013a0e5407a3f9bb938a2cc8b9983 +ENTROPY 0892820357b25dd1ddb403dbf385d6d44d9590c6c809bb34ee42a2edfd15be14 +ENTROPY 63973df710a159a8d2f5d6b722ca5951bfc418a2643b0b1cdf9eaa249bccb25a +ENTROPY 52be1bdc7285d34cbef650421fd5e9a89bdca41b6592906067f535c9c6d33a8e +ENTROPY 4da602be4f099a31c7109fba13a4503908deccc12900d64808e684234fe83a26 +ENTROPY 76907de4dff11db3cd23a476eba0e4fdcf04783572122146312caa90acb90099 +ENTROPY 41db5d4fc312641d8e26314e9ee4b829055a6a97bbde3dd0f35c36a4f088c62b +ENTROPY 6ac85de04b6d4c76ea32ea3bef82073646a2929fd981c617b0e3ee8550a46c40 +ENTROPY 805c8e88283ddefeec40e5e97864073990119d51ce9e73dc5e8ccb378041bc15 +ENTROPY 8fc533389ceb557a8dd7a19c1b1d13a35b0a83d7e338d9a51a62bc0c8a8b16b7 +ENTROPY 9d6ed26b2bb5100c69438d2b2124ade9b25007fa2ebb3294dd9222ecb63e0640 +ENTROPY 78477ea11644a351910cac54f24e888e446d5f1081e9b0f0b71dbb4a5bc0ef4c +ENTROPY ffe94fd4ec0853d8b736e3343cb4d30087e88afa55f2ca37985602f33bd44e84 +ENTROPY 7a536c7c71a9d9172400e5ac3076308eb60b886d877952ef81634f635ef076b3 +ENTROPY acf81bcb5dfe92189cf5d8c1a9d4db8b43593be0de7ce8f565bdea0c61f63d40 +ENTROPY db8ad251547f5a4603ee2625c39dced1a9b627ae048bea17011734df32ce60ab +ENTROPY e7b91e61184ee01990027f1a91f11814c8c3aaed1d830b9f8b0b6c06fc0432ee +ENTROPY c71e18759e551a079ff8252a99f22f2216b7e8835b13a62027221ea918f44b49 +ENTROPY d22897dc5ce65f3348027fcbaadd77eade9684d9159a755f3c503a48eb6d45bd +ENTROPY 589051d5b4974630ad748f37c84fd685303648f0a6c57e172e1495cb286c3b9c +ENTROPY daa5c68255abfbf4e8deb72c8cf7dd7e73abb156755b5352fb065d18a6ee2df0 +ENTROPY 325c7151b4194833105cd3f79f5413fe53400a9ed1a796e34d15a92febc945ac +ENTROPY 0f39e5f13f07691d6aee06c2e0d6c441bd722ecb2fc80541de0540386950a708 +ENTROPY c7c1f42260e5aafe9249b0ff5413abc34320dc5416f4638a93691bd04250ff0c +ENTROPY 12cf28e3ab4f5608f8fa1afda3b2969e40f53a80064c3de95635fea7fa7f3063 +ENTROPY 114feb4369cdf82dbd22efac738ecc174876cc2b08af634289d84d582dcf0ec1 +ENTROPY 5b7224980cffe11040886f9847564fcec8e1ff8f313bc32ab21796235c55e1e7 +ENTROPY 54c0faa4a76cca381368b82313ad3a86c189eb709e0fb6cc790a424a82ab58a5 +ENTROPY 9b11c0c83ccf5a82a279aa6f935148ec1514acedc59792bd33822ad9fa540f94 +ENTROPY cec31364eb7ca8f398ebaf4a0f71648efb9820d5e31f3641643c6eef27f398d4 +ENTROPY 99608b31b653e7a09e0df7c05944bd87e7bcf3c678e755153aa52d4f05066d41 +ENTROPY 650e973da65f7a9df5da27bb85191d2bc7d34454af626afddf1b5ff8b0dacdc7 +ENTROPY fbcba675d2c10d40a454eddec68dd3af199892bc6eb7a008eef5e2b0a8c742a6 +ENTROPY 243a17c82fa8fc6df316dd0c0944882d3eb599f731afa794b08364cc17897ee3 +ENTROPY 808bc4300b6b81e991516fbcc402f622f349d8f7d810a5e3b8e01637d96a1be5 +ENTROPY 7250d9a605cb74b94ec0ab6ccecf6e60867fd24ec958dbebe0b3c5bdad9f44f8 +ENTROPY 4fcfb14fae4fec49ebd22798b9e7bc5d9048f841229e84c627bc518ce479bc89 +ENTROPY 3d49ebba6face2318f4f86ae546301d1d7da36e48a8a72e491b08c1b5651fb76 +ENTROPY 94de10b86ddf42b26fc54dcd350b25ec4a5fdbc77c4528cd3a2bc40ed6f9cb17 +ENTROPY 7b9be34385bb22c614f66b6c91c5f2022b312a38223178dfd14738d73556ec3b +ENTROPY 00be6767c883c277ea98157c05da14aa186ad1db32cbd84c3c5bb1d976b3f69b +ENTROPY e71d33cfb3dc230f3b7ee4d46af1accd97dc04f4b6b102d7cb2682699a1ccc62 +ENTROPY 9e6aa844194b8e80e5dda735bdbacc78c599aa2e48d5b4b608b4c11749b3a5e7 +ENTROPY a986d9a9b0b4b4f324645ceb09b619362b165c5e87740713fb95c222f5c42923 +ENTROPY 51b088e8eeac1df00df5268e3ac5b58e6931414a3e2b751b96d5270d06019476 +ENTROPY 6f0ba3bfe2a52fcf31c4a44492bf1f31304fc02e5ed6e6f849bba38ee65dd947 +ENTROPY 5d687128f32c2fb368d90516a45c4dea600c131592089a846973f6a808c9a060 +ENTROPY d20313ba5c5ca8232bcaaefe483802baa1232519289d732cbdaed5d604a7d08f +ENTROPY 2374b2e57a08676141a15a1abe9f83a2fb99a1377fd1046e5953ba3d989f1acb +ENTROPY 3a92dfe45dc843b06ae3950e5cedff58004c22d15bfa69d32ecd10fe28f5c3ac +ENTROPY d932ca2d5035a60693284683de07bedfb638448fcd4670d2de1ebf11ef40130d +ENTROPY f1e393ab55c44b518bf5df42ce77c21b60fb909195043c4558d828d53969b61a +ENTROPY a9de40324c9139dc0c955b5dec82bcabf467169a003d362f6954f1d82785aab8 +ENTROPY 7fa78e797519a69b10e2b515d22b7f62ee863584c09b1f49b0dcbc4dd02e6023 +ENTROPY 6480ff5c9f09ed815cec773cf3dc12dcdbd016f8c5af2c818037bb1a5e11b793 +ENTROPY 0607f42818315c00dcfa5223a3d05991c93bf38a70b5fda3eda7b3608c15fc00 +ENTROPY 5f4e95b6887501f19e477b8c9a70611972dd4623774a4eb718fe3f85c334fda9 +ENTROPY 6c94e8816ceff0e0bab35561b0bf1f7881f93897cbeb8c0b159e1f907e499d01 +ENTROPY dfd76e38ae232d7601973561a7abfb81e5005fa21b0a928554c5b3878e77316c +ENTROPY 06d549c88e2527c3b679a9c50f70a04726986ac8beb1b4d62cd663d8bb73ba92 +ENTROPY 56eed6d8b58e597bb46b7ac0548cbfba78c43817d5e48560624f88c11b237fac +ENTROPY fd5c615e2ee87adcd99e21446891b40742f0214fffd4b2b3813ba7db0b9a5a22 +ENTROPY 63ed53dc529b7e2bb2d5cd6845e6f49c164eb7f5fdf16aef40fa59c8f6f89e48 +ENTROPY fbd7a8c0afc6637dadbe0206053ab0352d043669abfafcebc923f72ef593f2a0 +ENTROPY 0f5347b7c4428458e1ef0f8ab455d1dca7ac2be4f2f0f149aa8a64c78124dff6 +ENTROPY ad7ba824d2c7e57f9744799fb60b01ef80507ed8d882b806261a9eaa1c236590 +ENTROPY b205fb70aea96c7028a8974fecfdb90b118039412e115ca294ae87fdda270653 +ENTROPY bfad737f01fc41c9b8191198c3bbf7d2aeb81d830a5afe18b74445fb92f5392c +ENTROPY e0ab83bbe6b8c82e7d42da2a4f9998ec40e46fe15cb545ea77f7af3663f5cb07 +ENTROPY e7d63f696aa7d7373d9594c8e83698c860328d2608320336d984f6855130972b +ENTROPY 806d840edebadb44e67da4f78ec8d3a7153c75d1ed9f45547265bd0ac460afe4 +ENTROPY 0812d2ce27b9c6c65117e05f4d0625bf299ce8348c449e579ab9fac5b6b70168 +ENTROPY 2325c7ccd7e5fa416b877169796915a70283e7f03be154a195b5cf2f17277f1e +ENTROPY 6b0f89641fb9f43f2fa84c3dad58df65d894db7b2375b8cd07f80f8fda4800ec +ENTROPY b77a5e4ffe4d63470ff6d3e08434e4236e8d9b0b88969509c4f0d166569b2673 +ENTROPY 1428758f6427b15519169ebb1cf7bcd267376c530048fc15c47c671db95b066a +ENTROPY 33355f3da43e6e4b7a4bd7cb8d1c32d3981ee758076e469fbdbeb1159615b69a +ENTROPY 2d00b89e7b714f0f4780a16c6cca733486fc688ce098c3712e6d0a525324a16a +ENTROPY 585a541e82fa27e9ac37f8128f978e5f319b6f2f1d236d68a82811b64e7a35f5 +ENTROPY 076dbf1856243753d1784b04d4ac863cc71c4fc70a852c348f79df9078bb63c7 +ENTROPY bd3e95db33ec4bfb5cf6967bc8af7666e4cf36855bc88d492c9659e089b61b91 +ENTROPY c05b43e82c58ee956d8ddcd92f1bf972819c46496eca5c62d299778d90fc90de +ENTROPY c15a2a5b208f58380741567334cf85a001c2ef29f6ebf9543e9b9158dcd419aa +ENTROPY 1819091d9c24da67d49fe89cdc70683192780de276ef953348e3f81d38181b9e +ENTROPY ee523443831ccfc7d4c37a4cf8065739736a6999035625c88723281604dc175e +ENTROPY 97b358cf120ee5b6207457d5141db30f261c150a4e44f05fcf3f8ebb50c1f9d6 +ENTROPY bc57b37e4df97a0440fffe19e6f524a0a1f86b514803e9a7b919ceeb87c02c4c +ENTROPY b0b44e138fb6b75c3a2b343c86d8c39d4109ecc517df3142b049768f037ae08e +ENTROPY a9e7ce7bf448b3a9d3e5450cb6804fd6a5673cc277e7e8e0289f33946f7cc024 +ENTROPY 3fc5d82a6f7872397edc888dc2ae67c7eda92cb09e8cacd7cdc51a34881749df +ENTROPY 9aaab38c6fff1a2f91f9c94de31b8eee52807b5981ea3dcb0fe77ae7e4f55bf6 +ENTROPY f539a574d000656e8cefd6cb36cff2ffdcca8399e5ea2ebd075536bfed361c5a +ENTROPY ba0958b6a75981b0f4c5748a4991fc2b7aac6183982fdccfc3c813ed16f5b483 +ENTROPY e84842a260c75febb848a7978c7b9e95fbc5db4a1affdd643035c1029bc230ae +ENTROPY a75d61255a5ee03129bf3a3e679807527e63b23a525aef438f3bf47f8d238396 +ENTROPY ab36503d7358eccdd5de0c405cb9723f6598b6878b6eb811cad329d8fbc0cd2d +ENTROPY 1c71175bff5cebea25ac3833747fbedb5b06b9c59bfeb31385f57d88f977d67e +ENTROPY 501e4d18ad43aa18edfc8eb77bb5531a3cd3fafd7a1cc5c09024c08c7695b45f +ENTROPY 0979469dc9f7082f67c6d8223ff6234f0072142c9eb0502c2c0b67cf3dbab629 +ENTROPY 2b5a26a49cdc6529d5910deedd293353f680e6b3b7d80b27013c31d719522f12 +ENTROPY a7cccd0e56083856382f04023fa368c83410bdced4f41b0c88208eeb7037eba0 +ENTROPY 3a3f67a5b040be9e47b4a091a20edb5f289f2ee420be0b113b632ae1fe721743 +ENTROPY c73d1ccd393029d12bb5c93f4ebd0043ac29bb595ffece14debcdd7af55a0d8f +ENTROPY 536212353227d370e782a8d38d5e1aeab9754c431039a6608c8ce45feacc28d6 +ENTROPY 1cd0455caa9c69fee0a1291cdec71689edb0c7f956e0eccef4f7bb7ee138c176 +ENTROPY 7eed5efdf9c59007a7b10fab2292178017652794e8a56e339cd8739ca22dac0b +ENTROPY e7063a31ead8c066be02e3ce40a790eb0958eed12516839d0500f9639e5fab87 +ENTROPY 2be694a784ed1ac897339983aacb76ef27a25281880d1451f12a0a554fc7952d +ENTROPY 9cbd20871a08d03535e64c6a37347e5c2fcf06877ef779d2f2a2161aa2054a60 +ENTROPY 05cdf1e7dc4e0f650ecd9b74486710acdda4c693d6d704dc74267e04f0b0f676 +ENTROPY fdddf008425f37a79bc64cb66b055476b85a51f980f1f9e00083262767d50acb +ENTROPY 1515226c54ebf9a0ccf4c68c41bf584a74e5e1675453996ce6a32b5fa9432f5a +ENTROPY a3a5f45b43e53a92322b0cf3712b63578719dbd80af497b5e3658361e4c15010 +ENTROPY 6e166985ca38c6cb4b090ed2418e82ba1b0c7744c572dc7155f8d6a31412e844 +ENTROPY 213966d35f9fdd886fb2ce66a852749ab4b0dbf4373f3e1d8e94bb70cebc4278 +ENTROPY c1265f9dd2becf54a2c602db7f85b9b1eecb774c8f4ce4f97b5154f70123dc90 +ENTROPY 9690285412280f2b1439363c6e9f80aeb024c4322f839308fbe3244b7f2f9c7e +ENTROPY 498e42aca5c6a10dbfef7e3ff7943e9cf90386cc3ef3bad17d3f4aae03a980fd +ENTROPY b5fa18daf63b3b0eb09d13be75a1043a20cd32f7586051aeb968d630ed8f2994 +ENTROPY 233291aa7650727ece6219375110755d1c6ca35479eefd6c2983f41ff683492b +ENTROPY 2e4df204563c98b1e188af92e9bb7fa5c3cefd16e9f32d7509c031f80b443064 +ENTROPY 3c33057946cd1616c45d29e453385ed7c178802411f88b891ceb06bba677facb +ENTROPY b60d5af09d6d834085635d2b9dd915b41d836cf27fccfd9b6cdc8f4cffaf5c58 +ENTROPY 68965860c789342c4d89589664ae4c616081d902774a3571d7cd646e076eea0e +ENTROPY 2ce881f86e8f7e6b8f6deafbfb9b6a460245c17b9bfb91d302ae1a9708dad1f0 +ENTROPY 80989a7bd8b8fd6626c8182d6b0cdae68d46f617a4a00e30cffc06192bab2e85 +ENTROPY 57b59c6dd475bbc3469736d6f4addfe4dc9c0d633c2ebec344fb92ea715764d9 +ENTROPY 40bba7311f2e4852612729fd835e4b8cc331567a11fd07cc9cdbc9b25c02d9ba +ENTROPY bb5715a7a91dfd6e69a5c02abcb4ff43c6438fd96e66742e3d5f0cb8f2add9e3 +ENTROPY 1932b9fb91480ef506de214f19f37fcfa028747251a350308c3e02a5a53c8d46 +ENTROPY 244cba333ef94e7f2f8da425bffa0ec679fbecfb496d8df60e863a06bb2fa7a5 +ENTROPY 589ec130598d263b00de9c5390e7c3598a447990cebd35d3f0c76244b263c6c6 +ENTROPY c625fdd92cb57d04ea4b7498c6b30b15c891779d79f72f45e563bece9b39a086 +ENTROPY 0876691edafdd4a1b23522ad8e0af9e0efc772efbb062db17daec8976b24db23 +ENTROPY 9087d307063407efb6f81dae0a45f63790cdc1db0678a9816a372db70cec83b8 +ENTROPY d4d9df9904aa8d9aa1899e0c30aeeed6c1fabccef65fd2f51ad9ce7a1336d691 +ENTROPY 9ea295f25f35c0be91059845f8cfdbcbf140086c01829684225abcfe0405296f +ENTROPY 3972219e12d5ddcc4a16af5f3fc14cd0148be43063bb24314b86e160aa52e8cf +ENTROPY bb4530a11d36d54e85f3313bcfd6e86fe60c146c36bc59a0b2254435a2357b46 +ENTROPY 5194cb6c227197d365b71b11abcfb9e99a3be0a6cd6bcbf2dbf870e820caf4cc +ENTROPY ef3ff9176f5a984868efe7f5125415b44216ff2cd33887e1b2092bcd400734ce +ENTROPY 8faaf982d5cc5a50febbb68815890b0e6e590543cdbb0ea09ae6626e53aa4111 +ENTROPY b2005572329d02c16705e921fe21431bdbbb4bbcaad69ee35f705ebec3bc67fe +ENTROPY b28e05e97216baac743ebb3f5ecd23e6f0684892cfb2bffb2da8f5c2e06115bb +ENTROPY 1622987c5103a932aaaaa40810c4a5c16862674e2a65703fa3999a2f56a82341 +ENTROPY c50f561ead4f139efbe14600478ce534feb72aafe9d948e709cd4f09e444e45d +ENTROPY 25ee2a4272ecba1b4920b097ab779d06b7c5d4e123f9024dc8dddc26f8933a54 +ENTROPY 9d0c3392c940508e3e3682017a559bf43bc9ff5d7c3390e70013b75a7e302233 +ENTROPY e0513823ce57c6e78178c907269245504ec1b91d5299e557b9b01b61a73e2037 +ENTROPY c8ee3d12e6b7a999ab3c50a8cc64d3fd1acaba953db9f30e3aeaeeed01b30bb9 +ENTROPY d1fa8d508fa3957c7a74a2a34f4d1b48e53e48fc339903b9b7e12b13e7a3c8a7 +ENTROPY 20b4627afd4f8b4a1521be3cd33f960a8bed5892cb26afe6ceced27f05439f8e +ENTROPY 34d654e732bb016f3c28737263cedd7078423fe756cdaafe509bf8ca3f468a45 +ENTROPY 5f086475c0f266a1bcc0046e9be61ec4a5deb4313956e2e03ac0652102f9f51a +ENTROPY a12a65dc82cfee692eb22408e8662ac2c4dd71a54a043b38fd6e8192b935c264 +ENTROPY bcc5bb17a84a3d20994ce7f18f4410bf0a5e182dbabd0765f018d63a157e41e9 +ENTROPY 2a389c091243a1d30a0ff32ca494716644b63fca86b57ba20da92021792ef171 +ENTROPY 5ea77416fef8cd74231cf746413292f7f4a9fd99bcd0f6c652b65330ad2bec27 +ENTROPY 7a8dc8c04c6e96d37036f226173f58cbf301182afb53dddaaf40357deab9bd53 +ENTROPY b389eeba97f81b0b96915d4caec18d117272723c7ddf3a64ead6c790dde331ba +ENTROPY 4dadf300d8424d65bb6c219513c8b423fc71870cf0ba9c31e0c61c553ebb6d76 +ENTROPY 9a142feecf622670d589c084ad462d6d5385f8ddd8b371a014dacd0642c053bb +ENTROPY 22c5fe6890f803d253123b22e0d39a66fbe5e7ec3a67149f3a7087d420c8c3bb +ENTROPY 531e897840f0d2b2f99e3a6507fb3ea6ef79a733f185d41ff2525e7a9d9a01c4 +ENTROPY 7da6dcc237f40c049340ff2a5dcc2d89ecacecefc917657136cfce7af5eb1451 +ENTROPY 05c6bc194a255bfba89b75e6a7f1d51c3fae7c6af1bc11b6b7b72896effd4c97 +ENTROPY 633a2a555d27fec79d9daa685b65269e0ba64bb7f8a5141c26ed62ed0a8c340b +ENTROPY dc89b15ebdeaaef75e0202d00c0a00948c523c4999e65079b690b05e5b196e11 +ENTROPY beba3aa1d05f6ac9cd36649fe1734416a6e3b408518df0bd14fe5efdf802fcbb +ENTROPY a6e815481306088a4e91ee27f22f9b4f6f796cd97c8dd7cc17bf3b570737fc2c +ENTROPY 2128fa5428be466bcd796b518bf760cce83fc454682997ea702bb208725a41f8 +ENTROPY 27f4e9ce5854c11bcacc46e16592572506deb6da22f02f8efa517f28c27fae82 +ENTROPY 08f7d6f83392344c84da17e5e9b075bef6063b80d3a98617d35fe24a74b31496 +ENTROPY 2c75e21ed369e89d18853a09414291b6520b4ea45fe690ca552bcc7b4f4ad2c7 +ENTROPY bf3c2a86cc7f9c1b2bb8e0790551652484992d108a91d5bf643e8371b3bf9068 +ENTROPY cd930e9f49e0e5286511725739b5bdbf16afa3bcf5e2863a31bec548e56b782e +ENTROPY 3e7da051a0d9dade1b76714505a353f484bb3f481ffd65dc02c4c39003ce6028 +ENTROPY c8a78fac19bd0c654b7a3baf7ae6a5e80a9eb5e12155b074977524fba7a82e8a +ENTROPY d0dcb258a111a9391b5bda1e65bf9fb158f6a205ce1e47658af81123f5a78090 +ENTROPY c14b648cba1de446d08decaf5040a637153e7e8c44d75b8e33f6a1bf2e5c216a +ENTROPY df2fbe2c3b3c76b6c0e26b01cc398bed34272093a79422d4a7ce9ce435e35c84 +ENTROPY 0d85a272bf71982e7d7f812ac55736ab543dcb63ad699d7c48e3d6985f1aa508 +ENTROPY a66b4790292a292e1b3113f380ca51363c3dc04341675a60e5741205b52dff02 +ENTROPY f34038e077526c882679258e03449c8b0ac19a2bd56ae59a1331c6047e2edd95 +ENTROPY fe25f2c58d23378c353a15c001644d89059f9af6f0257ed83df92d85eb8b1f1b +ENTROPY 3abac3423eddccd4a8d91f9ab659856425d4459b736958add6ce56133f36c2bd +ENTROPY ab8785b6e3c32df9d5c764a77be24e55fa8194d7c930da4e3416f56fc003e7c6 +ENTROPY 856311f05fad064083745cf5351cd47464f3cf625f33447d1a702eeb15d3b022 +ENTROPY 11a852571d8aed15e76b5c033c55d3d0e3cac0f73973b5b324413b6ba6c54504 +ENTROPY da315f02ed43f6bc51f1e970fa1f4194591330cf84acb3aa6e46d12caf0e3371 +ENTROPY 1939723831942fe52bdf0b497694c214f20c81910f3cacd41cbf8b293527bc9b +ENTROPY 1b814b6529d4479e5b9f09c2aaef778a3b8630b61801195042cc1b2caf96d139 +ENTROPY b88444d91d9b67bc7dc7c33852606afcb04d6f9fd08c70e64f2ea724533e421d +ENTROPY 4e3a40bf860e3bd814a50d11de73bb13b9f428fe710ba4528829094b3a5332fe +ENTROPY a16fa302a52a47ce0b04687c61642880c97a5cc8080b6123624eb3554fb95280 +ENTROPY 7d15b3b3c64cf076735a2df9cc5a287696b98d4a8dac711e3bcc2d2ed77f9bf3 +ENTROPY 46a9cbc23235d6fa60d46eb8bac0bb9e0297281c4f6630593feb887b21cc26dc +ENTROPY 93b897f7168f6bc5b9ba87256a13d77923f8c3e3cf41a88b828d3ac1b68cd0c5 +ENTROPY 53499893ec518a4d04319dec289b6e04596e134db67ca2429e50984d896c1bfc +ENTROPY ff8a3a509e8d7e9f684774237cbf8914bed9348787b9975aa20d5ad66fc4e62f +ENTROPY 34e660ee3493df580e6a6e74dec3ea7680e557dedec8791200b6b3e6f77479e9 +ENTROPY e2d1efbc2719d17a8958f11a52546678d97810d35120884b87a86fe9c88e31f3 +ENTROPY 0ce79d87230a026033a03c0d324735fc6540aef091691125a89c4c021a00b540 +ENTROPY 4694a6b8e77d39cf66a9dc9a3e3e046e3cc566319a777c8453ed61d6bc333440 +ENTROPY 7965a0651b15515b4131ccc8bb1c727bbd44f18d2049df959ec09653f309da55 +ENTROPY b5cbfe08bc099f2cbef2a8fe3d720605b62aea14c7425a82c0d8232a90670698 +ENTROPY 17a7b966258d727697d936b96561b208e8e373391012f40d7d5e0520785e721c +ENTROPY 033f45f9fe0801b50d064ada920d90d97efe93eec95a3e169d3707c93a56f78b +ENTROPY f643941ff49c92f8806cdc4e1ed33e814d62f03ac43780c9bfc4490a047b9ed0 +ENTROPY d3d13588a78b8ad157d1a0d499de1b240da929f7f1d7425d8378848dab56da12 +ENTROPY c0b31382d9df2ec5898da5a7a6436b3afa49f1d54664df9cd180739e6fed20b3 +ENTROPY b263ee78230842832f67a17a81f38449772e3d9dc9b8f25fe101947deeeb1d09 +ENTROPY 28d4cc1ed1519fe593c908122e2e0afdfdda8af0c31905dcdc03baa7905e5394 +ENTROPY e4ac42b8362bda9114309b3d5a9eef504fc8f0591c3c8414943a6af02f2ddb48 +ENTROPY 92522570dfd869ee908bf0a645e0bce508cce7d664a580f3cd69cc017af3894f +ENTROPY f88bf4e7f4e2d07f4a2fccf242f5836a060b77993dc24ec2fd16b08158e81ca8 +ENTROPY f015f7e8aa8388aedb985405e854d44e2842b12201253a70b9f642a3c7aa2b99 +ENTROPY 40ca4835035aafa95efb0a6ac39c028a8a40aceb8e4094f857048d7e19e31653 +ENTROPY fb47c63844ff92e3d4dd916adce06fa0ddbbe2f98051b8e063e5fe5e26169646 +ENTROPY 8bb93db6b4b33ce625d5f918df12456d1fc599e3ca30253e2fc9746a61c65f4b +ENTROPY 4ac01a59c68a82726196e01610503561067d45973e0d1fe51a519962dacee22b +ENTROPY eb84ddfe11c23c56853234667ddc85375dd29a2881e5b6332c001cc41c7a8e3d +ENTROPY 636860d90d9fbc469c17480e2f6a8a53373d20b64df2f44663b4f2550152a517 +ENTROPY 973cac57aad46a57f18415c71bf9ba6cbe48964405c21a125abf4fdae7ee1c7c +ENTROPY cd6da810b43ae8105b0f6c5770aa1c4fc097a4aabaf59beff73e534e07262df0 +ENTROPY 037f561968a51fe2d419b51c69561b9ecf01a6f6d7bbfbca2a79f56daa3e1247 +ENTROPY 3f513310e837bf3a6a0c2a918c7b69a71041051399c3cf41c5da5a71d729ff68 +ENTROPY 2915c86f177a8855e67e1cdb937aeeb36615bbc8141285ec4426827e4f6ed3a6 +ENTROPY 450e9c07ad3d59d0076f38dba8d784e655db616be364231f0d54236136fd8261 +ENTROPY be877c6b1fdf4eb2da024e5f0e8fe32f4a2f97510d7500aa26a5f8a2c67a5435 +ENTROPY 0b49596f493429282c1754f265c6302ab5fb0388e922f1fca3d67ca4f3c70855 +ENTROPY c0f6abf38d2390c3771e7c953e7dd76b7c53616b7ae70554e5a3b1f6cdbac0d6 +ENTROPY 3575292dd2a36ffd90d258f98dcc11f21e5573fbb5280207e2a6e0d0a0ede0d2 +ENTROPY 39bfa66331b5843a7e39ed0a60826cca00225381bb7753e9a0a26b9beca191a1 +ENTROPY 3fa52b23feba4eb0a9eadbbf1514f72479d678c771b9d6d58fa7d9100ef6e208 +ENTROPY 218dcf31384ec80147c41604ff7453077da4e7135e8e8ed234e79f54f199f230 +ENTROPY db3c803a53df7299a2693a144b21a3297a356297f9f9902810e9da82a40069a3 +ENTROPY 1cc65be1faea8eb0bc65a30a1a20500fed2ea26f00e475a3b3b4a2efd2001655 +ENTROPY 37bbc9ee0cd5c103f2329acb4bda32a7d1e0fa8cf883ab2ab0852c2f89cb14c9 +ENTROPY cbbe1251cef6797311971684ec6f1ec874d3d751002fec3a8a40d70807715b14 +ENTROPY 1efd2af5b5a518a6f765e7b1ea79139884bdcac04671caf21e159aae0524634c +ENTROPY 2b7a7ad679417d302fe1910103e3933cc618d0d88154a087054cf0e8ef7c6071 +ENTROPY bc4e31210cd628c29ae5966b25f5bd0e4528380a4024dec2f67cde23352c0c40 +ENTROPY fc6642a0ac70586784170d25e16439610a03fc51f15cb9e31b9591c0b617ac91 +ENTROPY 63bea094520d42b148e4f5c2754ff21694bb5e180a900809e2087d6affa3d1aa +ENTROPY 395bfa23c2aefcba82b5903d57e554ebc50180427e367b4f4f7cd099a49cb593 +ENTROPY 2ce8e7e19e307e162deea636fa7a0c4a9db4eb4cfa6fe775c111e30d3d20a9e9 +ENTROPY c8627ba821413814ef90a71e02080839204f05c5ebdd225d1f0cc9b888aeff34 +ENTROPY 5d168e10770009e7569178ae3fee00f0a03fc846ed89299b0565a20020afa8ff +ENTROPY af5c9c23cff5942438698746a40f61daa584bd5caacc0e957cc1b82e706977e7 +ENTROPY 408a2c88c1014e6438c38cdabfab5321752a29ba04d80f8c1998652511d290c2 +ENTROPY 1c49262be97a94ed71078010b9f3eb6a57e2cb19b953ba1d59cf40f4fb903801 +ENTROPY f70de9d0c8592aa324894955d09a59600734e03c92e7b9ab7fe1d9562bb1c66e +ENTROPY 32e8d96ac1bb6d2cd3495581f1f968fae013652909c1fb83e91366bc31529f7f +ENTROPY 5ad16df7d0416f1a4fa57b234f337e9dcd79b1d634ceda2f38f5feaa583de67b +ENTROPY 6df9c71d17dc47d47607f9e0b170a968c4878e2e1fdfbfe5576c5e80b33ae181 +ENTROPY 13a8afa48d2c5472ce98fd545cad180037260f2d24f675b81e9d814119146f47 +ENTROPY ba12083fade35658a967f9f41221cd4c15ff51306f85c198dce744144dfb8d8f +ENTROPY b1adbe455bd4d9e674c5654236802ebf6d1c45f74851998b6578004cd4aaa067 +ENTROPY 4305c15d85fd077e74ad485d0140e494cdfde1650a42c608fe0e5c42f66b002f +ENTROPY e1a1b132bd2c1b8b869bf4e8425c199e7487e42ed9a17e32559c6e5e628a30e9 +ENTROPY 3e604b029568107e269d3e979b2397905ef49f5fbb984e9424ba5ba89994b6dc +ENTROPY ea60d011ccf67fa828757932484aecb125c4e5acb591bec1205171adcbf740a4 +ENTROPY d86e9f0bf81b84977f15c1476bcf0b02fa6af1542133fd2e00f6932eb8de11b9 +ENTROPY 41f20dde5e091d632d958da13aa372b5e6b0d17cc935af96ed5172365151842f +ENTROPY a86574ac3b601e2b9f12a5c8c4b41c70e9e5d11f062d5caae80665f0235b374f +ENTROPY d9b72f686c8d7e42455b8fa2a51616e91cb27634f292db0bb89cbbc0c44b7ba5 +ENTROPY 53db765fb2424e8017198d1b15e6ef75258acf59e796a5ad7c912b0db50cf0da +ENTROPY ec55af636dc1e7df0bff73dddb3551ba41d3a330c60eb17bbe483a0b40ad5361 +ENTROPY 4985020ff596887fccc16a33128f3cb4b0320b6ee7419fcf6850b639a7e3471a +ENTROPY c8455f7133a885184e0779c1f916bfe4c598b5dc0fd0dfe359e49b9b4dfeb4c2 +ENTROPY 07d53ff3025cdcc1244aa942baffa05cfd6459184c7fa05b73756062f1ba2194 +ENTROPY d3334709de786ba0aec1655b11c5db2b214210706450fd77ca27a15e7366607f +ENTROPY 9c76fd5a87bfbea199a5ca6a1b65c9332bc6418d69202fd5e0de1cae90f0f492 +ENTROPY 22b0c60882dd14b9f6274f1ed589f9450f170fab71a8228d14116ca8e6a90678 +ENTROPY d47aaf77747025476eed8ac19e40efc354434801f3c50ba80a8dcc8fa48d048b +ENTROPY a2eb90e6620561da29c41de9cdd3b164bbce5de94db8d35e7af5e806aeacbb71 +ENTROPY 1f5b0d8434b90d0500a2db7d33d02a47dafda00841154c011cce2c4fef49b016 +ENTROPY c7a09b94ee61f274bbbfb7720a3337b186d400630dad4e15e87df30180762332 +ENTROPY 99cdabe6b59275b521f5bd14ce1b541e17910ace7242e2d7f9f543c0697c05e2 +ENTROPY 286001cfa397b48dbaddb07ce07eb683700a5c9623e3a9505c90c91e771000a1 +ENTROPY bb4c4b1f49102635f3e3f051743a8f9577c33d17910e0ba19d0ea6ac7fae211d +ENTROPY 28be65714248cf53043108040a501e2f5aebf9c083f11539aace65518f76ce94 +ENTROPY 76537c18c43812c78da60ce3befae87df0754648931db35a8e63833245819cb2 +ENTROPY 115026e9e3ce5e13484f76d50eaecaa793853756e720f14fd6584d568f70e27d +ENTROPY 76288d88a8180938dd71b5426613bb0d1781450d1b5786993195d56a940502bf +ENTROPY 70d311e44508f58637b6eeac5f74fb80ef4174cde01e1180ccaff2039c29c8bb +ENTROPY 6d407ff10aff70053c6894838d148ae787e490cde976c06cbe99375c3b6f14a9 +ENTROPY 8b029f8ef666a82da12b03cdb87a5143b618011b33b9c5fe5bfa208860a58d1b +ENTROPY f43233af0b6064423524fdb31534dd5008d74bbc29bcb0d04c4b57d935c1dbab +ENTROPY 9aeda67793eb26196f3e3d9da481f9d92f2406fe35137c3a949fe00be576e004 +ENTROPY 368d87beb69c6f8be6c60bc36b25f9a919abc91ca5254ecc37f82e092c239836 +ENTROPY 44e3c2230ca932e2f23bb9ba9aa4b601042e228109f45da2be10939f8ab897ad +ENTROPY 437efcb497fe16fc2c6f2a2f26d8efc2d1b4ae9644bc4a3ecdad6e3b9fdf4545 +ENTROPY f2012cdb27e76f77288d596587e0e258ac4153c7926ca2ff36cdd5376b9b4e2a +ENTROPY 02dd7e7bd4808da69f6b1d581dedb02abd96ea92a7ce1a48799cbab005017c07 +ENTROPY 44f9297b58813f42b56fe08a2151f77232b5f3abe86e68cce8c636d3603c64d4 +ENTROPY b6a184df61e091b4c94e4771fee77a76d52202f6ad603d846f4520a29a529169 +ENTROPY d86343d025da588f6e92757f804b2cad82da8190f94693e865aafe7be318e8bf +ENTROPY a8eb075c2882db3d9e0b3f3dc9f95b40f8da1472a3ec582c0d501641c1a54d2b +ENTROPY 593e94ce69501a9add6112eda55c1298b6552413dd907a0eef7524d585ad0584 +ENTROPY ba5f8f79f9601ab0b184e104372b70bf9f8a6bc74c192bd4bc6df8cbce51be7f +ENTROPY efd9362de33e751c419a06c18ee13f24b528f0b6beb6a6571e16712667199dbb +ENTROPY 1ff1971785762777e5ee69b55313fde54f60d78af5d8076ee3b7721cf477f95f +ENTROPY e56cbb942949d4ee5a34d309129e40b2140533a9f66cdc0cf737bd13f8670a19 +ENTROPY 4fa9c43f535ca242027ba491b024b4a5776f25d0814534023e45a583964f7998 +ENTROPY c001ff71f4220cdde94b064bdefd4157e19fba52901239fb2851bc83cf39bbba +ENTROPY 5b7c2fad9aae2ec422fa697400456ce2f9798ba1766c8ef4c1303e394921ed1f +ENTROPY 3a15142c2f18a07e7b64f30b002604b3234c0dbe513978e5cc691974498ad41f +ENTROPY 9c311a2b72e10a7ba92746209f4bb425518e5ba91007fcb748ae082ab818add9 +ENTROPY ad4ed56c4f09d75add258a449ca2d3e8604be40b7dfaee4e7bb46b993ae282c9 +ENTROPY 2a7c7fb74022cffb869dae89451c3c323b37e0186eae0bcf01ba1b82aabbbca3 +ENTROPY 048d7ba4d6c50c3150dd23e4571e037265c666826f502ee5b3d590c31182b5b9 +ENTROPY d7ad2d5ac8f9b42a01935d789b143d9fd3e63a7341f1b9cab77a0d2de9680634 +ENTROPY 0d18bf6d4e8c27b16425aa4f86ca5b8acfc5db0a6e7044b2c2e66db4a2d1b85a +ENTROPY db0611fe41bb85980c6cc17cc5f04e1c243eb283a14afb7bc5ad772e563269d1 +ENTROPY 639025aa92a12937ae84c3b8db367029be6b4c15b886b05ce654c8090c36ff59 +ENTROPY 6fd938cd5cd2cda5885636c7db5760d0209b398aaf24e7351215e82868f15c4b +ENTROPY 9e65387c7170e98a8be709c422cb6f4d4848d81330217a6988d485ec539655bd +ENTROPY 9efd5822a629c415f5c25d23d29e9ca476ca01b98af139e13fb3fd793eebd08f +ENTROPY 043aceeb1c8dc05b0ea0e1e714c141941682936fc45c11cbee7f5bd6d19de1a6 +ENTROPY 08ee4fa726281c7300d70d71b99d21d868b139eef88be1f9fcb9cb1f20323fa4 +ENTROPY 42f7d1be928b1777f34af6bb41da4e2b3ce00409dfcd8c57cc72e4f06886e100 +ENTROPY 6023bc6284b9e104d57ccd0a9b8eef86d982316259e954b62ab67aacceedbaa7 +ENTROPY 8f100d6f5da1e8f5ba71f276a70c51345db4f73d4c1b012a07e79e964065a958 +ENTROPY 8a2ab7ce47ab8b6b48245a2e2819168230f17a58f221c9988f992301e3e010b2 +ENTROPY 6c29c90865ed8201ce2736475e4d7cb817c501fa96fb7895930477cd323c5a4d +ENTROPY 3f192ac40ea3d92c650a7fd6e4c9873929355302209d026a637189e6fe78338a +ENTROPY ed3e61de33d2d7ddf45457651ef0f7fdb27b1c0bb5371aec6f5b348f4abb12ff +ENTROPY f4d13a2f75081debc3804dba05b32b099e774c456fc4fbe5d6bb86a0351ba11a +ENTROPY 8e214caa44ca0709fd1740112b95d298e88db7cbef91f537df1ac48b5e353347 +ENTROPY 9acbefd81bdafeb1d5394525107b59f71c790cc75ba127e983e375953bedbf04 +ENTROPY b5557936fffe078dd03e24cbbe892b2882363625cf176eb75827c61b254ad6f6 +ENTROPY 7ab8547f89767f3ce2a1336982aac050c95e6c31696bbad7d39733bbe4bd1f07 +ENTROPY 80f8744e2112e9bd6bbd390486fbc78a061840db2ed2a06ee5c54778a690de8a +ENTROPY d5880a63f5f1105f7e3770807b9aa79b25e4e218c1d9dae2655ef473d976b310 +ENTROPY 4423d98bf190b647eebc48dd69d444a1039b548a28a6c833a243fa6e8614f355 +ENTROPY 064c0f23a87576b36db0028879a77f3514c4e9c3197741a8cdb08b27b620385b +ENTROPY fc6305d25882cb5f82886ddfd369a8d3c7fcf045f0b35aaf18a2eb5ab671733b +ENTROPY b1598b31f00d62a5c819e527c98e57a635e3772267f808439b43b42afd5fed12 +ENTROPY f2f14f4a84c6d88d39c3400e9ac742c58fb1d7c3f6820fcf06774b257127b860 +ENTROPY 05ff0498254f278a774a0a18e9ba5c9c7c60ac09a304657663b399aa9135e6e8 +ENTROPY 2a7bdd96d51114cee70ed63e6c31266f19be5cb54996c1e498fd598b37ffb6c3 +ENTROPY 9ca8486999aa6aa734542bf04b0871afbf91e3fa0081972871752c92a3b4acb1 +ENTROPY 38549e970f66ad70c2333702156fc66caa6862acbe2c26cfcf7355326397f5ec +ENTROPY f9e126b24f85d47d6a1ebd4f1f854f0061e5a9962679cc79ec36270d51a80d7d +ENTROPY a2d70c5afd02cc745bf238a1d585548067072f9c0b7bf033ed587ac8fb43f6ce +ENTROPY e88ca96089bb670df088756147b6ebe9fa82aecaf582746038fa954ed3edf495 +ENTROPY ce4fea12b217c61350dafd73603b086d26fc74a4db88b7e0a09bc8ea4eadeead +ENTROPY a6feb0d6aeee367b44caa95047df8df11237822803e66cfd072a1c7de83d684c +ENTROPY f1dba241736aebad04e9d672cd98fe9aefd7f6b699533a29b52c25b0b3a15aa8 +ENTROPY 939908caac6304f72240164106c7e3ede9ac7f4f405fcfbb3ef78a17ec762924 +ENTROPY a3a1ae14110c4ec023e8e0877e69cefde0d1bbc1ad17a44e840c21f4adeff425 +ENTROPY d786844d1e8ea02b70d5a2777e204db73d988411eba5c8187686c6765d11492f +ENTROPY f05006be9a1cac4d4d10ee51508b013329cd4bc5f9c2d8f590c2e3e25c25ac4f +ENTROPY 23f8ab4ca5dad19555bc162737fe20bad480ad3e51f6b611e17206ef02e80da5 +ENTROPY 33ca3de9f3a0e8e4824330b4c82c2dad56a54367034412a09f547e24af65ae36 +ENTROPY ed6e8e546618a49c03c5b89f5ed645c64e8c8c0312f9c2dfadbabf68d35f3e57 +ENTROPY 25eb11c4bea0011320eb6eba21d529b6aea181a20939044ae5802116ed30a54d +ENTROPY 747693ab8baa1e2abdec57d094bf898e7e7e1c443aba39f0ed189410154b989b +ENTROPY 0a065c9951a0e234d1279e3e6a493803d33725c9a8b05e0c577c95ccf93e826a +ENTROPY d1bc2bc33739bd19597ec5cd0f01964f63c84b7376cbd813a1157451e6313828 +ENTROPY f9b6861f7533618a0847fc0e72a978d32107438f0423ebfcc2b078dcc0af7071 +ENTROPY 4d46b471c83ccdaf500060f1656c1dcb281c2495379c59c49e0d21ea19bf3e54 +ENTROPY f9b99c74cb67531a9fb50bba31ff94e3bd9d5461079b4c18532284c69258e62f +ENTROPY 0e06ea26c02d6aa037e55dd00a0fcf4b92937daba83d187234b82047280906cc +ENTROPY b11ade69fb3efdcbbe9aa508e579bdb9421afae06c71b54e46630cf5c74e30b3 +ENTROPY 8a6e9789e7c40dae472293e6fe03e14b33eaa2cfc97cedaf3d004c35995df010 +ENTROPY e1939d8e95003079145144694838cb5ce88106ab1eeaa2f1bde5fec85a2e96a0 +ENTROPY 23509b425c83eae33856dba9a428604cac7e91516c9dfa5bf20414242fef3be2 +ENTROPY 24ad93662c1ffc7fd5ad2819aa0d7ded26666df56471f0a2141ffdad2dabbd0f +ENTROPY 2f6997575d98064221774e4a6728c88be6a4b4d8b273fd4d98aa219441cc9a13 +ENTROPY c6f2dd7518ff8a530d5f8dc44d483c515366a338874e812757cfa10a05ce5f67 +ENTROPY 799ca1b70461304814b9a85acaf2871e9d015ac85fc912eae5089f2ba69a115b +ENTROPY eabb0ccbc71538e73244e9b173eb22f155ed4b906f77d89af7d6682df486fb15 +ENTROPY d5cec358d645a7542da97e2fe5f960225cffdd4fbdb09cab4f3ce86d1796d276 +ENTROPY 93c79ad14bbd28be72f92258ceca05538332d2adccb4f72e032c3fa3bbbf6e4f +ENTROPY 2bc744952b5f85d1230f7edc0a36408cb8be11ddd9118854f417f60b6f5f6410 +ENTROPY 9dfb3b451b3b20779482f7deb5593840f396564297b8877b0ed9ff48509a657a +ENTROPY c5f174683762f3cad05faa46d4fb920e85ed1c004f0240190a1b7ef064ee90f2 +ENTROPY 8528a6124fd07d5f5dd413b4c4e742c3f535fa8fd5a76c59f41d6c2591737efb +ENTROPY d61a20f2e31ff3ef31c01f87999bf795913b53d4884ae2e69b0dff3baaf6594c +ENTROPY 5950f3a7d3116971319c485d030974f0a74d7aa74c78d8bffb23748fce5823cb +ENTROPY 3e86bed1f66f7d9a8df51bc9d0bb2af9ba730d1eed58720757d013ccbece7fa7 +ENTROPY e87b7f15b2ecd3e0b9c93d9a79f6ed28a59a988251fd70b95d017e43a63da1e4 +ENTROPY b359ab400a24e03c61b30777f215c863d84f02670f510fea0447eb5ab7366c86 +ENTROPY 9a0caeb0f30e845465f0b7fda1ea18edd92c880db00a5c81335f1e3c2e5e3dc3 +ENTROPY ca35b981506444ca01fbf50f269f3b0ce5e060cfdb4e30f70f3bb7b62cc378a4 +ENTROPY 50c20bbd7da1c6fae8b2c5911d86fd82c718eb96f04f1d2b2f308c889f860f10 +ENTROPY 5d436d3f510e397048f043ed548456d395e58e10cf146ba588a8dd78ed41f1bc +ENTROPY ac52164ba32ac12fc59012a4e2ffc4001859a724a9706cb67ef8a9133d7fb787 +ENTROPY a5d7ab56933df44430f59063a4fbc55235da3ff04002042d06491c0ee7b55e30 +ENTROPY 14a6acaa25f32ab41826a94d8277e18b9f5d65eb672fd958c8f8d99560a898f7 +ENTROPY 00120f092d4a5479069373db751a491c6e4508e41d3e11c5fb770ee50886a32c +ENTROPY bf311aa38926d92dbefca19c86f89f17381da4db617d321bb4d00175d4b802e7 +ENTROPY dd05177779d13fcc02c07c4a098deeb1ff0572c91bff71ba79a8df88fa4c36ed +ENTROPY 22e1ebd5feb0ea6f2eb809942167b76f95b3b287ede2f40a11ec0da5616899a9 +ENTROPY 6157b2b8c2040a0c08868fa1f59b6552990f1bb3b09e685f0dd7491cdc1c356b +ENTROPY c2da1702200c83120be2f0b4f6aaf13e034c5284cd620ee77650a308e37a8ffd +ENTROPY cb72ef2988d03044b1506823c308a7a63a402b1fff6ec95cbb0d8766b233a5da +ENTROPY 1c9139421710b784ee3ff2cf4514aee7719762f64c4b56a16584549d093f9684 +ENTROPY d05440ec3e88144848d740b04c1c4cc756bd77dc8f3fa5578e561926df98497d +ENTROPY c9d0c628d4795bab3a101848c7bbcf1eb8cd8a186a5ad821e8dda0d45d3dbb94 +ENTROPY 726a906d3a2869f7380cb84cbe5a1e85332b1a5e6d31c4fc327b99402c629018 +ENTROPY 74c639154433e9c7c937f536bb7fe558d7b1a7f4db58e42ac5d9835fbb77b8b9 +ENTROPY 06d325a0f412fb58916ce217f14fbb888ade0c9813c263bd5865eebccefb84d0 +ENTROPY 89275bc61d88d3921b1e5b3d0c9429bc2e0c1c4b927733120ebb87246d3eeea8 +ENTROPY 7a8608372c25c882c8783ce51d379a8ebd5af98e54a930abe4d9bfe877a58165 +ENTROPY 37c59206ca4c4a40bdba712b8c5630cbfbe0293be57b9b6e0467e38455685075 +ENTROPY 1cc549bbc2b95eb569102974b04377ad59f1f6bdc68caf2d7c16a7740481c77f +ENTROPY 70f2cc8a3bc8026f98b54ba2188005bcc00612eef94ff9debfbf3ce9135c5dd9 +ENTROPY f0333cdd76ab990308ef78ba0e5bfe75a35fefb15c720d9887ef7f9773e7e076 +ENTROPY c109d6b383c23e71a78cf4046f0f6740683598e2a817987b14ed5f70633ac4e8 +ENTROPY d45c53b43239ce2e2924695753eb360dbed15c47b600a3ff6f0b30f93922afce +ENTROPY c81c80e68b106cbdbc9bf3215b2c43bb7c6e3a8ac918ef6a3b958831eb59464f +ENTROPY 3cff10f24954f065629dd3e62a1a509ad33c063a9067dc92867a92351a6cd57c +ENTROPY 4bc8ca0b4359ace0546c1a89cee1d5d86bc099db7ba6d2f82b63dae169e6b7e7 +ENTROPY ae4b79319ba09bd6c14e7d3019d5f395f982b8a16cbf9d212db33cf5aad0ab0a +ENTROPY 4c7bee038fe9b8f1fe25cf27a67cfd55e890c62a7707201d7d56a095269016df +ENTROPY e9142cf470bab983d970b67b76b3a4fd6ae640cee3792f7070e6adc8dc841812 +ENTROPY 3292ffae9f18be7a0856e7a91aee574a277c41236d2485b8c54a1ad106dd1ce8 +ENTROPY 18b390b3c7458031a73e9f5394dcee0d889391b5d88389c4208a79c08f23bca3 +ENTROPY b887e1ed1469c5f91c17fd4eaff7c74ae27d11a9ae7fc4f94a8c74c49804cb45 +ENTROPY e5aed1adefee09c8a85130880145abc44195bd243669aadf66c29f7cb9c772cd +ENTROPY 94077d2d1772ca0c084b02238f6db7ad88db59ef2ca93691bc854f45be04ea90 +ENTROPY d744efcc4e015edf6f4cf11217186055f224e404b6451756a409ef60fa6ba74c +ENTROPY 0b8a386d083bdfb3aad554c1e109c7f26416c5f71aa4c6eca91c896bd1fddb2c +ENTROPY 2803d0c4f3a46ce55f827bb89258b986a0f5491796749a3c779b4b8f4283ccbf +ENTROPY 83163ce276d6f719b0e09a7b9c2d61a98b02c88f93248a9040905edcf0dfc9ba +ENTROPY db29c40799b872d814c2fe393f0d505db5893fcc76c903fc951186d0981747c6 +ENTROPY 9d71e22331bd042fc0ddc3bd4989077150246c9823262c8b3f654e693d081386 +ENTROPY 9686ee20b388711c89578e9af400a8c023402e1923ae0377e63ffacfbbbc696b +ENTROPY a11c9c7ddeefa307b27a2ab97649def977a6c5475dfd9a0747918280f16b3661 +ENTROPY 7b3867eeaf46424b3678d343b23ac92d79d61bd8d42c476062fd32c562cf0904 +ENTROPY 525c916f5c07d4e97e50f0c1bf77d4468f1393c71655da3d1d3519bb3a35ca4b +ENTROPY 6058252b0f20ad3ccea40ac54160449593032bef51e95580778e403bd5a4cd77 +ENTROPY 237c3f3aac673e3088ce748134e2e4941eb811ab91b3651785d068d2a9b46331 +ENTROPY 3830c7117fc4542f8454bb00cfb45854d20fb0fd9d4228f97d70d22c4eb43fa8 +ENTROPY d61c0c7e1226b46b59c02dd92579c418d08e7b3589bf4fe39ee552fe4b1116ba +ENTROPY 3dc521c29e5eb8cb7298ea45e92f5e6d2e3c1cac6e094d9eb6d86699c077bc0a +ENTROPY 0610b0bdf820612d09258a600bf1f60cd11a4ff592caf0d4c765791b7017f9b7 +ENTROPY 3332c58ada252f2dbc96f1071664e7f6b50eb75522f6d7ccbea0c539d53f6eac +ENTROPY 0290cbcf0b17182c4a237a19943c013f5ee9580fad21d3efc78f31b568d25537 +ENTROPY 35f5ba908c73f6bc2de131ac824ceaa14830aac588208b5d80d912b639131cbe +ENTROPY ce90a9a3cef802ea5dc25baed02345d93dbeafe8831e0b050c25726dac9b1853 +ENTROPY 826bfc2d53c872301f025f40f0ce20708c6b84ec673e339794650e4e1b9882bd +ENTROPY 73d8231be5dda7be9676c63a17898607bbaf256889acbfde73dec09818bf947b +ENTROPY df086c979249bc77266af51fa80c2e9c73b208591eb59d2abebdeaefb3e2c6bc +ENTROPY ea6b50cc244b6d4d0f8edefdd6bb90ece57d88ecfb09a67acd059665ef9dba2e +ENTROPY dcabe75740b412a94ef9e249db7d0f78633a9c4b1bc0eeb0c1a2b4f53a729890 +ENTROPY d3f43cd8caea13040c8cbba1ce69f0c59f75a324ed7bc3c734070c0ade9b3fd7 +ENTROPY 7884b5e586335d980253d5604e9833d732e47cb2b7a0c4a772b05119eccef7f0 +ENTROPY 7a85ebd95f6cb24dfb195a3a8948ff104fc40737db221ed4661cc99400166fff +ENTROPY 7fcffe27c5b44454385f5d3dd55d7c052e6b6733d61b862079c7749a5c1004e4 +ENTROPY ed6b92e828ccb844f76698935abb6d70860c4a72cbf00f0c8908b1dbc098f46b + entropy: 1048576 bytes in 107213 ms, 24 health failures + entropy: chi-square x100 24849 (255 degrees), ones 4195302 of 8388608 bits, transitions 4195557, longest byte repetition 3 +ENTROPY sample 65536 bytes sha256 f8b7f425a276a60b0603d2868091f87e5b0b3a28918cef06aa1ac928cb312eb7 + entropy: the mebibyte's sha256 f07830f16f9fa244e16a943e75ec91e0d59684e876f15c658968e034f4968d41 + -> ok + req SEC-012 DRV-001 +CASE entropy_board_a_mebibyte_passes_the_sanity_checks outcome=passed asserts=1042 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 118765 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.json new file mode 100644 index 00000000..120e729e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.json @@ -0,0 +1,115 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 1, + "name": "event_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "event_binding_fires_after_direct_waiters", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_wait_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "event_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "event_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "event_wait_times_out_cancels_and_ignores_clear", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "event_set_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_set_wakes_every_satisfied_waiter_in_one_pass", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "event_overlapping_clear_serves_waiters_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "event_any_all_and_clear", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:39Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_event" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_event.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_event.uf2": "ce01d07c2bbf268f556c8c1f78a1eb241b8652c7ecd741d547f30641d5359a4d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_event.elf", + "image_sha256": "b8822df216607e7c6a8dfdef5fbd55a654ab83f4551b3d1177ce6b146c1a759e", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:37Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.log new file mode 100644 index 00000000..e30c9da9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_event.log @@ -0,0 +1,52 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_event.elf sha256 b8822df216607e7c6a8dfdef5fbd55a654ab83f4551b3d1177ce6b146c1a759e +EVIDENCE v1 suite=test_event config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST event_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE event_define_constructs_in_init_table outcome=passed asserts=1 skips=0 +TEST event_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE event_storage_reuse_requires_destroy outcome=passed asserts=5 skips=0 +TEST event_binding_fires_after_direct_waiters + -> ok + req KRN-SYNC-035 KRN-NOTIF-004 KRN-NOTIF-005 KRN-NOTIF-013 +CASE event_binding_fires_after_direct_waiters outcome=passed asserts=15 skips=0 +TEST event_wait_validates_arguments + fault checks that reset the board: 3 + -> ok + req KRN-SYNC-029 API-015 +CASE event_wait_validates_arguments outcome=passed asserts=5 skips=0 +TEST event_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE event_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST event_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE event_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST event_wait_times_out_cancels_and_ignores_clear + -> ok + req KRN-SYNC-029 KRN-WAIT-004 KRN-WAIT-017 +CASE event_wait_times_out_cancels_and_ignores_clear outcome=passed asserts=12 skips=0 +TEST event_set_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-029 KRN-SYNC-027 +CASE event_set_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST event_set_wakes_every_satisfied_waiter_in_one_pass + -> ok + req KRN-SYNC-029 KRN-WAIT-013 +CASE event_set_wakes_every_satisfied_waiter_in_one_pass outcome=passed asserts=11 skips=0 +TEST event_overlapping_clear_serves_waiters_in_order + -> ok + req KRN-SYNC-029 KRN-WAIT-001 +CASE event_overlapping_clear_serves_waiters_in_order outcome=passed asserts=11 skips=0 +TEST event_any_all_and_clear + -> ok + req KRN-SYNC-029 +CASE event_any_all_and_clear outcome=passed asserts=15 skips=0 +ISR_STACK size=2048 used=216 +11 tests, 0 failed, 0 skipped, 115 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.json new file mode 100644 index 00000000..211afebb --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 2, + "name": "fault_status_policy_is_preserved", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "fault_successful_check_preserves_status", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:13Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_fault" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_fault.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_fault.uf2": "2f6b7aa2cf018b2510b072c97e125cd93ea7ac39364fa1af6f31ed2db2fb43ec" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fault.elf", + "image_sha256": "73bcdd6b28015408184019c6ebc30705567f1fa0c6a532c157130b9e0782feec", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:11Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.log new file mode 100644 index 00000000..31855516 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fault.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_fault.elf sha256 73bcdd6b28015408184019c6ebc30705567f1fa0c6a532c157130b9e0782feec +EVIDENCE v1 suite=test_fault config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST fault_status_policy_is_preserved + fault checks that reset the board: 2 + -> ok + req API-015 +CASE fault_status_policy_is_preserved outcome=passed asserts=2 skips=0 +TEST fault_successful_check_preserves_status + -> ok + req API-015 API-017 +CASE fault_successful_check_preserves_status outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 24 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.json new file mode 100644 index 00000000..a68176b6 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 80415, + "name": "first_execution_sequence_repeats_reliably", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:39Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_first_execution" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_first_execution.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_first_execution.uf2": "5aa128fdafd8332b88d7556539db5614fc0fbed89ab4388ee2846b990823a54a" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_first_execution.elf", + "image_sha256": "73efab940255ae22dd0e29b63d15e2d0c814dfd903c4a0d06f6dbc9bcbcd8c2a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:37Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.log new file mode 100644 index 00000000..fbbeba24 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_first_execution.log @@ -0,0 +1,10 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_first_execution.elf sha256 73efab940255ae22dd0e29b63d15e2d0c814dfd903c4a0d06f6dbc9bcbcd8c2a +EVIDENCE v1 suite=test_first_execution config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST first_execution_sequence_repeats_reliably + ticks seen 202, elapsed 203, timer start +1, late 0 + -> ok + req KRN-SCH-001 KRN-SCH-004 KRN-IRQ-010 KRN-TIM-010 KRN-NOTIF-003 +CASE first_execution_sequence_repeats_reliably outcome=passed asserts=80415 skips=0 +ISR_STACK size=2048 used=216 +1 tests, 0 failed, 0 skipped, 230 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.json new file mode 100644 index 00000000..f94251a4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.json @@ -0,0 +1,85 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "flash_polled_calls", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "flash_power_loss_tears_an_operation", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_area_stays_inside", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "flash_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "flash_program_read_erase", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "flash_geometry_and_sectors", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:14Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_flash" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_flash.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_flash.uf2": "535830192363160496a2370a715b383929d51dd9eae1a706236087976ccae744" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash.elf", + "image_sha256": "53cd46054dd9f6b23b768c96bfcf4fb448ebd87bf3e80320fa60c081e195023a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:12Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.log new file mode 100644 index 00000000..b8f40478 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash.log @@ -0,0 +1,30 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash.elf sha256 53cd46054dd9f6b23b768c96bfcf4fb448ebd87bf3e80320fa60c081e195023a +EVIDENCE v1 suite=test_flash config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST flash_polled_calls + -> ok + req DRV-007 +CASE flash_polled_calls outcome=passed asserts=6 skips=0 +TEST flash_power_loss_tears_an_operation + -> ok + req DRV-001 +CASE flash_power_loss_tears_an_operation outcome=passed asserts=15 skips=0 +TEST flash_area_stays_inside + -> ok + req DRV-001 +CASE flash_area_stays_inside outcome=passed asserts=10 skips=0 +TEST flash_refusals + fault checks that reset the board: 4 + -> ok + req DRV-001 DRV-003 +CASE flash_refusals outcome=passed asserts=14 skips=0 +TEST flash_program_read_erase + -> ok + req DRV-001 DRV-003 +CASE flash_program_read_erase outcome=passed asserts=10 skips=0 +TEST flash_geometry_and_sectors + -> ok + req DRV-001 +CASE flash_geometry_and_sectors outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=216 +6 tests, 0 failed, 0 skipped, 32 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.json new file mode 100644 index 00000000..f8ec08e2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 2312, + "name": "flash_board_program_and_read_back", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 260, + "name": "flash_board_erase_keeps_the_clock", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:19Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_flash_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_flash_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_flash_board.uf2": "a6496e398cee370bc3cb516b3222b65a5ed6d5256994ffbd9348b65e52804ebe" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_flash_board.elf", + "image_sha256": "8e7281f47efa2cab8a533ea95e0557b86a56b2a4d59b1cf4efc4023e1bfa864b", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:14Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.log new file mode 100644 index 00000000..58f751a2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_flash_board.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_flash_board.elf sha256 8e7281f47efa2cab8a533ea95e0557b86a56b2a4d59b1cf4efc4023e1bfa864b +EVIDENCE v1 suite=test_flash_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST flash_board_program_and_read_back + -> ok + req DRV-001 DRV-003 +CASE flash_board_program_and_read_back outcome=passed asserts=2312 skips=0 +TEST flash_board_erase_keeps_the_clock + erase of 64 KiB: 540 ms by the cycles, 541 ms by the clock -> ok + req DRV-001 DRV-003 +CASE flash_board_erase_keeps_the_clock outcome=passed asserts=260 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 3193 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.json new file mode 100644 index 00000000..7974564d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "fpu_state_survives_preemption", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "fpu_callee_saved_registers_survive_a_switch", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:50Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_fpu" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_fpu.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_fpu.uf2": "73ec908d80aab1a2895642a9c935994583df0ce2e96075f9c1ea4143fa7d901c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_fpu.elf", + "image_sha256": "0e93e73f799df4e9164f76132840523513d4e68607f215a321d6ce89dd33d26d", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:48Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.log new file mode 100644 index 00000000..7218bfe8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_fpu.log @@ -0,0 +1,11 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_fpu.elf sha256 0e93e73f799df4e9164f76132840523513d4e68607f215a321d6ce89dd33d26d +EVIDENCE v1 suite=test_fpu config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST fpu_state_survives_preemption + -> ok +CASE fpu_state_survives_preemption outcome=passed asserts=6 skips=0 +TEST fpu_callee_saved_registers_survive_a_switch + -> ok +CASE fpu_callee_saved_registers_survive_a_switch outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 36 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.json new file mode 100644 index 00000000..d7cacab0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "frame_write_misuse_is_refused", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 122, + "name": "frame_write_streams_the_encoders_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 383, + "name": "frame_random_stream_with_damage", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "frame_misuse_is_refused", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "frame_decoder_drops_an_overrun", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "frame_decoder_resynchronizes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "frame_round_trip_through_the_decoder", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 39, + "name": "frame_runs_at_the_cobs_boundary", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "frame_encoding_matches_the_host_tool", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:50Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_frame" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_frame.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_frame.uf2": "ba8550e70f74aa113ae1e9e961948f072611e865838c31bfc9b736b92d68221b" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_frame.elf", + "image_sha256": "521a2431361b8dd9bf6caf607ac29b99a71ffbe7d4084f35fdd8d79812154d8a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:48Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.log new file mode 100644 index 00000000..cc42b79b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_frame.log @@ -0,0 +1,41 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_frame.elf sha256 521a2431361b8dd9bf6caf607ac29b99a71ffbe7d4084f35fdd8d79812154d8a +EVIDENCE v1 suite=test_frame config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST frame_write_misuse_is_refused + -> ok + req OBS-019 +CASE frame_write_misuse_is_refused outcome=passed asserts=5 skips=0 +TEST frame_write_streams_the_encoders_bytes + -> ok + req OBS-019 +CASE frame_write_streams_the_encoders_bytes outcome=passed asserts=122 skips=0 +TEST frame_random_stream_with_damage + -> ok + req OBS-019 +CASE frame_random_stream_with_damage outcome=passed asserts=383 skips=0 +TEST frame_misuse_is_refused + -> ok + req OBS-019 +CASE frame_misuse_is_refused outcome=passed asserts=8 skips=0 +TEST frame_decoder_drops_an_overrun + -> ok + req OBS-019 +CASE frame_decoder_drops_an_overrun outcome=passed asserts=6 skips=0 +TEST frame_decoder_resynchronizes + -> ok + req OBS-019 +CASE frame_decoder_resynchronizes outcome=passed asserts=17 skips=0 +TEST frame_round_trip_through_the_decoder + -> ok + req OBS-019 +CASE frame_round_trip_through_the_decoder outcome=passed asserts=12 skips=0 +TEST frame_runs_at_the_cobs_boundary + -> ok + req OBS-019 +CASE frame_runs_at_the_cobs_boundary outcome=passed asserts=39 skips=0 +TEST frame_encoding_matches_the_host_tool + -> ok + req OBS-019 +CASE frame_encoding_matches_the_host_tool outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=216 +9 tests, 0 failed, 0 skipped, 125 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.json new file mode 100644 index 00000000..ba14759c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.json @@ -0,0 +1,79 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 11, + "name": "gpio_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "gpio_driver_refusals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "gpio_named_line_follows_its_sense", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "gpio_input_reads_its_pull", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "gpio_output_drives_and_reads_back", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:35:02Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_gpio" + }, + "exit": 0, + "fault_checks_by_reset": 10, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_gpio.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_gpio.uf2": "6e163e3418e53f5db73940d3f560919a1a150f4174f80974a96854695f593c12" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_gpio.elf", + "image_sha256": "c2e1c23185ea206ead32645e145c57c83ade73e52b16efa01f2790721dbbd6cc", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:35:00Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.log new file mode 100644 index 00000000..bb11327f --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_gpio.log @@ -0,0 +1,26 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_gpio.elf sha256 c2e1c23185ea206ead32645e145c57c83ade73e52b16efa01f2790721dbbd6cc +EVIDENCE v1 suite=test_gpio config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST gpio_misuse_faults + fault checks that reset the board: 10 + -> ok + req DRV-004 +CASE gpio_misuse_faults outcome=passed asserts=11 skips=0 +TEST gpio_driver_refusals + -> ok + req DRV-004 +CASE gpio_driver_refusals outcome=passed asserts=3 skips=0 +TEST gpio_named_line_follows_its_sense + -> ok + req DRV-004 +CASE gpio_named_line_follows_its_sense outcome=passed asserts=13 skips=0 +TEST gpio_input_reads_its_pull + -> ok + req DRV-004 +CASE gpio_input_reads_its_pull outcome=passed asserts=6 skips=0 +TEST gpio_output_drives_and_reads_back + -> ok + req DRV-004 +CASE gpio_output_drives_and_reads_back outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=216 +5 tests, 0 failed, 0 skipped, 52 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.json new file mode 100644 index 00000000..52dbf33d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "i2c_recover_waits_for_a_held_bus", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_recover_clocks_a_stuck_bus_free", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "i2c_held_bus_keeps_one_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "i2c_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "i2c_controller_and_target_at_once", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "i2c_target_answers_its_address", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "i2c_errors_and_timeout", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_segments_count_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "i2c_write_then_read_a_register", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:31Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_i2c" + }, + "exit": 0, + "fault_checks_by_reset": 12, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_i2c.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_i2c.uf2": "ba9dc3ac87bfb121576c4b94dca9336cf9664d03c96beab9c1265b8f8a32c68e" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c.elf", + "image_sha256": "2137c6719cd35e3ca58d070b535edd801ce19198e7c8f9175d1b559ce58a7177", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:29Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.log new file mode 100644 index 00000000..567832c0 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c.log @@ -0,0 +1,42 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c.elf sha256 2137c6719cd35e3ca58d070b535edd801ce19198e7c8f9175d1b559ce58a7177 +EVIDENCE v1 suite=test_i2c config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST i2c_recover_waits_for_a_held_bus + -> ok + req DRV-006 +CASE i2c_recover_waits_for_a_held_bus outcome=passed asserts=5 skips=0 +TEST i2c_recover_clocks_a_stuck_bus_free + -> ok + req DRV-006 +CASE i2c_recover_clocks_a_stuck_bus_free outcome=passed asserts=11 skips=0 +TEST i2c_held_bus_keeps_one_target + -> ok + req DRV-004 +CASE i2c_held_bus_keeps_one_target outcome=passed asserts=11 skips=0 +TEST i2c_misuse_faults + fault checks that reset the board: 12 + -> ok + req DRV-004 +CASE i2c_misuse_faults outcome=passed asserts=13 skips=0 +TEST i2c_controller_and_target_at_once + -> ok + req DRV-004 +CASE i2c_controller_and_target_at_once outcome=passed asserts=9 skips=0 +TEST i2c_target_answers_its_address + -> ok + req DRV-004 DRV-005 +CASE i2c_target_answers_its_address outcome=passed asserts=10 skips=0 +TEST i2c_errors_and_timeout + -> ok + req DRV-006 +CASE i2c_errors_and_timeout outcome=passed asserts=7 skips=0 +TEST i2c_segments_count_bytes + -> ok + req DRV-005 +CASE i2c_segments_count_bytes outcome=passed asserts=6 skips=0 +TEST i2c_write_then_read_a_register + -> ok + req DRV-004 DRV-005 +CASE i2c_write_then_read_a_register outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=216 +9 tests, 0 failed, 0 skipped, 68 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.json new file mode 100644 index 00000000..23cd4142 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 88, + "name": "i2c_loop_recovers_a_stuck_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "i2c_loop_listen_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "i2c_loop_fast_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_target_drops_beyond_its_buffer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "i2c_loop_nobody_answers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 32, + "name": "i2c_loop_register_reads_of_every_length", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "i2c_loop_write_to_the_target", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:33Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_i2c_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_i2c_loop.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_i2c_loop.uf2": "df6bea5851ee37f5b45d34397f4b8ac41803dbb92412dc1b2cd97d6d423b3e04" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_i2c_loop.elf", + "image_sha256": "a3048e7eeea96848307404ac10baad43ef4b71f4623b2ba8903f8f9aae2b7e57", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:31Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.log new file mode 100644 index 00000000..abc3e57e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_i2c_loop.log @@ -0,0 +1,33 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_i2c_loop.elf sha256 a3048e7eeea96848307404ac10baad43ef4b71f4623b2ba8903f8f9aae2b7e57 +EVIDENCE v1 suite=test_i2c_loop config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST i2c_loop_recovers_a_stuck_target + -> ok + req DRV-006 +CASE i2c_loop_recovers_a_stuck_target outcome=passed asserts=88 skips=0 +TEST i2c_loop_listen_times_out + -> ok + req DRV-006 +CASE i2c_loop_listen_times_out outcome=passed asserts=2 skips=0 +TEST i2c_loop_fast_mode + -> ok + req DRV-004 +CASE i2c_loop_fast_mode outcome=passed asserts=5 skips=0 +TEST i2c_loop_target_drops_beyond_its_buffer + -> ok + req DRV-006 +CASE i2c_loop_target_drops_beyond_its_buffer outcome=passed asserts=6 skips=0 +TEST i2c_loop_nobody_answers + -> ok + req DRV-006 +CASE i2c_loop_nobody_answers outcome=passed asserts=6 skips=0 +TEST i2c_loop_register_reads_of_every_length + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_register_reads_of_every_length outcome=passed asserts=32 skips=0 +TEST i2c_loop_write_to_the_target + -> ok + req DRV-004 DRV-005 +CASE i2c_loop_write_to_the_target outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=216 +7 tests, 0 failed, 0 skipped, 162 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.json new file mode 100644 index 00000000..c0c668f3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 1, + "name": "irq_unlock_without_lock_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_connect_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_blocking_call_from_isr_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "irq_disabled_source_stays_pending", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_scheduler_lock_defers_the_switch_not_the_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "irq_delivery_is_deferred_while_masked", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "irq_isr_wake_switches_at_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "irq_lock_is_nestable_and_lifo", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:17Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_irq" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_irq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_irq.uf2": "4cde7f8eda2f981d9eb106b6caa9bcc8fca8fdff31760a155a3779d60fc4b7dd" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq.elf", + "image_sha256": "d6e0ea220c10ad98e1db9254d7e4555bbf71755605d68973713d03db5ae09dcc", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:15Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.log new file mode 100644 index 00000000..f94d8658 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq.log @@ -0,0 +1,40 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq.elf sha256 d6e0ea220c10ad98e1db9254d7e4555bbf71755605d68973713d03db5ae09dcc +EVIDENCE v1 suite=test_irq config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST irq_unlock_without_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-IRQ-002 +CASE irq_unlock_without_lock_is_misuse outcome=passed asserts=1 skips=0 +TEST irq_connect_validates_arguments + fault checks that reset the board: 2 + -> ok + req KRN-IRQ-021 +CASE irq_connect_validates_arguments outcome=passed asserts=2 skips=0 +TEST irq_blocking_call_from_isr_is_misuse + fault checks that reset the board: 1 + -> ok + req API-013 KRN-IRQ-014 +CASE irq_blocking_call_from_isr_is_misuse outcome=passed asserts=1 skips=0 +TEST irq_disabled_source_stays_pending + -> ok + req KRN-IRQ-020 +CASE irq_disabled_source_stays_pending outcome=passed asserts=5 skips=0 +TEST irq_scheduler_lock_defers_the_switch_not_the_handler + -> ok + req KRN-SCH-016 KRN-SCH-018 KRN-SCH-019 +CASE irq_scheduler_lock_defers_the_switch_not_the_handler outcome=passed asserts=4 skips=0 +TEST irq_delivery_is_deferred_while_masked + -> ok + req KRN-IRQ-001 KRN-IRQ-033 +CASE irq_delivery_is_deferred_while_masked outcome=passed asserts=4 skips=0 +TEST irq_isr_wake_switches_at_outermost_exit + -> ok + req KRN-IRQ-010 KRN-IRQ-012 KRN-IRQ-013 KRN-SCH-021 +CASE irq_isr_wake_switches_at_outermost_exit outcome=passed asserts=7 skips=0 +TEST irq_lock_is_nestable_and_lifo + -> ok + req KRN-IRQ-001 KRN-IRQ-002 +CASE irq_lock_is_nestable_and_lifo outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=216 +8 tests, 0 failed, 0 skipped, 83 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.json new file mode 100644 index 00000000..74be7c39 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.json @@ -0,0 +1,109 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 17, + "name": "irq_priority_highest_kernel_level_is_masked", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_equal_levels_do_not_preempt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 25, + "name": "irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "irq_priority_higher_generic_level_preempts_lower", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "irq_priority_higher_generic_level_wins_pending_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 37, + "name": "irq_priority_encodings_and_invalid_write_guard", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_port_rejects_invalid_inputs", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "irq_priority_rejects_unknown_number", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_rejects_out_of_range_level", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "irq_priority_accepts_advertised_endpoints", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:19Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_irq_priority" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_irq_priority.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_irq_priority.uf2": "0c5337271253300f4ea864c7e5dd03e1320636068bd1840626c898735c034fff" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_irq_priority.elf", + "image_sha256": "fb4eeefc2fce3cea4aebb48a089c66a0a942875fa3ab84d816e99c5580e6c89a", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:17Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.log new file mode 100644 index 00000000..bff69148 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_irq_priority.log @@ -0,0 +1,47 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_irq_priority.elf sha256 fb4eeefc2fce3cea4aebb48a089c66a0a942875fa3ab84d816e99c5580e6c89a +EVIDENCE v1 suite=test_irq_priority config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST irq_priority_highest_kernel_level_is_masked + -> ok + req KRN-IRQ-018 KRN-IRQ-028 +CASE irq_priority_highest_kernel_level_is_masked outcome=passed asserts=17 skips=0 +TEST irq_priority_equal_levels_do_not_preempt + -> ok + req KRN-IRQ-028 +CASE irq_priority_equal_levels_do_not_preempt outcome=passed asserts=16 skips=0 +TEST irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback + -> ok + req KRN-WQ-007 KRN-TIM-025 KRN-IRQ-012 +CASE irq_priority_nested_interrupt_reschedules_work_in_a_timer_callback outcome=passed asserts=25 skips=0 +TEST irq_priority_higher_generic_level_preempts_lower + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_preempts_lower outcome=passed asserts=16 skips=0 +TEST irq_priority_higher_generic_level_wins_pending_order + -> ok + req KRN-IRQ-028 +CASE irq_priority_higher_generic_level_wins_pending_order outcome=passed asserts=18 skips=0 +TEST irq_priority_encodings_and_invalid_write_guard + -> ok + req KRN-IRQ-028 KRN-IRQ-031 +CASE irq_priority_encodings_and_invalid_write_guard outcome=passed asserts=37 skips=0 +TEST irq_priority_port_rejects_invalid_inputs + -> ok + req KRN-IRQ-028 +CASE irq_priority_port_rejects_invalid_inputs outcome=passed asserts=2 skips=0 +TEST irq_priority_rejects_unknown_number + fault checks that reset the board: 1 + -> ok + req API-015 KRN-IRQ-029 +CASE irq_priority_rejects_unknown_number outcome=passed asserts=1 skips=0 +TEST irq_priority_rejects_out_of_range_level + fault checks that reset the board: 2 + -> ok + req API-015 KRN-IRQ-028 +CASE irq_priority_rejects_out_of_range_level outcome=passed asserts=2 skips=0 +TEST irq_priority_accepts_advertised_endpoints + -> ok + req KRN-IRQ-028 KRN-IRQ-029 +CASE irq_priority_accepts_advertised_endpoints outcome=passed asserts=2 skips=0 +ISR_STACK size=2048 used=216 +10 tests, 0 failed, 0 skipped, 27 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.json new file mode 100644 index 00000000..93180336 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 1, + "name": "isr_stack_limit_stops_an_overflowing_interrupt", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "thread_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "isr_stack_guard_is_checked_at_the_outermost_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "isr_stack_info_reports_size_and_use", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:21Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_isr_stack" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_isr_stack.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_isr_stack.uf2": "4204209e080214ee6f71126c8fc3da37bf40b5929ad86a97b8f2d1604fb48592" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_isr_stack.elf", + "image_sha256": "eaae1261fa14c9db0e19dd1cf6af7dcc6e55d9c41508ba5fa069cef3ffe77e63", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:19Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.log new file mode 100644 index 00000000..318441f9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_isr_stack.log @@ -0,0 +1,24 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_isr_stack.elf sha256 eaae1261fa14c9db0e19dd1cf6af7dcc6e55d9c41508ba5fa069cef3ffe77e63 +EVIDENCE v1 suite=test_isr_stack config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST isr_stack_limit_stops_an_overflowing_interrupt + fault checks that reset the board: 1 + -> ok + req PORT-016 KRN-MEM-010 +CASE isr_stack_limit_stops_an_overflowing_interrupt outcome=passed asserts=1 skips=0 +TEST thread_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req KRN-MEM-010 PORT-016 +CASE thread_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +TEST isr_stack_guard_is_checked_at_the_outermost_exit + fault checks that reset the board: 1 + -> ok + req PORT-016 KRN-MEM-010 +CASE isr_stack_guard_is_checked_at_the_outermost_exit outcome=passed asserts=1 skips=0 +TEST isr_stack_info_reports_size_and_use + -> ok + req PORT-016 KRN-MEM-009 +CASE isr_stack_info_reports_size_and_use outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=216 +4 tests, 0 failed, 0 skipped, 26 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.json new file mode 100644 index 00000000..dd066bd7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 2828, + "name": "log_producers_at_once_keep_their_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "log_flush_sends_what_is_committed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "log_isr_record_waits_for_the_one_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 84, + "name": "log_overflow_drops_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "log_levels_compile_and_run_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "log_text_formats", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "log_record_layout", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:52Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_log" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_log.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_log.uf2": "12fb134a25306c0cfaca693addf4969f393f282521f2118a4affb9389bb1ff0d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_log.elf", + "image_sha256": "321c9394e101dcf44abd9ffb7c2a5682657fb57fe6d6448f9ded541be539045d", + "isr_stack": { + "size": 2048, + "used": 236 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:50Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.log new file mode 100644 index 00000000..eed880d9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_log.log @@ -0,0 +1,35 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_log.elf sha256 321c9394e101dcf44abd9ffb7c2a5682657fb57fe6d6448f9ded541be539045d +EVIDENCE v1 suite=test_log config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST log_producers_at_once_keep_their_order + -> ok + req OBS-003 +CASE log_producers_at_once_keep_their_order outcome=passed asserts=2828 skips=0 +TEST log_flush_sends_what_is_committed +[0.036] I t: flushed 1 +[0.036] I t: flushed 2 + -> ok + req OBS-003 +CASE log_flush_sends_what_is_committed outcome=passed asserts=4 skips=0 +TEST log_isr_record_waits_for_the_one_before_it + -> ok + req OBS-003 +CASE log_isr_record_waits_for_the_one_before_it outcome=passed asserts=6 skips=0 +TEST log_overflow_drops_and_counts + -> ok + req OBS-003 +CASE log_overflow_drops_and_counts outcome=passed asserts=84 skips=0 +TEST log_levels_compile_and_run_time + -> ok + req OBS-002 +CASE log_levels_compile_and_run_time outcome=passed asserts=9 skips=0 +TEST log_text_formats + -> ok + req OBS-013 +CASE log_text_formats outcome=passed asserts=11 skips=0 +TEST log_record_layout + -> ok + req OBS-013 +CASE log_record_layout outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=236 +7 tests, 0 failed, 0 skipped, 103 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.json new file mode 100644 index 00000000..bee205c9 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.json @@ -0,0 +1,121 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "msgq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "msgq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_binding_fires_on_empty_to_nonempty_only", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "msgq_init_validates_the_ring", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "msgq_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_destroy_aborts_receivers_and_senders", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "msgq_isr_send_and_receive_never_wait", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "msgq_waits_time_out_and_cancel_without_storing", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "msgq_receive_refills_the_freed_slot_from_a_waiting_sender", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "msgq_waiting_receivers_get_items_directly_in_priority_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "msgq_send_front_is_received_first_and_never_waits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 25, + "name": "msgq_fifo_order_counts_and_peek", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:43Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_msgq" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_msgq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_msgq.uf2": "d6ec32bb827ca93313da26564ad418ebca67661d285935878ec2f64e05552192" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_msgq.elf", + "image_sha256": "fd227a96bb8dcbfeedbbe0d11a42c8b8f259faf66cfd75b18f8cb733f24d1a30", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:41Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.log new file mode 100644 index 00000000..2f1125ba --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_msgq.log @@ -0,0 +1,56 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_msgq.elf sha256 fd227a96bb8dcbfeedbbe0d11a42c8b8f259faf66cfd75b18f8cb733f24d1a30 +EVIDENCE v1 suite=test_msgq config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST msgq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE msgq_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +TEST msgq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE msgq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST msgq_binding_fires_on_empty_to_nonempty_only + -> ok + req KRN-IPC-018 KRN-NOTIF-004 KRN-NOTIF-013 +CASE msgq_binding_fires_on_empty_to_nonempty_only outcome=passed asserts=15 skips=0 +TEST msgq_init_validates_the_ring + fault checks that reset the board: 6 + -> ok + req KRN-IPC-011 KRN-IPC-019 API-015 +CASE msgq_init_validates_the_ring outcome=passed asserts=6 skips=0 +TEST msgq_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE msgq_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST msgq_destroy_aborts_receivers_and_senders + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE msgq_destroy_aborts_receivers_and_senders outcome=passed asserts=11 skips=0 +TEST msgq_isr_send_and_receive_never_wait + -> ok + req KRN-IPC-003 KRN-IPC-010 KRN-IRQ-010 +CASE msgq_isr_send_and_receive_never_wait outcome=passed asserts=13 skips=0 +TEST msgq_waits_time_out_and_cancel_without_storing + -> ok + req KRN-IPC-010 KRN-WAIT-004 KRN-WAIT-017 +CASE msgq_waits_time_out_and_cancel_without_storing outcome=passed asserts=15 skips=0 +TEST msgq_receive_refills_the_freed_slot_from_a_waiting_sender + -> ok + req KRN-IPC-010 KRN-IPC-011 +CASE msgq_receive_refills_the_freed_slot_from_a_waiting_sender outcome=passed asserts=12 skips=0 +TEST msgq_waiting_receivers_get_items_directly_in_priority_order + -> ok + req KRN-IPC-010 KRN-IPC-005 KRN-WAIT-001 +CASE msgq_waiting_receivers_get_items_directly_in_priority_order outcome=passed asserts=11 skips=0 +TEST msgq_send_front_is_received_first_and_never_waits + -> ok + req KRN-IPC-012 +CASE msgq_send_front_is_received_first_and_never_waits outcome=passed asserts=9 skips=0 +TEST msgq_fifo_order_counts_and_peek + -> ok + req KRN-IPC-010 KRN-IPC-019 +CASE msgq_fifo_order_counts_and_peek outcome=passed asserts=25 skips=0 +ISR_STACK size=2048 used=216 +12 tests, 0 failed, 0 skipped, 129 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.json new file mode 100644 index 00000000..ba7d1f90 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.json @@ -0,0 +1,139 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 4, + "name": "mutex_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "mutex_waiter_priority_change_reorders_and_propagates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "mutex_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "mutex_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_owner_death_policy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_ceiling_violation_when_owned", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "mutex_ceiling_violation_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "mutex_ceiling_raises_the_owner", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "mutex_deadlock_is_detected_on_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 28, + "name": "mutex_inheritance_propagates_along_the_chain", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "mutex_timeout_removes_the_contribution", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 16, + "name": "mutex_contended_lock_inherits_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "mutex_recursive_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "mutex_lock_unlock_and_ownership", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:37Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_mutex" + }, + "exit": 0, + "fault_checks_by_reset": 11, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_mutex.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_mutex.uf2": "7f0e25d8581efa9997d6816b7a27d6fca4c939eb6727f19ba53b091e9c0c7393" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_mutex.elf", + "image_sha256": "b964ad83d3c0da0a1f0d46014c38f6ee60daf618a7ec7bbc84e6d719e61ac8be", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:35Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 15 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.log new file mode 100644 index 00000000..77a9b8d2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_mutex.log @@ -0,0 +1,73 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_mutex.elf sha256 b964ad83d3c0da0a1f0d46014c38f6ee60daf618a7ec7bbc84e6d719e61ac8be +EVIDENCE v1 suite=test_mutex config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST mutex_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE mutex_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +TEST mutex_init_validates_arguments + fault checks that reset the board: 3 + -> ok + req API-015 +CASE mutex_init_validates_arguments outcome=passed asserts=3 skips=0 +TEST mutex_waiter_priority_change_reorders_and_propagates + -> ok + req KRN-WAIT-003 KRN-SYNC-018 +CASE mutex_waiter_priority_change_reorders_and_propagates outcome=passed asserts=20 skips=0 +TEST mutex_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE mutex_storage_reuse_requires_destroy outcome=passed asserts=12 skips=0 +TEST mutex_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 +CASE mutex_destroy_rules outcome=passed asserts=15 skips=0 +TEST mutex_owner_death_policy + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-011 +CASE mutex_owner_death_policy outcome=passed asserts=3 skips=0 +TEST mutex_ceiling_violation_when_owned + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_when_owned outcome=passed asserts=5 skips=0 +TEST mutex_ceiling_violation_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-006 +CASE mutex_ceiling_violation_is_misuse outcome=passed asserts=3 skips=0 +TEST mutex_ceiling_raises_the_owner + -> ok + req KRN-SYNC-005 KRN-SYNC-006 +CASE mutex_ceiling_raises_the_owner outcome=passed asserts=7 skips=0 +TEST mutex_deadlock_is_detected_on_the_chain + fault checks that reset the board: 1 + -> ok + req KRN-SYNC-015 +CASE mutex_deadlock_is_detected_on_the_chain outcome=passed asserts=5 skips=0 +TEST mutex_inheritance_propagates_along_the_chain + -> ok + req KRN-SYNC-009 KRN-SYNC-010 KRN-SYNC-016 +CASE mutex_inheritance_propagates_along_the_chain outcome=passed asserts=28 skips=0 +TEST mutex_timeout_removes_the_contribution + -> ok + req KRN-SYNC-014 KRN-WAIT-013 +CASE mutex_timeout_removes_the_contribution outcome=passed asserts=14 skips=0 +TEST mutex_contended_lock_inherits_and_hands_off + -> ok + req KRN-SYNC-003 KRN-SYNC-009 KRN-SYNC-010 KRN-WAIT-012 +CASE mutex_contended_lock_inherits_and_hands_off outcome=passed asserts=16 skips=0 +TEST mutex_recursive_counts + -> ok + req KRN-SYNC-004 +CASE mutex_recursive_counts outcome=passed asserts=8 skips=0 +TEST mutex_lock_unlock_and_ownership + fault checks that reset the board: 2 + -> ok + req KRN-SYNC-001 KRN-SYNC-008 +CASE mutex_lock_unlock_and_ownership outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=216 +15 tests, 0 failed, 0 skipped, 12 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.json new file mode 100644 index 00000000..cfd66903 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.json @@ -0,0 +1,109 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "notify_bind_refuses_a_terminated_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "notify_bound_target_cannot_be_destroyed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "notify_unbind_stops_signals", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "notify_semaphore_binding_signals_ready_transition", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "notify_rejects_kernel_bits_and_terminated_targets", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wait_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "notify_wake_from_isr", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "notify_wake_from_thread_hands_off_bits", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "notify_any_and_all_modes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "notify_bits_are_level_sensitive", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:33Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_notify" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_notify.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_notify.uf2": "4b9a9a8a1a969c1b014e6cf8b0fb9a72c7c9d0d821ee4345aef75955a8e37972" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_notify.elf", + "image_sha256": "3e3685187f6494529e412850c342230f193719cd636627cdcee02ad6fd0af312", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:31Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 10 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.log new file mode 100644 index 00000000..c02b5747 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_notify.log @@ -0,0 +1,47 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_notify.elf sha256 3e3685187f6494529e412850c342230f193719cd636627cdcee02ad6fd0af312 +EVIDENCE v1 suite=test_notify config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST notify_bind_refuses_a_terminated_target + -> ok + req KRN-NOTIF-014 +CASE notify_bind_refuses_a_terminated_target outcome=passed asserts=6 skips=0 +TEST notify_bound_target_cannot_be_destroyed + fault checks that reset the board: 1 + -> ok + req KRN-NOTIF-014 KRN-NOTIF-009 +CASE notify_bound_target_cannot_be_destroyed outcome=passed asserts=11 skips=0 +TEST notify_unbind_stops_signals + -> ok + req KRN-NOTIF-009 KRN-NOTIF-013 +CASE notify_unbind_stops_signals outcome=passed asserts=14 skips=0 +TEST notify_semaphore_binding_signals_ready_transition + -> ok + req KRN-NOTIF-004 KRN-NOTIF-005 +CASE notify_semaphore_binding_signals_ready_transition outcome=passed asserts=10 skips=0 +TEST notify_rejects_kernel_bits_and_terminated_targets + fault checks that reset the board: 3 + -> ok + req KRN-NOTIF-002 KRN-NOTIF-006 +CASE notify_rejects_kernel_bits_and_terminated_targets outcome=passed asserts=6 skips=0 +TEST notify_wait_times_out + -> ok + req KRN-NOTIF-001 KRN-WAIT-004 +CASE notify_wait_times_out outcome=passed asserts=5 skips=0 +TEST notify_wake_from_isr + -> ok + req KRN-NOTIF-002 KRN-IRQ-010 +CASE notify_wake_from_isr outcome=passed asserts=3 skips=0 +TEST notify_wake_from_thread_hands_off_bits + -> ok + req KRN-NOTIF-003 KRN-WAIT-012 +CASE notify_wake_from_thread_hands_off_bits outcome=passed asserts=5 skips=0 +TEST notify_any_and_all_modes + -> ok + req KRN-NOTIF-001 +CASE notify_any_and_all_modes outcome=passed asserts=12 skips=0 +TEST notify_bits_are_level_sensitive + -> ok + req KRN-NOTIF-001 KRN-NOTIF-002 +CASE notify_bits_are_level_sensitive outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=216 +10 tests, 0 failed, 0 skipped, 75 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.json new file mode 100644 index 00000000..302cc0f3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.json @@ -0,0 +1,79 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "rtc_seeds_the_wall_clock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "rtc_backup_and_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_canceled_and_set_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "rtc_alarm_once_and_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "rtc_get_set_and_not_set", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:08Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_rtc" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_rtc.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_rtc.uf2": "ffc229a6886489e416f70b882dd41f4b9302e06a516f91ebe0e88873a2536161" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc.elf", + "image_sha256": "20262338845b494ac6337854e606ee1328a90fa43721ba03e77d1801c38b4199", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:06Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.log new file mode 100644 index 00000000..006cd268 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc.log @@ -0,0 +1,26 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc.elf sha256 20262338845b494ac6337854e606ee1328a90fa43721ba03e77d1801c38b4199 +EVIDENCE v1 suite=test_rtc config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST rtc_seeds_the_wall_clock + -> ok + req KRN-TIM-031 +CASE rtc_seeds_the_wall_clock outcome=passed asserts=3 skips=0 +TEST rtc_backup_and_misuse + fault checks that reset the board: 3 + -> ok + req DRV-001 +CASE rtc_backup_and_misuse outcome=passed asserts=8 skips=0 +TEST rtc_alarm_canceled_and_set_disarms + -> ok + req DRV-001 +CASE rtc_alarm_canceled_and_set_disarms outcome=passed asserts=10 skips=0 +TEST rtc_alarm_once_and_again + -> ok + req DRV-001 +CASE rtc_alarm_once_and_again outcome=passed asserts=10 skips=0 +TEST rtc_get_set_and_not_set + -> ok + req DRV-001 +CASE rtc_get_set_and_not_set outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=216 +5 tests, 0 failed, 0 skipped, 42 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.json new file mode 100644 index 00000000..80459c6d --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "rtc_board_keeps_its_time_across_a_reset", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "rtc_board_backup_registers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 42, + "name": "rtc_board_alarm_on_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "rtc_board_set_read_and_keep_time", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:12Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_rtc_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_rtc_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_rtc_board.uf2": "57f92dff34d962a76652b3d994218634e85818c7a7d729e717cd78ff2a5269e5" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_rtc_board.elf", + "image_sha256": "11136f33644b4b51d47c5007b30477efada1e71efd74a97198d1ba72ed425273", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:08Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.log new file mode 100644 index 00000000..ed606dbc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_rtc_board.log @@ -0,0 +1,22 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_rtc_board.elf sha256 11136f33644b4b51d47c5007b30477efada1e71efd74a97198d1ba72ed425273 +EVIDENCE v1 suite=test_rtc_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST rtc_board_keeps_its_time_across_a_reset + after the reset the RTC read 4 ms past the time set fault checks that reset the board: 1 + -> ok + req DRV-001 KRN-TIM-031 +CASE rtc_board_keeps_its_time_across_a_reset outcome=passed asserts=5 skips=0 +TEST rtc_board_backup_registers + -> ok + req DRV-001 +CASE rtc_board_backup_registers outcome=passed asserts=1 skips=0 +TEST rtc_board_alarm_on_time + an alarm 300 ms ahead fired after 300 ms -> ok + req DRV-001 +CASE rtc_board_alarm_on_time outcome=passed asserts=42 skips=0 +TEST rtc_board_set_read_and_keep_time + set and get took 0 ms; the RTC read 0 ms past the time set over 2006 ms of the kernel's clock the RTC moved 2005 ms -> ok + req DRV-001 +CASE rtc_board_set_read_and_keep_time outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=216 +4 tests, 0 failed, 0 skipped, 2762 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.json new file mode 100644 index 00000000..538a38ad --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "sched_raising_a_ready_thread_above_the_caller_preempts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_thread_self_and_priorities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sched_idle_runs_when_nothing_is_ready", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "sched_blocking_under_scheduler_lock_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "sched_preempted_thread_goes_ahead_of_its_peers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sched_fifo_within_level_and_yield_rotates", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "sched_yield_never_to_lower_priority", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sched_lock_defers_preemption_until_unlock", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "sched_higher_priority_runs_first", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:15Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_sched" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_sched.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_sched.uf2": "d3002d511d30ca3a775cd67aa71f8d1ecf02567143851519ad400457d6024e50" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sched.elf", + "image_sha256": "12888c30cde6b0347610d32414aaf4b9a2e4d33e9a5dc20f4267fddd6286f5cc", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:13Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.log new file mode 100644 index 00000000..913895b3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sched.log @@ -0,0 +1,42 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_sched.elf sha256 12888c30cde6b0347610d32414aaf4b9a2e4d33e9a5dc20f4267fddd6286f5cc +EVIDENCE v1 suite=test_sched config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST sched_raising_a_ready_thread_above_the_caller_preempts + -> ok + req KRN-THR-022 KRN-SYNC-032 +CASE sched_raising_a_ready_thread_above_the_caller_preempts outcome=passed asserts=6 skips=0 +TEST sched_thread_self_and_priorities + -> ok + req KRN-THR-002 KRN-SCH-009 +CASE sched_thread_self_and_priorities outcome=passed asserts=4 skips=0 +TEST sched_idle_runs_when_nothing_is_ready + -> ok + req KRN-SCH-043 SIM-005 +CASE sched_idle_runs_when_nothing_is_ready outcome=passed asserts=2 skips=0 +TEST sched_blocking_under_scheduler_lock_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-SCH-019 API-013 +CASE sched_blocking_under_scheduler_lock_is_misuse outcome=passed asserts=1 skips=0 +TEST sched_preempted_thread_goes_ahead_of_its_peers + -> ok + req KRN-SCH-041 KRN-IRQ-013 +CASE sched_preempted_thread_goes_ahead_of_its_peers outcome=passed asserts=8 skips=0 +TEST sched_fifo_within_level_and_yield_rotates + -> ok + req KRN-SCH-003 KRN-SCH-008 +CASE sched_fifo_within_level_and_yield_rotates outcome=passed asserts=5 skips=0 +TEST sched_yield_never_to_lower_priority + -> ok + req KRN-SCH-008 +CASE sched_yield_never_to_lower_priority outcome=passed asserts=3 skips=0 +TEST sched_lock_defers_preemption_until_unlock + -> ok + req KRN-SCH-016 KRN-SCH-017 KRN-SCH-018 +CASE sched_lock_defers_preemption_until_unlock outcome=passed asserts=4 skips=0 +TEST sched_higher_priority_runs_first + -> ok + req KRN-SCH-001 KRN-SCH-002 +CASE sched_higher_priority_runs_first outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=216 +9 tests, 0 failed, 0 skipped, 83 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.json new file mode 100644 index 00000000..8a3716ae --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.json @@ -0,0 +1,121 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "sem_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "sem_blocking_take_from_prekernel_or_isr_rejected", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "sem_destroy_with_waiters_is_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "sem_destroy_aborts_waiters_when_allowed", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "sem_init_validates_arguments", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_max_overflow_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "sem_give_from_isr_wakes_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_take_times_out_and_disarms", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "sem_fifo_option_orders_by_arrival", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "sem_give_hands_off_to_highest_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "sem_counts_and_nowait", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:35Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_sem" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_sem.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_sem.uf2": "c9ab3d5c4800521c29238bee9f218fc1639a604a7cbd8af08d26deb66f92a220" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_sem.elf", + "image_sha256": "615641c7d01eee19a95dc510a911be2a91442fb1d29048a98114d5a7febe3191", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:33Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 12 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.log new file mode 100644 index 00000000..2652665b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_sem.log @@ -0,0 +1,56 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_sem.elf sha256 615641c7d01eee19a95dc510a911be2a91442fb1d29048a98114d5a7febe3191 +EVIDENCE v1 suite=test_sem config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST sem_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE sem_define_constructs_in_init_table outcome=passed asserts=6 skips=0 +TEST sem_blocking_take_from_prekernel_or_isr_rejected + -> ok + req API-012 API-013 +CASE sem_blocking_take_from_prekernel_or_isr_rejected outcome=passed asserts=4 skips=0 +TEST sem_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE sem_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST sem_destroy_with_waiters_is_misuse + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-001 API-013 +CASE sem_destroy_with_waiters_is_misuse outcome=passed asserts=7 skips=0 +TEST sem_destroy_aborts_waiters_when_allowed + -> ok + req KRN-OBJ-001 KRN-WAIT-018 +CASE sem_destroy_aborts_waiters_when_allowed outcome=passed asserts=5 skips=0 +TEST sem_init_validates_arguments + fault checks that reset the board: 2 + -> ok + req API-015 +CASE sem_init_validates_arguments outcome=passed asserts=2 skips=0 +TEST sem_max_overflow_and_saturate + -> ok + req KRN-SYNC-020 +CASE sem_max_overflow_and_saturate outcome=passed asserts=13 skips=0 +TEST sem_give_from_isr_wakes_at_exit + -> ok + req KRN-SYNC-022 KRN-IRQ-010 KRN-IRQ-033 +CASE sem_give_from_isr_wakes_at_exit outcome=passed asserts=6 skips=0 +TEST sem_take_times_out_and_disarms + -> ok + req KRN-WAIT-004 KRN-WAIT-013 +CASE sem_take_times_out_and_disarms outcome=passed asserts=9 skips=0 +TEST sem_fifo_option_orders_by_arrival + -> ok + req KRN-WAIT-002 +CASE sem_fifo_option_orders_by_arrival outcome=passed asserts=9 skips=0 +TEST sem_give_hands_off_to_highest_waiter + -> ok + req KRN-WAIT-001 KRN-WAIT-012 KRN-SYNC-022 +CASE sem_give_hands_off_to_highest_waiter outcome=passed asserts=13 skips=0 +TEST sem_counts_and_nowait + -> ok + req KRN-SYNC-020 KRN-SYNC-021 +CASE sem_counts_and_nowait outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=216 +12 tests, 0 failed, 0 skipped, 102 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.json new file mode 100644 index 00000000..0a780897 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.json @@ -0,0 +1,67 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "smoke_libc_errno_from_a_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "smoke_sleep_advances_virtual_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "smoke_thread_runs_and_exits", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:11Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_smoke" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_smoke.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_smoke.uf2": "1d9bb7e9af787a560779322b082d2672d2f125dec4a279b7e0f1b9f5d0e353d7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_smoke.elf", + "image_sha256": "76b868b24fdd9a812f2322c0c58c68698a5cc4dc2b9beaa83484ae13307a8315", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:10Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 3 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.log new file mode 100644 index 00000000..45e743db --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_smoke.log @@ -0,0 +1,17 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_smoke.elf sha256 76b868b24fdd9a812f2322c0c58c68698a5cc4dc2b9beaa83484ae13307a8315 +EVIDENCE v1 suite=test_smoke config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST smoke_libc_errno_from_a_thread + -> ok + req PORT-015 +CASE smoke_libc_errno_from_a_thread outcome=passed asserts=3 skips=0 +TEST smoke_sleep_advances_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 +CASE smoke_sleep_advances_virtual_time outcome=passed asserts=2 skips=0 +TEST smoke_thread_runs_and_exits + -> ok + req KRN-THR-001 KRN-THR-005 KRN-THR-017 +CASE smoke_thread_runs_and_exits outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=216 +3 tests, 0 failed, 0 skipped, 51 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.json new file mode 100644 index 00000000..9e7fa383 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.json @@ -0,0 +1,103 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 15, + "name": "spi_other_threads_wait_for_a_held_bus", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_held_bus_refuses_another_target", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "spi_held_bus_keeps_the_chip_select", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "spi_chip_select_around_each_transfer", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_unsupported_and_stopped", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "spi_transfers_run_in_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_without_buffers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "spi_transfer_loops_back", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:35Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_spi" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_spi.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_spi.uf2": "bc80ce46f6cae889c8bddce89eff6028043600df01ea0c873e2a8fa88b554d83" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi.elf", + "image_sha256": "7914acc52a54102da1e4523769990671b68bb6c220b2a1e164c28342baa0e952", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:33Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 9 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.log new file mode 100644 index 00000000..b4efe0f1 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi.log @@ -0,0 +1,42 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi.elf sha256 7914acc52a54102da1e4523769990671b68bb6c220b2a1e164c28342baa0e952 +EVIDENCE v1 suite=test_spi config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST spi_other_threads_wait_for_a_held_bus + -> ok + req DRV-004 +CASE spi_other_threads_wait_for_a_held_bus outcome=passed asserts=15 skips=0 +TEST spi_held_bus_refuses_another_target + -> ok + req DRV-004 +CASE spi_held_bus_refuses_another_target outcome=passed asserts=10 skips=0 +TEST spi_held_bus_keeps_the_chip_select + -> ok + req DRV-004 +CASE spi_held_bus_keeps_the_chip_select outcome=passed asserts=15 skips=0 +TEST spi_chip_select_around_each_transfer + -> ok + req DRV-004 +CASE spi_chip_select_around_each_transfer outcome=passed asserts=11 skips=0 +TEST spi_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE spi_misuse_faults outcome=passed asserts=7 skips=0 +TEST spi_unsupported_and_stopped + -> ok + req DRV-006 +CASE spi_unsupported_and_stopped outcome=passed asserts=7 skips=0 +TEST spi_transfers_run_in_order + -> ok + req DRV-004 +CASE spi_transfers_run_in_order outcome=passed asserts=10 skips=0 +TEST spi_without_buffers + -> ok + req DRV-005 +CASE spi_without_buffers outcome=passed asserts=7 skips=0 +TEST spi_transfer_loops_back + -> ok + req DRV-004 DRV-005 +CASE spi_transfer_loops_back outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=216 +9 tests, 0 failed, 0 skipped, 57 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.json new file mode 100644 index 00000000..4ba0abf8 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 14, + "name": "spi_loop_runs_by_dma", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 21, + "name": "spi_loop_chip_select_at_the_pin", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "spi_loop_no_transmit_buffer_sends_ones", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "spi_loop_timeout_stops_after_whole_frames", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_refuses_a_clock_too_slow", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_slow_and_fast_clocks", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "spi_loop_every_mode", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "spi_loop_frames_come_back_intact", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:37Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_spi_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_spi_loop.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_spi_loop.uf2": "8ea8ca8d882e5e082c0604b10643dff4be8cfbd4a42cf2d8895bd0b8ac79799f" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_spi_loop.elf", + "image_sha256": "c36c23b16e0071391e21d71c88284b05117f6c456e969b7decc14f8ef28751ee", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:35Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.log new file mode 100644 index 00000000..7d456b5c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_spi_loop.log @@ -0,0 +1,37 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_spi_loop.elf sha256 c36c23b16e0071391e21d71c88284b05117f6c456e969b7decc14f8ef28751ee +EVIDENCE v1 suite=test_spi_loop config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST spi_loop_runs_by_dma + -> ok + req DRV-004 DRV-006 +CASE spi_loop_runs_by_dma outcome=passed asserts=14 skips=0 +TEST spi_loop_chip_select_at_the_pin + -> ok + req DRV-004 +CASE spi_loop_chip_select_at_the_pin outcome=passed asserts=21 skips=0 +TEST spi_loop_no_transmit_buffer_sends_ones + -> ok + req DRV-005 +CASE spi_loop_no_transmit_buffer_sends_ones outcome=passed asserts=17 skips=0 +TEST spi_loop_timeout_stops_after_whole_frames + -> ok + req DRV-006 +CASE spi_loop_timeout_stops_after_whole_frames outcome=passed asserts=5 skips=0 +TEST spi_loop_refuses_a_clock_too_slow + -> ok + req DRV-006 +CASE spi_loop_refuses_a_clock_too_slow outcome=passed asserts=4 skips=0 +TEST spi_loop_slow_and_fast_clocks + -> ok + req DRV-004 +CASE spi_loop_slow_and_fast_clocks outcome=passed asserts=4 skips=0 +TEST spi_loop_every_mode + -> ok + req DRV-004 +CASE spi_loop_every_mode outcome=passed asserts=8 skips=0 +TEST spi_loop_frames_come_back_intact + -> ok + req DRV-004 DRV-005 +CASE spi_loop_frames_come_back_intact outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=216 +8 tests, 0 failed, 0 skipped, 198 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.json new file mode 100644 index 00000000..25b2e953 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "stack_limit_stops_an_overflowing_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:46Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_stack_limit" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_stack_limit.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_stack_limit.uf2": "ac4034c9e1ff4822028bf7eb3f96745ab3dba2445d2201d4c089b70fd23ae488" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_stack_limit.elf", + "image_sha256": "ae205ba7916d95c2ebec2d273f453d4a68596b6489f54bc21cdad2afc1d36790", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:44Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.log new file mode 100644 index 00000000..816d1993 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_stack_limit.log @@ -0,0 +1,13 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_stack_limit.elf sha256 ae205ba7916d95c2ebec2d273f453d4a68596b6489f54bc21cdad2afc1d36790 +EVIDENCE v1 suite=test_stack_limit config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST stack_limit_stops_an_overflowing_thread +stack_limit_stops_an_overflowing_thread: first boot, overflowing +EVIDENCE v1 suite=test_stack_limit config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST stack_limit_stops_an_overflowing_thread +EMB_CRASH 454d424301006c000e939c714439e2c4f5c4000320e5c8ac52f3c79f302e322e300000000f0000000000000002000000070006000000000001000000000010000000000000000000e01d0020000000000000000004000000000010000000000034ed00e038ed00e0a9c82653 + -> ok + req KRN-MEM-010 OBS-016 +CASE stack_limit_stops_an_overflowing_thread outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=216 +1 tests, 0 failed, 0 skipped, 41 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.json new file mode 100644 index 00000000..ce157667 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.json @@ -0,0 +1,115 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 2, + "name": "thread_stack_info_reports_size", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_define_registers_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_state_reports_lifecycle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_priority_change_requeues_waiter", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_cancel_point_and_counts", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "thread_cancel_pending_delivered_at_next_point", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_cancel_wakes_a_sleeping_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_wake_while_suspended_is_applied_at_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 18, + "name": "thread_suspend_resume_are_idempotent_overlays", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "thread_start_twice_is_estate_and_destroy_rules", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_init_validates_arguments", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:23Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_thread" + }, + "exit": 0, + "fault_checks_by_reset": 8, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_thread.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_thread.uf2": "219ca6524fb2711f428fbf3b3c758debf3cb25206697c87d8766102a19712d92" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread.elf", + "image_sha256": "247b56c3614147b6bef72be3edc09b12fbaa361d3168d08f8aec6cad6547fe6d", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:21Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 11 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.log new file mode 100644 index 00000000..bf54888c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread.log @@ -0,0 +1,52 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread.elf sha256 247b56c3614147b6bef72be3edc09b12fbaa361d3168d08f8aec6cad6547fe6d +EVIDENCE v1 suite=test_thread config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST thread_stack_info_reports_size + -> ok + req KRN-MEM-009 +CASE thread_stack_info_reports_size outcome=passed asserts=2 skips=0 +TEST thread_define_registers_in_init_table + -> ok + req KRN-THR-015 API-017 +CASE thread_define_registers_in_init_table outcome=passed asserts=5 skips=0 +TEST thread_state_reports_lifecycle + -> ok + req KRN-THR-021 +CASE thread_state_reports_lifecycle outcome=passed asserts=11 skips=0 +TEST thread_priority_change_requeues_waiter + -> ok + req KRN-WAIT-003 KRN-SCH-009 KRN-SYNC-018 +CASE thread_priority_change_requeues_waiter outcome=passed asserts=13 skips=0 +TEST thread_cancel_point_and_counts + fault checks that reset the board: 1 + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_point_and_counts outcome=passed asserts=5 skips=0 +TEST thread_cancel_pending_delivered_at_next_point + -> ok + req KRN-THR-011 KRN-THR-020 +CASE thread_cancel_pending_delivered_at_next_point outcome=passed asserts=11 skips=0 +TEST thread_cancel_wakes_a_sleeping_thread + -> ok + req KRN-THR-011 KRN-WAIT-017 +CASE thread_cancel_wakes_a_sleeping_thread outcome=passed asserts=6 skips=0 +TEST thread_wake_while_suspended_is_applied_at_resume + -> ok + req KRN-WAIT-016 KRN-THR-010 +CASE thread_wake_while_suspended_is_applied_at_resume outcome=passed asserts=12 skips=0 +TEST thread_suspend_resume_are_idempotent_overlays + -> ok + req KRN-THR-010 KRN-THR-019 +CASE thread_suspend_resume_are_idempotent_overlays outcome=passed asserts=18 skips=0 +TEST thread_start_twice_is_estate_and_destroy_rules + fault checks that reset the board: 1 + -> ok + req KRN-THR-016 KRN-THR-022 KRN-OBJ-001 +CASE thread_start_twice_is_estate_and_destroy_rules outcome=passed asserts=13 skips=0 +TEST thread_init_validates_arguments + fault checks that reset the board: 6 + -> ok + req KRN-THR-001 API-015 +CASE thread_init_validates_arguments outcome=passed asserts=6 skips=0 +ISR_STACK size=2048 used=216 +11 tests, 0 failed, 0 skipped, 12 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.json new file mode 100644 index 00000000..52189e3b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.json @@ -0,0 +1,79 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "idle_context_is_not_an_application_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "thread_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "thread_identity_survives_suspend_and_resume", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1200, + "name": "thread_identity_repeated_construction_does_not_alias_live_object", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 15, + "name": "thread_identity_survives_priority_and_termination", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:27Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_thread_identity" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_thread_identity.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_thread_identity.uf2": "b2d7a2c5077804f070f44e81d8733230f1c4cff9d12c80b460cd8f14ec32b89c" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_identity.elf", + "image_sha256": "0502e791217fca6824ebf47a589ec26e6de843e36d05aca08bac44bec60d8640", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:25Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 5 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.log new file mode 100644 index 00000000..6d6e8a33 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_identity.log @@ -0,0 +1,28 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_identity.elf sha256 0502e791217fca6824ebf47a589ec26e6de843e36d05aca08bac44bec60d8640 +EVIDENCE v1 suite=test_thread_identity config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST idle_context_is_not_an_application_thread + fault checks that reset the board: 2 + -> ok + req KRN-THR-025 KRN-THR-026 +CASE idle_context_is_not_an_application_thread outcome=passed asserts=6 skips=0 +TEST thread_storage_reuse_requires_destroy + fault checks that reset the board: 2 + -> ok + req KRN-THR-015 KRN-THR-023 +CASE thread_storage_reuse_requires_destroy outcome=passed asserts=9 skips=0 +TEST thread_identity_survives_suspend_and_resume + -> ok + req KRN-THR-025 +CASE thread_identity_survives_suspend_and_resume outcome=passed asserts=12 skips=0 +TEST thread_identity_repeated_construction_does_not_alias_live_object + -> ok + req KRN-THR-025 +CASE thread_identity_repeated_construction_does_not_alias_live_object outcome=passed asserts=1200 skips=0 +TEST thread_identity_survives_priority_and_termination + fault checks that reset the board: 1 + -> ok + req KRN-THR-025 +CASE thread_identity_survives_priority_and_termination outcome=passed asserts=15 skips=0 +ISR_STACK size=2048 used=216 +5 tests, 0 failed, 0 skipped, 13 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.json new file mode 100644 index 00000000..42c71add --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.json @@ -0,0 +1,85 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 5, + "name": "thread_detach_after_exit_makes_reusable", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_self_and_detached_are_errors", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "thread_second_joiner_is_ebusy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "thread_join_timeout_then_success", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "thread_join_before_exit_blocks_and_hands_off", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "thread_join_after_exit_returns_code", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:25Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_thread_join" + }, + "exit": 0, + "fault_checks_by_reset": 2, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_thread_join.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_thread_join.uf2": "24f5d5498cbfaf98f3e0476328283b2ac2c794738af91ab77c0fb6edde124516" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_thread_join.elf", + "image_sha256": "c083f403fd004231612cf024db0b72bb110054042911998641969a860181f878", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:23Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 6 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.log new file mode 100644 index 00000000..0dafdc88 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_thread_join.log @@ -0,0 +1,31 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_thread_join.elf sha256 c083f403fd004231612cf024db0b72bb110054042911998641969a860181f878 +EVIDENCE v1 suite=test_thread_join config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST thread_detach_after_exit_makes_reusable + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 KRN-THR-022 +CASE thread_detach_after_exit_makes_reusable outcome=passed asserts=5 skips=0 +TEST thread_join_self_and_detached_are_errors + fault checks that reset the board: 1 + -> ok + req KRN-THR-017 +CASE thread_join_self_and_detached_are_errors outcome=passed asserts=5 skips=0 +TEST thread_second_joiner_is_ebusy + -> ok + req KRN-THR-018 +CASE thread_second_joiner_is_ebusy outcome=passed asserts=10 skips=0 +TEST thread_join_timeout_then_success + -> ok + req KRN-THR-017 KRN-WAIT-004 +CASE thread_join_timeout_then_success outcome=passed asserts=5 skips=0 +TEST thread_join_before_exit_blocks_and_hands_off + -> ok + req KRN-THR-017 KRN-WAIT-012 +CASE thread_join_before_exit_blocks_and_hands_off outcome=passed asserts=6 skips=0 +TEST thread_join_after_exit_returns_code + -> ok + req KRN-THR-004 KRN-THR-006 KRN-THR-017 +CASE thread_join_after_exit_returns_code outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=216 +6 tests, 0 failed, 0 skipped, 96 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.json new file mode 100644 index 00000000..a21fcded --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 40, + "name": "time_now_is_monotonic_across_sleeps", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_instant_helpers", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "time_at_least_adds_one_tick", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "time_conversions_round_up_and_saturate", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 14, + "name": "time_timeouts_expire_in_deadline_order", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "time_zero_sleep_and_past_deadline_yield", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 20, + "name": "time_sleep_until_does_not_drift", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "time_sleep_is_exact_in_virtual_time", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:29Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_time" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_time.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_time.uf2": "5224bfecaa7296107c36e1d87c7ff01ce6696a8d76fa1871d1fbe6529b5b7de8" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_time.elf", + "image_sha256": "ee7779030f24f40d42d23a497de5205e544e72579080885bc19a61d30c098141", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:27Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.log new file mode 100644 index 00000000..f57a57d5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_time.log @@ -0,0 +1,37 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_time.elf sha256 ee7779030f24f40d42d23a497de5205e544e72579080885bc19a61d30c098141 +EVIDENCE v1 suite=test_time config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST time_now_is_monotonic_across_sleeps + -> ok + req KRN-TIM-001 +CASE time_now_is_monotonic_across_sleeps outcome=passed asserts=40 skips=0 +TEST time_instant_helpers + -> ok + req API-021 +CASE time_instant_helpers outcome=passed asserts=6 skips=0 +TEST time_at_least_adds_one_tick + -> ok + req KRN-TIM-024 +CASE time_at_least_adds_one_tick outcome=passed asserts=6 skips=0 +TEST time_conversions_round_up_and_saturate + -> ok + req API-021 API-022 +CASE time_conversions_round_up_and_saturate outcome=passed asserts=12 skips=0 +TEST time_timeouts_expire_in_deadline_order + -> ok + req KRN-TIM-020 KRN-TIM-021 +CASE time_timeouts_expire_in_deadline_order outcome=passed asserts=14 skips=0 +TEST time_zero_sleep_and_past_deadline_yield + -> ok + req KRN-TIM-010 API-024 +CASE time_zero_sleep_and_past_deadline_yield outcome=passed asserts=3 skips=0 +TEST time_sleep_until_does_not_drift + -> ok + req KRN-TIM-011 +CASE time_sleep_until_does_not_drift outcome=passed asserts=20 skips=0 +TEST time_sleep_is_exact_in_virtual_time + -> ok + req KRN-TIM-001 KRN-TIM-010 API-023 +CASE time_sleep_is_exact_in_virtual_time outcome=passed asserts=4 skips=0 +ISR_STACK size=2048 used=216 +8 tests, 0 failed, 0 skipped, 181 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.json new file mode 100644 index 00000000..ff06f4b4 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 4, + "name": "timer_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "timer_init_needs_a_queue_or_isr_context", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_expiries_during_a_long_callback_are_overruns", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "timer_stop_sync_waits_for_a_running_callback", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "timer_callback_runs_on_its_work_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 22, + "name": "timer_restart_remaining_and_stop_states", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 22, + "name": "timer_isr_context_one_shot_and_periodic_without_drift", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:48Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_timer" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_timer.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_timer.uf2": "e57be71de2b8d7ee67297a478a52e2a23b6f17793f11b215d39126bc7d2b61cb" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_timer.elf", + "image_sha256": "a655f7ea29efe85a1ba3f06972c1354a34c3fc5a58951fd553cecca209aa1861", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:46Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.log new file mode 100644 index 00000000..85fc0f6a --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_timer.log @@ -0,0 +1,36 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_timer.elf sha256 a655f7ea29efe85a1ba3f06972c1354a34c3fc5a58951fd553cecca209aa1861 +EVIDENCE v1 suite=test_timer config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST timer_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE timer_define_constructs_in_init_table outcome=passed asserts=4 skips=0 +TEST timer_init_needs_a_queue_or_isr_context + fault checks that reset the board: 2 + -> ok + req KRN-TIM-013 API-015 +CASE timer_init_needs_a_queue_or_isr_context outcome=passed asserts=3 skips=0 +TEST timer_expiries_during_a_long_callback_are_overruns + -> ok + req KRN-TIM-027 +CASE timer_expiries_during_a_long_callback_are_overruns outcome=passed asserts=13 skips=0 +TEST timer_stop_sync_waits_for_a_running_callback + -> ok + req KRN-TIM-028 KRN-WAIT-012 +CASE timer_stop_sync_waits_for_a_running_callback outcome=passed asserts=13 skips=0 +TEST timer_callback_runs_on_its_work_queue + fault checks that reset the board: 1 + -> ok + req KRN-TIM-013 KRN-TIM-005 KRN-TIM-026 +CASE timer_callback_runs_on_its_work_queue outcome=passed asserts=11 skips=0 +TEST timer_restart_remaining_and_stop_states + fault checks that reset the board: 2 + -> ok + req KRN-TIM-025 KRN-TIM-028 +CASE timer_restart_remaining_and_stop_states outcome=passed asserts=22 skips=0 +TEST timer_isr_context_one_shot_and_periodic_without_drift + -> ok + req KRN-TIM-025 KRN-TIM-005 KRN-TIM-014 KRN-TIM-015 +CASE timer_isr_context_one_shot_and_periodic_without_drift outcome=passed asserts=22 skips=0 +ISR_STACK size=2048 used=216 +7 tests, 0 failed, 0 skipped, 60 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.json new file mode 100644 index 00000000..c50954fd --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.json @@ -0,0 +1,97 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 6, + "name": "uart_misuse_faults", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_break_runs_after_the_writes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_polled_calls_and_capabilities", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_read_times_out_with_what_it_got", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 11, + "name": "uart_overrun_and_damaged_bytes", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "uart_idle_ends_a_read_early", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_ring_keeps_bytes_no_read_waits_for", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "uart_read_and_write_run_at_once", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:56Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_uart" + }, + "exit": 0, + "fault_checks_by_reset": 5, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_uart.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_uart.uf2": "0a23680c0b2abb52d5cb07345305dbab92a3d7206038dc35f61ea46e9eeed181" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart.elf", + "image_sha256": "5480ac8614d8bb07b515391ab89640256a1ab8205739fd7b7bb4a85c4adcf823", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:54Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 8 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.log new file mode 100644 index 00000000..22eed9a3 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart.log @@ -0,0 +1,38 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart.elf sha256 5480ac8614d8bb07b515391ab89640256a1ab8205739fd7b7bb4a85c4adcf823 +EVIDENCE v1 suite=test_uart config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST uart_misuse_faults + fault checks that reset the board: 5 + -> ok + req DRV-004 +CASE uart_misuse_faults outcome=passed asserts=6 skips=0 +TEST uart_break_runs_after_the_writes + -> ok + req DRV-004 +CASE uart_break_runs_after_the_writes outcome=passed asserts=5 skips=0 +TEST uart_polled_calls_and_capabilities + -> ok + req DRV-007 +CASE uart_polled_calls_and_capabilities outcome=passed asserts=8 skips=0 +TEST uart_read_times_out_with_what_it_got + -> ok + req DRV-006 +CASE uart_read_times_out_with_what_it_got outcome=passed asserts=6 skips=0 +TEST uart_overrun_and_damaged_bytes + -> ok + req DRV-005 DRV-008 +CASE uart_overrun_and_damaged_bytes outcome=passed asserts=11 skips=0 +TEST uart_idle_ends_a_read_early + -> ok + req DRV-005 +CASE uart_idle_ends_a_read_early outcome=passed asserts=10 skips=0 +TEST uart_ring_keeps_bytes_no_read_waits_for + -> ok + req DRV-005 +CASE uart_ring_keeps_bytes_no_read_waits_for outcome=passed asserts=8 skips=0 +TEST uart_read_and_write_run_at_once + -> ok + req DRV-004 DRV-005 +CASE uart_read_and_write_run_at_once outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=216 +8 tests, 0 failed, 0 skipped, 99 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.json new file mode 100644 index 00000000..220c2286 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.json @@ -0,0 +1,73 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 1, + "name": "uart_console_polled_write", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 1, + "name": "uart_console_break_or_not_supported", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 2, + "name": "uart_console_read_times_out", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_console_writes_by_request", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:58Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_uart_board" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_uart_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_uart_board.uf2": "3313d307c3b3303b20ee4f896c674a76baef6eb2b974fcb0da46ab9c1798bf98" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_board.elf", + "image_sha256": "70a5f250879615d3abe7eedad4e7e66ae5e26b80986be5f25b809821a8ea6ee0", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:56Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 4 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.log new file mode 100644 index 00000000..e62a22c2 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_board.log @@ -0,0 +1,23 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart_board.elf sha256 70a5f250879615d3abe7eedad4e7e66ae5e26b80986be5f25b809821a8ea6ee0 +EVIDENCE v1 suite=test_uart_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST uart_console_polled_write +uart: a polled write + -> ok + req DRV-007 +CASE uart_console_polled_write outcome=passed asserts=1 skips=0 +TEST uart_console_break_or_not_supported + -> ok + req DRV-004 +CASE uart_console_break_or_not_supported outcome=passed asserts=1 skips=0 +TEST uart_console_read_times_out + -> ok + req DRV-006 +CASE uart_console_read_times_out outcome=passed asserts=2 skips=0 +TEST uart_console_writes_by_request +uart: a write by request, sent by the driver's interrupts + -> ok + req DRV-004 DRV-005 +CASE uart_console_writes_by_request outcome=passed asserts=5 skips=0 +ISR_STACK size=2048 used=228 +4 tests, 0 failed, 0 skipped, 77 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.json new file mode 100644 index 00000000..3edd90e5 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.json @@ -0,0 +1,91 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 16, + "name": "uart_loop_writes_by_dma", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_overrun_is_reported", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_break_arrives_as_a_framing_error", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 6, + "name": "uart_loop_a_kilobyte_intact", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "uart_loop_idle_line_ends_a_read", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 4, + "name": "uart_loop_ring_keeps_what_arrives", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "uart_loop_echo_full_duplex", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:35:00Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_uart_loop" + }, + "exit": 0, + "fault_checks_by_reset": 0, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_uart_loop.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_uart_loop.uf2": "71667d147d23b2eb423226bb1c96741c3239bf39b7b455a263a0290f4329a2ec" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_uart_loop.elf", + "image_sha256": "594e29b279202bb07d90f07b94d45a1f78f73b8a7275a896fb139be63e59ed12", + "isr_stack": { + "size": 2048, + "used": 228 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:58Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 7 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.log new file mode 100644 index 00000000..17bda073 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_uart_loop.log @@ -0,0 +1,33 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_uart_loop.elf sha256 594e29b279202bb07d90f07b94d45a1f78f73b8a7275a896fb139be63e59ed12 +EVIDENCE v1 suite=test_uart_loop config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST uart_loop_writes_by_dma + -> ok + req DRV-004 DRV-006 +CASE uart_loop_writes_by_dma outcome=passed asserts=16 skips=0 +TEST uart_loop_overrun_is_reported + -> ok + req DRV-005 DRV-008 +CASE uart_loop_overrun_is_reported outcome=passed asserts=4 skips=0 +TEST uart_loop_break_arrives_as_a_framing_error + -> ok + req DRV-004 DRV-008 +CASE uart_loop_break_arrives_as_a_framing_error outcome=passed asserts=4 skips=0 +TEST uart_loop_a_kilobyte_intact + -> ok + req DRV-004 DRV-005 +CASE uart_loop_a_kilobyte_intact outcome=passed asserts=6 skips=0 +TEST uart_loop_idle_line_ends_a_read + -> ok + req DRV-005 +CASE uart_loop_idle_line_ends_a_read outcome=passed asserts=5 skips=0 +TEST uart_loop_ring_keeps_what_arrives + -> ok + req DRV-005 +CASE uart_loop_ring_keeps_what_arrives outcome=passed asserts=4 skips=0 +TEST uart_loop_echo_full_duplex + -> ok + req DRV-004 DRV-005 +CASE uart_loop_echo_full_duplex outcome=passed asserts=7 skips=0 +ISR_STACK size=2048 used=228 +7 tests, 0 failed, 0 skipped, 229 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.json new file mode 100644 index 00000000..3457359c --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 9, + "name": "wallclock_adjust_moves_no_deadline", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "wallclock_set_and_get", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:31Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wallclock" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_wallclock.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wallclock.uf2": "7c48af8d6a64e54e525926f1d1a1d6ccd8765d5929fa4654f17b269a0b8a52d7" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wallclock.elf", + "image_sha256": "eaeb084952ff99c966dde01a1fe428e02f37e3e33dc34e7e13f4b85c78ea0e0b", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:29Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.log new file mode 100644 index 00000000..32badcf7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wallclock.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wallclock.elf sha256 eaeb084952ff99c966dde01a1fe428e02f37e3e33dc34e7e13f4b85c78ea0e0b +EVIDENCE v1 suite=test_wallclock config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wallclock_adjust_moves_no_deadline + -> ok + req KRN-TIM-031 +CASE wallclock_adjust_moves_no_deadline outcome=passed asserts=9 skips=0 +TEST wallclock_set_and_get + fault checks that reset the board: 1 + -> ok + req KRN-TIM-031 +CASE wallclock_set_and_get outcome=passed asserts=8 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 60 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.json new file mode 100644 index 00000000..4d24d60b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 123, + "name": "wdog_feeds_until_a_party_misses", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "wdog_refusals", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:23Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdog" + }, + "exit": 0, + "fault_checks_by_reset": 4, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_wdog.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdog.uf2": "498f603a54c8683b0e67af3467ad688e010541a1f76459c089ea807617cac125" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog.elf", + "image_sha256": "a3bccc0495356dba366b8d1463ab5a68079d78e6f3f59def15103b7bf399acb3", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:21Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.log new file mode 100644 index 00000000..0b2bacbc --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog.elf sha256 a3bccc0495356dba366b8d1463ab5a68079d78e6f3f59def15103b7bf399acb3 +EVIDENCE v1 suite=test_wdog config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdog_feeds_until_a_party_misses + -> ok + req FLT-004 +CASE wdog_feeds_until_a_party_misses outcome=passed asserts=123 skips=0 +TEST wdog_refusals + fault checks that reset the board: 4 + -> ok + req FLT-004 +CASE wdog_refusals outcome=passed asserts=13 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 9 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.json new file mode 100644 index 00000000..842bcece --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.json @@ -0,0 +1,55 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 10, + "name": "wdog_board_hung_thread_resets_the_board", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:29Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdog_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_wdog_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdog_board.uf2": "62d0f39b545953fe7ff485750815c58a43674e80b21c3215737cd32a6a59b767" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdog_board.elf", + "image_sha256": "2b35dbd13537b8f816da43f55e3ac0ef3257b8a734f8984668d1eeab616cd0c4", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:26Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 1 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.log new file mode 100644 index 00000000..735df30b --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdog_board.log @@ -0,0 +1,10 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdog_board.elf sha256 2b35dbd13537b8f816da43f55e3ac0ef3257b8a734f8984668d1eeab616cd0c4 +EVIDENCE v1 suite=test_wdog_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdog_board_hung_thread_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdog_board_hung_thread_resets_the_board outcome=passed asserts=10 skips=0 +ISR_STACK size=2048 used=216 +1 tests, 0 failed, 0 skipped, 11 ticks +EMB_TEST_END \ No newline at end of file diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.json new file mode 100644 index 00000000..9e87f652 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 7, + "name": "wdt_not_ready_and_misuse", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 13, + "name": "wdt_start_feed_and_cause", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:21Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdt" + }, + "exit": 0, + "fault_checks_by_reset": 3, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_wdt.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdt.uf2": "c24ea0912573c0d1b528a3e93cb87daef62704258acd881f5c4c8aee8768cf3d" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt.elf", + "image_sha256": "c1aa435afe3aa53070e7510c7447c1630a078c8f77aeffa0543528e1d2413139", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:19Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.log new file mode 100644 index 00000000..96357969 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt.elf sha256 c1aa435afe3aa53070e7510c7447c1630a078c8f77aeffa0543528e1d2413139 +EVIDENCE v1 suite=test_wdt config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdt_not_ready_and_misuse + fault checks that reset the board: 3 + -> ok + req FLT-004 +CASE wdt_not_ready_and_misuse outcome=passed asserts=7 skips=0 +TEST wdt_start_feed_and_cause + -> ok + req FLT-004 +CASE wdt_start_feed_and_cause outcome=passed asserts=13 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 20 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.json new file mode 100644 index 00000000..c4c345c7 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.json @@ -0,0 +1,61 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 3, + "name": "wdt_board_starved_resets_the_board", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "wdt_board_refuses_what_it_cannot_count", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:37:26Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_wdt_board" + }, + "exit": 0, + "fault_checks_by_reset": 1, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_wdt_board.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_wdt_board.uf2": "57a77d4cc04b7444ff365c890c79dd72d5e2b631b5350323ae50b67723baee94" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_wdt_board.elf", + "image_sha256": "5edcbe909de54ac03b4a7cba8eb8fc732dc464dc66b5609469cb8470696f9823", + "isr_stack": { + "size": 2048, + "used": 216 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:37:24Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 2 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.log new file mode 100644 index 00000000..5534a9f6 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_wdt_board.log @@ -0,0 +1,14 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_wdt_board.elf sha256 5edcbe909de54ac03b4a7cba8eb8fc732dc464dc66b5609469cb8470696f9823 +EVIDENCE v1 suite=test_wdt_board config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST wdt_board_starved_resets_the_board + fault checks that reset the board: 1 + -> ok + req FLT-004 +CASE wdt_board_starved_resets_the_board outcome=passed asserts=3 skips=0 +TEST wdt_board_refuses_what_it_cannot_count + -> ok + req FLT-004 +CASE wdt_board_refuses_what_it_cannot_count outcome=passed asserts=3 skips=0 +ISR_STACK size=2048 used=216 +2 tests, 0 failed, 0 skipped, 23 ticks +EMB_TEST_END diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.json b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.json new file mode 100644 index 00000000..3e529152 --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.json @@ -0,0 +1,145 @@ +{ + "baud": 115200, + "bench": [], + "board": "pico2_w", + "cases": [ + { + "asserts": 2, + "name": "workq_define_constructs_in_init_table", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 10, + "name": "dwork_cancel_sync_waits_for_a_running_handler", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 19, + "name": "dwork_cancel_reports_pending_for_a_delay_and_a_queued_item", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "dwork_rescheduled_during_its_expiry_keeps_the_new_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_reschedule_replaces_the_delay", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 7, + "name": "dwork_runs_after_its_delay_and_schedule_is_idempotent", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_system_queue_runs_items", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 3, + "name": "workq_storage_reuse_requires_destroy", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_destroy_refuses_a_busy_queue", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 8, + "name": "workq_thread_is_a_kernel_thread", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_submit_from_isr_runs_at_exit", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "workq_flush_waits_for_items_queued_before_it", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 17, + "name": "workq_cancel_reports_pending_running_and_idle", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 12, + "name": "workq_item_belongs_to_one_queue_at_a_time", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 5, + "name": "workq_resubmit_while_running_runs_again", + "outcome": "passed", + "skips": 0 + }, + { + "asserts": 9, + "name": "workq_runs_items_in_fifo_order_on_its_thread", + "outcome": "passed", + "skips": 0 + } + ], + "ended": "2026-11-13T05:34:46Z", + "evidence": { + "board": "pico2_w", + "checked": "1", + "config": "9461e3c42192b75e", + "profile": "base", + "suite": "test_workq" + }, + "exit": 0, + "fault_checks_by_reset": 6, + "flash_command": [ + "picotool", + "load", + "-v", + "-x", + "/Users/teooff1700/EmbLinkRTOS/build/wt/hil/build/pico-gcc/tests/conformance/test_workq.uf2", + "-t", + "uf2" + ], + "flashed_sha256": { + "test_workq.uf2": "fb9741ac235e8e4ef05ae174065ef033f378ac12a7a1ab1e5a00198fd90654c3" + }, + "format": "emb-hil-run v1", + "git": { + "commit": "34dde4f3d84c0082aa1f0763aed41d6506ba1d06", + "dirty": false + }, + "image": "test_workq.elf", + "image_sha256": "7e44aeba619d382de93805afc36c072159582b77d223c456a48d930059a328c5", + "isr_stack": { + "size": 2048, + "used": 252 + }, + "outcome": "passed", + "port": "/dev/cu.usbmodem31103", + "soc": "RP2350A", + "started": "2026-11-13T05:34:43Z", + "summary": { + "failed": 0, + "skipped": 0, + "tests": 16 + } +} diff --git a/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.log b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.log new file mode 100644 index 00000000..940c305e --- /dev/null +++ b/docs/engineering/hil-runs/2026-11-13-pico2_w-logging-gcc/test_workq.log @@ -0,0 +1,73 @@ +hil: board pico2_w, soc RP2350A, probe picotool load -v, port /dev/cu.usbmodem31103 at 115200 baud, image test_workq.elf sha256 7e44aeba619d382de93805afc36c072159582b77d223c456a48d930059a328c5 +EVIDENCE v1 suite=test_workq config=9461e3c42192b75e profile=base board=pico2_w checked=1 +TEST workq_define_constructs_in_init_table + -> ok + req API-021 KRN-OBJ-009 +CASE workq_define_constructs_in_init_table outcome=passed asserts=2 skips=0 +TEST dwork_cancel_sync_waits_for_a_running_handler + -> ok + req KRN-WQ-007 KRN-WQ-006 +CASE dwork_cancel_sync_waits_for_a_running_handler outcome=passed asserts=10 skips=0 +TEST dwork_cancel_reports_pending_for_a_delay_and_a_queued_item + fault checks that reset the board: 1 + -> ok + req KRN-WQ-007 KRN-WQ-004 +CASE dwork_cancel_reports_pending_for_a_delay_and_a_queued_item outcome=passed asserts=19 skips=0 +TEST dwork_rescheduled_during_its_expiry_keeps_the_new_delay + -> ok + req KRN-WQ-007 KRN-TIM-024 +CASE dwork_rescheduled_during_its_expiry_keeps_the_new_delay outcome=passed asserts=9 skips=0 +TEST dwork_reschedule_replaces_the_delay + -> ok + req KRN-WQ-007 +CASE dwork_reschedule_replaces_the_delay outcome=passed asserts=7 skips=0 +TEST dwork_runs_after_its_delay_and_schedule_is_idempotent + -> ok + req KRN-WQ-003 KRN-WQ-007 +CASE dwork_runs_after_its_delay_and_schedule_is_idempotent outcome=passed asserts=7 skips=0 +TEST workq_system_queue_runs_items + -> ok + req KRN-WQ-008 +CASE workq_system_queue_runs_items outcome=passed asserts=3 skips=0 +TEST workq_storage_reuse_requires_destroy + fault checks that reset the board: 1 + -> ok + req KRN-OBJ-007 KRN-OBJ-011 +CASE workq_storage_reuse_requires_destroy outcome=passed asserts=3 skips=0 +TEST workq_destroy_refuses_a_busy_queue + fault checks that reset the board: 2 + -> ok + req KRN-OBJ-001 KRN-WQ-010 API-013 +CASE workq_destroy_refuses_a_busy_queue outcome=passed asserts=8 skips=0 +TEST workq_thread_is_a_kernel_thread + fault checks that reset the board: 2 + -> ok + req KRN-WQ-009 KRN-WQ-010 +CASE workq_thread_is_a_kernel_thread outcome=passed asserts=8 skips=0 +TEST workq_submit_from_isr_runs_at_exit + -> ok + req KRN-WQ-001 KRN-IRQ-010 +CASE workq_submit_from_isr_runs_at_exit outcome=passed asserts=5 skips=0 +TEST workq_flush_waits_for_items_queued_before_it + -> ok + req KRN-WQ-006 KRN-WAIT-012 +CASE workq_flush_waits_for_items_queued_before_it outcome=passed asserts=9 skips=0 +TEST workq_cancel_reports_pending_running_and_idle + -> ok + req KRN-WQ-004 KRN-WQ-006 +CASE workq_cancel_reports_pending_running_and_idle outcome=passed asserts=17 skips=0 +TEST workq_item_belongs_to_one_queue_at_a_time + -> ok + req KRN-WQ-005 +CASE workq_item_belongs_to_one_queue_at_a_time outcome=passed asserts=12 skips=0 +TEST workq_resubmit_while_running_runs_again + -> ok + req KRN-WQ-005 +CASE workq_resubmit_while_running_runs_again outcome=passed asserts=5 skips=0 +TEST workq_runs_items_in_fifo_order_on_its_thread + -> ok + req KRN-WQ-001 KRN-WQ-002 KRN-WQ-005 KRN-WQ-009 +CASE workq_runs_items_in_fifo_order_on_its_thread outcome=passed asserts=9 skips=0 +ISR_STACK size=2048 used=252 +16 tests, 0 failed, 0 skipped, 101 ticks +EMB_TEST_END diff --git a/docs/engineering/index.md b/docs/engineering/index.md index 3fc5f3a1..5d34e6ad 100644 --- a/docs/engineering/index.md +++ b/docs/engineering/index.md @@ -53,6 +53,7 @@ hil-watchdog-2026-11-10 hil-flash-2026-11-10 hil-rtc-2026-11-12 hil-entropy-2026-11-12 +hil-logging-trace-2026-11-13 bench-esp32-freertos-2026-11-06 bench-uno-freertos-2026-11-05 bench-pico2w-freertos-2026-11-07 diff --git a/docs/engineering/support-matrix.md b/docs/engineering/support-matrix.md index 2c930418..7b9ee284 100644 --- a/docs/engineering/support-matrix.md +++ b/docs/engineering/support-matrix.md @@ -22,9 +22,9 @@ The toolchains column names each compiler CI builds the board with, from its pre | `mps2_an500` | Cortex-M7 | cortex-m7f | 2 emulated | Clang, GCC | CI runs `cm7-an500`, `cm7-an500-clang`, `cm7-an500-release` | | `mps2_an505` | Cortex-M33 | cortex-m33f | 2 emulated | Clang, GCC | CI runs `cm33-an505`, `cm33-an505-clang`, `cm33-an505-release`, `cm33-an505-tiny` | | `native` | host | posix | 2 emulated | Clang, EmbCC, GCC, GCC or Clang | CI runs, on the host, `native-asan`, `native-clang`, `native-coverage`, `native-embcc`, `native-embcc-periodic`, `native-embcc-release`, `native-embcc-tiny`, `native-gcc`, `native-periodic`, `native-release`, `native-timeslice`, `native-timeslice-tickless`, `native-tiny`, `native-tsan` | -| `nucleo_f446re` | STM32F446RE | cortex-m4f | 1 hardware | GCC | `cm4-nucleo-hil` checked 26/26, release 26/26, checked 26/26, release 26/26 (2026-11-07, [report](hil-nucleo-2026-11-07.md)); `cm4-nucleo-hil` checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26 (2026-11-07, [report](perf-lto-2026-11-07.md)); `cm4-nucleo-hil` checked 28/28, checked 28/28 (2026-11-09, [report](hil-devices-2026-11-09.md)); `cm4-nucleo-hil` checked 31/31, checked 31/31 (2026-11-09, [report](hil-uart-2026-11-09.md)); `cm4-nucleo-hil` checked 33/33, checked 33/33, checked 34/34, checked 34/34 (2026-11-09, [report](hil-spi-2026-11-09.md)); `cm4-nucleo-hil` checked 36/36, checked 36/36, checked 36/36, checked 36/36 (2026-11-09, [report](hil-i2c-2026-11-09.md)); `cm4-nucleo-hil` checked 37/37, checked 37/37, checked 37/37, checked 37/37 (2026-11-09, [report](hil-dma-2026-11-09.md)); `cm4-nucleo-hil` checked 39/39, checked 39/39, checked 41/41, checked 41/41 (2026-11-09, [report](hil-watchdog-2026-11-10.md)); `cm4-nucleo-hil` checked 43/43, checked 43/43 (2026-11-10, [report](hil-flash-2026-11-10.md)); `cm4-nucleo-hil` checked 46/46, checked 46/46 (2026-11-12, [report](hil-rtc-2026-11-12.md)); `cm4-nucleo-hil` checked 47/47, checked 47/47 (2026-11-12, [report](hil-entropy-2026-11-12.md)); CI also runs `cm4-nucleo-embsim` | +| `nucleo_f446re` | STM32F446RE | cortex-m4f | 1 hardware | GCC | `cm4-nucleo-hil` checked 26/26, release 26/26, checked 26/26, release 26/26 (2026-11-07, [report](hil-nucleo-2026-11-07.md)); `cm4-nucleo-hil` checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26, checked 26/26, release 26/26 (2026-11-07, [report](perf-lto-2026-11-07.md)); `cm4-nucleo-hil` checked 28/28, checked 28/28 (2026-11-09, [report](hil-devices-2026-11-09.md)); `cm4-nucleo-hil` checked 31/31, checked 31/31 (2026-11-09, [report](hil-uart-2026-11-09.md)); `cm4-nucleo-hil` checked 33/33, checked 33/33, checked 34/34, checked 34/34 (2026-11-09, [report](hil-spi-2026-11-09.md)); `cm4-nucleo-hil` checked 36/36, checked 36/36, checked 36/36, checked 36/36 (2026-11-09, [report](hil-i2c-2026-11-09.md)); `cm4-nucleo-hil` checked 37/37, checked 37/37, checked 37/37, checked 37/37 (2026-11-09, [report](hil-dma-2026-11-09.md)); `cm4-nucleo-hil` checked 39/39, checked 39/39, checked 41/41, checked 41/41 (2026-11-09, [report](hil-watchdog-2026-11-10.md)); `cm4-nucleo-hil` checked 43/43, checked 43/43 (2026-11-10, [report](hil-flash-2026-11-10.md)); `cm4-nucleo-hil` checked 46/46, checked 46/46 (2026-11-12, [report](hil-rtc-2026-11-12.md)); `cm4-nucleo-hil` checked 47/47, checked 47/47 (2026-11-12, [report](hil-entropy-2026-11-12.md)); `cm4-nucleo-hil` checked 49/49, checked 49/49 (2026-11-13, [report](hil-logging-trace-2026-11-13.md)); CI also runs `cm4-nucleo-embsim` | | `nucleo_f446ze` | STM32F446ZE | cortex-m4f | 2 emulated | GCC | CI runs `cm4-nucleo-f446ze` | -| `pico2_w` | RP2350A | cortex-m33f | 1 hardware | GCC | `cm33-pico2w-hil` checked 27/27, release 27/27, checked 27/27, release 27/27 (2026-11-07, [report](hil-pico2w-2026-11-07.md)); `cm33-pico2w-hil` checked 29/29, checked 29/29 (2026-11-09, [report](hil-devices-2026-11-09.md)); `cm33-pico2w-hil` checked 32/32, checked 32/32 (2026-11-09, [report](hil-uart-2026-11-09.md)); `cm33-pico2w-hil` checked 34/34, checked 34/34, checked 35/35, checked 35/35 (2026-11-09, [report](hil-spi-2026-11-09.md)); `cm33-pico2w-hil` checked 37/37, checked 37/37, checked 37/37, checked 37/37 (2026-11-09, [report](hil-i2c-2026-11-09.md)); `cm33-pico2w-hil` checked 38/38, checked 38/38, checked 38/38, checked 38/38 (2026-11-09, [report](hil-dma-2026-11-09.md)); `cm33-pico2w-hil` checked 40/40, checked 40/40, checked 42/42, checked 42/42 (2026-11-09, [report](hil-watchdog-2026-11-10.md)); `cm33-pico2w-hil` checked 44/44, checked 44/44 (2026-11-10, [report](hil-flash-2026-11-10.md)); `cm33-pico2w-hil` checked 47/47, checked 47/47 (2026-11-12, [report](hil-rtc-2026-11-12.md)); `cm33-pico2w-hil` checked 49/49, checked 49/49 (2026-11-12, [report](hil-entropy-2026-11-12.md)) | +| `pico2_w` | RP2350A | cortex-m33f | 1 hardware | GCC | `cm33-pico2w-hil` checked 27/27, release 27/27, checked 27/27, release 27/27 (2026-11-07, [report](hil-pico2w-2026-11-07.md)); `cm33-pico2w-hil` checked 29/29, checked 29/29 (2026-11-09, [report](hil-devices-2026-11-09.md)); `cm33-pico2w-hil` checked 32/32, checked 32/32 (2026-11-09, [report](hil-uart-2026-11-09.md)); `cm33-pico2w-hil` checked 34/34, checked 34/34, checked 35/35, checked 35/35 (2026-11-09, [report](hil-spi-2026-11-09.md)); `cm33-pico2w-hil` checked 37/37, checked 37/37, checked 37/37, checked 37/37 (2026-11-09, [report](hil-i2c-2026-11-09.md)); `cm33-pico2w-hil` checked 38/38, checked 38/38, checked 38/38, checked 38/38 (2026-11-09, [report](hil-dma-2026-11-09.md)); `cm33-pico2w-hil` checked 40/40, checked 40/40, checked 42/42, checked 42/42 (2026-11-09, [report](hil-watchdog-2026-11-10.md)); `cm33-pico2w-hil` checked 44/44, checked 44/44 (2026-11-10, [report](hil-flash-2026-11-10.md)); `cm33-pico2w-hil` checked 47/47, checked 47/47 (2026-11-12, [report](hil-rtc-2026-11-12.md)); `cm33-pico2w-hil` checked 49/49, checked 49/49 (2026-11-12, [report](hil-entropy-2026-11-12.md)); `cm33-pico2w-hil` checked 51/51, checked 51/51 (2026-11-13, [report](hil-logging-trace-2026-11-13.md)) | | `riscv32_virt` | qemu-virt-rv32 | rv32imac | 2 emulated | Clang, GCC | CI runs `rv32-virt`, `rv32-virt-clang`, `rv32-virt-release`, `rv32-virt-release-clang`, `rv32-virt-tiny` | Totals: 1 hardware: 4, 2 emulated: 9, 3 described: 0, untested: 0. From d0a94f7c35e0b5842f966a4cced8e15bb6cd54f7 Mon Sep 17 00:00:00 2001 From: teo1747 Date: Fri, 13 Nov 2026 07:05:16 +0100 Subject: [PATCH 25/25] analysis: the MISRA baseline after merging #146 Taken from CI's misra-baseline-now at 6e4f4afa. The two generated headers both branches added to (config.h, api_ids.h) count both sides' macros; the counts the merge kept at the higher of the two come down to what the code has. Signed-off-by: teo1747 --- tools/analysis/misra-baseline.json | 91 ++++++------------------------ 1 file changed, 16 insertions(+), 75 deletions(-) diff --git a/tools/analysis/misra-baseline.json b/tools/analysis/misra-baseline.json index d24667c7..5e0d2c2e 100644 --- a/tools/analysis/misra-baseline.json +++ b/tools/analysis/misra-baseline.json @@ -99,7 +99,7 @@ "misra-c2012-21.8": 2, "misra-c2012-22.8": 1, "misra-c2012-22.9": 1, - "misra-c2012-8.7": 22, + "misra-c2012-8.7": 20, "misra-c2012-8.9": 1 }, "arch/riscv/include/emb_arch.h": { @@ -132,124 +132,67 @@ "misra-c2012-8.6": 2, "misra-c2012-8.7": 6 }, - "boards/arduino/arduino_uno/generated/hw_config.h": { - "misra-c2012-2.5": 53 - }, "boards/arduino/arduino_uno/generated/include/hw_config.h": { "misra-c2012-2.5": 53 }, - "boards/arduino/arduino_uno/generated/soc_devices.c": { - "misra-c2012-2.3": 1 - }, "boards/arduino/arduino_uno/generated/src/soc_devices.c": { "misra-c2012-2.3": 1 }, - "boards/arm/mps2_an386/generated/hw_config.h": { - "misra-c2012-2.5": 16 - }, "boards/arm/mps2_an386/generated/include/hw_config.h": { "misra-c2012-2.5": 16 }, "boards/arm/mps2_an386/generated/include/soc_devices.h": { "misra-c2012-2.5": 4 }, - "boards/arm/mps2_an386/generated/soc_devices.c": { - "misra-c2012-8.7": 2 - }, - "boards/arm/mps2_an386/generated/soc_devices.h": { - "misra-c2012-2.5": 4 - }, "boards/arm/mps2_an386/generated/src/soc_devices.c": { "misra-c2012-8.7": 2 }, - "boards/arm/mps2_an505/generated/hw_config.h": { - "misra-c2012-2.5": 16 - }, "boards/arm/mps2_an505/generated/include/hw_config.h": { "misra-c2012-2.5": 16 }, "boards/arm/mps2_an505/generated/include/soc_devices.h": { "misra-c2012-2.5": 4 }, - "boards/arm/mps2_an505/generated/soc_devices.c": { - "misra-c2012-8.7": 2 - }, - "boards/arm/mps2_an505/generated/soc_devices.h": { - "misra-c2012-2.5": 4 - }, "boards/arm/mps2_an505/generated/src/soc_devices.c": { "misra-c2012-8.7": 2 }, - "boards/bbc/microbit/generated/hw_config.h": { - "misra-c2012-2.5": 16 - }, "boards/bbc/microbit/generated/include/hw_config.h": { "misra-c2012-2.5": 16 }, - "boards/bbc/microbit/generated/soc_devices.c": { - "misra-c2012-2.3": 1 - }, "boards/bbc/microbit/generated/src/soc_devices.c": { "misra-c2012-2.3": 1 }, "boards/native/native/board.c": { "misra-c2012-21.6": 2, - "misra-c2012-8.7": 4 + "misra-c2012-8.7": 3 }, "boards/native/native/include/emb_board.h": { "misra-c2012-2.5": 1 }, - "boards/qemu/riscv32_virt/generated/hw_config.h": { - "misra-c2012-2.5": 11 - }, "boards/qemu/riscv32_virt/generated/include/hw_config.h": { "misra-c2012-2.5": 11 }, "boards/qemu/riscv32_virt/generated/include/soc_devices.h": { "misra-c2012-2.5": 1 }, - "boards/qemu/riscv32_virt/generated/soc_devices.h": { - "misra-c2012-2.5": 1 - }, - "boards/rpi/pico2_w/generated/boot_block.c": { - "misra-c2012-8.4": 1 - }, - "boards/rpi/pico2_w/generated/hw_config.h": { - "misra-c2012-2.5": 42 - }, "boards/rpi/pico2_w/generated/include/hw_config.h": { "misra-c2012-2.5": 42 }, "boards/rpi/pico2_w/generated/include/soc_devices.h": { "misra-c2012-2.5": 27 }, - "boards/rpi/pico2_w/generated/soc_devices.c": { - "misra-c2012-8.7": 7 - }, - "boards/rpi/pico2_w/generated/soc_devices.h": { - "misra-c2012-2.5": 27 - }, "boards/rpi/pico2_w/generated/src/boot_block.c": { "misra-c2012-8.4": 1 }, "boards/rpi/pico2_w/generated/src/soc_devices.c": { "misra-c2012-8.7": 7 }, - "boards/st/nucleo_f446re/generated/hw_config.h": { - "misra-c2012-2.5": 134 - }, "boards/st/nucleo_f446re/generated/include/hw_config.h": { "misra-c2012-2.5": 134 }, "boards/st/nucleo_f446re/generated/include/soc_devices.h": { "misra-c2012-2.5": 28 }, - "boards/st/nucleo_f446re/generated/soc_devices.c": { - "misra-c2012-8.7": 9 - }, - "boards/st/nucleo_f446re/generated/soc_devices.h": { - "misra-c2012-2.5": 28 - }, "boards/st/nucleo_f446re/generated/src/soc_devices.c": { "misra-c2012-8.7": 9 }, @@ -436,20 +379,18 @@ "misra-config": 3 }, "examples/controller/main.c": { - "misra-c2012-10.4": 9, + "misra-c2012-10.4": 6, "misra-c2012-10.8": 1, "misra-c2012-12.1": 28, "misra-c2012-13.3": 3, "misra-c2012-15.7": 3, "misra-c2012-17.7": 4, "misra-c2012-17.8": 1, - "misra-c2012-19.2": 6, - "misra-c2012-8.4": 6, - "misra-c2012-8.9": 8, - "misra-config": 5 + "misra-c2012-8.9": 2, + "misra-config": 2 }, "generated/include/emb/config.h": { - "misra-c2012-2.5": 97 + "misra-c2012-2.5": 98 }, "generated/include/emb/storage.h": { "misra-c2012-19.2": 20, @@ -457,7 +398,7 @@ "misra-c2012-5.6": 16 }, "include/emb/api_ids.h": { - "misra-c2012-2.5": 195 + "misra-c2012-2.5": 201 }, "include/emb/compiler.h": { "misra-c2012-17.8": 3, @@ -474,7 +415,7 @@ "misra-c2012-21.1": 2 }, "include/emb/compiler/gcc.h": { - "misra-c2012-2.5": 5, + "misra-c2012-2.5": 3, "misra-c2012-20.10": 2, "misra-c2012-20.7": 1 }, @@ -700,7 +641,7 @@ "misra-c2012-12.1": 11, "misra-c2012-2.5": 1, "misra-c2012-8.11": 1, - "misra-c2012-8.7": 14 + "misra-c2012-8.7": 13 }, "kernel/fault/crash.c": { "misra-c2012-10.5": 1, @@ -892,7 +833,7 @@ }, "kernel/trace/trace.c": { "misra-c2012-11.1": 1, - "misra-c2012-8.7": 2 + "misra-c2012-8.7": 1 }, "kernel/wait/wait.c": { "misra-c2012-10.8": 1, @@ -938,7 +879,7 @@ "misra-c2012-11.4": 1, "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 1, "misra-c2012-8.7": 2 }, @@ -950,7 +891,7 @@ "misra-c2012-10.8": 2, "misra-c2012-11.5": 1, "misra-c2012-12.1": 1, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.7": 4 }, "soc/microchip/atmega/include/emb_board.h": { @@ -962,7 +903,7 @@ "misra-c2012-11.4": 6, "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 1, "misra-c2012-8.7": 2 }, @@ -975,7 +916,7 @@ "misra-c2012-11.4": 4, "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 2, "misra-c2012-8.7": 2 }, @@ -988,7 +929,7 @@ "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, "misra-c2012-12.2": 5, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-2.5": 3, "misra-c2012-8.6": 2, "misra-c2012-8.7": 2 @@ -1005,7 +946,7 @@ "misra-c2012-10.8": 1, "misra-c2012-11.5": 1, "misra-c2012-12.1": 2, - "misra-c2012-17.8": 2, + "misra-c2012-17.8": 1, "misra-c2012-8.6": 2, "misra-c2012-8.7": 2 },