93 lines
22 KiB
JSON
93 lines
22 KiB
JSON
{
|
||
"card":{"number":"10","slug":"notifications","title":"Direct-to-task notifications","topic":"count, overwrite, set bits i target-owned slot","status":"Gotowa","version":"v00.01"},
|
||
"front":{"goal":"Uczeń dobiera akcję notification do kontraktu informacji i odróżnia wartość slotu od stanu pending.","scope":"Jeden receiver i jeden slot index 0 przechodzą kolejno przez counting=3, overwrite=0x22 i bit-set=0x24. Sender p3 publikuje dopiero po potwierdzeniu receivera w eBlocked. Zero-time probe potwierdza wyczyszczenie slotu między fazami. Brak kolejki, semafora i EventGroup."},
|
||
"viewpoints":[
|
||
{"id":"A1","label":"CONTEXT","status":"unavailable","subtitle":"Granice","reason":"Brak nowej granicy sprzętowej."},
|
||
{"id":"A2","label":"STRUCTURE","status":"enabled","subtitle":"Target-owned slot 0"},
|
||
{"id":"A3","label":"DISPATCH","status":"enabled","subtitle":"TaskHandle_t → target TCB"},
|
||
{"id":"A4","label":"APPLICATION","status":"unavailable","subtitle":"Topologia","reason":"Sender/receiver topology jest kompletna w A2 i A5."},
|
||
{"id":"A5","label":"FLOW","status":"enabled","subtitle":"E01–E12 three protocols"},
|
||
{"id":"A6","label":"STATE","status":"enabled","subtitle":"Value plus pending state"},
|
||
{"id":"A7","label":"RUNTIME","status":"enabled","subtitle":"Public states, stacks and TCB slot"},
|
||
{"id":"A8","label":"PATTERNS","status":"enabled","subtitle":"Count, latest value and flags"}
|
||
],
|
||
"artifact":{"source":"src/tasks/task01_notifications.c","elf":"build/task01_notifications/prog.elf","image":"build/task01_notifications/prog.bin"},
|
||
"strategies":[
|
||
{"id":"code.contract","kind":"code","prerequisites":["źródło FC10"],"layout":["notification config","sender/receiver","no object storage"],"commands":["rg -n 'configUSE_TASK_NOTIFICATIONS|xTaskNotify|ulTaskNotify' include src"],"expected_observations":["one index","three explicit actions"],"assertions":["no queue/event group API","fixed target handle"],"evidence_fields":["API","action","code_ref"]},
|
||
{"id":"run.blocked","kind":"run","prerequisites":["clean Hazard3 RAM"],"layout":["receiver phase/state","sender priority","event log"],"commands":["print g_fc10.receiver_phase","print g_fc10.receiver_state_before_count"],"expected_observations":["eBlocked before each batch","p3 sender cannot be preempted by p2 receiver"],"assertions":["finite phase wait","three state proofs"],"evidence_fields":["phase","state","PC","SP","timestamp"]},
|
||
{"id":"run.values","kind":"run","prerequisites":["receiver blocked"],"layout":["count/overwrite/bits result","clear probes"],"commands":["print/x g_fc10.count_result","print/x g_fc10.overwrite_result","print/x g_fc10.bits_result"],"expected_observations":["3","0x22","0x24"],"assertions":["clear probes all 1","single receiver"],"evidence_fields":["value","clear","event order"]},
|
||
{"id":"run.pass","kind":"run","prerequisites":["sender and receiver done"],"layout":["PASS","bounded records","digest"],"commands":["print g_fc10_pass","print g_fc10.evidence_digest"],"expected_observations":["PASS=1","12 events"],"assertions":["three-run deterministic","distinct stacks"],"evidence_fields":["PASS","digest","hashes","timestamp"]}
|
||
],
|
||
"checkpoints":{
|
||
"task01.config":{"event_id":"E01","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 1"},"verify":{"expressions":[{"expr":"g_fc10_event_count","equals":1}]}},
|
||
"task01.sender-armed":{"event_id":"E02","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 2"},"verify":{"expressions":[{"expr":"g_fc10.sender_sp != 0","equals":1}]}},
|
||
"task01.wait-count":{"event_id":"E03","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 3"},"verify":{"expressions":[{"expr":"g_fc10.receiver_phase","equals":1},{"expr":"g_fc10.receiver_sp != 0","equals":1}]}},
|
||
"task01.post-count":{"event_id":"E04","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 4"},"verify":{"expressions":[{"expr":"g_fc10.receiver_state_before_count","equals":2}]}},
|
||
"task01.receive-count":{"event_id":"E05","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 5"},"verify":{"expressions":[{"expr":"g_fc10.count_result","equals":3}]}},
|
||
"task01.wait-overwrite":{"event_id":"E06","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 6"},"verify":{"expressions":[{"expr":"g_fc10.clear_after_count","equals":1}]}},
|
||
"task01.post-overwrite":{"event_id":"E07","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 7"},"verify":{"expressions":[{"expr":"g_fc10.receiver_state_before_overwrite","equals":2}]}},
|
||
"task01.receive-overwrite":{"event_id":"E08","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 8"},"verify":{"expressions":[{"expr":"g_fc10.overwrite_result","equals":34}]}},
|
||
"task01.wait-bits":{"event_id":"E09","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 9"},"verify":{"expressions":[{"expr":"g_fc10.clear_after_overwrite","equals":1}]}},
|
||
"task01.post-bits":{"event_id":"E10","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 10"},"verify":{"expressions":[{"expr":"g_fc10.receiver_state_before_bits","equals":2}]}},
|
||
"task01.receive-bits":{"event_id":"E11","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 11"},"verify":{"expressions":[{"expr":"g_fc10.bits_result","equals":36},{"expr":"g_fc10.clear_after_bits","equals":1}]}},
|
||
"task01.pass":{"event_id":"E12","stop":{"symbol":"fc10_checkpoint_committed","offset":0,"condition":"$a0 == 12"},"verify":{"expressions":[{"expr":"g_fc10_pass","equals":1},{"expr":"g_fc10_event_count","equals":12}]}}
|
||
},
|
||
"sections":[
|
||
{"id":"A2","label":"STRUCTURE","title":"Structure","order":20,"orientation":"landscape","description":"Notification state lives in the target task, not in an intermediary object.","content_tex":"TaskHandle_t selects one target TCB and index 0. Count, overwrite and bits are three actions on the same value/state pair.","assets":[{"stem":"a2-structure","title":"A2 · target-owned slot","caption":"A2 STRUCTURE — receiver TCB notification slot.","label":"fig:a2-structure","alt":"Struktura direct notification.","phases":[{"id":"structure","label":"SENDER / TARGET / MODES","steps":[
|
||
{"id":"sender","number":1,"label":"sender stores target handle","mode":"CODE","strategy_ref":"code.contract","svg_label":"01","code_ref":"include/task01_notifications.h:24","description":"No shared object handle is created.","evidence":"receiver_handle."},
|
||
{"id":"receiver","number":2,"label":"slot belongs to receiver TCB","mode":"RUN","event_id":"E03","strategy_ref":"run.blocked","svg_label":"02","code_ref":"src/tasks/task01_notifications.c:153","snapshot_ref":"task01.wait-count","description":"Only receiver consumes slot 0.","evidence":"receiver stack and phase."},
|
||
{"id":"count","number":3,"label":"counting accumulates occurrences","mode":"RUN","event_id":"E05","strategy_ref":"run.values","svg_label":"03","code_ref":"src/tasks/task01_notifications.c:164","snapshot_ref":"task01.receive-count","description":"pdTRUE returns and clears all three.","evidence":"3."},
|
||
{"id":"overwrite","number":4,"label":"overwrite keeps latest value","mode":"RUN","event_id":"E08","strategy_ref":"run.values","svg_label":"04","code_ref":"src/tasks/task01_notifications.c:177","snapshot_ref":"task01.receive-overwrite","description":"0x11 is intentionally lost.","evidence":"0x22."},
|
||
{"id":"bits","number":5,"label":"set bits combines flags","mode":"RUN","event_id":"E11","strategy_ref":"run.values","svg_label":"05","code_ref":"src/tasks/task01_notifications.c:196","snapshot_ref":"task01.receive-bits","description":"OR semantics.","evidence":"0x24."},
|
||
{"id":"absent","number":6,"label":"no intermediary kernel object","mode":"CODE","strategy_ref":"code.contract","svg_label":"06","code_ref":"src/tasks/task01_notifications.c:260","description":"No create API except tasks.","evidence":"link and source inspection."}
|
||
]}]}]},
|
||
{"id":"A3","label":"DISPATCH","title":"Dispatch","order":30,"orientation":"portrait","description":"A handle binds the action to one target slot.","content_tex":"xTaskGenericNotify receives target handle, index and action. Only the selected target can move from Blocked to Ready.","assets":[{"stem":"a3-dispatch","title":"A3 · target dispatch","caption":"A3 DISPATCH — handle to TCB slot 0.","label":"fig:a3-dispatch","alt":"Dispatch direct notification.","phases":[{"id":"dispatch","label":"HANDLE / ACTION / TARGET","steps":[
|
||
{"id":"sender","number":1,"label":"sender chooses protocol action","mode":"CODE","strategy_ref":"code.contract","svg_label":"01","code_ref":"src/tasks/task01_notifications.c:118","description":"Give, overwrite or bits.","evidence":"three call sites."},
|
||
{"id":"handle","number":2,"label":"receiver_handle fixes recipient","mode":"CODE","strategy_ref":"code.contract","svg_label":"02","code_ref":"src/tasks/task01_notifications.c:118","description":"Not broadcast.","evidence":"one TaskHandle_t."},
|
||
{"id":"api","number":3,"label":"generic API updates index 0","mode":"RUN","event_id":"E07","strategy_ref":"run.values","svg_label":"03","code_ref":"src/tasks/task01_notifications.c:124","snapshot_ref":"task01.post-overwrite","description":"Action controls information loss.","evidence":"latest value 0x22."},
|
||
{"id":"tcb","number":4,"label":"value and pending are distinct","mode":"RUN","event_id":"E09","strategy_ref":"run.values","svg_label":"04","code_ref":"src/tasks/task01_notifications.c:188","snapshot_ref":"task01.wait-bits","description":"Clear probe demonstrates value zero.","evidence":"probe=1."},
|
||
{"id":"ready","number":5,"label":"only blocked receiver wakes","mode":"RUN","event_id":"E10","strategy_ref":"run.blocked","svg_label":"05","code_ref":"src/tasks/task01_notifications.c:134","snapshot_ref":"task01.post-bits","description":"State captured before post.","evidence":"eBlocked."}
|
||
]}]}]},
|
||
{"id":"A5","label":"FLOW","title":"Flow","order":40,"orientation":"landscape","description":"Complete E01–E12 run through three protocols.","content_tex":"Phase and eBlocked handshakes prevent the receiver from running between posts while the p3 sender accumulates or combines values.","assets":[{"stem":"a5-flow","diagram_kind":"sequence","title":"A5 · three notification modes","caption":"A5 FLOW — count, overwrite and bits.","label":"fig:a5-flow","alt":"Sekwencja direct notifications.","phases":[{"id":"flow","label":"COUNT / OVERWRITE / BITS / PASS","steps":[
|
||
{"id":"config","number":1,"label":"clean slot contract","mode":"RUN","event_id":"E01","strategy_ref":"run.blocked","svg_label":"01","code_ref":"src/tasks/task01_notifications.c:263","snapshot_ref":"task01.config","description":"One index configured.","evidence":"event count 1."},
|
||
{"id":"arm","number":2,"label":"sender waits for phase and Blocked","mode":"RUN","event_id":"E02","strategy_ref":"run.blocked","svg_label":"02","code_ref":"src/tasks/task01_notifications.c:115","snapshot_ref":"task01.sender-armed","description":"No timing-only synchronization.","evidence":"sender SP."},
|
||
{"id":"wait-count","number":3,"label":"receiver waits for count","mode":"RUN","event_id":"E03","strategy_ref":"run.blocked","svg_label":"03","code_ref":"src/tasks/task01_notifications.c:162","snapshot_ref":"task01.wait-count","description":"Phase 1.","evidence":"receiver SP."},
|
||
{"id":"post-count","number":4,"label":"three gives while receiver Blocked","mode":"RUN","event_id":"E04","strategy_ref":"run.blocked","svg_label":"04","code_ref":"src/tasks/task01_notifications.c:116","snapshot_ref":"task01.post-count","description":"p3 posts without receiver interleave.","evidence":"state eBlocked."},
|
||
{"id":"count","number":5,"label":"take returns 3","mode":"RUN","event_id":"E05","strategy_ref":"run.values","svg_label":"05","code_ref":"src/tasks/task01_notifications.c:164","snapshot_ref":"task01.receive-count","description":"Clear all count.","evidence":"3."},
|
||
{"id":"wait-overwrite","number":6,"label":"slot zero before overwrite","mode":"RUN","event_id":"E06","strategy_ref":"run.values","svg_label":"06","code_ref":"src/tasks/task01_notifications.c:169","snapshot_ref":"task01.wait-overwrite","description":"Zero-time probe.","evidence":"clear=1."},
|
||
{"id":"post-overwrite","number":7,"label":"latest value wins","mode":"RUN","event_id":"E07","strategy_ref":"run.blocked","svg_label":"07","code_ref":"src/tasks/task01_notifications.c:124","snapshot_ref":"task01.post-overwrite","description":"0x11 then 0x22.","evidence":"receiver Blocked."},
|
||
{"id":"overwrite","number":8,"label":"wait returns 0x22","mode":"RUN","event_id":"E08","strategy_ref":"run.values","svg_label":"08","code_ref":"src/tasks/task01_notifications.c:177","snapshot_ref":"task01.receive-overwrite","description":"Intermediate state lost by contract.","evidence":"34."},
|
||
{"id":"wait-bits","number":9,"label":"slot zero before bit phase","mode":"RUN","event_id":"E09","strategy_ref":"run.values","svg_label":"09","code_ref":"src/tasks/task01_notifications.c:188","snapshot_ref":"task01.wait-bits","description":"Second clear proof.","evidence":"clear=1."},
|
||
{"id":"post-bits","number":10,"label":"two flags OR while Blocked","mode":"RUN","event_id":"E10","strategy_ref":"run.blocked","svg_label":"10","code_ref":"src/tasks/task01_notifications.c:136","snapshot_ref":"task01.post-bits","description":"0x04 and 0x20.","evidence":"state eBlocked."},
|
||
{"id":"bits","number":11,"label":"wait returns 0x24","mode":"RUN","event_id":"E11","strategy_ref":"run.values","svg_label":"11","code_ref":"src/tasks/task01_notifications.c:196","snapshot_ref":"task01.receive-bits","description":"Both flags preserved.","evidence":"36 and clear=1."},
|
||
{"id":"pass","number":12,"label":"verifier commits PASS","mode":"RUN","event_id":"E12","strategy_ref":"run.pass","svg_label":"12","code_ref":"src/tasks/task01_notifications.c:234","snapshot_ref":"task01.pass","description":"All three contracts hold.","evidence":"digest c60747cb."}
|
||
]}]}]},
|
||
{"id":"A6","label":"STATE","title":"State","order":50,"orientation":"portrait","description":"Notification value and pending state are not synonyms.","content_tex":"A pending notification can contain different values according to action. Consume/clear semantics are selected separately by receive API arguments.","assets":[{"stem":"a6-state","title":"A6 · notification state","caption":"A6 STATE — value and pending across three phases.","label":"fig:a6-state","alt":"Maszyna stanu notification.","phases":[{"id":"state","label":"CLEAR / WAITING / PENDING / CONSUMED","steps":[
|
||
{"id":"clear","number":1,"label":"slot begins clear","mode":"RUN","event_id":"E01","strategy_ref":"run.values","svg_label":"01","code_ref":"src/tasks/task01_notifications.c:263","snapshot_ref":"task01.config","description":"Value zero, not pending.","evidence":"clean RAM."},
|
||
{"id":"count","number":4,"label":"three increments create count 3","mode":"RUN","event_id":"E05","strategy_ref":"run.values","svg_label":"04","code_ref":"src/tasks/task01_notifications.c:118","snapshot_ref":"task01.receive-count","description":"pdTRUE clears whole count.","evidence":"3 then zero."},
|
||
{"id":"overwrite","number":7,"label":"overwrite replaces prior value","mode":"RUN","event_id":"E08","strategy_ref":"run.values","svg_label":"07","code_ref":"src/tasks/task01_notifications.c:124","snapshot_ref":"task01.receive-overwrite","description":"Latest state semantics.","evidence":"0x22."},
|
||
{"id":"bits","number":10,"label":"set bits combines flags","mode":"RUN","event_id":"E11","strategy_ref":"run.values","svg_label":"10","code_ref":"src/tasks/task01_notifications.c:136","snapshot_ref":"task01.receive-bits","description":"OR semantics.","evidence":"0x24 then zero."}
|
||
]}]}]},
|
||
{"id":"A7","label":"RUNTIME","title":"Runtime","order":60,"orientation":"landscape","description":"Public state proves blocking; TCB slot is debugger-only evidence.","content_tex":"Acceptance does not read private TCB fields. GDB may correlate ulNotifiedValue and ucNotifyState with the public results and source lines.","assets":[{"stem":"a7-runtime","title":"A7 · runtime evidence","caption":"A7 RUNTIME — task stacks and notification slot.","label":"fig:a7-runtime","alt":"Runtime direct notifications.","phases":[{"id":"runtime","label":"EXPERIMENT / TASKS / SLOT / LOG","steps":[
|
||
{"id":"exp","number":1,"label":"g_fc10 stores public results","mode":"CODE","strategy_ref":"code.contract","svg_label":"01","code_ref":"include/task01_notifications.h:22","description":"Persistent evidence object.","evidence":"states, values, probes."},
|
||
{"id":"sender","number":2,"label":"sender p3 owns distinct stack","mode":"RUN","event_id":"E02","strategy_ref":"run.blocked","svg_label":"02","code_ref":"src/tasks/task01_notifications.c:114","snapshot_ref":"task01.sender-armed","description":"Posting context.","evidence":"sender_sp."},
|
||
{"id":"receiver","number":3,"label":"receiver is public eBlocked","mode":"RUN","event_id":"E04","strategy_ref":"run.blocked","svg_label":"03","code_ref":"src/tasks/task01_notifications.c:116","snapshot_ref":"task01.post-count","description":"No private state assertion.","evidence":"receiver_sp and eBlocked."},
|
||
{"id":"slot","number":4,"label":"TCB slot is debugger evidence","mode":"RUN","event_id":"E07","strategy_ref":"run.values","svg_label":"04","code_ref":"vendor/FreeRTOS-Kernel/tasks.c:7800","snapshot_ref":"task01.post-overwrite","description":"Inspect value/state, do not depend on layout.","evidence":"0x22 pending."},
|
||
{"id":"absent","number":5,"label":"no queue or EventGroup object","mode":"CODE","strategy_ref":"code.contract","svg_label":"05","code_ref":"src/tasks/task01_notifications.c:260","description":"Direct path is part of topology.","evidence":"source and symbols."},
|
||
{"id":"log","number":6,"label":"twelve commit-last records","mode":"RUN","event_id":"E12","strategy_ref":"run.pass","svg_label":"06","code_ref":"src/tasks/task01_notifications.c:53","snapshot_ref":"task01.pass","description":"Stable evidence chain.","evidence":"digest."}
|
||
]}]}]},
|
||
{"id":"A8","label":"PATTERNS","title":"Patterns","order":70,"orientation":"landscape","description":"Choose action by what information may be lost.","content_tex":"Count preserves multiplicity, overwrite preserves only latest state, and set-bits preserves a set of flags. None is a broadcast or general message queue.","assets":[{"stem":"a8-patterns","title":"A8 · notification contracts","caption":"A8 PATTERNS — count, latest value and flags.","label":"fig:a8-patterns","alt":"Wzorce notification actions.","phases":[{"id":"patterns","label":"COUNT / LATEST / FLAGS / LIMITS","steps":[
|
||
{"id":"count","number":1,"label":"count preserves occurrences","mode":"RUN","event_id":"E05","strategy_ref":"run.values","svg_label":"01","code_ref":"src/tasks/task01_notifications.c:164","snapshot_ref":"task01.receive-count","description":"Choose clear-all or decrement-one.","evidence":"3."},
|
||
{"id":"overwrite","number":2,"label":"overwrite preserves latest only","mode":"RUN","event_id":"E08","strategy_ref":"run.values","svg_label":"02","code_ref":"src/tasks/task01_notifications.c:124","snapshot_ref":"task01.receive-overwrite","description":"0x11 may be lost intentionally.","evidence":"0x22."},
|
||
{"id":"bits","number":3,"label":"bits preserve independent flags","mode":"RUN","event_id":"E11","strategy_ref":"run.values","svg_label":"03","code_ref":"src/tasks/task01_notifications.c:136","snapshot_ref":"task01.receive-bits","description":"OR combines flags.","evidence":"0x24."},
|
||
{"id":"limits","number":4,"label":"slot is not queue or broadcast","mode":"CODE","strategy_ref":"code.contract","svg_label":"04","code_ref":"doc/card-plan.md:1","description":"One target consumes its own slot.","evidence":"explicit limitation."}
|
||
]}]}]}
|
||
],
|
||
"learning":{"model_label":"Model slotu notification","model":"Uczeń rozdziela target binding, pending state, value and action semantics.","replay_label":"Replay three modes","replay":"Uczeń odtwarza E01–E12 i pokazuje eBlocked, 3, 0x22, 0x24, clear probes, stacks and digest.","criterion":"PASS; receiver Blocked before each batch; results 3/0x22/0x24; three clear probes; deterministic digest.","requirement":"Dobór i zbadanie direct-to-task notification bez ukrytego obiektu synchronizacyjnego."},
|
||
"task":{"short_label":"notification modes","title":"Count, overwrite i bit flags na jednym slocie","prompt_tex":"Przejdź po A2, A3, A5, A6, A7 i A8. Odtwórz E01–E12 i wyjaśnij, jaką informację zachowuje i traci każda akcja.","conclusion_tex":"Direct notification jest szybkim protokołem skierowanym do jednego taska. Poprawność zależy od jawnego wyboru semantyki wartości, pending i clear.","flow":[
|
||
{"kind":"block","id":"predict","title":"A — kontrakty informacji","content_tex":"Przewidź wynik każdej pary API.","steps":[{"id":"values","title":"Zapisz 3, 0x22 i 0x24.","content_tex":"Wskaż, dlaczego 0x11 nie musi być obserwowalne."},{"id":"clear","title":"Rozdziel value i pending.","content_tex":"Opisz działanie pdTRUE oraz bits-to-clear."}]},
|
||
{"kind":"block","id":"replay","title":"B — replay Hazard3","content_tex":"Każdy RUN startuje od clean RAM.","steps":[{"id":"blocked","title":"Zbadaj E03/E06/E09.","content_tex":"Potwierdź receiver phase i Blocked."},{"id":"results","title":"Zbadaj E05/E08/E11.","content_tex":"Porównaj wyniki i clear probes."},{"id":"pass","title":"Zbadaj E12.","content_tex":"Zapisz PASS, SP i digest."}]},
|
||
{"kind":"exercise","id":"choose-action","title":"Ćwiczenie — dobór akcji","prompt_tex":"Dla licznika impulsów, najnowszej nastawy i dwóch niezależnych alarmów dobierz give/take, overwrite albo set-bits. Zapisz kontrakt utraty informacji.","evidence_tex":"Tabela protocol→action→clear oraz trzy krótkie ślady.","criterion":"Każdy wybór zachowuje dokładnie informację wymaganą przez protokół.","based_on":["predict","replay"]}
|
||
]}
|
||
}
|