Files
2026-07-21 19:14:20 +02:00

195 lines
7.5 KiB
TeX

\documentclass[10pt]{article}
\usepackage[T1]{fontenc}\usepackage[utf8]{inputenc}\usepackage[polish]{babel}
\usepackage[a4paper,margin=1.55cm]{geometry}
\usepackage{array,tabularx,booktabs,amsmath,amssymb,xcolor,listings,hyperref,fancyhdr,lastpage,enumitem}
\definecolor{accent}{HTML}{16324A}\definecolor{accentlight}{HTML}{EEF3F7}\definecolor{rulegray}{HTML}{D7DEE5}
\hypersetup{colorlinks=true,linkcolor=accent,urlcolor=blue}
\IfFileExists{build-meta.tex}{\input{build-meta.tex}}{\newcommand{\BuildCommit}{local}}
\newcommand{\PublisherDomain}{mpabi}
\newcommand{\CardArea}{inf}
\newcommand{\CardSeries}{freertos-cpp}
\newcommand{\CardNumber}{14}
\newcommand{\CardCount}{16}
\newcommand{\CardSlug}{sw-timer}
\newcommand{\CardVersion}{v00.01}
\newcommand{\DocumentUUID}{78db37df-63e5-4c5b-80ce-f73a411f0b50}
\newcommand{\blank}[1]{\rule{#1}{.2pt}}
\lstset{language=C++,basicstyle=\ttfamily\scriptsize,columns=fullflexible,keepspaces=true,frame=single,breaklines=true,showstringspaces=false,numbers=none,backgroundcolor=\color{accentlight},rulecolor=\color{rulegray}}
\pagestyle{fancy}\fancyhf{}
\lhead{\textbf{K14 · FreeRTOS C++ · SoftwareTimer}}\rhead{\small L13 · timer daemon task}
\lfoot{\scriptsize commit \BuildCommit}\cfoot{\scriptsize \thepage/\pageref{LastPage}}\rfoot{\scriptsize V11.3.0 / \CardVersion}
\setlength{\headheight}{14pt}\setlength{\footskip}{19pt}
\setlist[itemize]{nosep,leftmargin=1.45em}\setlist[enumerate]{nosep,leftmargin=1.65em}
\begin{document}\sloppy
\begin{center}
{\LARGE\bfseries Software timer i timer daemon task}\par
\vspace{.25em}{\large one-shot, periodic, command queue i typed callback context}\par
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.65cm}Xp{1.75cm}X@{}}
\toprule
Karta & K14 / \CardCount & Czas & 30 minut \\
Platforma & Hazard3 / RV32I & Kernel & FreeRTOS V11.3.0 \\
Timery & static one-shot + periodic & Heap delta & 0 B \\
Wersja & \CardVersion & UUID karty & \texttt{78db37df-...} \\
\bottomrule
\end{tabularx}
\section*{Polityka jest częścią typu}
\begin{lstlisting}
OneShotTimer<Probe> one(storage1, "one", 5, probe1);
PeriodicTimer<Probe> cycle(storage2, "cycle", 2, probe2);
auto accepted = cycle.start(); // command queue
// callback jeszcze nie musi byc wykonany
\end{lstlisting}
\noindent\fcolorbox{accent}{accentlight}{\begin{minipage}{.94\textwidth}
\textbf{Kontrakt K14.} Wrapper nie jest copy/move. \texttt{start/reset/change/stop}
zwracają przyjęcie polecenia przez kolejkę daemona. Callback działa później na
współdzielonym timer service tasku, a context i storage muszą nadal istnieć.
\end{minipage}}
\section*{Plan 30 minut}
\noindent\begin{tabularx}{\textwidth}{@{}p{1.35cm}p{3.1cm}X@{}}
\toprule Czas & Tryb & Dowód \\
\midrule
0--5 & contract & non-copy, typed policy, explicit start \\
5--10 & queue & 2 start accepted; callback snapshot 0 \\
10--15 & periodic & callback w tickach 2 i 4 \\
15--20 & commands & reset@1, change 2--3@4 \\
20--25 & daemon & handle/name, osobny stos \\
25--30 & stop/lifetime & tick 7, inactive, bez 4. callbacku \\
\bottomrule
\end{tabularx}
\section*{Predykcja}
Czy \texttt{pdPASS} ze start oznacza wykonany callback? \blank{2cm}.
Gdzie callback się wykona: ISR, caller czy daemon? \blank{4cm}.
\newpage
\section{Kolejka poleceń a wykonanie}
\begin{center}
\texttt{main: start(one), start(periodic) -- accepted, callbacks=0}\\
$\downarrow$ \texttt{scheduler + Tmr Svc processes commands}\\
$\downarrow$ \texttt{expiry -- daemon invokes typed trampoline}
\end{center}
\noindent\begin{tabularx}{\textwidth}{@{}p{5.2cm}p{3.1cm}X@{}}
\toprule Pomiar & Predykcja & Odczyt \\
\midrule
start commands accepted & 2 & \blank{2.5cm} \\
callbacks przy return ze start & 0 & \blank{2.5cm} \\
verifier entry tick & 0 & \blank{2.5cm} \\
periodic first expiry & 2 & \blank{2.5cm} \\
periodic second expiry & 4 & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section{Reset one-shot i zmiana okresu}
\begin{lstlisting}
// tick 1
one.reset(); // new expiry: 1 + 5 = 6
// tick 4, after periodic callbacks 2 and 4
cycle.change_period(3); // next expiry: 4 + 3 = 7
\end{lstlisting}
\noindent\begin{tabularx}{\textwidth}{@{}p{5.2cm}p{3.1cm}X@{}}
\toprule Pomiar & Predykcja & Odczyt \\
\midrule
reset command tick / accepted & 1 / true & \blank{2.5cm} \\
one-shot callback tick & 6 & \blank{2.5cm} \\
one-shot active po expiry & false & \blank{2.5cm} \\
change command tick / accepted & 4 / true & \blank{2.5cm} \\
periodic next callback & 7 & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
Wyjaśnij różnicę między reset i change-period:\\[.4em]
\blank{16cm}\\[.8em]\blank{16cm}
\newpage
\section{Dowód kontekstu timer daemon}
Callback nie działa w przerwaniu ani na stosie taska, który wywołał
\texttt{start}. Wszystkie software timers współdzielą jeden daemon.
\noindent\begin{tabularx}{\textwidth}{@{}p{5.4cm}p{3.1cm}X@{}}
\toprule Pomiar & Predykcja & Odczyt \\
\midrule
current == timer daemon handle & true & \blank{2.5cm} \\
task name zaczyna się od \texttt{Tmr S} & true & \blank{2.5cm} \\
callback SP != verifier SP & true & \blank{2.5cm} \\
callback może blokować & nie & \blank{2.5cm} \\
\bottomrule
\end{tabularx}
\section*{Dlaczego callback ma być krótki?}
Jeden długi callback opóźnia obsługę poleceń i expiries wszystkich timerów.
Ciężką pracę przekaż taskowi przez notification, semaphore albo queue.
Zaproponuj granicę callback/task dla sterowania LED:\\[.4em]
\blank{16cm}\\[.8em]\blank{16cm}
\section{Storage i lifetime}
\begin{lstlisting}
StaticTimer_t storage; // control block, caller-owned
Probe context; // timer ID points here
PeriodicTimer<Probe> timer(storage, "led", 2, context);
\end{lstlisting}
\begin{itemize}
\item oba control blocks i verifier storage są w \texttt{.bss};
\item heap przed/po \texttt{xTimerCreateStatic}: bez zmiany;
\item context, storage i wrapper żyją dłużej niż pending command/callback;
\item wrapper nie udaje, że destruktor synchronicznie opróżnił daemon queue.
\end{itemize}
\section*{Stop}
\texttt{stop()} accepted: \blank{2cm}. Active po przetworzeniu: \blank{2cm}.
Callback count po dalszych 4 tickach: \blank{2cm}. Dlaczego samo accepted nie
wystarcza jako dowód? \blank{5cm}.
\newpage
\section{Hazard3/GDB i zaliczenie}
\begin{lstlisting}[language=bash]
make check
riscv64-unknown-elf-gdb build/task01_sw_timer/prog.elf
b software_timer_debug_checkpoint
\end{lstlisting}
\begin{lstlisting}
p g_start_commands_accepted
p g_callbacks_when_start_returned
p g_verifier_entry_tick
p g_reset_tick
p g_change_tick
p g_one_shot_tick
p g_periodic_ticks
p g_one_shot_active_after_expiry
p g_periodic_active_after_stop
p g_daemon_handle_match
p g_daemon_name_match
p g_heap_before_timer_create
p g_heap_after_timer_create
p g_timer_pass
\end{lstlisting}
\section*{Zaliczenie}
\begin{itemize}
\item $\square$ rozróżniam accepted command od wykonanego callbacku;
\item $\square$ pokazuję periodic ticks 2, 4, potem po zmianie 7;
\item $\square$ reset@1 przesuwa one-shot na tick 6 i timer staje inactive;
\item $\square$ callback działa na \texttt{Tmr Svc} i osobnym stosie;
\item $\square$ stop pozostawia inactive i brak czwartego callbacku;
\item $\square$ static storage daje heap delta 0 i wrapper bez runtime C++.
\end{itemize}
\section*{Wyjście}
Dlaczego nie wolno przechwycić wskaźnika do krótkotrwałego obiektu jako timer
ID?\\[.5em]\blank{16cm}\\[1em]
Co długi callback robi z innymi timerami?\\[.5em]\blank{16cm}
\vfill
\noindent\textbf{Następna karta K15:} jawne API FromISR, kontrakt
\texttt{higherPriorityTaskWoken}, UART RX i GPIO edge wrappers.
\end{document}