Compare commits

...

5 Commits

20 changed files with 1236 additions and 127 deletions
+6
View File
@@ -5,6 +5,12 @@ Publiczny manifest wspólnego workspace EDU.
Repo opisuje serie i karty pracy dostępne dla `stemctl`. Nie przechowuje Repo opisuje serie i karty pracy dostępne dla `stemctl`. Nie przechowuje
tokenów, lokalnych ścieżek użytkownika ani plików roboczych ucznia. tokenów, lokalnych ścieżek użytkownika ani plików roboczych ucznia.
Widoczność karty w katalogu nie jest uprawnieniem do jej wykonania. W
zarządzanej usłudze nauczyciel uruchamia kartę przez `teactl`, a `stemctl`
ucznia może otworzyć i wykonać tylko wersję wskazaną bieżącym
`CardRunGrant`. Bezpośrednie przeglądanie katalogu pozostaje funkcją
developerską i standalone.
`workspace.json.series` zawiera wyłącznie aktywne serie obsługiwane przez `workspace.json.series` zawiera wyłącznie aktywne serie obsługiwane przez
`stemctl`. `workspace.json.catalog_subjects` zasila drzewo UI także seriami `stemctl`. `workspace.json.catalog_subjects` zasila drzewo UI także seriami
planowanymi, ale nie udostępnia ich poleceniom pobierania. Pozycję można dodać planowanymi, ale nie udostępnia ich poleceniom pobierania. Pozycję można dodać
+8 -8
View File
@@ -3,13 +3,13 @@
"title": "Bash · Console Tools", "title": "Bash · Console Tools",
"catalog_only": true, "catalog_only": true,
"cards": [ "cards": [
{"id": "L01", "repo": "lab-console-busybox", "number": "01", "title": "BusyBox — the Swiss Army Knife", "status": "planned"}, {"id": "L01", "repo": "lab-console-busybox", "number": "01", "title": "BusyBox — the Swiss Army Knife", "status": "existing"},
{"id": "L02", "repo": "lab-console-tmux", "number": "02", "title": "Tmux — sessions, windows and panes", "status": "planned"}, {"id": "L02", "repo": "lab-console-tmux", "number": "02", "title": "Tmux — sessions, windows and panes", "status": "existing"},
{"id": "L03", "repo": "lab-console-neovim", "number": "03", "title": "Neovim — navigation and editing", "status": "planned"}, {"id": "L03", "repo": "lab-console-neovim", "number": "03", "title": "Neovim — navigation and editing", "status": "existing"},
{"id": "L04", "repo": "lab-console-git-basics-1", "number": "04", "title": "Git Basics I — status, add and commit", "status": "planned"}, {"id": "L04", "repo": "lab-console-git-basics-1", "number": "04", "title": "Git Basics I — status, add and commit", "status": "existing"},
{"id": "L05", "repo": "lab-console-git-basics-2", "number": "05", "title": "Git Basics II — log, diff and restore", "status": "planned"}, {"id": "L05", "repo": "lab-console-git-basics-2", "number": "05", "title": "Git Basics II — log, diff and restore", "status": "existing"},
{"id": "L06", "repo": "lab-console-git-branching-1", "number": "06", "title": "Git Branching I — branch, switch and merge", "status": "planned"}, {"id": "L06", "repo": "lab-console-git-branching-1", "number": "06", "title": "Git Branching I — branch, switch and merge", "status": "existing"},
{"id": "L07", "repo": "lab-console-git-branching-2", "number": "07", "title": "Git Branching II — rebase and conflicts", "status": "planned"}, {"id": "L07", "repo": "lab-console-git-branching-2", "number": "07", "title": "Git Branching II — rebase and conflicts", "status": "existing"},
{"id": "L08", "repo": "lab-console-docker", "number": "08", "title": "Docker Fundamentals", "status": "planned"} {"id": "L08", "repo": "lab-console-docker", "number": "08", "title": "Docker Fundamentals", "status": "existing"}
] ]
} }
+12 -17
View File
@@ -1,22 +1,17 @@
{ {
"id": "cpp", "id": "cpp",
"title": "C++", "title": "C++ · Rok 2 · Semestr 1",
"catalog_only": true, "catalog_only": false,
"cards": [ "cards": [
{"id": "CPP01", "repo": "lab-cpp-build-namespaces", "number": "01", "title": "Translation Units, Linkage and Namespaces", "status": "planned"}, {"id": "CPP01", "repo": "lab-cpp-build-namespaces", "number": "01", "title": "Oddzielna kompilacja, linkage i przestrzenie nazw", "status": "existing"},
{"id": "CPP02", "repo": "lab-cpp-classes-invariants", "number": "02", "title": "Classes, Encapsulation and Invariants", "status": "planned"}, {"id": "CPP02", "repo": "lab-cpp-types-initialization", "number": "02", "title": "Typy, inicjalizacja, auto, const i enum class", "status": "existing"},
{"id": "CPP03", "repo": "lab-cpp-lifetime-raii", "number": "03", "title": "Construction, Destruction and RAII", "status": "planned"}, {"id": "CPP03", "repo": "lab-cpp-pointers-references", "number": "03", "title": "Wskaźniki, referencje, tablice i nullptr", "status": "existing"},
{"id": "CPP04", "repo": "lab-cpp-references-const", "number": "04", "title": "References, const and Value Categories", "status": "planned"}, {"id": "CPP04", "repo": "lab-cpp-functions-overloading", "number": "04", "title": "Funkcje, przeciążanie i modułowość", "status": "existing"},
{"id": "CPP05", "repo": "lab-cpp-copy-move", "number": "05", "title": "Copy, Move and the Rule of Zero/Five", "status": "planned"}, {"id": "CPP05", "repo": "lab-cpp-classes-objects", "number": "05", "title": "Klasa i obiekt: interfejs oraz implementacja", "status": "existing"},
{"id": "CPP06", "repo": "lab-cpp-ownership", "number": "06", "title": "Ownership and Resource Types", "status": "planned"}, {"id": "CPP06", "repo": "lab-cpp-invariants", "number": "06", "title": "Hermetyzacja, niezmienniki i odpowiedzialność klasy", "status": "existing"},
{"id": "CPP07", "repo": "lab-cpp-templates", "number": "07", "title": "Function and Class Templates", "status": "planned"}, {"id": "CPP07", "repo": "lab-cpp-construction-destruction", "number": "07", "title": "Konstruktory, destruktory i inicjalizacja obiektu", "status": "existing"},
{"id": "CPP08", "repo": "lab-cpp-static-polymorphism", "number": "08", "title": "Static Polymorphism and CRTP", "status": "planned"}, {"id": "CPP08", "repo": "lab-cpp-scope-lifetime", "number": "08", "title": "Zakres i czas życia obiektów", "status": "existing"},
{"id": "CPP09", "repo": "lab-cpp-dynamic-polymorphism", "number": "09", "title": "Inheritance, Interfaces and Dynamic Dispatch", "status": "planned"}, {"id": "CPP09", "repo": "lab-cpp-raii", "number": "09", "title": "RAII i zasób związany z czasem życia", "status": "existing"},
{"id": "CPP10", "repo": "lab-cpp-strong-types", "number": "10", "title": "Operator Overloading and Strong Types", "status": "planned"}, {"id": "CPP10", "repo": "lab-cpp-copy-move", "number": "10", "title": "Kopiowanie, przenoszenie i Rule of Zero/Five", "status": "existing"}
{"id": "CPP11", "repo": "lab-cpp-containers-iterators", "number": "11", "title": "Containers, Iterators and Algorithms", "status": "planned"},
{"id": "CPP12", "repo": "lab-cpp-lambdas-callables", "number": "12", "title": "Lambdas, Function Objects and Callables", "status": "planned"},
{"id": "CPP13", "repo": "lab-cpp-error-models", "number": "13", "title": "Error Models with and without Exceptions", "status": "planned"},
{"id": "CPP14", "repo": "lab-cpp-abi-evidence", "number": "14", "title": "Object Layout, ABI and Binary Evidence", "status": "planned"},
{"id": "CPP15", "repo": "lab-cpp-resource-integration", "number": "15", "title": "Resource-type Integration Project", "status": "planned"}
] ]
} }
+5 -5
View File
@@ -3,7 +3,7 @@
"title": "FreeRTOS C", "title": "FreeRTOS C",
"catalog_only": true, "catalog_only": true,
"cards": [ "cards": [
{"id": "FC01", "repo": "lab-rv32i-freertos-heap4", "number": "01", "title": "heap_1heap_5 and heap_4 mechanics", "status": "existing"}, {"id": "FC01", "repo": "lab-rv32i-freertos-heap4", "number": "01", "title": "heap_4: From Linear Cursor to Reusable Blocks", "status": "existing"},
{"id": "FC02", "repo": "lab-rv32i-freertos-c-first-task", "number": "02", "title": "First Task, TCB and Task Stack", "status": "existing"}, {"id": "FC02", "repo": "lab-rv32i-freertos-c-first-task", "number": "02", "title": "First Task, TCB and Task Stack", "status": "existing"},
{"id": "FC03", "repo": "lab-rv32i-freertos-c-scheduler", "number": "03", "title": "Tick, Scheduler, Priorities and Time Slicing", "status": "existing"}, {"id": "FC03", "repo": "lab-rv32i-freertos-c-scheduler", "number": "03", "title": "Tick, Scheduler, Priorities and Time Slicing", "status": "existing"},
{"id": "FC04", "repo": "lab-rv32i-freertos-c-delay-state", "number": "04", "title": "Delay, Blocking and Task States", "status": "existing"}, {"id": "FC04", "repo": "lab-rv32i-freertos-c-delay-state", "number": "04", "title": "Delay, Blocking and Task States", "status": "existing"},
@@ -14,9 +14,9 @@
{"id": "FC09", "repo": "lab-rv32i-freertos-c-event-groups", "number": "09", "title": "Event Groups and Multi-event Synchronization", "status": "existing"}, {"id": "FC09", "repo": "lab-rv32i-freertos-c-event-groups", "number": "09", "title": "Event Groups and Multi-event Synchronization", "status": "existing"},
{"id": "FC10", "repo": "lab-rv32i-freertos-c-notifications", "number": "10", "title": "Direct-to-task Notifications", "status": "existing"}, {"id": "FC10", "repo": "lab-rv32i-freertos-c-notifications", "number": "10", "title": "Direct-to-task Notifications", "status": "existing"},
{"id": "FC11", "repo": "lab-rv32i-freertos-c-static-allocation", "number": "11", "title": "Static Allocation and Bounded Storage", "status": "existing"}, {"id": "FC11", "repo": "lab-rv32i-freertos-c-static-allocation", "number": "11", "title": "Static Allocation and Bounded Storage", "status": "existing"},
{"id": "FC12", "repo": "lab-rv32i-freertos-c-diagnostics", "number": "12", "title": "Assertions, Hooks, Stack Checks and Runtime Diagnostics", "status": "planned"}, {"id": "FC12", "repo": "lab-rv32i-freertos-c-diagnostics", "number": "12", "title": "Assertions, Hooks, Stack Checks and Runtime Diagnostics", "status": "existing"},
{"id": "FC13", "repo": "lab-rv32i-freertos-c-uart", "number": "13", "title": "UART Interrupt-to-task Pipeline", "status": "planned"}, {"id": "FC13", "repo": "lab-rv32i-freertos-c-uart", "number": "13", "title": "UART Interrupt-to-task Pipeline", "status": "existing"},
{"id": "FC14", "repo": "lab-rv32i-freertos-c-gpio-timer", "number": "14", "title": "GPIO, Hardware Timer and Deferred Work", "status": "planned"}, {"id": "FC14", "repo": "lab-rv32i-freertos-c-gpio-timer", "number": "14", "title": "GPIO, Hardware Timer and Deferred Work", "status": "existing"},
{"id": "FC15", "repo": "lab-rv32i-freertos-c-integration", "number": "15", "title": "Integrated Deterministic FreeRTOS C Application", "status": "planned"} {"id": "FC15", "repo": "lab-rv32i-freertos-c-integration", "number": "15", "title": "Integrated Deterministic FreeRTOS C Application", "status": "existing"}
] ]
} }
+15 -15
View File
@@ -3,20 +3,20 @@
"title": "FreeRTOS C++", "title": "FreeRTOS C++",
"catalog_only": true, "catalog_only": true,
"cards": [ "cards": [
{"id": "K02", "repo": "lab-rv32i-freertos-task-stack-vector", "number": "02", "title": "First Task, Stack, Tick, Scheduler and Vector V0", "status": "existing"}, {"id": "K02", "repo": "lab-rv32i-freertos-task-stack-vector", "number": "02", "title": "C++ Task<Derived> Wrapper, CRTP and Lifecycle", "status": "existing"},
{"id": "K03", "repo": "lab-rv32i-freertos-vector-raii", "number": "03", "title": "Vector V1 — Destructor, Move, Ownership and RAII", "status": "planned"}, {"id": "K03", "repo": "lab-rv32i-freertos-vector-raii", "number": "03", "title": "Vector V1 — Destructor, Move, Ownership and RAII", "status": "existing"},
{"id": "K04", "repo": "lab-rv32i-freertos-scheduler-states", "number": "04", "title": "Scheduler States, Priorities and Typed Ticks", "status": "planned"}, {"id": "K04", "repo": "lab-rv32i-freertos-scheduler-states", "number": "04", "title": "Scheduler States, Priorities and Typed Ticks", "status": "existing"},
{"id": "K05", "repo": "lab-rv32i-freertos-heap-models", "number": "05", "title": "C++ Heap Bridge, Heap Models and HeapStats", "status": "planned"}, {"id": "K05", "repo": "lab-rv32i-freertos-heap-models", "number": "05", "title": "C++ Heap Bridge, Heap Models and HeapStats", "status": "existing"},
{"id": "K06", "repo": "lab-rv32i-freertos-allocator-resource", "number": "06", "title": "MemoryResource and FreeRtosAllocator<T>", "status": "planned"}, {"id": "K06", "repo": "lab-rv32i-freertos-allocator-resource", "number": "06", "title": "MemoryResource and FreeRtosAllocator<T>", "status": "existing"},
{"id": "K07", "repo": "lab-rv32i-freertos-task-wrapper", "number": "07", "title": "TaskHandle_t, Explicit Start and Static Trampoline", "status": "planned"}, {"id": "K07", "repo": "lab-rv32i-freertos-task-wrapper", "number": "07", "title": "TaskHandle_t, Explicit Start and Static Trampoline", "status": "existing"},
{"id": "K08", "repo": "lab-rv32i-freertos-static-task", "number": "08", "title": "DynamicTask, StaticTask, Deletion and Lifetime", "status": "planned"}, {"id": "K08", "repo": "lab-rv32i-freertos-static-task", "number": "08", "title": "DynamicTask, StaticTask, Deletion and Lifetime", "status": "existing"},
{"id": "K09", "repo": "lab-rv32i-freertos-kernel-facade", "number": "09", "title": "Scheduler Facade and Scoped Kernel Guards", "status": "planned"}, {"id": "K09", "repo": "lab-rv32i-freertos-kernel-facade", "number": "09", "title": "Scheduler Facade and Scoped Kernel Guards", "status": "existing"},
{"id": "K10", "repo": "lab-rv32i-freertos-queue", "number": "10", "title": "Queue<T> and StaticQueue<T, N>", "status": "planned"}, {"id": "K10", "repo": "lab-rv32i-freertos-queue", "number": "10", "title": "Queue<T> and StaticQueue<T, N>", "status": "existing"},
{"id": "K11", "repo": "lab-rv32i-freertos-mutex", "number": "11", "title": "Mutex, LockGuard and Priority Inheritance", "status": "planned"}, {"id": "K11", "repo": "lab-rv32i-freertos-mutex", "number": "11", "title": "Mutex, LockGuard and Priority Inheritance", "status": "existing"},
{"id": "K12", "repo": "lab-rv32i-freertos-semaphore-notify", "number": "12", "title": "Semaphores and Task Notifications", "status": "planned"}, {"id": "K12", "repo": "lab-rv32i-freertos-semaphore-notify", "number": "12", "title": "Semaphores and Task Notifications", "status": "existing"},
{"id": "K13", "repo": "lab-rv32i-freertos-event-group", "number": "13", "title": "EventGroup and Coordinated State", "status": "planned"}, {"id": "K13", "repo": "lab-rv32i-freertos-event-group", "number": "13", "title": "EventGroup and Coordinated State", "status": "existing"},
{"id": "K14", "repo": "lab-rv32i-freertos-sw-timer", "number": "14", "title": "Software Timer and the Timer Daemon Task", "status": "planned"}, {"id": "K14", "repo": "lab-rv32i-freertos-sw-timer", "number": "14", "title": "Software Timer and the Timer Daemon Task", "status": "existing"},
{"id": "K15", "repo": "lab-rv32i-freertos-isr-drivers", "number": "15", "title": "Explicit FromISR, UART and GPIO Wrappers", "status": "planned"}, {"id": "K15", "repo": "lab-rv32i-freertos-isr-drivers", "number": "15", "title": "Explicit FromISR, UART and GPIO Wrappers", "status": "existing"},
{"id": "K16", "repo": "lab-rv32i-freertos-integration", "number": "16", "title": "Integrated Real-time Application and Evidence", "status": "planned"} {"id": "K16", "repo": "lab-rv32i-freertos-integration", "number": "16", "title": "Integrated Real-time Application and Evidence", "status": "existing"}
] ]
} }
+9 -9
View File
@@ -3,14 +3,14 @@
"title": "ASM · RV32I From Blinker to RISC-V", "title": "ASM · RV32I From Blinker to RISC-V",
"catalog_only": true, "catalog_only": true,
"cards": [ "cards": [
{"id": "L01", "repo": "lab-rv32i-asm-number-systems", "number": "01", "title": "Number Systems and Storage", "status": "planned"}, {"id": "L01", "repo": "lab-rv32i-asm-number-systems", "number": "01", "title": "Number Systems and Storage", "status": "existing"},
{"id": "L02", "repo": "lab-rv32i-asm-fpga-bringup", "number": "02", "title": "FPGA Bring-up and Programming", "status": "planned"}, {"id": "L02", "repo": "lab-rv32i-asm-fpga-bringup", "number": "02", "title": "FPGA Bring-up and Programming", "status": "existing"},
{"id": "L03", "repo": "lab-rv32i-asm-blinker", "number": "03", "title": "Blinker and Synchronous Logic", "status": "planned"}, {"id": "L03", "repo": "lab-rv32i-asm-blinker", "number": "03", "title": "Blinker and Synchronous Logic", "status": "existing"},
{"id": "L04", "repo": "lab-rv32i-asm-decoder", "number": "04", "title": "The RISC-V ISA and Instruction Decoder", "status": "planned"}, {"id": "L04", "repo": "lab-rv32i-asm-decoder", "number": "04", "title": "The RISC-V ISA and Instruction Decoder", "status": "existing"},
{"id": "L05", "repo": "lab-rv32i-asm-alu", "number": "05", "title": "ALU and the Verilog Assembler", "status": "planned"}, {"id": "L05", "repo": "lab-rv32i-asm-alu", "number": "05", "title": "ALU and the Verilog Assembler", "status": "existing"},
{"id": "L06", "repo": "lab-rv32i-asm-control-flow", "number": "06", "title": "Control Flow — Jumps and Branches", "status": "planned"}, {"id": "L06", "repo": "lab-rv32i-asm-control-flow", "number": "06", "title": "Control Flow — Jumps and Branches", "status": "existing"},
{"id": "L07", "repo": "lab-rv32i-asm-addresses-memory", "number": "07", "title": "Addresses and Memory", "status": "planned"}, {"id": "L07", "repo": "lab-rv32i-asm-addresses-memory", "number": "07", "title": "Addresses and Memory", "status": "existing"},
{"id": "L08", "repo": "lab-rv32i-asm-subroutines-abi", "number": "08", "title": "Subroutines and the RISC-V ABI", "status": "planned"}, {"id": "L08", "repo": "lab-rv32i-asm-subroutines-abi", "number": "08", "title": "Subroutines and ABI", "status": "existing"},
{"id": "L09", "repo": "lab-rv32i-asm-load-store", "number": "09", "title": "Load and Store", "status": "planned"} {"id": "L09", "repo": "lab-rv32i-asm-load-store", "number": "09", "title": "Load and Store Semantics", "status": "existing"}
] ]
} }
+7 -5
View File
@@ -14,7 +14,8 @@ INF · Informatyka
│ ├── ASM · RV32I From Blinker to RISC-V [9] │ ├── ASM · RV32I From Blinker to RISC-V [9]
│ └── C · Freestanding RV32I and K&R [13] │ └── C · Freestanding RV32I and K&R [13]
├── Rok 2 ├── Rok 2
│ ├── C++ [15] │ ├── C++ · semestr 1 [10 active]
│ ├── C++ · semestr 2 [10 planned]
│ ├── FreeRTOS C [15] │ ├── FreeRTOS C [15]
│ ├── FreeRTOS C++ [15] │ ├── FreeRTOS C++ [15]
│ ├── POSIX Threads [15] │ ├── POSIX Threads [15]
@@ -29,10 +30,11 @@ INF · Informatyka
``` ```
Pierwszy blok zawiera dokładnie 30 tematów: Bash 8 + ASM 9 + C 13. Pierwszy blok zawiera dokładnie 30 tematów: Bash 8 + ASM 9 + C 13.
Drugi blok zawiera dokładnie 60 tematów: FreeRTOS C 15 + C++ 15 + FreeRTOS Drugi rok zawiera dwusemestralny kurs teoretyczny C++ (10 + 10 lekcji) oraz
C++ 15 + POSIX Threads 15. OOP and Design Patterns jest osobnym kursem i nie osobne serie laboratoryjne FreeRTOS C, FreeRTOS C++ i POSIX Threads po 15
jest wliczany do tych 60. `std::thread`/`std::jthread` i Boost.Asio są kolejnym kart. OOP and Design Patterns jest osobnym kursem odniesienia. Aktywna seria
etapem i nie są jeszcze częścią tego katalogu. `cpp` obejmuje obecnie komplet pierwszego semestru. Biblioteka standardowa,
`std::thread`/`std::jthread` i Boost.Asio należą do kolejnych semestrów.
Kolejność stosowania języków jest jawna: Kolejność stosowania języków jest jawna:
+58 -1
View File
@@ -1,6 +1,6 @@
# C — Freestanding RV32I and K&R # C — Freestanding RV32I and K&R
Status: 8 kart istniejących lub rozpoczętych, 5 planowanych. Status: C01C13 gotowe; seria C zakończona przed rozpoczęciem serii C++.
```text ```text
C · Freestanding RV32I and K&R C · Freestanding RV32I and K&R
@@ -23,5 +23,62 @@ RV32I ASM jest osobną serią-prerekwizytem. C01C03 tworzą przejście z
freestanding assemblera do środowiska C, ale pozostają kartami serii C, freestanding assemblera do środowiska C, ale pozostają kartami serii C,
ponieważ ich wynikiem jest rozumienie uruchomienia i ABI programu C. ponieważ ich wynikiem jest rozumienie uruchomienia i ABI programu C.
## Układ każdego przykładu: A1A8
Każdy przykład źródłowy w karcie serii C jest osobnym taskiem i jawnie
odpowiada na komplet pytań A1A8:
```text
A1 CONTEXT granica systemu i odpowiedzialność przykładu
A2 STRUCTURE typy, obiekty, reprezentacja i ownership
A3 DISPATCH granica wywołania, callbacku albo ISR
A4 APPLICATION konkretne funkcje, dane i inwariant przykładu
A5 FLOW kolejność wykonania oraz checkpointy
A6 STATE stan, lifetime i przejścia wartości
A7 RUNTIME ABI, rejestry, adresy, sekcje ELF i wynik pomiaru
A8 PATTERNS nazwana, rzeczywiście wielokrotnego użytku decyzja
```
A1A8 jest profilem pytań, a nie nakazem tworzenia ośmiu dekoracyjnych
diagramów. Każda pozycja ma status `enabled` albo `unavailable`. Widok
`enabled` musi wnosić odrębny dowód; `unavailable` zawiera konkretny powód.
Wartościowy opis tekstowy jest pełnoprawnym widokiem. Diagram powstaje tylko
wtedy, gdy relacja, kolejność lub stan są mniej czytelne w krótkim tekście.
Dla C04C06 nowe źródło JSON, TeX, HTML i nowy PDF są dodawane obok
historycznych kart. Oryginalne `doc/main.tex`, PDF-y oraz przykłady w
`src/tasks/` pozostają niezmienionym materiałem referencyjnym.
Pełne cele C10C13 i granica roku znajdują się w Pełne cele C10C13 i granica roku znajdują się w
`series/inf/lab-rv32i-c-pointers-arrays/guidelines/year-01-interrupts-to-year-02-freertos.md`. `series/inf/lab-rv32i-c-pointers-arrays/guidelines/year-01-interrupts-to-year-02-freertos.md`.
## Stan odbioru serii C — 2026-07-20
Każda karta ma wygenerowane źródło JSON, widok web i nowy PDF. Odbiór
potwierdza dokładną kolejność A1A8 w każdym tasku, jawne uzasadnienie każdego
N/D, poprawny JSON i JavaScript, poprawność PDF według `qpdf` oraz brak pustych,
anonimowych i przepełnionych stron. Przykłady uruchamialne przeszły właściwe
testy hostowe i/lub wyrocznie Hazard3.
```text
karta przykłady bloki A1A8
C01 3 24
C02 4 32
C03 2 16
C04 12 96
C05 8 64
C06 11 88
C07 12 96
C08 4 32
C09 5 40
C10 3 24
C11 3 24
C12 3 24
C13 4 32
RAZEM 74 592
```
PDF-y mają łącznie 180 stron. Spośród 592 widoków 508 ma stan `enabled`, a 84
ma stan `unavailable` z konkretnym powodem. Historyczne źródła C04C06 nadal są
materiałem referencyjnym: nowy układ nie nadpisuje `doc/main.tex`, starych
PDF-ów ani przykładów w `src/tasks/`.
+49 -3
View File
@@ -1,6 +1,7 @@
# Bash · Console Tools — plan kart # Bash · Console Tools — plan kart
Status: plan, 8 lekcji. Status: L01L08 gotowe; seria zakończona i odbierana w profilu
`native-amd64` przez `stemctl`.
Seria przygotowuje warsztat przed FPGA, assemblerem i C. Nazwa obejmuje pracę Seria przygotowuje warsztat przed FPGA, assemblerem i C. Nazwa obejmuje pracę
w powłoce i terminalu; BusyBox może udostępniać `ash`, więc nie utożsamiamy w powłoce i terminalu; BusyBox może udostępniać `ash`, więc nie utożsamiamy
@@ -18,8 +19,53 @@ Bash · Console Tools
└── L08 · Docker Fundamentals └── L08 · Docker Fundamentals
``` ```
Każda karta kończy się małym dowodem wykonania: komendą, stanem terminala albo Każda karta zawiera trzy wykonywalne taski. Repozytorium karty dostarcza
historią Git, którą uczeń potrafi odtworzyć i wyjaśnić. kontrakt `stem-card.yaml`, testy stanu, wygenerowany widok React, dwustronicowy
PDF A4 oraz akcje `build`, `test`, `run` i `debug`. Debug zapisuje
`trace.log` w katalogu artefaktów tasku.
## Stan odbioru serii — 2026-07-21
| Karta | Dowód końcowy |
| --- | --- |
| L01 BusyBox | dispatch multicall, operacje plikowe, proces i host |
| L02 Tmux | sesja, okna i panele, zachowanie stanu po detach/attach |
| L03 Neovim | nawigacja, search/edit/save, undo/redo |
| L04 Git Basics I | init, status/add, pierwszy commit i clean |
| L05 Git Basics II | log, diff staged/worktree, bezpieczne restore |
| L06 Git Branching I | branch/switch, rozbieżność, merge commit |
| L07 Git Branching II | rebase, rzeczywisty konflikt UU, liniowa historia |
| L08 Docker | specyfikacja image, lifecycle, volume i bind mount |
Wszystkie 24 taski przechodzą w kontenerze `native-amd64`. Każdy task pracuje
w izolowanym katalogu tymczasowym i raportuje mierzalny komunikat `PASS`.
### Granice środowiska
Obraz `native-amd64` nie zawiera BusyBox. L01 używa więc audytowalnego
fixture C implementującego wyłącznie ćwiczony mechanizm multicall, wykrywa
prawdziwy BusyBox, gdy jest dostępny, i zawsze raportuje użyty backend. Fixture
nie jest przedstawiany jako binarka BusyBox.
Profil ucznia nie otrzymuje socketu Docker/Podman. L08 używa jawnego modelu
stanów offline do sprawdzenia semantyki image/container/storage. Jego `PASS`
nie oznacza uruchomienia prawdziwego silnika. Powtórzenie ćwiczenia z realnym
CLI należy wykonać na kontrolowanej maszynie operatorskiej, najlepiej z
rootless Podmanem albo Dockerem, bez montowania socketu do kontenera ucznia.
### Sposób uruchamiania
```bash
stemctl series show console-bash
stemctl list-cards console-bash
stemctl card use console-bash L01
stemctl test native-amd64 console-bash L01 1
stemctl debug native-amd64 console-bash L01 3
```
Numer karty i tasku można podmienić na dowolne L01L08 i 13. Identyfikatory,
repozytoria i kolejność kart są zapisane w `series/console-bash.json`, a stan
realizacji w `catalog/console-bash.json`.
Pierwotne ustalenia znajdują się również w Pierwotne ustalenia znajdują się również w
`series/inf/lab-rv32i-c-pointers-arrays/guidelines/console-series.md`. `series/inf/lab-rv32i-c-pointers-arrays/guidelines/console-series.md`.
+49 -26
View File
@@ -1,32 +1,55 @@
# C++ — plan kart # C++ — plan wielosemestralny i stan wdrożenia
Status: plan, 15 tematów. Źródło zakresu: `/home/user/dev/keys/cxx.md`. Standard kursu: C++20 z
wybranymi, jawnie oznaczonymi elementami C++23. Cykl obejmuje 53 lekcje
teoretyczne. Projekty, FreeRTOS i praca na urządzeniu pozostają osobnymi
zajęciami.
Seria uczy języka i modelu obiektu bez zależności od RTOS. Dopiero po niej | Etap | Lekcje | Oś merytoryczna | Stan |
uczeń przechodzi do FreeRTOS C++ i rozpoznaje, które zachowanie pochodzi z C++, | --- | ---: | --- | --- |
a które z wrappera lub kernela. Kurs może być prowadzony równolegle z | Rok 2, semestr 1 | 10 | fundamenty języka, klasy, czas życia i RAII | **wdrożony** |
FreeRTOS C, ponieważ oba mają wspólny ukończony prerekwizyt C. | Rok 2, semestr 2 | 10 | OOP i C++ w systemach wbudowanych | plan |
| Rok 3, semestr 1 | 16 | STL i biblioteka standardowa | plan |
| Rok 3, semestr 2 | 17 | współbieżność, korutyny i Boost.Asio | plan |
## Rok 2, semestr 1 — aktywna seria `cpp`
Książka prowadząca: Bjarne Stroustrup, *A Tour of C++, 3rd Edition*.
*The C++ Programming Language, 4th Edition* jest źródłem uzupełniającym dla
nauczyciela. Karty parafrazują pojęcia i zawierają własne eksperymenty; nie
kopiują treści książek.
```text ```text
C++ C++ · Rok 2 · Semestr 1
├── CPP01 · Translation Units, Linkage and Namespaces ├── CPP01 · Oddzielna kompilacja, deklaracja, definicja, linkage i namespace
├── CPP02 · Classes, Encapsulation and Invariants ├── CPP02 · Typy, inicjalizacja, auto, const, enum class i typ użytkownika
├── CPP03 · Construction, Destruction and RAII ├── CPP03 · Wskaźniki, referencje, tablice, nullptr i argumenty
├── CPP04 · References, const and Value Categories ├── CPP04 · Funkcje, przeciążanie, wartości zwracane, zakres i modułowość
├── CPP05 · Copy, Move and the Rule of Zero/Five ├── CPP05 · Klasa i obiekt: pola, metody, dostęp, interfejs i implementacja
├── CPP06 · Ownership and Resource Types ├── CPP06 · Hermetyzacja, niezmienniki i odpowiedzialność klasy
├── CPP07 · Function and Class Templates ├── CPP07 · Konstruktory, destruktory i inicjalizacja obiektu
├── CPP08 · Static Polymorphism and CRTP ├── CPP08 · Zakres i czas życia obiektów automatycznych, statycznych i dynamicznych
├── CPP09 · Inheritance, Interfaces and Dynamic Dispatch ├── CPP09 · RAII i powiązanie zasobu z czasem życia obiektu
── CPP10 · Operator Overloading and Strong Types ── CPP10 · Kopiowanie, przenoszenie, Rule of Zero/Five i własność zasobu
├── CPP11 · Containers, Iterators and Algorithms
├── CPP12 · Lambdas, Function Objects and Callables
├── CPP13 · Error Models with and without Exceptions
├── CPP14 · Object Layout, ABI and Binary Evidence
└── CPP15 · Resource-type Integration Project
``` ```
Kurs OOP/wzorców pozostaje osobną serią. Karty C++ mogą przygotowywać potrzebny Każda karta ma trzy niezależne programy, kompilację
mechanizm, ale nie udają, że każda cecha języka jest wzorcem GoF. Gdy w kodzie `-std=c++20 -Wall -Wextra -Wpedantic -Werror`, dokładny kontrakt stdout,
pojawia się rzeczywisty problem projektowy, karta C++ linkuje do odpowiedniej testy Node, widok React, PDF A4 i akcje `build/test/run/debug` dla profilu
karty OOP jako rozwinięcia decyzji. `native-amd64`. Generator źródeł znajduje się w
`tools/generate_cpp_y2s1.py` tego repozytorium.
## Granice kolejnych semestrów
- Semestr 2 rozpoczyna się od typów wartościowych i operatorów, a kończy
teorią wrapperów `Task`, `StaticQueue<T,N>`, `Mutex` i `LockGuard`.
- Rok 3, semestr 1 należy do STL: kontenery, iteratory, algorytmy, ranges,
typy pomocnicze, smart pointery i narzędzia biblioteki standardowej.
- Rok 3, semestr 2 obejmuje `thread`/`jthread`, synchronizację, atomiki,
futures, korutyny i Boost.Asio.
- Szczegóły API FreeRTOS, portu, ISR i uruchamiania na płytce pozostają w
seriach FreeRTOS C oraz FreeRTOS C++.
Kurs OOP/wzorców jest osobną serią odniesienia. Karta C++ linkuje do niej
dopiero wtedy, gdy występuje rzeczywisty problem projektowy, a nie tylko
pojedynczy mechanizm języka.
+39 -20
View File
@@ -1,8 +1,8 @@
# FreeRTOS C — book-led card sequence # FreeRTOS C — book-led card sequence
Status: FC01FC02 exist; FC03 is the next implementation; FC04FC15 are Status: FC01FC15 istnieją; blok 15 kart FreeRTOS C jest kompletny i stanowi
planned. This series uses only the FreeRTOS C API. C++ wrappers belong to a zamknięty fundament przed serią FreeRTOS C++. Każda karta używa publicznego
later, separate series. API C, a końcowa FC15 scala mechanizmy w jeden deterministyczny eksperyment.
## Primary source and ordering rule ## Primary source and ordering rule
@@ -62,7 +62,7 @@ simulator.
```text ```text
FreeRTOS C — 15 cards FreeRTOS C — 15 cards
├── FC01 · Heap schemes and heap_4 block mechanics ├── FC01 · heap_4: from a linear cursor to reusable blocks
├── FC02 · First task, typed context, TCB and task stack ├── FC02 · First task, typed context, TCB and task stack
├── FC03 · Tick, priorities, preemption and time slicing ├── FC03 · Tick, priorities, preemption and time slicing
├── FC04 · Delay, blocking, task states and deletion ├── FC04 · Delay, blocking, task states and deletion
@@ -79,22 +79,37 @@ FreeRTOS C — 15 cards
└── FC15 · Integrated deterministic FreeRTOS C application └── FC15 · Integrated deterministic FreeRTOS C application
``` ```
## FC01 — Heap schemes and heap_4 block mechanics ## FC01 — `heap_4`: from a linear cursor to reusable blocks
**Book basis:** 3.13.4: `heap_1``heap_5`, heap utilities, allocation **Duration:** one 30-minute lesson.
failure and static allocation introduction.
**Direct predecessor:** C07, K&R 5.4 Task04 — `allocbuf[64]`, `allocp`,
`alloc(5)`, `alloc(7)` and cursor offsets `0 -> 5 -> 12`.
**Book basis:** the `heap_4` and heap-statistics parts of Chapter 3. The other
FreeRTOS heap implementations are a one-minute map of alternatives, not
parallel lesson content.
- Opening problem: the linear project cannot release the first 5-byte area
while preserving the later 7-byte area, cannot remember reusable holes and
recovers the arena only with a whole-arena reset.
- New model: a block header, an address-ordered free list, first-fit selection,
splitting and coalescing of physically adjacent free blocks.
- Raw API: `pvPortMalloc`, `vPortFree`, `xPortGetFreeHeapSize`, - Raw API: `pvPortMalloc`, `vPortFree`, `xPortGetFreeHeapSize`,
`xPortGetMinimumEverFreeHeapSize`, `vPortGetHeapStats`. `xPortGetMinimumEverFreeHeapSize`, `vPortGetHeapStats`.
- Main task: compare allocator policies, then walk allocation, split, free - Task 1 and Task 2 are short teacher-led models with a student prediction;
and coalescing in `heap_4`. they are not separate build/debug sessions during the lesson.
- Blocks: A1 allocator boundary; A2 block/list layout; A5 allocation flow; - Task 3 is the only central student replay: real upstream `heap_4.c`, two
A6 free/allocated block state; A7 heap addresses and statistics. stable checkpoints, fragmentation metrics, recovery and OOM.
- Exercise: predict the free-list shape for a new allocate/free order. - Pico 2 W supplies one prebuilt RP2350 hardware observation. `heap_4` is the
- Hazard3/GDB proof: block headers, aligned sizes and coalesced neighbors allocator selected and linked by the project, not a hardware feature of the
agree with the final heap statistics. microcontroller.
- Main pitfall: treating the minimum-ever-free value as current free space or - Acceptance: the student names the three additions over the linear allocator
assuming all heap implementations support free/coalescing. (header, free list, coalescing), predicts `2 free blocks -> 1 free block`,
and distinguishes current free bytes, largest free block and minimum-ever
free bytes.
- Main pitfall: assuming that a large sum of free bytes guarantees one large
allocation, or that minimum-ever-free increases after `free`.
## FC02 — First task, typed context, TCB and task stack ## FC02 — First task, typed context, TCB and task stack
@@ -367,10 +382,12 @@ Every new card must contain:
8. HTML and TeX generated from one `card_source.json`; 8. HTML and TeX generated from one `card_source.json`;
9. no PDF generation and no commit unless explicitly requested. 9. no PDF generation and no commit unless explicitly requested.
## Implementation order ## Completed implementation order
```text ```text
FC03 scheduler FC01 heap_4
→ FC02 first task
→ FC03 scheduler
→ FC04 state/delay → FC04 state/delay
→ FC05 queues → FC05 queues
→ FC06 software timers → FC06 software timers
@@ -385,5 +402,7 @@ FC03 scheduler
→ FC15 integration → FC15 integration
``` ```
Ukończenie FC15 jest pierwszą z dwóch bramek wejścia do FreeRTOS C++; drugą Obie bramki wejścia do FreeRTOS C++ są spełnione: FC15 zamyka tor systemowy C,
jest ukończenie właściwych kart językowych C++/OOP. a właściwe karty językowe C++/OOP dostarczają model własności, RAII, szablony i
statyczne trampoline. Następnym etapem jest audyt i realizacja serii FreeRTOS
C++ karta po karcie, bez mieszania wrapperów z implementacją kernela w C.
+8 -4
View File
@@ -1,14 +1,18 @@
# FreeRTOS C++ — plan kart # FreeRTOS C++ — plan kart
Status: K02 istnieje i jest bieżącą kartą; K03K16 są planem. Status: K02K16 są gotowe; blok 15 kart jest kompletny. Każda karta ma
freestanding build C++17, test hosta, kontrolę ABI, wykonanie na Hazard3 oraz
sprawdzony PDF. Źródła i artefakty używają wspólnej numeracji Kxx/16.
Karta `heap_4` należy do serii FreeRTOS C. FreeRTOS C++ zaczyna się dopiero po Karta `heap_4` należy do serii FreeRTOS C. FreeRTOS C++ zaczyna się dopiero po
ukończeniu dwóch torów prowadzonych równolegle: FreeRTOS C oraz C++. K02 ukończeniu dwóch torów prowadzonych równolegle: FreeRTOS C oraz C++. K02
porównuje znany już surowy task C z freestanding wrapperem C++ i Vector V0. wprowadza freestanding wrapper `Task<Derived>`, CRTP i statyczny trampoline.
K03 pokazuje krótki, celowo niepełny Vector V0 bez ukrytego wymagania wykonania
osobnej karty, a następnie buduje z niego move-only Vector V1 z RAII.
```text ```text
FreeRTOS C++ FreeRTOS C++
├── K02 · First Task, Stack, Tick, Scheduler and Vector V0 ├── K02 · C++ Task<Derived> Wrapper, CRTP and Lifecycle
├── K03 · Vector V1 — Destructor, Move, Ownership and RAII ├── K03 · Vector V1 — Destructor, Move, Ownership and RAII
├── K04 · Scheduler States, Priorities and Typed Ticks ├── K04 · Scheduler States, Priorities and Typed Ticks
├── K05 · C++ Heap Bridge, Heap Models and HeapStats ├── K05 · C++ Heap Bridge, Heap Models and HeapStats
@@ -32,7 +36,7 @@ freestanding, bez wyjątków, RTTI i zależności od hosted `libstdc++`.
Każda karta linkuje również do osobnej serii OOP, gdy wrapper rzeczywiście Każda karta linkuje również do osobnej serii OOP, gdy wrapper rzeczywiście
realizuje wzorzec lub idiom wymagający osobnego omówienia. realizuje wzorzec lub idiom wymagający osobnego omówienia.
Szczegółowy plan bieżącej K02 oraz kontrolowane porównanie z FC02: Materiały wejściowe K02 oraz kontrolowane porównanie z FC02:
- [K02 Task01 — A1A8 plan](../../../../series/freertos/lab-rv32i-freertos-task-stack-vector/doc/task01-a1-a8-plan.md) - [K02 Task01 — A1A8 plan](../../../../series/freertos/lab-rv32i-freertos-task-stack-vector/doc/task01-a1-a8-plan.md)
- [FC02/K02 — paired first-task experiment](freertos-first-task-a1-a8.md) - [FC02/K02 — paired first-task experiment](freertos-first-task-a1-a8.md)
+54 -12
View File
@@ -1,24 +1,66 @@
# ASM · RV32I From Blinker to RISC-V # ASM · RV32I From Blinker to RISC-V
Status: plan, 9 lekcji. Status: L01--L09 opracowane, testowane i zarejestrowane; seria zakończona.
```text ```text
ASM · RV32I From Blinker to RISC-V ASM · RV32I From Blinker to RISC-V
├── L01 · Number Systems and Storage ├── L01 · Number Systems and Storage [existing · 3 taski]
├── L02 · FPGA Bring-up and Programming ├── L02 · FPGA Bring-up and Programming [existing · 3 taski]
├── L03 · Blinker and Synchronous Logic [steps 13] ├── L03 · Blinker and Synchronous Logic [existing · 3 taski]
├── L04 · The RISC-V ISA and Instruction Decoder [steps 45] ├── L04 · The RISC-V ISA and Instruction Decoder [existing · 3 taski]
├── L05 · ALU and the Verilog Assembler [steps 67] ├── L05 · ALU and the Verilog Assembler [existing · 3 taski]
├── L06 · Control Flow — Jumps and Branches [steps 89] ├── L06 · Control Flow — Jumps and Branches [existing · 3 taski]
├── L07 · Addresses and Memory [steps 1011] ├── L07 · Addresses and Memory [existing · 3 taski]
├── L08 · Subroutines and the RISC-V ABI [steps 1314] ├── L08 · Subroutines and ABI [existing · 3 taski]
└── L09 · Load and Store [steps 1516] └── L09 · Load and Store Semantics [existing · 3 taski]
``` ```
L01 dostarcza języka liczb, kodowania i pamięci. L02 ustanawia fizyczną L01 dostarcza języka liczb, kodowania i pamięci. L02 ustanawia fizyczną
drabinkę FPGA. Kolejne karty prowadzą od logiki synchronicznej do rdzenia, drabinkę FPGA. Kolejne karty prowadzą od logiki synchronicznej do rdzenia,
który wykonuje podstawowe instrukcje RV32I. Step 12 pozostaje późniejszym który wykonuje podstawowe instrukcje RV32I.
przeglądem jakości implementacji.
## Stan odbioru serii — 2026-07-21
Każda karta ma trzy wykonywalne taski, niezależny model `native-amd64`,
self-checking SystemVerilog w profilu `hazard3-sim`, akcję debug zapisującą
VCD, testy kontraktu i stanu, widok React oraz dwustronicowy PDF A4.
| Karta | Dowód końcowy |
| --- | --- |
| L01 | systemy pozycyjne, sign/zero extension, shifts i little-endian |
| L02 | polaryzacja, znany reset, blinker i uporządkowany preflight FPGA |
| L03 | clock enable, counter blinker i pattern ROM |
| L04 | dekoder, legalność opcode i bank rejestrów |
| L05 | ALU, kodowanie instrukcji i wykonanie małego programu |
| L06 | warunki branch, immediate/target i ślad PC |
| L07 | LUI/AUIPC, pamięć słów, adres i fault |
| L08 | JAL/JALR, role ABI i zagnieżdżone powroty |
| L09 | store strobes, rozszerzenia load i roundtrip pamięci |
Odbiór obejmuje 27 tasków wykonanych w obu profilach: 54/54 zakończyły się
komunikatem `PASS`. PDF-y przechodzą `qpdf --check`, a ich pliki
`source-commit.txt` wskazują bezpośredni commit źródłowy.
### Granica sprzętowa L02
Repozytorium L02 nie zgaduje modelu płytki, pinów ani programatora. Dostarcza
`board/board-contract.yaml` jako bezpieczny szablon oraz osobny formularz
dowodu fizycznego. Automatyczny preflight i symulacja zawsze raportują
`hardware_observed=0` oraz `claim=preflight-only`; nie są przedstawiane jako
zbudowanie bitstreamu ani zaprogramowanie FPGA. Fizyczne zaliczenie wymaga
konkretnej płytki, SHA-256 bitstreamu, zgodnego device ID, logu konfiguracji i
zmierzonej obserwacji LED.
### Sposób uruchamiania
```bash
stemctl series show rv32i-asm
stemctl list-cards rv32i-asm
stemctl card use rv32i-asm L01
stemctl test native-amd64 rv32i-asm L01 1
stemctl test hazard3-sim rv32i-asm L01 1
stemctl debug hazard3-sim rv32i-asm L01 3
```
Materiał źródłowy programu: Materiał źródłowy programu:
`series/inf/lab-rv32i-c-pointers-arrays/guidelines/year-01-interrupts-to-year-02-freertos.md`. `series/inf/lab-rv32i-c-pointers-arrays/guidelines/year-01-interrupts-to-year-02-freertos.md`.
+22
View File
@@ -0,0 +1,22 @@
{
"id": "console-bash",
"title": "Bash · Console Tools",
"source_org": "edu-inf",
"answer_org": "c2025-1a-inf",
"source_remote": "r1",
"answer_remote": "r1a",
"fallback_branch": "main",
"workspace_dir": "console",
"source_dir": "console",
"default_card": "L01",
"cards": [
{"id": "L01", "repo": "lab-console-busybox", "branch": "main", "title": "BusyBox — the Swiss Army Knife"},
{"id": "L02", "repo": "lab-console-tmux", "branch": "main", "title": "Tmux — sessions, windows and panes"},
{"id": "L03", "repo": "lab-console-neovim", "branch": "main", "title": "Neovim — navigation and editing"},
{"id": "L04", "repo": "lab-console-git-basics-1", "branch": "main", "title": "Git Basics I — status, add and commit"},
{"id": "L05", "repo": "lab-console-git-basics-2", "branch": "main", "title": "Git Basics II — log, diff and restore"},
{"id": "L06", "repo": "lab-console-git-branching-1", "branch": "main", "title": "Git Branching I — branch, switch and merge"},
{"id": "L07", "repo": "lab-console-git-branching-2", "branch": "main", "title": "Git Branching II — rebase and conflicts"},
{"id": "L08", "repo": "lab-console-docker", "branch": "main", "title": "Docker Fundamentals"}
]
}
+24
View File
@@ -0,0 +1,24 @@
{
"id": "cpp",
"title": "C++ · Rok 2 · Semestr 1",
"source_org": "edu-cpp",
"answer_org": "c2025-2a-inf",
"source_remote": "r1",
"answer_remote": "r1a",
"fallback_branch": "main",
"workspace_dir": "cpp",
"source_dir": "cpp",
"default_card": "CPP01",
"cards": [
{"id": "CPP01", "repo": "lab-cpp-build-namespaces", "branch": "main", "title": "Oddzielna kompilacja, linkage i przestrzenie nazw"},
{"id": "CPP02", "repo": "lab-cpp-types-initialization", "branch": "main", "title": "Typy, inicjalizacja, auto, const i enum class"},
{"id": "CPP03", "repo": "lab-cpp-pointers-references", "branch": "main", "title": "Wskaźniki, referencje, tablice i nullptr"},
{"id": "CPP04", "repo": "lab-cpp-functions-overloading", "branch": "main", "title": "Funkcje, przeciążanie i modułowość"},
{"id": "CPP05", "repo": "lab-cpp-classes-objects", "branch": "main", "title": "Klasa i obiekt: interfejs oraz implementacja"},
{"id": "CPP06", "repo": "lab-cpp-invariants", "branch": "main", "title": "Hermetyzacja, niezmienniki i odpowiedzialność klasy"},
{"id": "CPP07", "repo": "lab-cpp-construction-destruction", "branch": "main", "title": "Konstruktory, destruktory i inicjalizacja obiektu"},
{"id": "CPP08", "repo": "lab-cpp-scope-lifetime", "branch": "main", "title": "Zakres i czas życia obiektów"},
{"id": "CPP09", "repo": "lab-cpp-raii", "branch": "main", "title": "RAII i zasób związany z czasem życia"},
{"id": "CPP10", "repo": "lab-cpp-copy-move", "branch": "main", "title": "Kopiowanie, przenoszenie i Rule of Zero/Five"}
]
}
+25 -1
View File
@@ -14,7 +14,7 @@
"id": "FC01", "id": "FC01",
"repo": "lab-rv32i-freertos-heap4", "repo": "lab-rv32i-freertos-heap4",
"branch": "main", "branch": "main",
"title": "heap_1heap_5 and heap_4 mechanics" "title": "heap_4: From Linear Cursor to Reusable Blocks"
}, },
{ {
"id": "FC02", "id": "FC02",
@@ -75,6 +75,30 @@
"repo": "lab-rv32i-freertos-c-static-allocation", "repo": "lab-rv32i-freertos-c-static-allocation",
"branch": "main", "branch": "main",
"title": "Static Allocation and Bounded Storage" "title": "Static Allocation and Bounded Storage"
},
{
"id": "FC12",
"repo": "lab-rv32i-freertos-c-diagnostics",
"branch": "main",
"title": "Assertions, Hooks, Stack Checks and Runtime Diagnostics"
},
{
"id": "FC13",
"repo": "lab-rv32i-freertos-c-uart",
"branch": "main",
"title": "UART Interrupt-to-task Pipeline"
},
{
"id": "FC14",
"repo": "lab-rv32i-freertos-c-gpio-timer",
"branch": "main",
"title": "GPIO, Hardware Timer and Deferred Work"
},
{
"id": "FC15",
"repo": "lab-rv32i-freertos-c-integration",
"branch": "main",
"title": "Integrated Deterministic FreeRTOS C Application"
} }
] ]
} }
+84
View File
@@ -15,6 +15,90 @@
"repo": "lab-rv32i-freertos-task-stack-vector", "repo": "lab-rv32i-freertos-task-stack-vector",
"branch": "main", "branch": "main",
"title": "C++ Task wrapper: OOP and lifecycle" "title": "C++ Task wrapper: OOP and lifecycle"
},
{
"id": "K03",
"repo": "lab-rv32i-freertos-vector-raii",
"branch": "main",
"title": "Vector V1: destructor, move, ownership and RAII"
},
{
"id": "K04",
"repo": "lab-rv32i-freertos-scheduler-states",
"branch": "main",
"title": "Scheduler states, priorities and typed ticks"
},
{
"id": "K05",
"repo": "lab-rv32i-freertos-heap-models",
"branch": "main",
"title": "C++ heap bridge, heap models and HeapStats"
},
{
"id": "K06",
"repo": "lab-rv32i-freertos-allocator-resource",
"branch": "main",
"title": "MemoryResource and FreeRtosAllocator<T>"
},
{
"id": "K07",
"repo": "lab-rv32i-freertos-task-wrapper",
"branch": "main",
"title": "TaskHandle_t, explicit start and static trampoline"
},
{
"id": "K08",
"repo": "lab-rv32i-freertos-static-task",
"branch": "main",
"title": "DynamicTask, StaticTask, deletion and lifetime"
},
{
"id": "K09",
"repo": "lab-rv32i-freertos-kernel-facade",
"branch": "main",
"title": "Scheduler facade and scoped kernel guards"
},
{
"id": "K10",
"repo": "lab-rv32i-freertos-queue",
"branch": "main",
"title": "Queue<T> and StaticQueue<T, N>"
},
{
"id": "K11",
"repo": "lab-rv32i-freertos-mutex",
"branch": "main",
"title": "Mutex, LockGuard and priority inheritance"
},
{
"id": "K12",
"repo": "lab-rv32i-freertos-semaphore-notify",
"branch": "main",
"title": "Semaphores and task notifications"
},
{
"id": "K13",
"repo": "lab-rv32i-freertos-event-group",
"branch": "main",
"title": "EventGroup and coordinated state"
},
{
"id": "K14",
"repo": "lab-rv32i-freertos-sw-timer",
"branch": "main",
"title": "Software timer and the timer daemon task"
},
{
"id": "K15",
"repo": "lab-rv32i-freertos-isr-drivers",
"branch": "main",
"title": "Explicit FromISR, UART and GPIO wrappers"
},
{
"id": "K16",
"repo": "lab-rv32i-freertos-integration",
"branch": "main",
"title": "Integrated real-time application and evidence"
} }
] ]
} }
+68
View File
@@ -0,0 +1,68 @@
{
"id": "rv32i-asm",
"title": "ASM · RV32I From Blinker to RISC-V",
"source_org": "edu-inf",
"answer_org": "c2025-1a-inf",
"source_remote": "r1",
"answer_remote": "r1a",
"fallback_branch": "main",
"workspace_dir": "inf",
"source_dir": "inf",
"default_card": "L01",
"cards": [
{
"id": "L01",
"repo": "lab-rv32i-asm-number-systems",
"branch": "main",
"title": "Number Systems and Storage"
},
{
"id": "L02",
"repo": "lab-rv32i-asm-fpga-bringup",
"branch": "main",
"title": "FPGA Bring-up and Programming"
},
{
"id": "L03",
"repo": "lab-rv32i-asm-blinker",
"branch": "main",
"title": "Blinker and Synchronous Logic"
},
{
"id": "L04",
"repo": "lab-rv32i-asm-decoder",
"branch": "main",
"title": "The RISC-V ISA and Instruction Decoder"
},
{
"id": "L05",
"repo": "lab-rv32i-asm-alu",
"branch": "main",
"title": "ALU and the Verilog Assembler"
},
{
"id": "L06",
"repo": "lab-rv32i-asm-control-flow",
"branch": "main",
"title": "Control Flow — Jumps and Branches"
},
{
"id": "L07",
"repo": "lab-rv32i-asm-addresses-memory",
"branch": "main",
"title": "Addresses and Memory"
},
{
"id": "L08",
"repo": "lab-rv32i-asm-subroutines-abi",
"branch": "main",
"title": "Subroutines and ABI"
},
{
"id": "L09",
"repo": "lab-rv32i-asm-load-store",
"branch": "main",
"title": "Load and Store Semantics"
}
]
}
+675
View File
@@ -0,0 +1,675 @@
#!/usr/bin/env python3
"""Generate the ten C++20 cards for Year 2, semester 1.
The lesson scope comes from /home/user/dev/keys/cxx.md. The generated cards
share the same runtime, React viewer and PDF contract as the existing STEM
cards, while every task contains an independently compilable C++ experiment.
"""
from __future__ import annotations
import json
import os
from pathlib import Path
import shutil
import stat
import textwrap
import uuid
ROOT = Path(__file__).resolve().parents[3]
OUTPUT = ROOT / "series" / "cpp"
TEMPLATE = ROOT / "series" / "console" / "lab-console-busybox"
UUID_NAMESPACE = uuid.UUID("1b43af4e-354f-51dc-a42a-67593c614624")
def clean(text: str) -> str:
return textwrap.dedent(text).lstrip()
LESSONS = [
{
"id": "CPP01",
"number": "01",
"repo": "lab-cpp-build-namespaces",
"slug": "build-namespaces",
"title": "Od C do C++: oddzielna kompilacja i przestrzenie nazw",
"topic": "Deklaracja, definicja, translation unit, linkage i namespace",
"chapter": "A Tour of C++ 3e: rozdziały 1 i 3",
"mission": "Zbudować program z wielu jednostek translacji i odczytać granice nazw oraz linkage.",
"tasks": [
("Deklaracja i definicja", "Rozdziel deklarację funkcji, definicję i punkt wejścia między trzy pliki.", "sum=7", {
"calculator.hpp": """#pragma once
namespace lab { int add(int left, int right); }
""",
"calculator.cpp": """#include "calculator.hpp"
namespace lab { int add(int left, int right) { return left + right; } }
""",
"main.cpp": """#include "calculator.hpp"
#include <iostream>
int main() { std::cout << "sum=" << lab::add(3, 4) << '\\n'; }
""",
}),
("Linkage zewnętrzny i wewnętrzny", "Porównaj symbol dostępny między plikami z nazwą ukrytą w anonimowej przestrzeni nazw.", "external=5 internal_bias_result=8", {
"api.hpp": """#pragma once
int global_value();
int shifted_value();
""",
"global.cpp": """#include "api.hpp"
int global_value() { return 5; }
""",
"shifted.cpp": """#include "api.hpp"
namespace { constexpr int bias = 3; }
int shifted_value() { return global_value() + bias; }
""",
"main.cpp": """#include "api.hpp"
#include <iostream>
int main() { std::cout << "external=" << global_value() << " internal_bias_result=" << shifted_value() << '\\n'; }
""",
}),
("Kwalifikacja przestrzeni nazw", "Użyj dwóch funkcji o tej samej nazwie bez kolizji i wywołaj je kwalifikowaną nazwą.", "sensor=21 network=204", {
"main.cpp": """#include <iostream>
namespace sensor { int read() { return 21; } }
namespace network { int read() { return 204; } }
int main() { std::cout << "sensor=" << sensor::read() << " network=" << network::read() << '\\n'; }
""",
}),
],
},
{
"id": "CPP02", "number": "02", "repo": "lab-cpp-types-initialization", "slug": "types-initialization",
"title": "Typy, inicjalizacja, auto, const i enum class",
"topic": "Bezpieczna inicjalizacja i typy definiowane przez użytkownika",
"chapter": "A Tour of C++ 3e: rozdziały 1 i 2",
"mission": "Rozpoznać typy wyrażeń i używać inicjalizacji, const oraz enum class bez niejawnego mieszania domen.",
"tasks": [
("Inicjalizacja i auto", "Zastosuj inicjalizację klamrową i potwierdź typ dedukowany przez auto.", "count=4 twice=8 type=int", {
"main.cpp": """#include <iostream>
#include <type_traits>
int main() {
int count{4};
auto twice = count * 2;
static_assert(std::is_same_v<decltype(twice), int>);
std::cout << "count=" << count << " twice=" << twice << " type=int\\n";
}
""",
}),
("const i constexpr", "Oddziel wartość obliczaną w czasie kompilacji od obiektu tylko do odczytu.", "square=49 limit=12", {
"main.cpp": """#include <iostream>
constexpr int square(int value) { return value * value; }
int main() {
constexpr int result = square(7);
const int limit{12};
static_assert(result == 49);
std::cout << "square=" << result << " limit=" << limit << '\\n';
}
""",
}),
("enum class i struktura", "Zbuduj typ rekordu oraz silnie typowany stan bez niejawnej konwersji do int.", "sample=23 state=ready", {
"main.cpp": """#include <iostream>
enum class State { idle, ready };
struct Sample { int value; State state; };
int main() {
Sample sample{23, State::ready};
std::cout << "sample=" << sample.value << " state=" << (sample.state == State::ready ? "ready" : "idle") << '\\n';
}
""",
}),
],
},
{
"id": "CPP03", "number": "03", "repo": "lab-cpp-pointers-references", "slug": "pointers-references",
"title": "Wskaźniki, referencje, tablice i nullptr",
"topic": "Tożsamość obiektu, dostęp pośredni i przekazywanie argumentów",
"chapter": "A Tour of C++ 3e: sekcje 1.7 i 3.4",
"mission": "Odróżnić wskaźnik od referencji i tablicę od wskaźnika podczas przekazywania danych.",
"tasks": [
("Wskaźnik i nullptr", "Sprawdź brak obiektu przed dereferencją, a następnie zmodyfikuj wskazywaną wartość.", "null=1 value=9", {
"main.cpp": """#include <iostream>
int main() {
int value{7};
int* pointer = nullptr;
const bool was_null = pointer == nullptr;
pointer = &value;
*pointer += 2;
std::cout << "null=" << was_null << " value=" << value << '\\n';
}
""",
}),
("Referencja jako alias", "Przekaż dwa obiekty przez referencję i zamień ich wartości.", "left=8 right=3", {
"main.cpp": """#include <iostream>
void swap_values(int& left, int& right) { const int temp = left; left = right; right = temp; }
int main() { int left{3}; int right{8}; swap_values(left, right); std::cout << "left=" << left << " right=" << right << '\\n'; }
""",
}),
("Tablica i jej rozmiar", "Policz elementy w referencji do tablicy, zanim argument zaniknie do wskaźnika.", "count=4 sum=20", {
"main.cpp": """#include <cstddef>
#include <iostream>
template <std::size_t N> int sum(const int (&values)[N]) { int result{}; for (int value : values) result += value; return result; }
int main() { int values[]{2, 4, 6, 8}; std::cout << "count=" << (sizeof(values) / sizeof(values[0])) << " sum=" << sum(values) << '\\n'; }
""",
}),
],
},
{
"id": "CPP04", "number": "04", "repo": "lab-cpp-functions-overloading", "slug": "functions-overloading",
"title": "Funkcje, przeciążanie, wartości zwracane i modułowość",
"topic": "Sygnatura funkcji, wybór przeciążenia, zakres i granica modułu",
"chapter": "A Tour of C++ 3e: rozdziały 1 i 3",
"mission": "Zaprojektować mały interfejs funkcji i sprawdzić wybór przeciążenia oraz zwracanie wartości.",
"tasks": [
("Przeciążanie", "Wywołaj dwie funkcje o tej samej nazwie i różnych typach parametrów.", "int=6 double=3.5", {
"main.cpp": """#include <iostream>
int twice(int value) { return value * 2; }
double twice(double value) { return value * 2.0; }
int main() { std::cout << "int=" << twice(3) << " double=" << twice(1.75) << '\\n'; }
""",
}),
("Zwracanie przez wartość", "Zwróć kompletny wynik obliczenia jako wartość, bez ujawniania obiektu lokalnego.", "quotient=3 remainder=2", {
"main.cpp": """#include <iostream>
struct Division { int quotient; int remainder; };
Division divide(int value, int by) { return {value / by, value % by}; }
int main() { const Division result = divide(17, 5); std::cout << "quotient=" << result.quotient << " remainder=" << result.remainder << '\\n'; }
""",
}),
("Interfejs modułu", "Oddziel publiczne deklaracje statystyk od ich implementacji.", "min=2 max=9", {
"stats.hpp": """#pragma once
namespace stats { int minimum(int left, int right); int maximum(int left, int right); }
""",
"stats.cpp": """#include "stats.hpp"
namespace stats { int minimum(int left, int right) { return left < right ? left : right; } int maximum(int left, int right) { return left > right ? left : right; } }
""",
"main.cpp": """#include "stats.hpp"
#include <iostream>
int main() { std::cout << "min=" << stats::minimum(9, 2) << " max=" << stats::maximum(9, 2) << '\\n'; }
""",
}),
],
},
{
"id": "CPP05", "number": "05", "repo": "lab-cpp-classes-objects", "slug": "classes-objects",
"title": "Klasa i obiekt: interfejs oraz implementacja",
"topic": "Pola, metody, kontrola dostępu i zachowanie obiektu",
"chapter": "A Tour of C++ 3e: rozdziały 2 i 5",
"mission": "Zamknąć stan i operacje w klasie oraz oddzielić interfejs publiczny od implementacji.",
"tasks": [
("Klasa w dwóch plikach", "Zdefiniuj interfejs licznika w nagłówku, a metody w osobnej jednostce translacji.", "counter=3", {
"counter.hpp": """#pragma once
class Counter { public: explicit Counter(int start); void increment(); int value() const; private: int value_; };
""",
"counter.cpp": """#include "counter.hpp"
Counter::Counter(int start) : value_{start} {}
void Counter::increment() { ++value_; }
int Counter::value() const { return value_; }
""",
"main.cpp": """#include "counter.hpp"
#include <iostream>
int main() { Counter counter{2}; counter.increment(); std::cout << "counter=" << counter.value() << '\\n'; }
""",
}),
("Stan prywatny", "Udostępnij operacje rachunku bez publicznego zapisu pola balance.", "accepted=1 rejected=1 balance=15", {
"main.cpp": """#include <iostream>
class Account {
public:
explicit Account(int balance) : balance_{balance} {}
bool deposit(int amount) { if (amount <= 0) return false; balance_ += amount; return true; }
int balance() const { return balance_; }
private: int balance_;
};
int main() { Account account{10}; const bool accepted = account.deposit(5); const bool rejected = !account.deposit(-2); std::cout << "accepted=" << accepted << " rejected=" << rejected << " balance=" << account.balance() << '\\n'; }
""",
}),
("Metody opisują zachowanie", "Przenieś obliczenie pola i skalowanie do obiektu prostokąta.", "area=24 scaled=96", {
"main.cpp": """#include <iostream>
class Rectangle { public: Rectangle(int width, int height) : width_{width}, height_{height} {} int area() const { return width_ * height_; } void scale(int factor) { width_ *= factor; height_ *= factor; } private: int width_; int height_; };
int main() { Rectangle rectangle{6, 4}; const int before = rectangle.area(); rectangle.scale(2); std::cout << "area=" << before << " scaled=" << rectangle.area() << '\\n'; }
""",
}),
],
},
{
"id": "CPP06", "number": "06", "repo": "lab-cpp-invariants", "slug": "invariants",
"title": "Hermetyzacja, niezmienniki i odpowiedzialność klasy",
"topic": "Poprawny stan obiektu przed i po każdej operacji publicznej",
"chapter": "A Tour of C++ 3e: sekcja 4.3 i rozdział 5",
"mission": "Zdefiniować niezmiennik klasy i utrzymywać go we wszystkich publicznych operacjach.",
"tasks": [
("Walidowana zmiana stanu", "Odrzuć temperaturę spoza przyjętego zakresu bez uszkodzenia obiektu.", "accepted=1 rejected=1 value=25", {
"main.cpp": """#include <iostream>
class Temperature { public: explicit Temperature(int value) : value_{value} {} bool set(int value) { if (value < -50 || value > 150) return false; value_ = value; return true; } int value() const { return value_; } private: int value_; };
int main() { Temperature temperature{20}; const bool accepted = temperature.set(25); const bool rejected = !temperature.set(400); std::cout << "accepted=" << accepted << " rejected=" << rejected << " value=" << temperature.value() << '\\n'; }
""",
}),
("Pojemność kolejki", "Nie dopuść, by liczba elementów przekroczyła pojemność lub spadła poniżej zera.", "pushes=2 overflow=1 pops=2 empty=1 depth=0", {
"main.cpp": """#include <iostream>
class QueueDepth { public: explicit QueueDepth(int capacity) : capacity_{capacity} {} bool push() { if (depth_ == capacity_) return false; ++depth_; return true; } bool pop() { if (depth_ == 0) return false; --depth_; return true; } int depth() const { return depth_; } private: int capacity_; int depth_{}; };
int main() { QueueDepth queue{2}; int pushes{}; pushes += queue.push(); pushes += queue.push(); const bool overflow = !queue.push(); int pops{}; pops += queue.pop(); pops += queue.pop(); const bool empty = !queue.pop(); std::cout << "pushes=" << pushes << " overflow=" << overflow << " pops=" << pops << " empty=" << empty << " depth=" << queue.depth() << '\\n'; }
""",
}),
("Normalizacja przedziału", "Skonstruuj przedział zawsze spełniający start <= end.", "start=3 end=10 width=7", {
"main.cpp": """#include <iostream>
class Interval { public: Interval(int first, int second) : start_{first < second ? first : second}, end_{first < second ? second : first} {} int start() const { return start_; } int end() const { return end_; } int width() const { return end_ - start_; } private: int start_; int end_; };
int main() { Interval interval{10, 3}; std::cout << "start=" << interval.start() << " end=" << interval.end() << " width=" << interval.width() << '\\n'; }
""",
}),
],
},
{
"id": "CPP07", "number": "07", "repo": "lab-cpp-construction-destruction", "slug": "construction-destruction",
"title": "Konstruktory, destruktory i inicjalizacja obiektu",
"topic": "Kolejność inicjalizacji, delegowanie konstruktorów i porządek destrukcji",
"chapter": "A Tour of C++ 3e: rozdziały 5 i 6",
"mission": "Zaobserwować pełny cykl tworzenia i niszczenia obiektu oraz kolejność jego części.",
"tasks": [
("Kolejność konstrukcji", "Zaobserwuj, że pole jest konstruowane przed ciałem konstruktora obiektu.", "member\nobject\nready", {
"main.cpp": """#include <iostream>
struct Member { Member() { std::cout << "member\\n"; } };
struct Object { Member member; Object() { std::cout << "object\\n"; } };
int main() { Object object; (void)object; std::cout << "ready\\n"; }
""",
}),
("Destrukcja w odwrotnej kolejności", "Utwórz dwa obiekty automatyczne i sprawdź kolejność destruktorów.", "enter\nconstruct=A\nconstruct=B\ndestroy=B\ndestroy=A\nleave", {
"main.cpp": """#include <iostream>
struct Trace { const char* name; explicit Trace(const char* value) : name{value} { std::cout << "construct=" << name << '\\n'; } ~Trace() { std::cout << "destroy=" << name << '\\n'; } };
void scope() { Trace first{"A"}; Trace second{"B"}; }
int main() { std::cout << "enter\\n"; scope(); std::cout << "leave\\n"; }
""",
}),
("Konstruktor delegujący", "Skieruj konstruktor domyślny do jednego konstruktora utrzymującego reguły inicjalizacji.", "point=0,0 other=3,4", {
"main.cpp": """#include <iostream>
class Point { public: Point() : Point{0, 0} {} Point(int x, int y) : x_{x}, y_{y} {} int x() const { return x_; } int y() const { return y_; } private: int x_; int y_; };
int main() { Point point; Point other{3, 4}; std::cout << "point=" << point.x() << ',' << point.y() << " other=" << other.x() << ',' << other.y() << '\\n'; }
""",
}),
],
},
{
"id": "CPP08", "number": "08", "repo": "lab-cpp-scope-lifetime", "slug": "scope-lifetime",
"title": "Zakres i czas życia obiektów",
"topic": "Obiekty automatyczne, statyczne i dynamiczne oraz przesłanianie nazw",
"chapter": "A Tour of C++ 3e: sekcja 1.5 i rozdział 6",
"mission": "Powiązać miejsce przechowywania obiektu z początkiem i końcem jego czasu życia.",
"tasks": [
("Automatyczny i statyczny", "Porównaj nowy obiekt automatyczny z zachowującym stan obiektem statycznym.", "auto=7 static_calls=1,2", {
"main.cpp": """#include <iostream>
int next_call() { static int calls{}; return ++calls; }
int main() { int automatic{7}; const int first = next_call(); const int second = next_call(); std::cout << "auto=" << automatic << " static_calls=" << first << ',' << second << '\\n'; }
""",
}),
("Obiekt dynamiczny", "Jawnie zestaw new z delete i obserwuj moment wykonania destruktora.", "construct\nvalue=11\ndestroy", {
"main.cpp": """#include <iostream>
struct Dynamic { explicit Dynamic(int value) : value{value} { std::cout << "construct\\n"; } ~Dynamic() { std::cout << "destroy\\n"; } int value; };
int main() { Dynamic* object = new Dynamic{11}; std::cout << "value=" << object->value << '\\n'; delete object; }
""",
}),
("Zakres i przesłanianie", "Pokaż, że nazwa wewnętrzna nie zmienia obiektu o tej samej nazwie w zakresie zewnętrznym.", "outer=7\ninner=9\nouter=7", {
"main.cpp": """#include <iostream>
int main() { int value{7}; std::cout << "outer=" << value << '\\n'; { int value{9}; std::cout << "inner=" << value << '\\n'; } std::cout << "outer=" << value << '\\n'; }
""",
}),
],
},
{
"id": "CPP09", "number": "09", "repo": "lab-cpp-raii", "slug": "raii",
"title": "RAII: zasób związany z czasem życia obiektu",
"topic": "Pozyskanie w konstruktorze, zwolnienie w destruktorze i wszystkie wyjścia z zakresu",
"chapter": "A Tour of C++ 3e: sekcja 6.3",
"mission": "Zapewnić zwolnienie zasobu przez strukturę programu, także przy wczesnym return.",
"tasks": [
("Uchwyt jako obiekt", "Zwiąż stan otwarcia uchwytu z konstruktorem i destruktorem.", "acquire\nopen=1\nrelease\nopen=0", {
"main.cpp": """#include <iostream>
bool resource_open{};
class Handle { public: Handle() { resource_open = true; std::cout << "acquire\\n"; } ~Handle() { resource_open = false; std::cout << "release\\n"; } Handle(const Handle&) = delete; Handle& operator=(const Handle&) = delete; };
int main() { { Handle handle; (void)handle; std::cout << "open=" << resource_open << '\\n'; } std::cout << "open=" << resource_open << '\\n'; }
""",
}),
("Wczesny return", "Potwierdź zwolnienie strażnika przy wyjściu z funkcji przed jej końcem.", "acquire\nwork=short\nrelease\nafter", {
"main.cpp": """#include <iostream>
struct Guard { Guard() { std::cout << "acquire\\n"; } ~Guard() { std::cout << "release\\n"; } };
void work(bool short_path) { Guard guard; if (short_path) { std::cout << "work=short\\n"; return; } std::cout << "work=long\\n"; }
int main() { work(true); std::cout << "after\\n"; }
""",
}),
("Zagnieżdżone zasoby", "Sprawdź zwalnianie zagnieżdżonych zasobów w odwrotnej kolejności.", "acquire=A\nacquire=B\ninside\nrelease=B\nrelease=A", {
"main.cpp": """#include <iostream>
struct Resource { const char* name; explicit Resource(const char* value) : name{value} { std::cout << "acquire=" << name << '\\n'; } ~Resource() { std::cout << "release=" << name << '\\n'; } };
int main() { Resource first{"A"}; { Resource second{"B"}; std::cout << "inside\\n"; } }
""",
}),
],
},
{
"id": "CPP10", "number": "10", "repo": "lab-cpp-copy-move", "slug": "copy-move",
"title": "Kopiowanie, przenoszenie i Rule of Zero/Five",
"topic": "Głębokie kopiowanie, transfer własności i typy składowe zarządzające zasobem",
"chapter": "A Tour of C++ 3e: sekcje 6.26.4",
"mission": "Rozróżnić kopię od przeniesienia i wybrać Rule of Zero dla bezpiecznego typu zasobowego.",
"tasks": [
("Głęboka kopia", "Zaimplementuj kopię bufora tak, aby dwa obiekty nie współdzieliły jednej komórki.", "original=7 copy=9 distinct=1", {
"main.cpp": """#include <iostream>
class Buffer { public: explicit Buffer(int value) : data_{new int{value}} {} ~Buffer() { delete data_; } Buffer(const Buffer& other) : data_{new int{*other.data_}} {} Buffer& operator=(const Buffer&) = delete; int value() const { return *data_; } void set(int value) { *data_ = value; } const int* address() const { return data_; } private: int* data_; };
int main() { Buffer original{7}; Buffer copy{original}; copy.set(9); std::cout << "original=" << original.value() << " copy=" << copy.value() << " distinct=" << (original.address() != copy.address()) << '\\n'; }
""",
}),
("Przeniesienie własności", "Przenieś bufor move-only i pozostaw obiekt źródłowy w poprawnym stanie pustym.", "src_empty=1 value=42", {
"main.cpp": """#include <iostream>
#include <utility>
class Buffer { public: explicit Buffer(int value) : data_{new int{value}} {} ~Buffer() { delete data_; } Buffer(const Buffer&) = delete; Buffer& operator=(const Buffer&) = delete; Buffer(Buffer&& other) noexcept : data_{std::exchange(other.data_, nullptr)} {} bool empty() const { return data_ == nullptr; } int value() const { return *data_; } private: int* data_; };
int main() { Buffer source{42}; Buffer target{std::move(source)}; std::cout << "src_empty=" << source.empty() << " value=" << target.value() << '\\n'; }
""",
}),
("Rule of Zero", "Zbuduj typ z bezpiecznych składowych standardowych bez własnego destruktora i operacji copy/move.", "copy=alpha original=beta moved=alpha", {
"main.cpp": """#include <iostream>
#include <string>
#include <utility>
struct Document { std::string text; };
int main() { Document original{"alpha"}; Document copy = original; original.text = "beta"; Document moved = std::move(copy); std::cout << "copy=" << moved.text << " original=" << original.text << " moved=" << moved.text << '\\n'; }
""",
}),
],
},
]
CARD_ACTION = r'''#!/usr/bin/env bash
set -euo pipefail
action="${1:?action is required}"
root="${STEM_REPO:-${CARD_ROOT:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)}}"
profile="${STEM_PROFILE:-native-amd64}"
target="${STEM_TARGET:-native}"
selector="${STEM_TASK:-task1}"
card_id="$(sed -n 's/^card: cpp\///p' "$root/lesson-flow.yaml" | head -n1)"
resolve_task() {
local value="${1,,}"
if [[ "$value" =~ ^(task|t)?[-_]?0*([1-3])($|[-_].*) ]]; then printf 'task%02d\n' "${BASH_REMATCH[2]}"; return; fi
[[ "$value" =~ ^task0[1-3]$ ]] && { printf '%s\n' "$value"; return; }
printf 'Unknown task selector: %s\n' "$1" >&2; exit 2
}
task="$(resolve_task "$selector")"
artifact_dir="$root/.stem/artifacts/$profile/$target/$task"
binary="$artifact_dir/program"
mkdir -p "$artifact_dir"
compile_task() {
local selected="$1" output="$2"
mapfile -t sources < <(find "$root/src/$selected" -maxdepth 1 -type f -name '*.cpp' | sort)
[[ ${#sources[@]} -gt 0 ]] || { printf 'No C++ sources for %s\n' "$selected" >&2; exit 2; }
"${CXX:-g++}" -std=c++20 -Wall -Wextra -Wpedantic -Werror -O0 -g3 -fno-omit-frame-pointer -I"$root/src/$selected" "${sources[@]}" -o "$output"
}
verify_task() {
local selected="$1" output="$2" actual="$artifact_dir/actual.txt"
compile_task "$selected" "$output"
"$output" >"$actual"
diff -u "$root/tests/expected/$selected.txt" "$actual"
}
case "$profile:$target:$action" in
native-amd64:native:build)
for item in task01 task02 task03; do
current="$root/.stem/artifacts/$profile/$target/$item"
mkdir -p "$current"
compile_task "$item" "$current/program"
done
printf 'BUILD %s standard=c++20 tasks=3\n' "$card_id"
;;
native-amd64:native:test|native-amd64:native:run)
verify_task "$task" "$binary"
printf 'PASS %s %s standard=c++20\n' "$card_id" "$task"
;;
native-amd64:native:debug)
verify_task "$task" "$binary"
trace="$artifact_dir/debug.log"
if command -v gdb >/dev/null 2>&1; then
gdb -q -batch -ex 'set pagination off' -ex 'set debuginfod enabled off' -ex 'break main' -ex run -ex 'info source' -ex 'info args' -ex continue "$binary" >"$trace" 2>&1
else
{ printf 'gdb unavailable; binary evidence follows\n'; "${NM:-nm}" -C "$binary" | head -n 80; "$binary"; } >"$trace" 2>&1
fi
cat "$trace"
[[ -s "$trace" ]]
printf 'TRACE %s %s log=%s\n' "$card_id" "$task" "$trace"
;;
*) printf 'Unsupported profile/target/action: %s/%s/%s\n' "$profile" "$target" "$action" >&2; exit 2 ;;
esac
'''
def write(path: Path, content: str, executable: bool = False) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(clean(content), encoding="utf-8")
if executable:
path.chmod(path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
def card_source(lesson: dict, document_uuid: str) -> dict:
prefix = lesson["id"]
sections = []
tasks = {}
scope_rows = []
for index, (title, prompt, expected, _files) in enumerate(lesson["tasks"], 1):
task_id = f"task{index:02d}"
expected_tex = expected.replace("_", "\\_")
sections.append({
"title": f"Task{index:02d} · {title}",
"content_kind": "prose",
"content_tex": f"{prompt} Najpierw przewidź wynik, następnie skompiluj program z ostrzeżeniami traktowanymi jako błędy i porównaj dokładny stdout z kontraktem: {expected_tex.replace(chr(10), '; ')}.",
"educational_requirement_refs": [f"{prefix}.WE01"],
"learning_effect_refs": [f"{prefix}.EN01", f"{prefix}.EK01"],
"assessment_criterion_refs": [f"{prefix}.KW01"],
"area_tree_refs": [f"{prefix}.WE01.OG.IP.01", f"{prefix}.WE01.TECH.I4.01"],
"steps": [
{"id": f"T{index:02d}-PREDICT", "title": "Zapisz przewidywany wynik i wskaż regułę języka.", "tree_refs": [f"{prefix}.WE01.OG.IP.01"]},
{"id": f"T{index:02d}-VERIFY", "title": "Uruchom test i zachowaj mierzalny dowód wykonania.", "tree_refs": [f"{prefix}.WE01.TECH.I4.01"]},
],
})
tasks[task_id] = {
"prompt_tex": prompt,
"criterion": expected_tex.replace("\n", "; "),
"assessment_criterion_ref": f"{prefix}.KW01",
}
scope_rows.append({"chapter": "1", "task": f"Task{index:02d}", "idea_tex": title, "priority": "obowiązkowe", "status": "ready", "version": "v00.01"})
return {
"$schema": "../../../../tools/card-layouts/schemas/card-source.schema.json",
"schema": "esc-card-source.v1",
"card": {
"id": f"mpabi-inf-cpp-y2s1-{lesson['number']}-{lesson['slug']}",
"series": "cpp",
"series_title": "C++ · Rok 2 · Semestr 1",
"number": lesson["number"], "count": "10", "slug": lesson["slug"],
"title": f"{lesson['id']} · {lesson['title']}", "topic": lesson["topic"],
"project": "C++20 · fundamenty języka i modelu obiektu", "subject": "Informatyka",
"level": "Rok 2 · Semestr 1", "revision_date": "2026-07-21T00:00:00+02:00",
"status": "Gotowa do wykonania", "version": "v00.01", "uuid": document_uuid,
"author": "M. Pabiszczak", "year": "2026",
},
"generated": {"tex": "doc/generated/main.tex", "html": "web/index.html", "html_css": "web/style.css", "react_app": True, "html_tree_inspector": False},
"template": "templates/karta-klasyczna.json",
"title_block": {
"category": "KARTA PRACY · INFORMATYKA · C++20", "standard": "ISO 7200",
"prepared_by": "M. Pabiszczak", "prepared_on": "21.07.2026", "checked_by": "testy automatyczne", "approved_by": "",
"url": "http://localhost:8080", "repository_url": f"https://zsl-gitea.mpabi.pl/edu-cpp/{lesson['repo']}",
"revision": "1", "issued_on": "21.07.2026", "series": f"CPP-Y2S1-{lesson['number']}", "document_type": "karta pracy",
"tool": "card-layouts", "sheet": "1 / 1", "show_qr": False, "show_repository_qr": False,
"height_cm": 3, "repeat_on_every_page": True, "replace_front_matter": True,
},
"front_page_scope": {"title": "Cel karty", "content_tex": lesson["mission"], "scope_title": "Zakres tasków", "scope_table": {"headers": ["Krok", "Numer tasku", "Najważniejsza idea", "Priorytet", "Status", "Version"], "rows": scope_rows}},
"learning_effects": {
f"{prefix}.EN01": {"text": f"Uczeń wyjaśnia reguły C++20 związane z tematem: {lesson['topic']}.", "label": "Model języka", "bloom_level": "Analiza", "assessment_criteria": [f"{prefix}.KW01"]},
f"{prefix}.EK01": {"text": "Uczeń implementuje, kompiluje i weryfikuje trzy małe eksperymenty C++20.", "label": "Eksperyment C++", "bloom_level": "Zastosowanie", "assessment_criteria": [f"{prefix}.KW01"]},
},
"assessment_criteria": {f"{prefix}.KW01": {"text": "Trzy taski kompilują się bez ostrzeżeń i zwracają dokładny, testowany wynik.", "learning_effects": [f"{prefix}.EN01", f"{prefix}.EK01"]}},
"educational_requirements": {
f"{prefix}.WE01": {"text": lesson["mission"], "label": lesson["topic"], "learning_effects": [f"{prefix}.EN01", f"{prefix}.EK01"],
"learning_tree": {"schema": "we-learning-tree.v1", "policy": "Każde twierdzenie o języku ma dowód w kodzie, wyniku programu albo symbolach binarnych.",
"ogolne": [{"tree_id": f"{prefix}.WE01.OG.IP.01", "effect_ref": f"{prefix}.EN01", "display": f"EN IP {prefix}", "text": "Uczeń przewiduje zachowanie programu na podstawie reguł języka.", "kw": [{"criterion_ref": f"{prefix}.KW01", "display": f"KW IP {prefix}", "text": "Uzasadnia przewidywany wynik."}]}],
"zawodowe": [{"tree_id": f"{prefix}.WE01.TECH.I4.01", "effect_ref": f"{prefix}.EK01", "display": f"EK INF04 {prefix}", "text": "Uczeń buduje i testuje program C++20.", "kw": [{"criterion_ref": f"{prefix}.KW01", "display": f"KW INF04 {prefix}", "text": "Uzyskuje trzy komunikaty PASS."}]}],
},
}
},
"sections": sections, "tasks": tasks, "tasks_order": ["task01", "task02", "task03"],
"mission": lesson["mission"],
"objectives": ["Wyjaśnisz badaną regułę C++20.", "Skompilujesz program z pełnym zestawem ostrzeżeń.", "Porównasz dokładny wynik i ślad debuggera."],
"agenda": [{"time": "0--15 min", "work": "Model i przewidywanie."}, {"time": "15--45 min", "work": "Trzy eksperymenty kodowe."}, {"time": "45--60 min", "work": "Debug, wnioski i raport."}],
"tech_stack": {"software": [{"name": "C++20", "use": "standard języka"}, {"name": "GCC/GDB", "use": "kompilacja i dowód wykonania"}, {"name": "stemctl", "use": "izolowany profil native-amd64"}], "hardware": [{"name": "Brak", "use": "laboratorium kontenerowe"}]},
"container_test": {"title": "Test w profilu native-amd64", "commands": [f"stemctl test native-amd64 cpp {lesson['id']} 1", f"stemctl test native-amd64 cpp {lesson['id']} 2", f"stemctl debug native-amd64 cpp {lesson['id']} 3"], "pass_condition": "Trzy wyniki zgodne z expected i niepusty debug.log."},
"safety_rules": [{"title": "Brak niezdefiniowanego zachowania", "body": "Kod testowy nie dereferencjonuje nullptr i nie używa obiektu po zakończeniu czasu życia."}, {"title": "Jedna zmienna naraz", "body": "Każdy task izoluje jedną regułę języka i ma deterministyczny stdout."}],
"hardware_procedure": [{"step": "1", "action": "Przewidź wynik.", "condition": "Reguła języka zapisana przed uruchomieniem."}, {"step": "2", "action": "Uruchom trzy taski.", "condition": "Trzy komunikaty PASS."}, {"step": "3", "action": "Odczytaj debug.log.", "condition": "Debugger zatrzymał program w main."}],
"references": [],
}
def generate_lesson(lesson: dict) -> None:
repo = OUTPUT / lesson["repo"]
if repo.exists() and (repo / ".git").exists():
raise SystemExit(f"Refusing to overwrite Git repository: {repo}")
if repo.exists():
shutil.rmtree(repo)
repo.mkdir(parents=True)
shutil.copytree(TEMPLATE / "scripts", repo / "scripts")
shutil.copy2(TEMPLATE / ".gitignore", repo / ".gitignore")
(repo / "web").mkdir(parents=True)
shutil.copy2(TEMPLATE / "web" / "app.css", repo / "web" / "app.css")
(repo / "doc" / "pdf").mkdir(parents=True)
write(repo / "doc" / "pdf" / ".gitkeep", "")
package = json.loads((TEMPLATE / "package.json").read_text(encoding="utf-8"))
package["name"] = f"mpabi-inf-cpp-y2s1-{lesson['number']}-{lesson['slug']}"
write(repo / "package.json", json.dumps(package, ensure_ascii=False, indent=2) + "\n")
lock = json.loads((TEMPLATE / "package-lock.json").read_text(encoding="utf-8"))
lock["name"] = package["name"]
if "packages" in lock and "" in lock["packages"]:
lock["packages"][""]["name"] = package["name"]
write(repo / "package-lock.json", json.dumps(lock, ensure_ascii=False, indent=2) + "\n")
write(repo / "stem-card.yaml", """
schema: 1
targets:
native: {profile: native-amd64, actions: [build, test, run, debug]}
actions:
build: [bash, tools/card-action.sh, build]
test: [bash, tools/card-action.sh, test]
run: [bash, tools/card-action.sh, run]
debug: [bash, tools/card-action.sh, debug]
artifacts: {directory: .stem/artifacts}
""")
write(repo / "tools" / "card-action.sh", CARD_ACTION, executable=True)
write(repo / "Makefile", """
TASK ?= task01
.PHONY: build test run trace clean
build:
\t@CARD_ROOT="$(CURDIR)" tools/card-action.sh build
test:
\t@CARD_ROOT="$(CURDIR)" STEM_TASK="$(TASK)" tools/card-action.sh test
run: test
trace:
\t@CARD_ROOT="$(CURDIR)" STEM_TASK="$(TASK)" tools/card-action.sh debug
clean:
\t@find .stem/artifacts -mindepth 1 -maxdepth 7 -type f -delete 2>/dev/null || true
""")
flow = ["schema: 1", f"card: cpp/{lesson['id']}", f"title: {lesson['title']}", "steps:"]
for index, (title, _prompt, _expected, _files) in enumerate(lesson["tasks"], 1):
flow.extend([
f" - id: task-{index:02d}", f" task: task{index:02d}", " action: test", " profile: native-amd64", " target: native",
f" command: stemctl test native-amd64 cpp {lesson['id']} {index}",
f" board:", f" show: [source, stdout, binary]", f" highlight: [cxx20, {lesson['slug'].replace('-', '_')}]",
f" question: {title} — jaka reguła języka wyjaśnia dokładny wynik?",
f" evidence: [compile_warnings_zero, expected_stdout, exit_zero]",
])
write(repo / "lesson-flow.yaml", "\n".join(flow) + "\n")
for index, (_title, _prompt, expected, files) in enumerate(lesson["tasks"], 1):
task = f"task{index:02d}"
for name, source in files.items():
write(repo / "src" / task / name, source)
write(repo / "tests" / "expected" / f"{task}.txt", expected + "\n")
document_uuid = str(uuid.uuid5(UUID_NAMESPACE, lesson["repo"]))
source = card_source(lesson, document_uuid)
write(repo / "json" / "card_source.json", json.dumps(source, ensure_ascii=False, indent=2) + "\n")
write(repo / "doc" / "main.tex", f"""
\\newcommand{{\\PublisherDomain}}{{mpabi}}
\\newcommand{{\\CardArea}}{{inf}}
\\newcommand{{\\CardSeries}}{{cpp-y2s1}}
\\newcommand{{\\CardNumber}}{{{lesson['number']}}}
\\newcommand{{\\CardSlug}}{{{lesson['slug']}}}
\\newcommand{{\\CardVersion}}{{v00.01}}
\\newcommand{{\\DocumentUUID}}{{{document_uuid}}}
""")
expected_rows = "\n".join(f"| Task{index:02d} | `{title}` | `{expected.replace(chr(10), ' / ')}` |" for index, (title, _prompt, expected, _files) in enumerate(lesson["tasks"], 1))
write(repo / "README.md", f"""
# {lesson['id']}{lesson['title']}
Karta {lesson['number']}/10 kursu **C++ · Rok 2 · Semestr 1**. Standard: C++20.
Oś merytoryczna: {lesson['chapter']}. Materiał książkowy jest parafrazowany;
repozytorium zawiera samodzielne eksperymenty i testy, a nie kopię książki.
## Taski
| Task | Temat | Dokładny dowód stdout |
| --- | --- | --- |
{expected_rows}
Każdy task jest osobnym programem w `src/task0N`. Test kompiluje wszystkie
jednostki translacji poleceniem zgodnym z `-std=c++20 -Wall -Wextra
-Wpedantic -Werror`, uruchamia program i porównuje dokładny wynik.
## Uruchomienie
```bash
stemctl build native-amd64 cpp {lesson['id']} 1
stemctl test native-amd64 cpp {lesson['id']} 1
stemctl test native-amd64 cpp {lesson['id']} 2
stemctl debug native-amd64 cpp {lesson['id']} 3
```
Lokalnie można użyć `make build`, `make test TASK=task02` i
`make trace TASK=task03`. Ślad debuggera trafia do `.stem/artifacts`.
## Granica semestru
Ta seria nie uczy API RTOS, zaawansowanych kontenerów STL ani
współbieżności. Są to osobne bloki następnych semestrów opisanych w
`/home/user/dev/keys/cxx.md`.
""")
answer_lines = [f"# Odpowiedzi — {lesson['id']}", "", lesson["mission"], ""]
for index, (title, prompt, expected, files) in enumerate(lesson["tasks"], 1):
answer_lines.extend([
f"## Task{index:02d}{title}", "", prompt, "",
f"Oczekiwany stdout: `{expected.replace(chr(10), ' / ')}`.", "",
f"Pliki dowodu: {', '.join(f'`src/task{index:02d}/{name}`' for name in sorted(files))}.", "",
"Wynik nie jest oceniany wzrokowo: test kompiluje kod bez ostrzeżeń, uruchamia go i wykonuje dokładne `diff` z plikiem `tests/expected`.", "",
])
write(repo / "answers" / "solutions.md", "\n".join(answer_lines))
write(repo / "tests" / "card_contract.test.mjs", f"""
import assert from 'node:assert/strict';
import {{ access, readFile }} from 'node:fs/promises';
import test from 'node:test';
const source = JSON.parse(await readFile(new URL('../json/card_source.json', import.meta.url), 'utf8'));
test('{lesson['id']} identity and task order are stable', () => {{
assert.equal(source.card.number, '{lesson['number']}');
assert.equal(source.card.uuid, '{document_uuid}');
assert.deepEqual(source.tasks_order, ['task01', 'task02', 'task03']);
assert.match(JSON.stringify(source), /C\\+\\+20/);
}});
test('all task programs and expected outputs exist', async () => {{
for (const task of ['task01', 'task02', 'task03']) {{
await access(new URL(`../src/${{task}}/main.cpp`, import.meta.url));
await access(new URL(`./expected/${{task}}.txt`, import.meta.url));
}}
}});
""")
shutil.copy2(TEMPLATE / "tests" / "card_state_db.test.mjs", repo / "tests" / "card_state_db.test.mjs")
def main() -> None:
OUTPUT.mkdir(parents=True, exist_ok=True)
for lesson in LESSONS:
generate_lesson(lesson)
print(f"generated {lesson['id']} {lesson['repo']}")
if __name__ == "__main__":
main()
+19 -1
View File
@@ -13,7 +13,7 @@
"title": "Legacy Informatyka series", "title": "Legacy Informatyka series",
"role": "series", "role": "series",
"legacy": true, "legacy": true,
"series": ["inf", "freertos"] "series": ["console-bash", "inf", "rv32i-asm", "freertos"]
}, },
{ {
"id": "edu-fiz", "id": "edu-fiz",
@@ -32,13 +32,27 @@
"title": "FreeRTOS C++ series", "title": "FreeRTOS C++ series",
"role": "series", "role": "series",
"series": ["freertos-cpp"] "series": ["freertos-cpp"]
},
{
"id": "edu-cpp",
"title": "C++ course series",
"role": "series",
"series": ["cpp"]
} }
], ],
"series": [ "series": [
{
"id": "console-bash",
"file": "series/console-bash.json"
},
{ {
"id": "inf", "id": "inf",
"file": "series/inf.json" "file": "series/inf.json"
}, },
{
"id": "rv32i-asm",
"file": "series/rv32i-asm.json"
},
{ {
"id": "fiz", "id": "fiz",
"file": "series/fiz.json" "file": "series/fiz.json"
@@ -54,6 +68,10 @@
{ {
"id": "freertos-cpp", "id": "freertos-cpp",
"file": "series/freertos-cpp.json" "file": "series/freertos-cpp.json"
},
{
"id": "cpp",
"file": "series/cpp.json"
} }
], ],
"catalog_subjects": [ "catalog_subjects": [