{{indexmenu_n>9}}
======== HW 9 - Vícevláknová aplikace s meziprocesovou komunikací ========
/*^ **[[courses:bab36prga:hw:start#ulohy_hw8_a_hw9 | Časný termín]]** | **[[courses:bab36prga:hw:start#Úloha HW9 | 20.05.2023 23:59 PDT]]** |*/
^ Termín odevzdání | 20.5.2023 23:59 AoE ** 24.05.2023 23:59 CEST (st) ** |
^ Povinné zadání | 5b |
^ Volitelné zadání | 5b |
^ Bonusové zadání | není |
^ Počet uploadů | bez omezení |
^ Výchozí soubory | {{ :courses:bab36prga:hw:bab36prga-hw9.zip |}} |
^ Výchozí soubory | [[courses:bab36prga:hw:hw9hints|Doporučený postup při vypracování HW9]]|
Cílem úlohy je rozvést zkušenosti s využitím pojmenované roury pro komunikaci aplikace v počítači s poskytnutým Modulem a s prací s více vlákny pro zpracování více zdrojů událostí.
Specifikum práce s pojmenovanou rourou je, že při otevření souboru (roury) pro zápis musí být roura otevřena pro čtení, aby bylo kam případně ukládat data. Proto je volání ''io_open_write()'' blokované. Řešením je tak spustit program generátoru signálu''./binaries/bab36prga-hw9-sigen'' nebo vyčítání roury programem ''tail -f /tmp/sigen.in''.
/*
HW9 vychází z HW8, kterou je možné přímo rozšířit o výpočet fraktálu a využití fronty pro komunikaci mezi vlákny.
*/
====== Povinné zadání ======
Implementujete více-vláknový program, který bude komunikovat s programem generujícím signál (''sigen'') prostřednictvím pojmenované roury, ovládat generování signálu (nastavovat parametry) a vyčítat generovaný signál, který zobrazí v grafickém okně s využitím přiložené knihovny ''xwin_otk_plot'' založené na grafické knihovně ''otk_lib''. Komunikační protokol probíhá prostřednictvím zpráv definovaných v přiložených souborech ''messages.h'' a ''messages.c'', které obsahují funkce pro //marshaling// a //unmarshaling// struktur zpráv do/z pole bajtů.
Od programu se očekává následující funkcionalita:
* Program využívá samostatná vlákna pro zpracování vstupu z klavesnice, čtení zpráv z generátoru ''sigen'' (pojmenovaná roura) a hlavní vlákna.
* K synchronizace můžete využít přiloženou implementaci fronty zpráv ''event_queue.h'' a ''event_queue.c''.
* Program nastavuje generátor a spouští generování signálu, který zobrazuje prostřednictvím přiložené knihovny funkcí ''xwin_set_plot()'' a ''xwin_redraw_plot()''.
* Nastavuje parametry generátoru EKG (ECG) signálu //heart_rate_mean//, //low_frequency//, //high_frequency// a //low_high_frequency_ratio//, například klávesami '1' až '8' a to v rozsahu definovaném v ''message.h''.
* Na stisk klávesy ''g'' reaguje zasláním zprávy ''MSG_GET_VERSION'' a následně zobrazí odpověď.
* Na stisk klávesy ''s'' reaguje zasláním zprávy ''MSG_SET_SIGNAL'' s aktuálním nastavením generátoru signálu.
* Na stisk klávesy ''r'' reaguje zasláním požadavku na generování signálu ''MSG_SIGNAL'', který následně přijme a zobrazí v grafu. **Signál je zaslán v jedné nebo několika zprávách o maximální delce 128 hodnot.**
* Přijem signálu je možné přerušit stiskem klávesy ''a''.
* Na stisk klávesy ''c'' reaguje smazáním grafu.
* Program je korektně ukončen po stisku klávesy ''q''.
* **Úkol**: Implementujte generování, příjem a zobrazení několika signálu (vícenásobné zaslání ''MSG_SIGNAL'') ideálně každý s jiným nastavením. Program bude po stisku klávesy ''b'' automaticky komunikovat s generátorem, spouštět genrování signálu a nastavovat jeho parametry. Generování je možné kdykoliv přerušit stiskem klávesy ''a'' (abort).
{{:courses:bab36prga:hw:prga-hw9.png?400|}}
===== Ovládací aplikace =====
Ovladací aplikace ''sigen'' je více-vláknovým program, který reaguje na stisk kláves, vstup z pojmenované roury a zapisuje do pojmenované roury. Program má dva volitelné argumenty, kterými jsou pojmenovaná roura vstupu a pojmenovaná roura výstupu. Výchozí hodnoty odpovídají volání:
./sigen /tmp/sigen.in /tmp/sigen.out
Po spouštení program zasílá (zapisuje do výstupní pojmenované roury) zprávu ''MSG_STARTUP'', která obsahuje textovou zprávu "PRG-SIGEN". Program reaguje na příjem zpráv (viz komunikační protokol) a generuje signál, jehož parametry lze měnit zasláním zprávy ''MSG_SET_SIGNAL''
Program reaguje na stisk následujících kláves
* ''a'' - **ABORT** - Přerušení generování (posílání signálu) a zaslání zprávy ''MSG_ABORT''.
* ''r'' - **REBOOT** - Soft "restart" generátoru, zašle zprávu ''MSG_STARTUP'' podobně jako při spuštení programu.
* ''q'' - **QUIT** Ukončení programu.
===== Komunikační protokol =====
Program na Nucleo desce počítá konkrétní část fraktálu podle zadaných parametrů, které jsou z ovládací aplikace zasílány po sériovém portu. Vlastní výpočet probíhá tak, že řídicí aplikace zašle zprávu ''MSG_COMPUTE'', která specifikuje část výpočtu tzv. chunk ID (cid). Výchozím bodem obdélníkového výřezu pro výpočet je dán komplexním číslem $re + im j$ a počtem hodnot (sloupců) na reálné ose (z leva do prava) a počtem hodnot (řádku) na imaginární ose (zhora dolů). Krok sloupce a řádku, spolu s hodnotou komplexního čísla $c$ a počtem kroků je součástí zprávy ''MSG_SET_COMPUTE''. Definice jednotlivých zpráv odpovídá definici složeného typu ''struct message'' v souboru ''message.h''
// Definition of the communication messages
typedef enum {
MSG_OK, // ack of the received message
MSG_ERROR, // report error on the previously received command
MSG_ABORT, // abort - from user button or from serial port
MSG_DONE, // report the requested work has been done
MSG_GET_VERSION, // request version of the firmware
MSG_VERSION, // send version of the firmware as major,minor, patch level, e.g., 1.0p1
MSG_STARTUP, // init message (id, up to 9 bytes long string, cksum)
MSG_SET_SIGNAL, // set signal parameters
MSG_SIGNAL, // request signal of a batch of tasks (chunk_id)
MSG_SIGNAL_DATA, // computed result (chunk_id, result)
MSG_NBR
} message_type;
typedef struct {
uint8_t major;
uint8_t minor;
uint8_t patch;
} msg_version;
typedef struct {
uint8_t message[STARTUP_MSG_LEN];
} msg_startup;
#define HEART_RATE_MEAN_MIN 10.0
#define HEART_RATE_MEAN_MAX 200.0
#define LOW_FREQ_MIN 0.1
#define LOW_FREQ_MAX 0.5
#define HIGH_FREQ_MIN 0.25
#define HIGH_FREQ_MAX 1.0
#define LOW_HIGH_FREQ_RATIO_MIN 0.0
#define LOW_HIGH_FREQ_RATIO_MAX 1.0
typedef struct {
double heart_rate_mean; // default: 60; 10--200;
double low_frequency; // default: 0.1; 0.1--0.5;
double high_frequency; //default: 0.25; 0.25--1.0;
double low_high_frequency_ratio; //default: 0.5 0-1;
} msg_set_signal;
typedef struct {
uint8_t cid; // chunk id
uint8_t n; // actual no. of valid data values
float values[SIGNAL_DATA_SIZE];
} msg_signal_data;
typedef struct {
uint8_t type; // message type
uint8_t cksum; // message command
union {
msg_version version;
msg_startup startup;
msg_set_signal set_signal;
msg_signal_data signal_data;
} data;
} message;
Inicializační zpráva ''MSG_STARTUP'' je definována jako
message msg = { .data.startup.message = { 'P', 'R', 'G', '-', 'S', 'I', 'G', 'E', 'N' } };
=== Výměna zpráv a průběh komunikace ===
* Po startu program posílá zprávu ''MSG_STARTUP''
* Na příjem zprávy ''MSG_GET_VERSION'' odpovídá ''MSG_VERSION'' nebo ''MSG_ERROR''
* Na příjem zprávy ''MSG_SET_SIGNAL'' odpovídá Nucleo ''MSG_OK'' nebo ''MSG_ERROR'' (v případě, že požadované parametry jsou mimo definovaný rozsah).
* Na příjem zprávy ''MSG_SIGNAL'' odpovídá ''MSG_OK'' a zahajuje generování signálu nebo v případě chyby posílá ''MSG_ERROR''. Generovaný signál je posílán postupně v několika zprávách ''MSG_SIGNAL_DATA''. Po dokončení výpočtu zasílá zprávu ''MSG_DONE''.
* Generování je možné přerušit zasláním zprávy ''MSG_ABORT'', na kterou odpovídá ''MSG_OK'' a přeruší a ukončí aktuáně probíhající generování/zasílání signálu.
* Po přerušení posílá zprávu ''MSG_ABORT''.
* Přerušení je možné také stiskem klávesy 'a'.
V případě zaslání zprávy ''MSG_SET_SIGNAL'' nebo i ''MSG_SIGNAL'' jsou nastaveny nové hodnoty a generování signálu pokračuje podle posledně zadaných hodnot. Kdykoliv (i v případě běžícího generování signálu) je možné si vyžádat verzi programu zasláním zprávy ''MSG_GET_VERSION'', na kterou generátor promptně odpovídá ''MSG_VERSION''.
Typický průběh komunikace mezi PC a Nucleo deskou může vypadat například následovně:
* //sigen//: ''MSG_STARTUP''
* //Prog.//: ''MSG_GET_VERSION''
* //sigen//: ''MSG_VERSION''
* //Prog.//: ''MSG_SET_SIGNAL''
* //sigen//: ''MSG_OK''
* //Prog.//: ''MSG_SIGNAL''
* //sigen//: ''MSG_OK''
* //sigen//: ''MSG_COMPUTE_DATA''
* //sigen//: ''MSG_COMPUTE_DATA''
* //sigen//: ''MSG_COMPUTE_DATA''
* //sigen//: ''MSG_COMPUTE_DATA''
* ...
* //sigen//: ''MSG_COMPUTE_DATA''
* //sigen//: ''MSG_DONE''
==== Doporučený postup implementace ====
Doporučený postup implementace a tipy k implementaci naleznete zde [[courses:bab36prga:hw:hw9hints|Doporučení a tipy pro HW9]]
====== Odevzdávané soubory ======
Odevzdávejte zip archiv, který bude obsahovat všechny podpůrné soubory, které jste dostali k dispozici, implementovanou logiku aplikace ''prga-hw09-main.c'', implementovanou frontu ''event_queue.c'', a všechny další soubory, které využíváte.
====== Odevzdání a hodnocení ======
/* Veřejné příklady + Makefile: {{ :courses:bab36prga:hw:bab36prga-hw09.zip |}} */
Program pokud možno realizujte na cvičení, nahrajte do odevzdávacího systému. Funkčnost programu ověří učitel.
^ ^ Povinné zadání ^
^ Název v BRUTE | HW9 |
^ Odevzdávané soubory | ''prga-hw9-main.c'', ''event_queue.c'', podpůrné soubory |
^ Argumenty při spuštění | žádné |
^ Procvičované oblasti | vlákna, pojmenovaná roura |