Files
workspace-info/plans/informatyka/freertos-first-task-a1-a8.md
T

380 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Paired FC02/K02 Plan — First FreeRTOS Task through A1A8
Status: agreed paired design; FC02 C and K02 C++ now have local
implementations that follow the shared E01E12 contract.
This plan defines one controlled teaching experiment rendered twice:
- **FC02 / FreeRTOS C:** raw `TaskFunction_t`, `void *pvParameters`,
`TaskHandle_t` and `xTaskCreate`;
- **K02 / FreeRTOS C++:** the existing header-only `Task<Derived>` CRTP
wrapper, explicit `start()` and static trampoline.
The design remains the comparison contract. FC02 now has a local executable,
HTML and TeX implementation; PDF generation and publication remain separate
operations.
## Learning question
The student must be able to answer one question with source, binary and
runtime evidence:
> What remains identical when a FreeRTOS task is expressed through raw C or a
> small C++ wrapper, and what new compile-time and runtime boundaries does the
> wrapper introduce?
The C and C++ cards therefore use the same calculation and kernel behaviour.
Only the language-facing task abstraction changes.
## Curriculum position
```text
C pointers
→ C structures and memory regions
→ heap_4 mechanics in C
→ FC02 raw FreeRTOS task in C
→ C++ language/OOP prerequisites
→ K02 FreeRTOS task wrapper in C++
→ later lifetime, RAII, communication and synchronization cards
```
FC02 establishes the raw kernel boundary first. K02 reuses that known
behaviour and makes the abstraction delta observable instead of teaching the
kernel and C++ wrapper as two simultaneous unknowns.
## Controlled experiment contract
Both cards must share these invariants:
| Property | Required value |
|---|---|
| Kernel | FreeRTOS-Kernel V11.3.0, same pinned source revision |
| Target | RV32I/Hazard3 simulator, cycle-exact teaching profile |
| Workers | two equal-priority CPU-bound workers, created before the scheduler |
| Work | sum integers `1..20000` independently |
| Expected result | `200010000` for each worker |
| Supervisor | one lower-priority task validates both workers |
| Scheduling proof | elapsed work crosses at least two ticks and records `A -> B -> A` |
| Allocation | dynamic `xTaskCreate` backed by the same `heap_4` configuration |
| Completion | diagnostic state/result is published before self-delete: `NULL` in C, `nullptr` in C++ |
| Replay | clean RAM and a new generation for every requested RUN checkpoint |
The comparison is valid only when the two builds also use byte-identical
`FreeRTOSConfig.h`, the same tick rate, time-slicing setting, priorities, stack
depths, worker creation order and checkpoint-sink signature. CI must compare
those inputs rather than relying on prose.
Language flags differ only where the lesson requires it:
- FC02: freestanding C11;
- K02: freestanding C++17, no exceptions, no RTTI and no hosted C++ runtime.
The workload must remain present in disassembly. Bounds, trace writes and
published results are observable; a compiler-folded constant is a failed
teaching build.
## A1A8 is a palette, not a quota
The stable viewer keeps all eight positions. A card enables only viewpoints
that answer a real question. An unavailable tab remains visible with a short
reason, and the print index repeats that reason.
| Viewpoint | FC02 C | K02 C++ | Reason |
|---|---:|---:|---|
| A1 CONTEXT | yes | yes | system and language boundaries |
| A2 STRUCTURE | yes | yes | C contexts/handles versus C++ classes/fields |
| A3 DISPATCH | yes | yes | C function pointer versus CRTP trampoline |
| A4 APPLICATION | no | yes | raw C module already is the application; C++ specializes a generic wrapper |
| A5 FLOW | yes | yes | common E01E12 scenario |
| A6 STATE | yes | yes | diagnostic/language lifetime separated from kernel task state |
| A7 RUNTIME | yes | yes | addresses, TCB, stack, registers, PC and ticks |
| A8 PATTERNS | no | yes | a separate C pattern view would be decorative; K02 provides the comparison |
FC02 may label local idioms such as **context object**, **opaque handle** and
**C callback ABI** in A2/A3. It must not manufacture an A8 diagram merely to
fill the tab.
## Teaching hierarchy
Each applicable viewpoint is a normal `Block`. This preserves the existing
card tree and does not add a new hierarchy level.
```text
Series
└── Card
└── Task01 · First FreeRTOS task
├── Block · A1 CONTEXT
├── Block · A2 STRUCTURE
├── Block · A3 DISPATCH
├── Block · A4 APPLICATION K02 only
├── Block · A5 FLOW
│ ├── Phase · CREATE / START
│ └── Phase · DISPATCH / FINISH
├── Block · A6 STATE
│ ├── Phase · LANGUAGE / DIAGNOSTIC
│ └── Phase · KERNEL
├── Block · A7 RUNTIME
│ ├── Phase · MEMORY
│ └── Phase · CPU / SCHEDULER
├── Block · A8 PATTERNS K02 only
└── Exercise · Paired timestamped trace
```
The A1A8 top strip jumps to its block. `Up/Down` walks steps inside a block;
`Ctrl+Up/Down` crosses blocks. Cursor movement is inert. `Enter` in the viewer
and `F2` from Neovim explicitly activate the selected item.
## Common semantic event vocabulary
Snapshot identifiers remain local to each card and container. A shared
`event_id` makes the observations comparable without pretending that one
debugger checkpoint can be reused across two binaries.
| Event | Shared meaning | FC02 C boundary | K02 C++ boundary |
|---|---|---|---|
| E01 | application representation prepared | static worker contexts initialized | static `SumTask` objects constructed |
| E02 | launch interface entered | first raw create request | first `workerA.start()` entry |
| E03 | kernel create boundary | `xTaskCreate(entry, ctx)` | `xTaskCreate(trampoline, this)` |
| E04 | task ready and handle stored | context handle is non-null | wrapper state `ready`, handle non-null |
| E05 | scheduler start | `vTaskStartScheduler()` | `vTaskStartScheduler()` |
| E06 | C callback entry | `sum_task_entry(void *)` | static `trampoline(void *)` |
| E07 | calculation running | typed `WorkerContext *` body | `SumTask::run()` and state `running` |
| E08 | deterministic time slice | worker A observes `A -> B -> A` | worker A observes `A -> B -> A` |
| E09 | result published | context/global result stored | `g_results[id]` stored, `run()` returns |
| E10 | diagnostic completion | context state complete, public handle cleared | wrapper state complete, public handle cleared |
| E11 | current task self-deletes | `vTaskDelete(NULL)` | `vTaskDelete(nullptr)` |
| E12 | lower-priority supervisor passes | raw context invariants pass | wrapper/object invariants pass |
E02 is the first launch hit and is guarded by prior checkpoint state. E08 is
pinned to worker A. Per-instance conditions must prevent worker B from
accidentally satisfying worker A checkpoints.
The supervisor executes before the idle task necessarily reclaims deleted
TCBs. Heap reclamation is therefore not an E01E12 acceptance event. A7 may
measure allocator deltas, but it must describe them as observations at a
defined instant.
## CODE and RUN semantics
An interactive anchor has one of two modes:
- **CODE** selects source or a deterministic binary query. It never resets or
runs the target and does not require `snapshot_ref`.
- **RUN** opens the associated source and performs a clean deterministic
replay to its card-local `snapshot_ref`.
Compile-time facts—types, inheritance, `friend`, field layout, absence of
virtual dispatch and ABI restrictions—are CODE facts. Scheduling, registers,
task states and memory values are RUN facts. A class diagram must never fake a
runtime event.
Repeated visible step numbers are permitted in different blocks, but tooling
must address a step by its full `task/block/phase/step` key. A bare ambiguous
`--step` request is rejected.
## Debug strategy attached to every step
Every selectable UML anchor owns one default debugging strategy. The strategy
is keyed by the full navigation position rather than embedded as unstructured
prose in the step.
```text
strategy
├── id and kind: code | run
├── prerequisites: card, profile, target and required artifact
├── code_ref: repository-validated file and line/range
├── action: open | replay
├── layout: source, asm, registers, stack, memory, kernel state
├── commands: deterministic GDB or artifact queries
├── expected_observations
├── assertions
└── evidence_fields
```
RUN assertions reuse `debug_checkpoints.verify.expressions`. CODE assertions
are exact command/pattern pairs over an identified ELF or source blob, for
example `nm`, `readelf` or a bounded disassembly query. A screenshot of an
unidentified terminal is not sufficient CODE evidence.
The minimum Termdebug observation set is chosen per step, not displayed by
habit:
- source and assembly at the boundary being taught;
- `a0` only where the RV32 ABI still carries the callback argument;
- `sp` and task stack interval where stack ownership is the question;
- object/context address, public handle and TCB address where identity is the
question;
- PC, tick and trace when scheduling is the question;
- result and diagnostic state when completion is the question.
`pxCurrentTCB` may be inspected by the debugger and is marked **kernel
internal**. Card code uses public FreeRTOS APIs and does not make this symbol a
program contract.
## Visual and code evidence contract
Each UML element has a visible numbered anchor and a stable authored
`svg_target`. Selection by mouse and keyboard controls the same cursor.
- disabled content remains readable and uses a neutral outline plus an
explicit unavailable marker/reason;
- selectable inactive neighbours alternate two restrained treatments so their
hit areas remain distinguishable;
- active selection adds a stronger outline, small positional marker and light
fill;
- focus, selectability and completion remain distinguishable in grayscale and
do not rely on hue alone;
- non-selected elements remain legible rather than disappearing.
Code shown beside a diagram is read-only evidence. Neovim remains the editor
and live debugger. The component receives a validated `code_ref`, source blob
hash and explicit highlighted line range; it never fetches an arbitrary file
path supplied by the browser.
The planned `CodeEvidence` pipeline uses **Shiki at generator/build time**, not
as a browser editor or runtime highlighter. A fine-grained, version-pinned
highlighter loads only `c`, `cpp`, `riscv`, `shellscript` and `json`, produces
flat per-line token arrays, and the React viewer renders that allow-listed
data. This keeps the browser bundle free of the regex/WASM engine while
retaining an actual RISC-V TextMate grammar and exact line/range classes.
Rendering never relies on `dangerouslySetInnerHTML`.
A custom Shiki theme emits CSS-variable values rather than stock-theme hex
colours. Light, dark and print treatments therefore remain viewer CSS
decisions. Assembly source uses the `riscv` grammar directly. Objdump `.lst`
input first passes through a small deterministic column parser: address, byte
and symbol fields receive fixed semantic classes, while only the instruction
tail is tokenized as RISC-V. A non-matching listing line falls back to plain
text. Disassembly keeps `white-space: pre` and horizontal scrolling rather
than soft wrapping.
## Audit chain and later evidence capture
The intended chain is:
```text
goal and scope
→ applicable A1A8 viewpoints
→ UML anchor
→ checkpoint debugging strategy
→ CODE proof or RUN replay
→ Neovim + Termdebug + Hazard3 measurement
→ approved checkpoint
→ later composite screenshot
→ later lesson report
```
Approval must be bound to `snapshot_ref`, replay generation and verification
result. A later capture must reject stale identity/generation, retain the raw
PNG, store an image SHA-256 and record backend timestamp, card/version/source
hash, target, event, checkpoint and viewer state. Metadata is rendered from
the database rather than burned irreversibly into the original image.
This plan does **not** implement screenshot capture or report generation.
## Page plan
### FC02 — seven sheets
1. goal, scope, experiment invariants and viewpoint index;
2. compact A1 plus main A2;
3. A3 callback/parameter dispatch;
45. joined A5 CREATE/START and DISPATCH/FINISH spread;
6. A6 diagnostic and kernel state lanes;
7. A7 runtime evidence plus exercise.
A4 and A8 are printed in the index as unavailable with their reasons.
### K02 — eight sheets
1. goal, scope, experiment invariants and viewpoint index;
2. compact A1 plus main A2;
3. main A3 plus compact A4;
45. joined A5 CREATE/START and DISPATCH/FINISH spread;
6. A6 object/wrapper and kernel state lanes;
7. A7 runtime evidence;
8. A8 C-versus-wrapper role table plus exercise and rubric.
One diagram must fit the content box. A long logical diagram is split only at
a phase/group boundary and shares a `spread_group`; the viewer may join those
sheets side by side without changing print pagination.
## Acceptance gates for a future implementation
1. Parity check proves common kernel/config/workload/priority/stack inputs.
2. Every enabled viewpoint has purpose, model kind and ordered anchors.
3. Every disabled viewpoint has a non-empty reason.
4. Every `svg_target` resolves after rendering and anchor order passes lint.
5. Every CODE step has a validated code/artifact proof and no snapshot.
6. Every RUN step has a card-local snapshot and non-empty assertions.
7. E01E12 are unique, ordered and comparable across the two cards.
8. A clean replay produces two sums of `200010000` and the `A -> B -> A`
trace.
9. FC02 has C-only ABI evidence; K02 has no exceptions, RTTI, vtables or hosted
runtime.
10. Navigation never mutates the simulator until explicit `Enter`/`F2`.
11. No program assertion depends on undocumented kernel internals.
12. Print remains meaningful without viewer controls or colour.
## Decisions from the Claude review
Accepted corrections:
- treat viewpoints as blocks and A1A8 as an optional palette;
- enforce the paired-experiment parity gates in tooling;
- add shared semantic `event_id` while keeping snapshots card-local;
- validate viewpoint availability, anchors, RUN snapshots and strategies;
- make assertions mandatory rather than merely displaying observations;
- bind approval and later capture to a verified replay generation;
- support deterministic text evidence for CODE steps;
- pre-tokenize source with fine-grained Shiki grammars and keep the React
component display-only;
- pin the highlighter/grammar versions and test the objdump-column parser with
fixed listing fixtures;
- distinguish diagnostic state from `eTaskState` and mark kernel internals;
- keep idle-task reclamation outside E01E12.
Rejected for these cards:
- replacing K02 CRTP with the upstream virtual `TaskBase` design;
- forcing A4/A8 into FC02;
- automatic replay on cursor movement;
- claiming RAII or ownership semantics before the later lifetime card;
- using `pxCurrentTCB` as application code;
- treating a class relationship as a runtime checkpoint.
## Deferred curriculum envelope — not part of this implementation
For Year 2, a later curriculum pass will attach three coordinated layers to a
lesson:
1. one FreeRTOS mechanism/concurrent algorithm being learned, for example a
task or queue;
2. one algorithm selected from the course book;
3. one examination task selected from the current matura schedule/material.
The current technology is the execution medium, not a decorative appendix:
- a bare-C card implements and debugs the work in bare C;
- a FreeRTOS-C task card places suitable work inside raw C task(s);
- a FreeRTOS-C++ card expresses the same responsibility through the wrapper
under study.
Later work may capture approved UML/debugger evidence, compose a lesson report,
generate a PDF and prepare it for Teams. None of that is implemented or
assigned to FC02/K02 by this plan.
## Primary references
- FreeRTOS task creation:
<https://www.freertos.org/Documentation/02-Kernel/04-API-references/01-Task-creation/01-xTaskCreate>
- FreeRTOS task states:
<https://www.freertos.org/Documentation/02-Kernel/02-Kernel-features/01-Tasks-and-co-routines/02-Task-states>
- FreeRTOS task implementation and self-deletion:
<https://www.freertos.org/Documentation/02-Kernel/02-Kernel-features/01-Tasks-and-co-routines/05-Implementing-a-task>
- Shared A1A8 convention:
`tools/card-layouts/docs/UML-VIEWPOINTS.md`
- Shiki bundled languages and transformers:
<https://shiki.style/languages>,
<https://shiki.style/packages/transformers>