{{indexmenu_n>10}}
======== HW 9B - Vícevláknová aplikace s meziprocesovou komunikací ========
^ Termín odevzdání |** 22.05.2024@09:00 CEST (st) ** |
^ Povinné zadání | [[courses:bab36prga:hw:hw9|HW 9]] |
^ Volitelné zadání | není |
^ Bonusové zadání | 5b |
^ Počet uploadů | bez omezení |
^ Výchozí soubory | {{ :courses:bab36prga:hw:bab36prga-hw9b.zip |}} |
^ Výchozí soubory | [[courses:bab36prga:hw:hw9bhints|Doporučený postup při vypracování HW9B]]|
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-hw9b-sigen'' nebo vyčítání roury programem ''tail -f /tmp/sigen.in''.
/*
HW9B vychází z HW9, 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|}}
OTK je jednoduchá knihova grafických prvků implementovaná v OpenGL. Kompilace může vyžadovat instalaci potřebných knihoven. Např. v operačním systému založeném na Ubuntu to může být ''libxmu-dev'' tedy ''apt install libxmu-dev''.
===== 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 ''sigen'' generuje signál dle zadaných parametrů, které jsou zasílány z ovládací aplikace zprávou ''MSG_SET_SIGNAL''. Vlastní generování probíhá tak, že řídicí aplikace zašle zprávu ''MSG_SIGNAL'', na kterou ''sigen'' reaguje zasláním několika zpráva ''MSG_SIGNAL_DATA'' s obsahem hodnot definující konkrétní rozsah signálu. 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:hw9bhints|Doporučení a tipy pro HW 9B]]
====== Odevzdávané soubory ======
Odevzdávejte zip archiv, který bude obsahovat všechny podpůrné soubory, které jste dostali k dispozici, implementovanou logiku aplikace ''prga-hw9b-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 | HW9B |
^ Odevzdávané soubory | ''prga-hw9b-main.c'', ''event_queue.c'', podpůrné soubory |
^ Argumenty při spuštění | žádné |
^ Procvičované oblasti | vlákna, pojmenovaná roura |