\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 one(storage1, "one", 5, probe1); PeriodicTimer 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 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}