1270 lines
42 KiB
JSON
1270 lines
42 KiB
JSON
{
|
||
"$schema": "../../../tools/card-layouts/schemas/card-source.schema.json",
|
||
"schema": "esc-card-source.v1",
|
||
"card": {
|
||
"id": "mpabi-freertos-c-04-delay-state",
|
||
"series": "freertos-c",
|
||
"series_title": "FreeRTOS C",
|
||
"number": "04",
|
||
"count": "15",
|
||
"slug": "delay-state",
|
||
"title": "Delay, blokowanie, stany taska i usuwanie",
|
||
"topic": "vTaskDelayUntil, Blocked, Suspended i vTaskDelete",
|
||
"project": "Freestanding C nad FreeRTOS",
|
||
"subject": "Informatyka",
|
||
"level": "Rok 2 · L04 · RV32I/Hazard3",
|
||
"revision_date": "2026-07-19T00:00:00+02:00",
|
||
"status": "Gotowa",
|
||
"version": "v00.01",
|
||
"uuid": "7691d61c-eaae-5228-b9c8-fa42527b75b9",
|
||
"author": "M. Pabiszczak",
|
||
"year": "2026"
|
||
},
|
||
"generated": {
|
||
"tex": "doc/generated/main.tex",
|
||
"html": "web/index.html",
|
||
"html_css": "web/style.css",
|
||
"html_tree_inspector": false,
|
||
"react_app": true
|
||
},
|
||
"render_dictionary": false,
|
||
"viewpoints": [
|
||
{
|
||
"id": "A1",
|
||
"label": "CONTEXT",
|
||
"subtitle": "Granice systemu",
|
||
"status": "unavailable",
|
||
"reason": "Granica aplikacja–kernel–Hazard3 nie zmienia się względem FC03."
|
||
},
|
||
{
|
||
"id": "A2",
|
||
"label": "STRUCTURE",
|
||
"subtitle": "Konteksty i oś wybudzeń",
|
||
"status": "enabled",
|
||
"target_label": "fig:a2-structure"
|
||
},
|
||
{
|
||
"id": "A3",
|
||
"label": "DISPATCH",
|
||
"subtitle": "Callback ABI",
|
||
"status": "unavailable",
|
||
"reason": "TaskFunction_t i void* zostały udowodnione w FC02."
|
||
},
|
||
{
|
||
"id": "A4",
|
||
"label": "APPLICATION",
|
||
"subtitle": "Topologia",
|
||
"status": "unavailable",
|
||
"reason": "Topologia trzech tasków jest już kompletna w A2 i A5."
|
||
},
|
||
{
|
||
"id": "A5",
|
||
"label": "FLOW",
|
||
"subtitle": "E01–E10 od startu do PASS",
|
||
"status": "enabled",
|
||
"target_label": "fig:a5-flow"
|
||
},
|
||
{
|
||
"id": "A6",
|
||
"label": "STATE",
|
||
"subtitle": "Ready, Running, Blocked, Suspended, Deleted",
|
||
"status": "enabled",
|
||
"target_label": "fig:a6-state"
|
||
},
|
||
{
|
||
"id": "A7",
|
||
"label": "RUNTIME",
|
||
"subtitle": "eTaskState, TCB, stack i tick",
|
||
"status": "enabled",
|
||
"target_label": "fig:a7-runtime"
|
||
},
|
||
{
|
||
"id": "A8",
|
||
"label": "PATTERNS",
|
||
"subtitle": "Wzorce",
|
||
"status": "unavailable",
|
||
"reason": "Karta bada semantykę stanu kernela, nie wzorzec aplikacyjny."
|
||
}
|
||
],
|
||
"debug_strategies": {
|
||
"code.state-model": {
|
||
"id": "code.state-model",
|
||
"kind": "code",
|
||
"action": "open",
|
||
"expected_observations": [
|
||
"stan aplikacyjny i eTaskState są osobnymi pojęciami",
|
||
"context pozostaje po self-delete"
|
||
],
|
||
"assertions": [
|
||
"Blocked ma warunek wybudzenia",
|
||
"Suspended nie ma automatycznego wake tick"
|
||
],
|
||
"evidence_fields": [
|
||
"code_ref",
|
||
"typ pola",
|
||
"kotwica UML"
|
||
],
|
||
"prerequisites": [
|
||
"źródło FC04"
|
||
],
|
||
"layout": [
|
||
"nagłówek kontekstów",
|
||
"kod tasków",
|
||
"diagram stanu"
|
||
],
|
||
"commands": [
|
||
"rg -n 'PeriodicContext|SuspendContext|eTaskState|Fc04Phase' include src"
|
||
]
|
||
},
|
||
"run.state": {
|
||
"id": "run.state",
|
||
"kind": "run",
|
||
"action": "replay",
|
||
"expected_observations": [
|
||
"observer widzi eBlocked i eSuspended",
|
||
"resume wybiera wyższy task"
|
||
],
|
||
"assertions": [
|
||
"publiczne handle są ważne podczas obserwacji",
|
||
"każdy task czyści własny handle"
|
||
],
|
||
"evidence_fields": [
|
||
"event_id",
|
||
"state",
|
||
"handle",
|
||
"PC",
|
||
"SP",
|
||
"timestamp"
|
||
],
|
||
"prerequisites": [
|
||
"Hazard3 online",
|
||
"czysta RAM"
|
||
],
|
||
"layout": [
|
||
"source",
|
||
"eTaskState",
|
||
"handle/TCB",
|
||
"PC/SP"
|
||
],
|
||
"commands": [
|
||
"print g_periodic",
|
||
"print g_suspend_target",
|
||
"print g_observer"
|
||
]
|
||
},
|
||
"run.timeline": {
|
||
"id": "run.timeline",
|
||
"kind": "run",
|
||
"action": "replay",
|
||
"expected_observations": [
|
||
"kolejne delty wynoszą dokładnie 2",
|
||
"task jest Blocked między wybudzeniami"
|
||
],
|
||
"assertions": [
|
||
"release count=3",
|
||
"SP mieści się w stack range"
|
||
],
|
||
"evidence_fields": [
|
||
"initial tick",
|
||
"release ticks",
|
||
"SP",
|
||
"stack range"
|
||
],
|
||
"prerequisites": [
|
||
"scheduler uruchomiony",
|
||
"period=2"
|
||
],
|
||
"layout": [
|
||
"vTaskDelayUntil call",
|
||
"wake ticks",
|
||
"task stack"
|
||
],
|
||
"commands": [
|
||
"print g_periodic.initial_tick",
|
||
"print g_periodic.release_tick",
|
||
"print g_periodic.release_count"
|
||
]
|
||
},
|
||
"run.pass": {
|
||
"id": "run.pass",
|
||
"kind": "run",
|
||
"action": "replay",
|
||
"expected_observations": [
|
||
"timeline 2/4/6",
|
||
"resumed=1",
|
||
"PASS=1"
|
||
],
|
||
"assertions": [
|
||
"observer uruchamia się po wyższych taskach",
|
||
"forensic context nie jest dereferencją usuniętego TCB"
|
||
],
|
||
"evidence_fields": [
|
||
"PASS",
|
||
"timeline",
|
||
"source blob",
|
||
"image hash",
|
||
"timestamp"
|
||
],
|
||
"prerequisites": [
|
||
"oba taski robocze zakończone"
|
||
],
|
||
"layout": [
|
||
"contexts",
|
||
"timeline",
|
||
"final assertions"
|
||
],
|
||
"commands": [
|
||
"print g_fc04_pass",
|
||
"print g_periodic",
|
||
"print g_suspend_target"
|
||
]
|
||
}
|
||
},
|
||
"template": "templates/karta-klasyczna.json",
|
||
"title_block": {
|
||
"category": "KARTA PRACY · INFORMATYKA",
|
||
"prepared_by": "M. Pabiszczak",
|
||
"prepared_on": "2026-07-19T00:00:00+02:00",
|
||
"title": "Delay, blokowanie, stany taska i usuwanie",
|
||
"url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/4a7ef04c-ab08-5783-9192-5b02a90f05f8",
|
||
"repository_url": "https://zsl-gitea.mpabi.pl/edu-freertos-c/lab-rv32i-freertos-c-delay-state",
|
||
"url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84",
|
||
"url_domain": "mpabi.pl",
|
||
"doc_uuid": "4a7ef04c-ab08-5783-9192-5b02a90f05f8",
|
||
"revision": "v00.01",
|
||
"issued_on": "2026-07-19T00:00:00+02:00",
|
||
"series": "FREERTOS-C-04",
|
||
"document_type": "karta pracy",
|
||
"tool": "card-layouts",
|
||
"show_qr": true,
|
||
"show_repository_qr": true,
|
||
"height_cm": 2.6,
|
||
"repeat_on_every_page": true,
|
||
"replace_front_matter": true
|
||
},
|
||
"front_page_scope": {
|
||
"title": "Cel karty",
|
||
"content_tex": "Uczeń odróżnia Ready, Running, Blocked, Suspended i Deleted oraz wiąże każdy stan z konkretną przyczyną i publiczną obserwacją FreeRTOS.",
|
||
"scope_title": "Zakres karty",
|
||
"scope_content_tex": "Task okresowy budzi się co dwa ticki przez vTaskDelayUntil. Drugi task zawiesza się bez warunku czasowego i jest jawnie wznawiany. Observer sprawdza publiczne eTaskState, dokładną oś 2/4/6, osobny stos i bezpieczny zapis przed self-delete.",
|
||
"scope_table": {
|
||
"headers": [
|
||
"Lekcja",
|
||
"Task",
|
||
"Najważniejsza idea",
|
||
"Priorytet",
|
||
"Status",
|
||
"Version"
|
||
],
|
||
"rows": [
|
||
{
|
||
"chapter": "FC04",
|
||
"task": "Task01",
|
||
"idea_tex": "vTaskDelayUntil, Blocked, Suspended i vTaskDelete",
|
||
"priority": "główny",
|
||
"status": "ready",
|
||
"version": "v00.01",
|
||
"key": true
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"side_margin_tree_layout": {
|
||
"columns": [
|
||
{
|
||
"id": "zawodowe",
|
||
"label": "TECH",
|
||
"side": "left",
|
||
"tree": "WE -> EK -> KW",
|
||
"description": "Dowody runtime."
|
||
},
|
||
{
|
||
"id": "ogolne",
|
||
"label": "OG",
|
||
"side": "right",
|
||
"tree": "WE -> EN -> KW",
|
||
"description": "Model FreeRTOS C."
|
||
}
|
||
]
|
||
},
|
||
"learning_effects": {
|
||
"FC04.EN01": {
|
||
"bloom_level": "Analiza",
|
||
"label": "Model stanów taska",
|
||
"text": "Uczeń rozróżnia Ready, Running, Blocked, Suspended i Deleted oraz przyczynę każdego przejścia.",
|
||
"assessment_criteria": [
|
||
"FC04.KW01"
|
||
]
|
||
},
|
||
"FC04.EK01": {
|
||
"bloom_level": "Zastosowanie",
|
||
"label": "Replay delay i resume",
|
||
"text": "Uczeń odtwarza E01–E10 i wiąże publiczny stan, tick, PC/SP, TCB oraz stos.",
|
||
"assessment_criteria": [
|
||
"FC04.KW01"
|
||
]
|
||
}
|
||
},
|
||
"assessment_criteria": {
|
||
"FC04.KW01": {
|
||
"text": "Program kończy się PASS; observer widzi eBlocked i eSuspended; timeline ma dokładne delty 2; resume działa raz; context, TCB i stack pozostają rozdzielone.",
|
||
"learning_effects": [
|
||
"FC04.EN01",
|
||
"FC04.EK01"
|
||
]
|
||
}
|
||
},
|
||
"educational_requirements": {
|
||
"FC04.WE01": {
|
||
"text": "Zaprojektowanie i zbadanie deterministycznego eksperymentu delay, suspend, resume i self-delete.",
|
||
"label": "vTaskDelayUntil, Blocked, Suspended i vTaskDelete",
|
||
"learning_effects": [
|
||
"FC04.EN01",
|
||
"FC04.EK01"
|
||
],
|
||
"learning_tree": {
|
||
"schema": "we-learning-tree.v1",
|
||
"policy": "Każda aktywna kotwica wskazuje kod lub checkpoint.",
|
||
"ogolne": [
|
||
{
|
||
"effect_ref": "FC04.EN01",
|
||
"display": "EN LOCAL RTOS.04",
|
||
"source": "LOCAL",
|
||
"official": "RTOS",
|
||
"local": "04",
|
||
"kind": "EN",
|
||
"tree_id": "FC04.WE01.OG.LOCAL.RTOS.04",
|
||
"text": "Uczeń rozróżnia Ready, Running, Blocked, Suspended i Deleted oraz przyczynę każdego przejścia.",
|
||
"kw": [
|
||
{
|
||
"criterion_ref": "FC04.KW01",
|
||
"display": "KW LOCAL RTOS.04",
|
||
"source": "LOCAL",
|
||
"kind": "KW",
|
||
"official": "RTOS",
|
||
"local": "04",
|
||
"text": "Łączy kod, diagram i zweryfikowany dowód."
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"zawodowe": [
|
||
{
|
||
"effect_ref": "FC04.EK01",
|
||
"display": "EK LOCAL RTOS.04",
|
||
"source": "LOCAL",
|
||
"official": "RTOS",
|
||
"local": "04",
|
||
"kind": "EK",
|
||
"tree_id": "FC04.WE01.TECH.LOCAL.RTOS.04",
|
||
"text": "Uczeń odtwarza E01–E10 i wiąże publiczny stan, tick, PC/SP, TCB oraz stos.",
|
||
"kw": [
|
||
{
|
||
"criterion_ref": "FC04.KW01",
|
||
"display": "KW LOCAL RTOS.04",
|
||
"source": "LOCAL",
|
||
"kind": "KW",
|
||
"official": "RTOS",
|
||
"local": "04",
|
||
"text": "Łączy kod, diagram i zweryfikowany dowód."
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
},
|
||
"debug_checkpoints": {
|
||
"schema": "stem-debug-checkpoints.v1",
|
||
"semantics": "deterministic-replay",
|
||
"artifact": {
|
||
"source": "src/tasks/task01_delay_state.c",
|
||
"source_git_blob": "0a1cbe0370664498693cefb30c22112b9a7ceae6",
|
||
"elf": "build/task01_delay_state/prog.elf",
|
||
"hazard3_elf_sha256": "14ca6067a49ed05baa8f545a4694e1f6e4c722d9cac06c316d116caf761ef4f6",
|
||
"hazard3_image": "build/task01_delay_state/prog.bin",
|
||
"hazard3_image_sha256": "9e7091e3ba1389bbc2e2d92b7f87ee1add277c284297df1b62c074410bca16f6"
|
||
},
|
||
"targets": {
|
||
"hazard3-sim": {
|
||
"adapter": "hazard3-reset-load-replay.v1",
|
||
"baseline": "restart-backend",
|
||
"clean_ram": true
|
||
}
|
||
},
|
||
"items": {
|
||
"task01.config": {
|
||
"event_id": "E01",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 1"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_fc04_last_checkpoint",
|
||
"equals": 1
|
||
},
|
||
{
|
||
"expr": "g_periodic.handle == 0",
|
||
"equals": 1
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.scheduler": {
|
||
"event_id": "E02",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 2"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_periodic.handle != 0",
|
||
"equals": 1
|
||
},
|
||
{
|
||
"expr": "g_suspend_target.handle != 0",
|
||
"equals": 1
|
||
},
|
||
{
|
||
"expr": "g_observer.handle != 0",
|
||
"equals": 1
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.periodic-entry": {
|
||
"event_id": "E03",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 3 && $a1 == &g_periodic"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_periodic.phase",
|
||
"equals": 4
|
||
},
|
||
{
|
||
"expr": "g_periodic.release_count",
|
||
"equals": 0
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.states": {
|
||
"event_id": "E04",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 4 && $a1 == &g_observer"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_observer.periodic_state",
|
||
"equals": 2
|
||
},
|
||
{
|
||
"expr": "g_observer.suspend_state",
|
||
"equals": 3
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.resumed": {
|
||
"event_id": "E05",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 5 && $a1 == &g_suspend_target"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_suspend_target.resumed",
|
||
"equals": 1
|
||
},
|
||
{
|
||
"expr": "g_suspend_target.phase",
|
||
"equals": 4
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.release-1": {
|
||
"event_id": "E06",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 6 && $a1 == &g_periodic"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_periodic.release_count",
|
||
"equals": 1
|
||
},
|
||
{
|
||
"expr": "g_periodic.release_tick[0] - g_periodic.initial_tick",
|
||
"equals": 2
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.release-2": {
|
||
"event_id": "E07",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 7 && $a1 == &g_periodic"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_periodic.release_count",
|
||
"equals": 2
|
||
},
|
||
{
|
||
"expr": "g_periodic.release_tick[1] - g_periodic.release_tick[0]",
|
||
"equals": 2
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.release-3": {
|
||
"event_id": "E08",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 8 && $a1 == &g_periodic"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_periodic.release_count",
|
||
"equals": 3
|
||
},
|
||
{
|
||
"expr": "g_periodic.release_tick[2] - g_periodic.release_tick[1]",
|
||
"equals": 2
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.periodic-finished": {
|
||
"event_id": "E09",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 9 && $a1 == &g_periodic"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_periodic.phase",
|
||
"equals": 5
|
||
},
|
||
{
|
||
"expr": "g_periodic.handle == 0",
|
||
"equals": 1
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"task01.pass": {
|
||
"event_id": "E10",
|
||
"stop": {
|
||
"symbol": "fc04_checkpoint_committed",
|
||
"offset": 0,
|
||
"condition": "$a0 == 10 && $a1 == &g_observer"
|
||
},
|
||
"verify": {
|
||
"expressions": [
|
||
{
|
||
"expr": "g_fc04_pass",
|
||
"equals": 1
|
||
},
|
||
{
|
||
"expr": "g_suspend_target.resumed",
|
||
"equals": 1
|
||
},
|
||
{
|
||
"expr": "g_periodic.release_count",
|
||
"equals": 3
|
||
}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"sections": [
|
||
{
|
||
"title": "A2 — Structure",
|
||
"order": 20,
|
||
"content_kind": "prose",
|
||
"asset_page_mode": "one-per-page",
|
||
"page_orientation": "landscape",
|
||
"content_tex": "Konteksty aplikacyjne przechowują uchwyty, stan diagnostyczny i bounded evidence; nie kopiują prywatnych list kernela.",
|
||
"assets": [
|
||
{
|
||
"path": "assets/a2-structure.png",
|
||
"html_path": "assets/a2-structure.svg",
|
||
"source_path": "assets/a2-structure.puml",
|
||
"caption": "A2 STRUCTURE — trzy konteksty i absolutna oś wybudzeń.",
|
||
"label": "fig:a2-structure",
|
||
"alt": "PeriodicContext, SuspendContext, ObserverContext i timeline.",
|
||
"kind": "diagram",
|
||
"width": 1.0,
|
||
"page_grid": {
|
||
"columns": 1,
|
||
"rows": 1,
|
||
"page_width": 940,
|
||
"page_height": 560,
|
||
"overview": true,
|
||
"step_tiles": {
|
||
"periodic": 1,
|
||
"suspend": 1,
|
||
"observer": 1,
|
||
"timeline": 1
|
||
}
|
||
},
|
||
"interactive": {
|
||
"kind": "uml-class",
|
||
"storage_key": "fc04-a2-structure",
|
||
"title": "A2 · konteksty i timeline",
|
||
"task": {
|
||
"id": "task01",
|
||
"label": "Task01 · delay i stany"
|
||
},
|
||
"block": {
|
||
"id": "a2",
|
||
"label": "A2 STRUCTURE",
|
||
"description": "Konteksty C i ograniczona oś czasu."
|
||
},
|
||
"phases": [
|
||
{
|
||
"id": "contexts",
|
||
"label": "CONTEXTS / TIMELINE",
|
||
"steps": [
|
||
{
|
||
"id": "periodic",
|
||
"number": 1,
|
||
"label": "periodic context owns wake evidence",
|
||
"mode": "CODE",
|
||
"strategy_ref": "code.state-model",
|
||
"svg_label": "01",
|
||
"svg_target": "Periodic",
|
||
"code_ref": "include/task01_delay_state.h:23",
|
||
"description": "Context zachowuje t0 i trzy release ticks.",
|
||
"evidence": "Static storage przeżywa self-delete."
|
||
},
|
||
{
|
||
"id": "suspend",
|
||
"number": 2,
|
||
"label": "suspend context records explicit resume",
|
||
"mode": "CODE",
|
||
"strategy_ref": "code.state-model",
|
||
"svg_label": "02",
|
||
"svg_target": "Suspend",
|
||
"code_ref": "include/task01_delay_state.h:37",
|
||
"description": "Suspended nie ma time-based wake.",
|
||
"evidence": "resumed zmienia się wyłącznie po vTaskResume."
|
||
},
|
||
{
|
||
"id": "observer",
|
||
"number": 3,
|
||
"label": "observer stores public eTaskState",
|
||
"mode": "RUN",
|
||
"event_id": "E04",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "03",
|
||
"svg_target": "Observer",
|
||
"code_ref": "src/tasks/task01_delay_state.c:150",
|
||
"snapshot_ref": "task01.states",
|
||
"description": "Publiczne API odróżnia Blocked i Suspended.",
|
||
"evidence": "eBlocked oraz eSuspended."
|
||
},
|
||
{
|
||
"id": "timeline",
|
||
"number": 4,
|
||
"label": "absolute timeline has exact deltas",
|
||
"mode": "RUN",
|
||
"event_id": "E10",
|
||
"strategy_ref": "run.timeline",
|
||
"svg_label": "04",
|
||
"svg_target": "Timeline",
|
||
"code_ref": "src/tasks/task01_delay_state.c:168",
|
||
"snapshot_ref": "task01.pass",
|
||
"description": "Deltas nie zależą od momentu powrotu z pracy.",
|
||
"evidence": "t0, t0+2, t0+4, t0+6."
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"title": "A5 — Flow",
|
||
"order": 40,
|
||
"content_kind": "prose",
|
||
"asset_page_mode": "one-per-page",
|
||
"page_orientation": "landscape",
|
||
"content_tex": "Sekwencja pokazuje przyczynę każdego przejścia i jawny moment zapisu dowodu.",
|
||
"assets": [
|
||
{
|
||
"path": "assets/a5-flow.png",
|
||
"html_path": "assets/a5-flow.svg",
|
||
"source_path": "assets/a5-flow.puml",
|
||
"caption": "A5 FLOW — od konfiguracji do okresowych wybudzeń i PASS.",
|
||
"label": "fig:a5-flow",
|
||
"alt": "Sekwencja periodic, suspend target, observer i scheduler.",
|
||
"kind": "diagram",
|
||
"width": 1.0,
|
||
"page_grid": {
|
||
"columns": 1,
|
||
"rows": 1,
|
||
"page_width": 940,
|
||
"page_height": 560,
|
||
"overview": true,
|
||
"step_tiles": {
|
||
"config": 1,
|
||
"scheduler": 1,
|
||
"periodic-entry": 1,
|
||
"states": 1,
|
||
"resumed": 1,
|
||
"release-1": 1,
|
||
"release-2": 1,
|
||
"release-3": 1,
|
||
"periodic-finished": 1,
|
||
"pass": 1
|
||
}
|
||
},
|
||
"interactive": {
|
||
"kind": "uml-sequence",
|
||
"storage_key": "fc04-a5-flow",
|
||
"title": "A5 · delay i resume",
|
||
"task": {
|
||
"id": "task01",
|
||
"label": "Task01 · delay i stany"
|
||
},
|
||
"block": {
|
||
"id": "a5",
|
||
"label": "A5 FLOW",
|
||
"description": "Jeden deterministyczny przebieg E01–E10."
|
||
},
|
||
"phases": [
|
||
{
|
||
"id": "replay",
|
||
"label": "DELAY / STATE / DELETE",
|
||
"steps": [
|
||
{
|
||
"id": "config",
|
||
"number": 1,
|
||
"label": "configuration committed",
|
||
"mode": "RUN",
|
||
"event_id": "E01",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "01",
|
||
"code_ref": "src/tasks/task01_delay_state.c:227",
|
||
"snapshot_ref": "task01.config",
|
||
"description": "Czysta RAM i konfiguracja FC04.",
|
||
"evidence": "Brak uchwytów przed create."
|
||
},
|
||
{
|
||
"id": "scheduler",
|
||
"number": 2,
|
||
"label": "three tasks created",
|
||
"mode": "RUN",
|
||
"event_id": "E02",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "02",
|
||
"code_ref": "src/tasks/task01_delay_state.c:256",
|
||
"snapshot_ref": "task01.scheduler",
|
||
"description": "Wszystkie publiczne handle są ważne.",
|
||
"evidence": "Priorytety 3,2,1."
|
||
},
|
||
{
|
||
"id": "periodic-entry",
|
||
"number": 3,
|
||
"label": "periodic starts and blocks",
|
||
"mode": "RUN",
|
||
"event_id": "E03",
|
||
"strategy_ref": "run.timeline",
|
||
"svg_label": "03",
|
||
"code_ref": "src/tasks/task01_delay_state.c:87",
|
||
"snapshot_ref": "task01.periodic-entry",
|
||
"description": "t0 jest punktem odniesienia vTaskDelayUntil.",
|
||
"evidence": "release_count=0."
|
||
},
|
||
{
|
||
"id": "states",
|
||
"number": 4,
|
||
"label": "observer sees Blocked and Suspended",
|
||
"mode": "RUN",
|
||
"event_id": "E04",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "04",
|
||
"code_ref": "src/tasks/task01_delay_state.c:150",
|
||
"snapshot_ref": "task01.states",
|
||
"description": "Oba stany mają różną przyczynę.",
|
||
"evidence": "eBlocked i eSuspended."
|
||
},
|
||
{
|
||
"id": "resumed",
|
||
"number": 5,
|
||
"label": "target resumes and self-deletes",
|
||
"mode": "RUN",
|
||
"event_id": "E05",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "05",
|
||
"code_ref": "src/tasks/task01_delay_state.c:122",
|
||
"snapshot_ref": "task01.resumed",
|
||
"description": "Wyższy priorytet preemptuje observera.",
|
||
"evidence": "resumed=1."
|
||
},
|
||
{
|
||
"id": "release-1",
|
||
"number": 6,
|
||
"label": "release at t0 plus 2",
|
||
"mode": "RUN",
|
||
"event_id": "E06",
|
||
"strategy_ref": "run.timeline",
|
||
"svg_label": "06",
|
||
"code_ref": "src/tasks/task01_delay_state.c:96",
|
||
"snapshot_ref": "task01.release-1",
|
||
"description": "Pierwszy absolute wake.",
|
||
"evidence": "delta=2."
|
||
},
|
||
{
|
||
"id": "release-2",
|
||
"number": 7,
|
||
"label": "release at t0 plus 4",
|
||
"mode": "RUN",
|
||
"event_id": "E07",
|
||
"strategy_ref": "run.timeline",
|
||
"svg_label": "07",
|
||
"code_ref": "src/tasks/task01_delay_state.c:96",
|
||
"snapshot_ref": "task01.release-2",
|
||
"description": "Drugi absolute wake.",
|
||
"evidence": "delta=2."
|
||
},
|
||
{
|
||
"id": "release-3",
|
||
"number": 8,
|
||
"label": "release at t0 plus 6",
|
||
"mode": "RUN",
|
||
"event_id": "E08",
|
||
"strategy_ref": "run.timeline",
|
||
"svg_label": "08",
|
||
"code_ref": "src/tasks/task01_delay_state.c:96",
|
||
"snapshot_ref": "task01.release-3",
|
||
"description": "Trzeci absolute wake.",
|
||
"evidence": "delta=2."
|
||
},
|
||
{
|
||
"id": "periodic-finished",
|
||
"number": 9,
|
||
"label": "periodic clears handle before delete",
|
||
"mode": "RUN",
|
||
"event_id": "E09",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "09",
|
||
"code_ref": "src/tasks/task01_delay_state.c:99",
|
||
"snapshot_ref": "task01.periodic-finished",
|
||
"description": "Context zachowuje forensic values.",
|
||
"evidence": "phase=COMPLETED, handle=NULL."
|
||
},
|
||
{
|
||
"id": "pass",
|
||
"number": 10,
|
||
"label": "observer verifies PASS",
|
||
"mode": "RUN",
|
||
"event_id": "E10",
|
||
"strategy_ref": "run.pass",
|
||
"svg_label": "10",
|
||
"code_ref": "src/tasks/task01_delay_state.c:192",
|
||
"snapshot_ref": "task01.pass",
|
||
"description": "Observer sprawdza stany, timeline i stack.",
|
||
"evidence": "PASS=1."
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"title": "A6 — State",
|
||
"order": 50,
|
||
"content_kind": "prose",
|
||
"asset_page_mode": "one-per-page",
|
||
"page_orientation": "landscape",
|
||
"content_tex": "Blocked ma warunek czasu lub zdarzenia; Suspended wymaga jawnego resume. Deleted nie oznacza natychmiastowego wymazania wszystkich śladów.",
|
||
"assets": [
|
||
{
|
||
"path": "assets/a6-state.png",
|
||
"html_path": "assets/a6-state.svg",
|
||
"source_path": "assets/a6-state.puml",
|
||
"caption": "A6 STATE — Ready, Running, Blocked, Suspended i Deleted.",
|
||
"label": "fig:a6-state",
|
||
"alt": "Maszyna stanów taska FreeRTOS.",
|
||
"kind": "diagram",
|
||
"width": 1.0,
|
||
"page_grid": {
|
||
"columns": 1,
|
||
"rows": 1,
|
||
"page_width": 940,
|
||
"page_height": 560,
|
||
"overview": true,
|
||
"step_tiles": {
|
||
"ready": 1,
|
||
"running": 1,
|
||
"blocked": 1,
|
||
"suspended": 1,
|
||
"resumed-ready": 1,
|
||
"completed": 1,
|
||
"deleted": 1
|
||
}
|
||
},
|
||
"interactive": {
|
||
"kind": "uml-class",
|
||
"storage_key": "fc04-a6-state",
|
||
"title": "A6 · stany taska",
|
||
"task": {
|
||
"id": "task01",
|
||
"label": "Task01 · delay i stany"
|
||
},
|
||
"block": {
|
||
"id": "a6",
|
||
"label": "A6 STATE",
|
||
"description": "Przyczyny przejść między stanami taska."
|
||
},
|
||
"phases": [
|
||
{
|
||
"id": "states",
|
||
"label": "TASK STATE",
|
||
"steps": [
|
||
{
|
||
"id": "ready",
|
||
"number": 1,
|
||
"label": "Ready waits for selection",
|
||
"mode": "RUN",
|
||
"event_id": "E02",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "01",
|
||
"code_ref": "src/tasks/task01_delay_state.c:229",
|
||
"snapshot_ref": "task01.scheduler",
|
||
"description": "Created nie znaczy Running.",
|
||
"evidence": "handle ważny przed startem."
|
||
},
|
||
{
|
||
"id": "running",
|
||
"number": 2,
|
||
"label": "highest Ready task runs",
|
||
"mode": "RUN",
|
||
"event_id": "E03",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "02",
|
||
"code_ref": "src/tasks/task01_delay_state.c:72",
|
||
"snapshot_ref": "task01.periodic-entry",
|
||
"description": "Periodic ma priorytet 3.",
|
||
"evidence": "PC/SP w periodic."
|
||
},
|
||
{
|
||
"id": "blocked",
|
||
"number": 3,
|
||
"label": "delay moves task to Blocked",
|
||
"mode": "RUN",
|
||
"event_id": "E04",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "03",
|
||
"code_ref": "src/tasks/task01_delay_state.c:92",
|
||
"snapshot_ref": "task01.states",
|
||
"description": "Wake tick istnieje.",
|
||
"evidence": "eBlocked."
|
||
},
|
||
{
|
||
"id": "suspended",
|
||
"number": 4,
|
||
"label": "self-suspend has no wake tick",
|
||
"mode": "RUN",
|
||
"event_id": "E04",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "04",
|
||
"code_ref": "src/tasks/task01_delay_state.c:118",
|
||
"snapshot_ref": "task01.states",
|
||
"description": "Tylko jawne resume przywraca Ready.",
|
||
"evidence": "eSuspended."
|
||
},
|
||
{
|
||
"id": "resumed-ready",
|
||
"number": 5,
|
||
"label": "resume makes target Ready",
|
||
"mode": "RUN",
|
||
"event_id": "E05",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "05",
|
||
"code_ref": "src/tasks/task01_delay_state.c:160",
|
||
"snapshot_ref": "task01.resumed",
|
||
"description": "Priorytet 2 wyprzedza observera 1.",
|
||
"evidence": "target Running po resume."
|
||
},
|
||
{
|
||
"id": "completed",
|
||
"number": 6,
|
||
"label": "application records completion",
|
||
"mode": "RUN",
|
||
"event_id": "E09",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "06",
|
||
"code_ref": "src/tasks/task01_delay_state.c:99",
|
||
"snapshot_ref": "task01.periodic-finished",
|
||
"description": "COMPLETED jest stanem diagnostycznym aplikacji.",
|
||
"evidence": "Zapis przed delete."
|
||
},
|
||
{
|
||
"id": "deleted",
|
||
"number": 7,
|
||
"label": "self-delete delegates cleanup",
|
||
"mode": "RUN",
|
||
"event_id": "E10",
|
||
"strategy_ref": "run.pass",
|
||
"svg_label": "07",
|
||
"code_ref": "src/tasks/task01_delay_state.c:102",
|
||
"snapshot_ref": "task01.pass",
|
||
"description": "Idle może później odzyskać TCB/stack.",
|
||
"evidence": "Context static pozostaje."
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"title": "A7 — Runtime",
|
||
"order": 60,
|
||
"content_kind": "prose",
|
||
"asset_page_mode": "one-per-page",
|
||
"page_orientation": "landscape",
|
||
"content_tex": "A7 wiąże publiczne eTaskState z pamięcią taska i bounded evidence, bez uzależniania programu od pxCurrentTCB.",
|
||
"assets": [
|
||
{
|
||
"path": "assets/a7-runtime.png",
|
||
"html_path": "assets/a7-runtime.svg",
|
||
"source_path": "assets/a7-runtime.puml",
|
||
"caption": "A7 RUNTIME — stany publiczne, task memory, wake ticks i PASS.",
|
||
"label": "fig:a7-runtime",
|
||
"alt": "Runtime evidence dla delay i suspend.",
|
||
"kind": "diagram",
|
||
"width": 1.0,
|
||
"page_grid": {
|
||
"columns": 1,
|
||
"rows": 1,
|
||
"page_width": 940,
|
||
"page_height": 560,
|
||
"overview": true,
|
||
"step_tiles": {
|
||
"public": 1,
|
||
"periodic-runtime": 1,
|
||
"wake": 1,
|
||
"suspend-runtime": 1,
|
||
"evidence": 1
|
||
}
|
||
},
|
||
"interactive": {
|
||
"kind": "uml-class",
|
||
"storage_key": "fc04-a7-runtime",
|
||
"title": "A7 · runtime evidence",
|
||
"task": {
|
||
"id": "task01",
|
||
"label": "Task01 · delay i stany"
|
||
},
|
||
"block": {
|
||
"id": "a7",
|
||
"label": "A7 RUNTIME",
|
||
"description": "Publiczny stan, TCB/stack i oś ticków."
|
||
},
|
||
"phases": [
|
||
{
|
||
"id": "runtime",
|
||
"label": "STATE / MEMORY / TIME",
|
||
"steps": [
|
||
{
|
||
"id": "public",
|
||
"number": 1,
|
||
"label": "public API exposes two states",
|
||
"mode": "RUN",
|
||
"event_id": "E04",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "01",
|
||
"svg_target": "Public",
|
||
"code_ref": "src/tasks/task01_delay_state.c:150",
|
||
"snapshot_ref": "task01.states",
|
||
"description": "Program nie czyta prywatnych list.",
|
||
"evidence": "eBlocked, eSuspended."
|
||
},
|
||
{
|
||
"id": "periodic-runtime",
|
||
"number": 2,
|
||
"label": "periodic has separate TCB and stack",
|
||
"mode": "RUN",
|
||
"event_id": "E03",
|
||
"strategy_ref": "run.timeline",
|
||
"svg_label": "02",
|
||
"svg_target": "Periodic",
|
||
"code_ref": "src/tasks/task01_delay_state.c:59",
|
||
"snapshot_ref": "task01.periodic-entry",
|
||
"description": "SP należy do task stack.",
|
||
"evidence": "created_handle i stack range."
|
||
},
|
||
{
|
||
"id": "wake",
|
||
"number": 3,
|
||
"label": "absolute wake timeline is exact",
|
||
"mode": "RUN",
|
||
"event_id": "E08",
|
||
"strategy_ref": "run.timeline",
|
||
"svg_label": "03",
|
||
"svg_target": "Wake",
|
||
"code_ref": "src/tasks/task01_delay_state.c:96",
|
||
"snapshot_ref": "task01.release-3",
|
||
"description": "Trzy wybudzenia zachowują okres.",
|
||
"evidence": "2/4/6."
|
||
},
|
||
{
|
||
"id": "suspend-runtime",
|
||
"number": 4,
|
||
"label": "suspended task resumes explicitly",
|
||
"mode": "RUN",
|
||
"event_id": "E05",
|
||
"strategy_ref": "run.state",
|
||
"svg_label": "04",
|
||
"svg_target": "Suspend",
|
||
"code_ref": "src/tasks/task01_delay_state.c:107",
|
||
"snapshot_ref": "task01.resumed",
|
||
"description": "Brak time-based wake.",
|
||
"evidence": "resumed=1."
|
||
},
|
||
{
|
||
"id": "evidence",
|
||
"number": 5,
|
||
"label": "forensic evidence remains bounded",
|
||
"mode": "RUN",
|
||
"event_id": "E10",
|
||
"strategy_ref": "run.pass",
|
||
"svg_label": "05",
|
||
"svg_target": "Evidence",
|
||
"code_ref": "src/tasks/task01_delay_state.c:192",
|
||
"snapshot_ref": "task01.pass",
|
||
"description": "Snapshot wiąże wynik ze źródłem i ELF.",
|
||
"evidence": "PASS, source blob, image hash, timestamp."
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"title": "Task01 — delay i stany",
|
||
"order": 90,
|
||
"content_kind": "tasks",
|
||
"task_refs": [
|
||
"task01"
|
||
]
|
||
}
|
||
],
|
||
"tasks": {
|
||
"task01": {
|
||
"title": "Delay, blokowanie, zawieszenie i self-delete",
|
||
"uuid": "4a7ef04c-ab08-5783-9192-5b02a90f05f8",
|
||
"prompt_tex": "Przejdź po A2, A5, A6 i A7. Odtwórz E01–E10, rozróżnij Blocked od Suspended i udowodnij dokładny okres vTaskDelayUntil.",
|
||
"criterion": "Program kończy się PASS; observer widzi eBlocked i eSuspended; timeline ma dokładne delty 2; resume działa raz; context, TCB i stack pozostają rozdzielone.",
|
||
"conclusion_tex": "Blocked task ma warunek wybudzenia, Suspended wymaga jawnego resume, a vTaskDelayUntil utrzymuje absolutną fazę okresu. Self-delete kończy task, lecz aplikacyjny context może zachować bounded forensic evidence.",
|
||
"flow": [
|
||
{
|
||
"kind": "block",
|
||
"id": "state-model",
|
||
"title": "A — model stanów",
|
||
"content_tex": "Najpierw przewidź przyczynę i wyjście z każdego stanu.",
|
||
"steps": [
|
||
{
|
||
"id": "classify",
|
||
"title": "Sklasyfikuj Blocked i Suspended.",
|
||
"content_tex": "Wskaż warunek automatycznego wybudzenia albo jego brak."
|
||
},
|
||
{
|
||
"id": "predict",
|
||
"title": "Przewidź oś czasu.",
|
||
"content_tex": "Zapisz oczekiwane t0+2, t0+4 i t0+6."
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"kind": "block",
|
||
"id": "runtime-replay",
|
||
"title": "B — replay Hazard3",
|
||
"content_tex": "Każdy RUN zaczyna się od czystej RAM.",
|
||
"steps": [
|
||
{
|
||
"id": "observe",
|
||
"title": "Zbadaj E04.",
|
||
"content_tex": "Zapisz publiczne stany obu tasków i ich przyczyny."
|
||
},
|
||
{
|
||
"id": "resume",
|
||
"title": "Zbadaj E05.",
|
||
"content_tex": "Wyjaśnij, dlaczego target preemptuje observera."
|
||
},
|
||
{
|
||
"id": "timeline",
|
||
"title": "Zbadaj E06–E08.",
|
||
"content_tex": "Policz delty release ticks i sprawdź stack taska."
|
||
},
|
||
{
|
||
"id": "finish",
|
||
"title": "Zbadaj E09–E10.",
|
||
"content_tex": "Oddziel application completion od cleanup kernela."
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"kind": "exercise",
|
||
"id": "relative-delay-drift",
|
||
"title": "Ćwiczenie — względny delay i dryf",
|
||
"prompt_tex": "Zastąp vTaskDelayUntil przez vTaskDelay i dodaj bounded workload trwający jeden tick po każdym wybudzeniu. Zmierz trzy release ticks i porównaj fazę z wersją bazową.",
|
||
"evidence_tex": "Timestampowane snapshoty release ticks oraz krótka tabela różnic względem 2/4/6.",
|
||
"criterion": "Uczeń poprawnie wyjaśnia, dlaczego relative delay kumuluje czas pracy i przesuwa fazę.",
|
||
"based_on": [
|
||
"state-model",
|
||
"runtime-replay"
|
||
]
|
||
}
|
||
],
|
||
"educational_requirement_refs": [
|
||
"FC04.WE01"
|
||
],
|
||
"learning_effect_refs": [
|
||
"FC04.EN01",
|
||
"FC04.EK01"
|
||
],
|
||
"assessment_criterion_ref": "FC04.KW01"
|
||
}
|
||
},
|
||
"tasks_order": [
|
||
"task01"
|
||
]
|
||
}
|