This repository was archived by the owner on Mar 15, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproject.tex
More file actions
304 lines (199 loc) · 61.9 KB
/
project.tex
File metadata and controls
304 lines (199 loc) · 61.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
\subsection{Introduzione al progetto}
Con questo firmware (scritto in C) si vuole implementare una parte del progetto \textit{Foo} (il vero nome non pu\`o essere reso pubblico), che mira a fornire un controllo remoto per le colorazioni delle vetrine di un negozio (o una catena di negozi), con possibilit\`a di essere esteso con nuove funzionalit\`a e di essere il pi\`u possibile automatizzato nella diagnosi degli errori e nell'assistenza remota. All'interno del negozio ogni vetrina avr\`a un led RGB, controllato con \textit{PWM} da una schedina \textit{STM32} (da definire se \textit{F401} o \textit{F072}), ognuna di queste schede sar\`a in contatto bluetooth con una scheda centrale (per cui questo firmware \`e pensato), unica per ogni negozio, che sar\`a a sua volta connessa via ethernet ad un server web, contenente il database utilizzato nel progetto e i firmware per poter eseguire un aggiornamento \textit{OTA} (Over The Air). Un operatore con accesso al server (attraverso credenziali), sar\`a in grado di gestire le vetrine all'interno del proprio negozio e un amministratore sar\`a in grado di accedere a tutte le vetrine presenti (immaginate come vetrine delle varie filiali).
Verranno utilizzati principalmente software e hardware prodotti dalla \textit{ST Microelectronics}, azienda italo-francese specializzata nella produzione di dispositivi elettronici, essenzialmente utilizzati nello sviluppo di tecnologie embedded. \textit{STM32} \`e una famiglia di microcontrollori basati su processori \textit{ARM} a 32 bit, la \textit{ST} produce piattaforme hardware e software per poter sviluppare su questi dispositivi.
Questo specifico progetto \`e nato inizialmente per la singola gestione della comunicazione via ethernet dei dati con il server (\texttt{eth\_test}), successivamente \`e stata implementata in maniera separata la funzionalit\`a bluetooth (\texttt{bl\_merge}) e infine le due sezioni sono state unite per comporre il progetto come lo si trova al momento della stesura di questo documento (\texttt{shop429}). Uno storico delle varie modifiche pu\`o essere consultato nella sezione \textit{CHANGELOG} del documento, questa ripercorre quasi completamente i commit effettuati sulle repository \textit{git} dei diversi progetti, divisi opportunamente tra versioni in base all'entit\`a delle modifiche.
\subsubsection{Hardware impiegato}
\textdesc{figura \ref{fig:boards}}
Questo progetto mira a scrivere un firmware per la board \texttt{STM32F429ZI Nucleo}, una scheda di sviluppo fornita dalla ST e basata su processore \textit{ARM Cortex-M4}, l'architettura presente \`e interamente a 32 bit. La board presenta 144 pin utilizzabili per collegare altre periferiche (tra cui quelle che soddisfano le specifiche \textit{ST morpho} e \textit{Arduino R3}) ed \`e costruita per poter essere assemblata con altre board simili in una pila avente i pin comunicanti. Il \textit{SoC} supporta diverse periferiche tra cui diversi bus \textit{SPI} e una presa ethernet (il connettore \`e presente sulla board).
Per poter utilizzare la connettivit\`a bluetooth \`e necessario includere una estensione. In questo caso, \`e stata utilizzata la scheda \texttt{X-NUCLEO-IDB05A1}, un modulo che implementa la connettivit\`a \textit{BLE} (Bluetooth Low Energy) e installabile sulle board di sviluppo STM32 utilizzando i connettori Arduino R3. A causa di sovrapposizione tra alcuni pin del processore, utilizzabili sia per ethernet che \textit{SPI}, \`e stato necessario effettuare delle modifiche su entrambe le board per poterli spostare. Questo \`e stato facilmente ottenibile muovendo i relativi solder bridge sulle schede.
Le board di sviluppo \textit{STM32} (tra cui quella utilizzata) contengono l'interfaccia ST-Link per agevolare la connessione e l'interazione della scheda con il PC, questa sezione contiene l'hardware necessario per permettere programmazione e debug del microcontrollore e pu\`o essere collegata con un cavetto micro-USB (in alternativa \`e possibile configurare l'\textit{UART}). Tale estensione pu\`o essere rimossa, se necessario, o collegata ad altre schede per poterle programmare.
\begin{figure}[ht]
\center
\begin{subfigure}{.45\textwidth}
\includegraphics[width=\textwidth]{st_nucleof429zi}
\caption{STM32F429ZI-NUCLEO}
\end{subfigure}
\hfill
\begin{subfigure}{.45\textwidth}
\includegraphics[width=\textwidth]{x_nucleo_idb05a1}
\caption{X-NUCLEO-IDB05A1}
\end{subfigure}
\caption{Board di sviluppo ST}
\label{fig:boards}
\end{figure}
\subsubsection{Ambiente di sviluppo}
\textdesc{figura \ref{fig:apps}}
Il progetto \`e portato avanti sull'\textit{IDE} \texttt{Atollic TrueStudio for STM32}, toolchain basata su \textit{Eclipse} che usa i tool di compilazione e debug GNU (\textit{gcc} e \textit{gdb}) recentemente acquisita dalla ST stessa (\`e stata utilizzata la versione 9.0.0).
Si \`e partiti da un progetto generato dal software \texttt{STM32CubeMX}, in grado di creare progetti per le varie toolchain contenenti le estensioni Driver e Middleware fornite da ST, impostando i valori specifici per ogni board o SoC. Vengono generate anche le varie inizializzazioni di periferiche e software aggiuntivi e quasi tutti i parametri possono essere direttamente configurati dalle apposite schermate del tool (\`e stata utilizzata la versione 4.25.1).
Per il controllo delle versioni si ricorre a \texttt{git}, direttamente accessibile da \textit{TrueStudio} attraverso l'apposita estensione di Eclipse, \`e cos\`i possibile avere una traccia puntuale dei progressi (attraverso lo storico dei commit) ed \`e possibile creare pi\`u varianti di test del progetto (attraverso i branch) che si potranno integrare quando avranno raggiunto sufficiente stabilit\`a (merge).
Il debug pu\`o essere portato avanti con gdb sempre su \textit{Atollic}, nella \textit{Perspective} di debug appare anche una finestra con la console SWV dove, se abilitato tramite la flag \texttt{DEBUG} in \texttt{includes/debug.h} (definita tra le sorgenti \textit{BlueNRG}), appaiono i log lanciati con \texttt{PRINTF}. In alternativa pu\`o essere utilizzato il software \texttt{STMStudio} per tenere traccia del valore delle variabili durante l'esecuzione (non \`e possibile usare entrambi i metodi contemporaneamente).
Nonostante la programmazione del firmware in flash (in formato \texttt{ELF}) avvenga direttamente in fase di debug utilizzando Atollic, esiste anche il tool \texttt{STM32Programmer}, utile per gestire direttamente la flash con operazioni come lettura e scrittura. Con questo software si pu\`o dunque programmare la scheda a partire dall'area di memoria specifica e utilizzando diversi formati (utile se si utilizza un \textit{bootloader} all'inizio della flash e per avere un eseguibile con dimensioni pi\`u contenute) oppure leggere specifiche aree di memoria che possono essere state programmate dalla board stessa (eeprom simulata o download del firmware).
\begin{figure}
\center
\begin{subfigure}{\textwidth}
\includegraphics[width=\textwidth]{cube}
\caption{STM32CubeMX}
\end{subfigure}
\hfill \break
\newline
\begin{subfigure}{\textwidth}
\includegraphics[width=\textwidth]{atollic}
\caption{Atollic TrueStudio}
\end{subfigure}
\caption{Software di sviluppo}
\label{fig:apps}
\end{figure}
\subsection{Struttura del software}
\subsubsection{Multithreading con FreeRTOS}
Nel firmware \`e abilitata la funzionalit\`a di \textit{FreeRTOS} (Real Time Operating System), una sorta di rudimentale sistema operativo in grado di gestire funzionalit\`a base di programmazione concorrenziale su dispositivi embedded. Supporta thread multiple e varie strutture per sincronizzare e gestire queste ultime, come semafori e timer. A causa di limitazioni hardware (il processore \`e unico), le thread non possono essere realmente eseguite in parallelo, ma l'\textit{RTOS} \`e in grado di alternare le esecuzioni delle varie thread quando queste vengono temporizzate. In pratica ogni thread \`e strutturata all'interno di una funzione contenente un loop infinito, all'interno di questo risiede l'effettivo codice da eseguire e al termine viene chiamata la funzione \texttt{osDelay()}. Questa informa il sistema operativo che le risorse possono essere impiegate per un'altra thread in attesa e la precedente viene messa in coda per un numero di millisecondi passato come argomento della chiamata. Al termine di tale intervallo la thread potr\`a essere eseguita non appena il sistema sar\`a in grado di allocarle le risorse.
All'inizio dell'esecuzione (\texttt{main()}), vengono effettuate tutte le inizializzazioni necessarie di hardware, strutture dati e OS, a questo punto \`e possibile caricare quest'ultimo. Al momento in cui ci\`o accade, il controllo passa allo \textit{scheduler} (\texttt{osKernelStart()}), che eseguir\`a le thread allocate precedentemente e tutto il codice, all'interno del main, che viene dopo questa chiamata non sar\`a pi\`u eseguito, in quanto il controllo passer\`a unicamente dalle thread.
La memoria utilizzata dall'\textit{RTOS} \`e allocata dinamicamente (nella \textit{heap}), viene per\`o settato un limite all'interno della configurazione in \textit{STM32Cube} che rappresenter\`a la memoria effettivamente designata al sistema operativo, utilizzata poi per allocare le varie thread, semafori e altre strutture. Ogni thread avr\`a a sua volta (all'interno della definizione) un limite di memoria che potr\`a utilizzare, questa memoria far\`a chiaramente parte di quella destinata all'OS e verr\`a utilizzata come stack della funzione (e delle varie funzioni richiamate da questa, nonostante sia fisicamente in heap). \`E importante notare che questo limite di memoria per thread dev'essere aggiustato a dovere, da un lato per evitare di utilizzare pi\`u risorse del necessario (questo pu\`o dipendere dal metodo di allocazione utilizzato, sempre impostabile dal \textit{STM32Cube}), dall'altro per\`o deve esserci spazio per tutte le variabili locali dichiarate all'interno della thread (di fatto dinamiche). Una mancata considerazione di tale limite pu\`o portare a comportamenti inaspettati, in quanto il sistema non \`e in grado di capire quando la memoria a disposizione \`e giunta al termine e quindi, utilizzando memoria che non potrebbe usare, smette semplicemente di funzionare, spesso senza mostrare errori in particolare. Tutte le variabili globali sono allocate staticamente (in quanto accessibili da ogni thread), non vanno quindi ad impattare sulla memoria dedicata all'OS, in maniera analoga si possono impostare le variabili locali come \texttt{static} per ottenere un risultato pi\`u simile a quello delle variabili globali (con tutto ci\`o che ne consegue, la \textit{keyword} \texttt{static} in questo caso permette un'allocazione statica, ma non \`e questa la sua funzione).
Il progetto implementa le due connettivit\`a (ethernet e bluetooth) in thread separate, all'interno di queste viene eseguita un'azione a seconda del valore della variabile \texttt{*\_state} (presente sia per eth che per ble), che permette di eseguire un operazione per ogni ciclo, quando deve essere effettuata. Una terza thread pu\`o innescare ciascuna trasmissione settando lo stato come \texttt{INIT} (ora viene gestito alla pressione del pulsante). Quando si trova in \texttt{END} il processo \`e in attesa di essere innescato (ritorna da ogni chiamata senza eseguire nessuna operazione), anche se in particolari condizioni \`e possibile che da quello stato inizi il processo di aggiornamento del firmware.
Per tenere traccia dei passaggi fatti, dunque, vengono utilizzate variabili create come \texttt{static}, che si comportano esattamente come variabili globali, mantenendo il valore tra una chiamata e l'altra, ma il loro scopo \`e ristretto alla funzione in cui sono definite (come quelle locali). Per quanto riguarda invece le variabili globali che vengono utilizzate in pi\`u thread o che vengono modificate a seguito di \textit{interrupt}, il modificatore \texttt{volatile} \`e utilizzato, in questa maniera si informa il compilatore che tali variabili non devono essere ottimizzate in alcun modo. Il compilatore infatti pu\`o non essere completamente consapevole di come tali variabili vengono modificate e potrebbe quindi rimuovere alcune istruzioni che considera superflue, compromettendo per\`o il corretto funzionamento di determinate procedure.
\subsubsection{Stati di esecuzione}
\textdesc{file \textit{Src/main.c}, \textit{Inc/main.h} e figura \ref{fig:sm}}
Dopo le inizializzazioni di hardware e database il sistema entra in funzione e periodicamente aggiorna i dati (ora questo avviene con la pressione del pulsante). Inizialmente, se necessario (\textbf{TODO} da definire) la data viene sincronizzata (\textit{eth}), successivamente parte il fetch dei dati dal server (\textit{eth}), prima i dati del negozio e poi delle vetrine. Questo processo viene saltato qualora la versione locale sia aggiornata, quando questo arriva al termine parte la scrittura dei nuovi dati su ciascuna vetrina (\textit{ble}). Nel mentre \`e stata effettuata una lettura dei dati attivi sui dispositivi (\textit{ble}) e la risposta al server con questi dati (\textit{eth}) \`e stata inviata. I processi si svolgono in parallelo, \`e stato impostato per\`o che le operazioni che coinvolgono la stessa interfaccia (\textit{ble} o \textit{eth}) si svolgano separatamente e che ogni scrittura deve essere eseguita dopo le relative letture (nello specifico le scritture da ciascuna interfaccia aspettano le letture dall'altra interfaccia, purch\'e non si verifichino errori).
Le definizioni di questi processi avvengono nelle funzioni \texttt{[BLE,ETH]\_Process()}, quando lo stato diventa \texttt{INIT} comincia la connessione, ad ogni esecuzione viene eseguita l'operazione indicata (\texttt{READ/WRITE/SYNC}) e se questa va a buon fine, si passa alla successiva, altrimenti in base al problema riscontrato si ripete il procedimento o si termina il servizio (stato \texttt{END}). (\textbf{TODO} implementare una trasmissione delle informazioni sugli errori al server utilizzando lo stato in \texttt{running\_shop}).
\begin{figure}[ht]
\includegraphics[width=\textwidth]{state_machine}
\caption{Schema della macchina a stati}
\label{fig:sm}
\end{figure}
\subsection{Strutture dati}
\subsubsection{Implementazione del database locale}
\textdesc{file \textit{Src/db\_struct.c}, \textit{Inc/db\_struct.h}}
Il database interno, per quanto riguarda la comunicazione con il server web, contiene due \texttt{struct}, rispettivamente per i dati del negozio e quelli delle vetrine (array), entrambi hanno 2 istanze statiche e 2 puntatori, \texttt{shadow\_} e \texttt{active\_} (che puntano rispettivamente a una delle due versioni) durante il fetch da ETH i dati vengono salvati all'interno delle strutture puntate da \texttt{shadow\_} e se sono coerenti i puntatori \texttt{shadow\_} e \texttt{active\_} vengono scambiati. Alla ricezione della linea riguardante il negozio, vengono controllati l'id e la versione (riguardante il database), se il primo coincide e la seconda \`e maggiore di quella salvata localmente, il fetch delle vetrine prosegue. Visto che la versione viene salvata in una variabile \texttt{uint8\_t}, \`e gestita anche la possibilit\`a di \textit{overflow} .Su ogni riga (negozio e vetrina) viene calcolato un checksum utilizzando l'algoritmo \textit{BSD} su 2 byte, se la sua verifica fallisce si tenter\`a una ritrasmissione.
Questo algoritmo per il checksum non fa altro che calcolare un valore, il pi\`u possibile univoco, partendo dai dati che vengono passati: iniziando da zero, ad ogni passo il valore (su 16 bit) subisce una rotazione \textit{bitwise} a destra e gli viene sommato il dato (8 bit) corrente. In questa maniera sia un cambiamento nei dati che un dato mancante modificherebbero il checksum e in generale \`e improbabile che una modifica arbitraria generi lo stesso valore. Questo dato viene utilizzato sia in ETH che leggendo dalla memoria locale (eeprom), un confronto tra il valore calcolato prima (e salvato/ricevuto assieme ai dati effettivi) e quello calcolato in lettura/ricezione rivela con una certa accuratezza se i dati sono corretti.
I dati ricevuti dal server web vengono trasferiti dalla struttura \texttt{active\_} alle rispettive vetrine (\textit{ble}), l\`i saranno gestiti in una tabella pronti per essere attivati in base alla data. Ora \`e possibile la lettura dei dati effettivamente attivi su ciascuna vetrina, che verranno poi salvati in una tabella specifica, contenente anche dati relativi al negozio (\texttt{running\_shop} e \texttt{running\_entries}). Quando tutti i dati sono pronti \`e possibile spedirli al server. Anche l\`i verr\`a controllato il checksum dei dati ricevuti e nel responso sar\`a utilizzato il codice 206 (al posto di 200) per chiedere una ritrasmissione, discorso analogo quando si verifica un errore nel database, qui il codice sar\`a 205. Nel caso di \texttt{shop\_id} errato viene restituito 404 (\texttt{NOT FOUND}) e la scrittura si blocca.
Le tabelle (array di tipo \texttt{struct vetrina}), contengono i dati di ciascuna vetrina, nello specifico i colori (\textit{rgb}), l'intensit\`a, la data in cui il cambiamento diverr\`a attivo e alcuni byte lasciati volutamente inutilizzati (\textit{spare}). L'ordine delle righe \`e quello con cui vengono ricevute dal server (non necessariamente ordinate per id) senza lasciare spazi vuoti tra una e l'altra, viene quindi utilizzata la funzione \texttt{findEntry(id)} che restituisce l'indice corrispondente alla vetrina con id passato come parametro, se presente (ritorna \texttt{0xFF} altrimenti). Per come \`e costruita, se viene raggiunto un id nullo la tabella \`e giunta al termine. La scrittura dei dati ricevuti dai dispositivi ble segue l'ordinamento imposto dal server (usando quindi \texttt{findEntries} che tiene come riferimento \texttt{active\_entries}), cos\`i facendo se una vetrina presente sul server non pu\`o essere raggiunta, la sua riga nella tabella \texttt{running\_entries} viene segnata con id=0 (e non viene inoltrata nella risposta).
Le funzioni di trasferimento hanno nomi del tipo \texttt{[get/set][Shop/Entry][Eth/Ble]}, dove vengono indicati rispettivamente se devono leggere o scrivere dati, per quale struttura e da che interfaccia, in generale servono per decodificare i dati ricevuti o preparare i dati da inviare.
Le variabili che fanno parte del database contengono valori iniziali che verranno usati prima del fetch (e qualora questo non andasse a buon fine), i valori del negozio sono inizializzati come default (definite attraverso costanti) mentre quelli delle vetrine sono tutti nulli fatta eccezione per alcuni id della tabella che diventer\`a \texttt{active\_} che conterr\`a le vetrine 1, 2 e 3. Durante la procedura di inizializzazione del database, viene controllata anche la eeprom e vengono acquisiti gli eventuali dati, solo se coerenti. La procedura \`e simile a quella effettuata per la ricezione da \textit{ETH}, in cui le tabelle \texttt{shadow\_} vengono popolate e successivamente attivate se il checksum corrisponde (o in generale il dato letto ha senso). Le funzioni \texttt{Activate*} utilizzate a tal proposito, salvano anche i dati ricevuti sulla eeprom se questa operazione \`e abilitata (cosa che capita in ricezione dal server e chiaramente non dopo la lettura dalla stessa eeprom).
\begin{figure}[ht]
\includegraphics[width=\textwidth]{structures}
\caption{Struttura del database locale}
\end{figure}
\subsubsection{Database remoto e interfaccia web}
Il database remoto viene gestito su server \texttt{Apache} (o qualunque altra alternativa che supporti \texttt{php} e \texttt{mysql}). \`E stato preferito il binomio php-mysql a tecnologie pi\`u moderne come ad esempio \texttt{Node.js} (accompagnato con database \texttt{NoSQL}) principalmente per la sua semplicit\`a d'uso. In questo progetto l'obiettivo principale non \`e un'interfaccia web dinamica, dove \textit{Node} sarebbe particolarmente indicato, ma un accesso rapido dei dati sia da dispositivi embedded (dove verosimilmente non viene impiegato javascript) che da utenti che passano da un browser, vengono quindi privilegiate le funzionalit\`a base di php.
Nella cartella \texttt{server\_files} sono contenute le pagine che devono stare nella cartella pubblica sul server (\textit{www} in Apache) e gli script di creazione del database. \texttt{index.php} non \`e nient'altro che il form iniziale per accedere (lato utente) alla visualizzazione grafica delle tabelle, che avviene su \texttt{control.php}. Qui \`e possibile la modifica dei parametri e la lettura dei dati ricevuti dai dispositivi. All'interno di \texttt{fetchData.php} vengono gestite tutte le richieste di lettura dalla board (in base alla query string che viene passata) mentre i file \texttt{write*.php} gestiscono rispettivamente la scrittura su server delle vetrine e dei dati del negozio.
Lo script \texttt{create\_table.sql} contiene le istruzioni per definire le due tabelle (vetrine e negozi), collegate da una \textit{foreign key} che \`e l'id del negozio. Sono presenti anche tabelle \texttt{feedback\_*} con la stessa struttura di vetrine e negozi, che conterranno i dati attivi letti dalle board, queste due versioni presentano una colonna che indica se la vetrina ha risposto nell'ultimo collegamento (ed \`e dunque attiva).
Le tabelle vengono popolate con alcuni dati iniziali e viene creato un utente per gestire l'unico negozio inserito, al momento per il negozio 1, l'utente \`e \texttt{shop1} con \texttt{password1} come chiave (chiaramente da cambiare), \`e importante per\`o che dal nome utente sia deducibile l'id del negozio (per come \`e ora deve essere l'unico numero all'interno del nome). Per evitare di permettere a ciascun utente di poter accedere all'intero database, si possono creare delle \texttt{VIEW} sulle tabelle, in modo da limitare la visione e gestione dell'utente \texttt{i} alle sole righe con \texttt{i} come \texttt{shop\_id} (l'amministratore non avr\`a queste limitazioni).
Per poter aggiornare i dati delle tabelle o del negozio da questa scheda su server, \`e necessario che le righe in tabella siano gi\`a presenti, per questa ragione, ogni volta che verr\`a inserita un vetrina o un negozio si dovr\`a inserire anche nella tabella \texttt{feedback\_*} (o quantomeno inserire una riga contenente gli id corretti). Questo capita perch\'e l'inserimento \`e consentito solamente all'utente \textit{root} (l'amministratore), mentre gli utenti specifici di ogni negozio possono soltanto eseguire \texttt{UPDATE} su dati gi\`a esistenti (la gestione sulle \texttt{VIEW} risulta pi\`u lineare). Per ogni nuovo negozio vanno inoltre creati l'utente e tutte le rispettive \texttt{VIEWS} (4 in totale). (\textbf{TODO} includere queste istruzioni in script specifici o crearne un'interfaccia dedicata)
Il fatto che le board possano soltanto aggiornare i dati ricevuti dalle vetrine salvati sul server, implica che non si tenga traccia delle vetrine che non hanno dato risposta (semplicemente non ne vengono modificati i dati). Implementare un \texttt{DELETE} potrebbe risultare rischioso o poco pratico, ma \`e necessario segnare quali vetrine sono effettivamente presenti e attive. La soluzione impiegata \`e stata l'impostazione di una flag \texttt{ENABLED} all'interno del database su tutte le vetrine ad ogni aggiornamento e settarla come vera soltanto per le vetrine effettivamente aggiornate.
All'interno degli script php per la gestione del database sono utilizzati dei \textit{prepared statement} al posto di istruzioni tradizionali, con la spesa di qualche riga di codice in pi\`u, vengono prodotte istruzioni generali, alla quale vengono sostituiti i dati come variabili al momento dell'esecuzione. Questo in genere migliora notevolmente le prestazioni al livello del database, in quanto non \`e necessario un nuovo parsing ad ogni istruzione che differisce solo per valori numerici dalle precedenti (da valutare l'impatto reale su questa applicazione). Inoltre questo metodo protegge ulteriormente da \textit{sql injection} in quanto i dati inseriti sono sempre numerici (non possono essere inseriti comandi maligni da input).
\subsection{Gestione firmware e memoria}
\subsubsection{Mappatura delle memorie}
I dispositivi basati su processori \textit{Cortex-M*} (come la board impiegata in questo progetto), vedono le varie memorie disponibili mappate all'interno dello stesso spazio di indirizzi, indipendentemente dalla loro tecnologia. In questo caso, il processore \`e in grado di indirizzare 4GB di memoria (da \texttt{0x00000000} a \texttt{0xFFFFFFFF}, potendo utilizzare 32 bit) ma solo alcuni di questi sono effettivamente attivi. Nello specifico sulla board sono presenti nativamente una \textit{SRAM}, allocata tra \texttt{0x20000000} e \texttt{0x20030000} (192k) utilizzata come ram principale, una \textit{CCRAM}, allocata tra \texttt{0x10000000} e \texttt{0x10010000} (64k) al momento inutilizzata e la flash, allocata tra \texttt{0x08000000} e \texttt{0x0820000} (2M) utilizzata per contenere il firmware e tutti i dati che non devono essere volatili (perdersi con uno spegnimento).
\subsubsection{Emulazione di una EEPROM su memoria flash}
La board \textit{STM32F429ZI} non possiede di base una eeprom, ma ha una memoria flash di 2MB e nonostante la differente tecnologia che utilizzano le due memorie, pu\`o simulare il comportamento della eeprom. La prima difficolt\`a \`e rappresentata dal fatto che la flash pu\`o essere programmata solo se la scrittura coinvolge un passaggio da 1 a 0, altrimenti \`e solo possibile la cancellazione dell'intera pagina (o settore, in questo caso grande 16kB). Per ovviare a questo problema, le pagine vengono prima cancellate (settando i bit ad 1) e invece di scrivere word (32 bit) negli indirizzi dedicati, si scrive il dato solamente in mezza word (16 bit) e la restante parte viene utilizzata come indirizzo virtuale (abbastanza arbitrario). Ogni scrittura successiva aggiunger\`a una nuova coppia indirizzo dato al fondo della memoria utilizzata (dove \`e ancora possibile programmare), la lettura dunque andr\`a a prendere soltanto l'ultimo dei valori con l'indirizzo specificato (sar\`a dunque necessaria una scansione lineare della pagina). Quando una pagina viene terminata, le coppie ancora attive (le ultime scritte per ogni indirizzo) vengono scritte nella seconda pagina, questa viene segnata come attiva e la precedente viene cancellata, in questo caso le pagine utilizzate sono 2 di cui solo una attiva. Il tutto \`e gestito utilizzando librerie esterne che implementano questo algoritmo.
In questo caso la emulazione su flash avviene nei primi due settori del secondo banco (12 e 13 a partire da \texttt{0x08000000}, entrambi da 16k), sufficientemente distanti per essere sicuri di non sovrascrivere settori utilizzati dal firmware e riprogrammare la scheda con risultati inaspettati (se non addirittura pericolosi). \`E consigliato che entrambi abbiano la stessa grandezza e questa \`e stata scelta pi\`u piccola possibile per evitare di consumare troppa flash quando non necessario. In questa sezione sar\`a salvato il contenuto del database interno per poter essere ripristinato dopo uno spegnimento, che in totale non dovrebbe superare i 2kB di memoria utilizzata.
\subsubsection{Aggiornamenti FOTA}
Per poter apportare modifiche senza dover sempre intervenire fisicamente sulle schede, si \`e scelto di implementare l'aggiornamento \textit{Firmware Over The Air}, ovvero il download del firmware tramite connettivit\`a (in questo caso ethernet, per le vetrine avverr\`a lo stesso con il bluetooth). Il firmware viene scritto in una zona inutilizzata della flash, che deve quindi essere abbastanza capiente per poter tenere entrambe le versioni, poi quando l'eseguibile \`e stato correttamente ricevuto, il dispositivo si riavvia. Appena acceso il dispositivo non esegue immediatamente l'applicazione, ma inizia dal \textit{bootloader} (scritto all'inizio della memoria flash), questo controlla se \`e stato effettuato un aggiornamento e in caso positivo copia il contenuto della seconda partizione nella prima, sovrascrivendo dunque la vecchia versione (\textbf{TODO} copiare solo i settori necessari per ridurre il tempo impiegato). A questo punto l'applicazione che si trova nella prima partizione pu\`o essere eseguita.
I firmware presenti sul server sono in formato binario, non contengono quindi niente pi\`u del necessario all'esecuzione. Di default Atollic produce eseguibili in formato \texttt{elf}, in grado di contenere anche librerie condivise e simboli utilizzati nel debug, ma in in genere i file di questo tipo sono molto pi\`u grandi di quelli binari puri. Per poterlo convertire \`e sufficiente chiamare l'\textit{utility} \texttt{objcopy} (disponibile come comando nella toolchain) con il firmware \texttt{elf} come argomento e l'opzione del formato binario abilitata. Il risultato pu\`o essere direttamente scritto in flash per essere eseguito, questi file sul server vengono salvati con nomi del tipo \texttt{fota\_update*.bin}.
\subsubsection{Struttura base del bootloader}
Il \textit{bootloader} si trova, per necessit\`a, in un progetto separato, in questo viene inizializzato il poco hardware necessario, vengono fatte le varie copie del firmware per avere l'applicazione nella partizione desiderata e viene preparato l'ambiente per poterla eseguire. Essenzialmente viene deinizializzato l'hardware (che sar\`a eventualmente ri-inizializzato all'interno dell'applicazione) e vengono spostati \textit{program-counter} e stack-pointer nella posizione preposta all'esecuzione.
Quando la board viene accesa (in condizioni normali), vengono eseguite le prime istruzioni che si trovano in flash (\texttt{0x08000000}), a tal proposito il \textit{bootloader} deve trovarsi in quella posizione, cos\`i da essere eseguito direttamente dopo ogni reset o spegnimento. In un'altra posizione ben definita dovr\`a trovarsi l'applicativo, cos\`i da permettere al \textit{bootloader} di effettuare il `salto' nella posizione voluta.
Di norma un firmware contiene nella prima word (4 byte) la cosiddetta \textit{vector table}, utilizzata nell'inizializzazione degli interrupt, prima di effettuare il \textit{jump}, dunque, si dovr\`a spostare il \textit{main-stack-pointer} in questa posizione, ma l'esecuzione effettiva partir\`a dopo la \textit{vector table} (\texttt{ADDR+4}), si dovr\`a quindi lanciare l'esecuzione di una funzione a tale indirizzo in flash.
\`E importante che anche l'applicazione sia consapevole della sua posizione in memoria, principalmente per conoscere dove cercare la \textit{vector table} e per avere un eseguibile compilato correttamente. A tal proposito va modificato il linker script, impostando uno scostamento nell'inizio della flash (\texttt{0x20000} in questo caso), in questa maniera la compilazione dell'eseguibile sar\`a effettuata considerando l'ambiente di destinazione. Inoltre l'applicazione deve contenere tale offset all'interno del proprio codice, cos\`i da generare correttamente il puntatore alla \textit{vector table}, invece di settare un diverso indirizzo iniziale della flash, viene impostata la specifica costante \texttt{VECT\_TAB\_OFFSET} in modo da spostare soltanto tale struttura, senza rendere inaccessibile la prima sezione di memoria flash.
A questo punto l'eseguibile dovr\`a essere programmato all'indirizzo corretto (con \textit{STM32Programmer} o via \textit{OTA}), anche se \`e ancora possibile la programmazione attraverso la toolchain Atollic, in quanto l'eseguibile elf contiene le informazioni su dove deve essere \textit{flashato}. Non sar\`a dunque possibile il debug dal progetto del \textit{bootloader} (contiene solo la propria sorgente), ma sar\`a perfettamente funzionale utilizzando quello dell'applicativo.
\begin{figure}[ht]
\vspace{15pt}
\center
\begin{subfigure}{.45\textwidth}
\includegraphics[width=\textwidth]{flash}
\caption{Partizioni della flash}
\end{subfigure}
\hfill
\begin{subfigure}{.45\textwidth}
\includegraphics[width=\textwidth]{boot}
\caption{Fase di accensione}
\end{subfigure}
\caption{}
\end{figure}
\subsection{Collegamento Bluetooth STM32F429ZI}
\subsubsection{Funzionamento delle librerie e dei protocolli}
Le librerie per la gestione del \textit{BLE} (Bluetooth Low Energy), utilizzano i servizi \textit{GAP} (Generic Access Profile), per quanto riguarda l'apertura/chiusura della connessione, e \textit{GATT} (Generic ATTribute profile), per lettura/scrittura e altre funzionalit\`a. In entrambi i casi il paradigma utilizzato \`e quello \textit{callback}, cos\`i le chiamate a funzione lanciano richieste all'estensione bluetooth e quando queste ricevono risposta, un interrupt viene generato e la funzione \texttt{HCI\_Event\_CB()} viene chiamata con argomento il puntatore all'evento (una struct che contiene i dati necessari), in base al tipo di tale evento viene eseguita l'azione corrispondente.
Queste sorgenti sono fornite dalla ST come test per l'interfaccia \textit{BlueNRG} (il modulo di rete ble) utilizzando alcune delle schede a 64 pin, anche se l'estensione \`e compatibile in generale con i pin Arduino R3, quindi con qualche modifica \`e stato possibile effettuare un \textit{porting}.
Nel protocollo \textit{gap} sono definiti 4 ruoli che i dispositivi possono assumere, in questo caso vengono utilizzati solo quello di \textit{Peripheral} e \textit{Central}. Il primo non fa altro che notificare l'ambiente circostante della sua presenza (\textit{advertising}) informando delle sue capacit\`a di offrire servizi. Il secondo \`e in grado di stabilire una connessione con un \textit{peripheral} e di richiedere servizi, svolge quindi un ruolo attivo nella topologia. Questi concetti si trasportano nel protocollo \textit{gatt}, dove in genere il peripheral coincide con il \textit{Server} mentre il central assume il ruolo di \textit{Client}.
Gli standard gatt, consentono ai server di fornire i propri servizi sotto forma di caratteristiche, strutture dati logicamente omogenee all'interno di un servizio che a loro volta possono contenere una coppia propriet\`a/valore e dei descrittori. I client connessi sono in grado di leggere o scrivere all'interno di tali caratteristiche e cos\`i avvengono i passaggi di dati. Il client, in genere non conosce le varie caratteristiche presenti sul server, a tal proposito esiste una chiamata di \textit{discovery} per poter appunto capire quali servizi (e caratteristiche) sono disponibili e come accedere ad esse. Il protocollo prevede che ogni caratteristica o servizio abbia un proprio \texttt{UUID} da 128 bit, che dovrebbe essere il pi\`u possibile unico, sono anche definiti degli \texttt{UUID} pi\`u brevi (16 o 32 bit) per quanto riguarda servizi predefiniti dallo standard. Ad ogni modo, quando il client viene a conoscenza dei vari \texttt{UUID} dei servizi accessibili, \`e in grado di accedervi attraverso degli indirizzi specifici sul server, detti \textit{handle}.
In questa specifica applicazione, non era necessaria tutta questa genericit\`a, il client \`e programmato per dialogare solamente con le vetrine, pu\`o dunque conoscere a priori la struttura dei servizi e accedervi direttamente attraverso gli \textit{handle} che sono gi\`a conosciuti (evitando dunque tutta la procedura di \textit{discovery}).
\begin{figure}[ht]
\vspace{10pt}
\center
\begin{subfigure}{.65\textwidth}
\includegraphics[width=\textwidth]{ble}
\caption{Architettura Bluetooth Low Energy}
\end{subfigure}
\hfill
\begin{subfigure}{.30\textwidth}
\includegraphics[width=\textwidth]{gatt}
\caption{Struttura GATT}
\end{subfigure}
\caption{protocolli BLE}
\end{figure}
\subsubsection{Comunicazione come client BLE}
\textdesc{funzione \textit{BLE\_Process} e file \textit{Src/sensor\_service.c}, \textit{Inc/sensor\_service.h}}
La connessione bluetooth tra master (negozio) e slaves (vetrine) viene gestita utilizzando il primo come client BLE, che richiede letture e scritture sui servizi, detti caratteristiche, forniti dai server (colori, intensit\`a, data...). Le operazioni disponibili sono lettura di un parametro dalla vetrina, scrittura di tale parametro e sincronizzazione della data corrente sulle vetrine (non \`e altro che una scrittura ma su un attributo particolare che non \`e incluso nel database).
L'interazione con ciascuna caratteristica viene effettuata in maniera separata ad ogni esecuzione della thread, per fare s\`i che ogni pacchetto sia correttamente ricevuto e gestito. Si interagisce con una vetrina alla volta, vengono dunque eseguite le operazioni su questa, lo stato viene impostato a \texttt{NEXT}e viene chiusa la vecchia connessione per aprirne una nuova con la vetrina successiva. Al termine, per tutte le vetrine, di un'operazione (\textit{r/w} o \textit{sync}) si ricomincia dalla prima vetrina con l'operazione seguente. \`E importante tener conto dell'operazione che \`e terminata in quanto la variabile che determina lo stato viene modificata quando si passa tra una vetrina e l'altra (diventa \texttt{NEXT}) ma dopo l'ultima vetrina \`e necessario conoscere quale operazione sia finita, viene dunque salvato tale dato in una variabile a parte che sar\`a dunque utilizzata per decidere il nuovo stato. La vetrina che dev'essere utilizzata viene decisa dalle funzioni \texttt{nextEntry()} e \texttt{currEntry()} in \texttt{db\_struct}, che attraverso un indice globale, restituiscono progressivamente gli id delle vetrine presenti in \texttt{active\_table} oppure 0 quando si \`e giunti al termine (e l'indice utilizzato viene ri-inizializzato).
Ogni volta che una richiesta (r/w) viene inoltrata al dispositivo, quest'ultimo pu\`o non essere pronto per riceverla, spesso perch\'e ancora impegnato a gestire la richiesta precedente, visto che il processo viene eseguito ad una frequenza elevata. Dal client un evento simile viene percepito come richiesta non autorizzata, a questo punto la richiesta viene nuovamente inoltrata, finch\'e non \`e effettivamente ricevuta e confermata dal server. Bisogna per\`o tener conto che, per una qualsiasi ragione, il server pu\`o sistematicamente rifiutare le richieste, va quindi effettuato un conteggio per poter terminare i tentativi dopo che il server \`e entrato in questa condizione (da capirne le motivazioni).
Le caratteristiche numeriche vengono convertite in formato testuale, 3 cifre come caratteri \textit{ascii} per tutte eccetto la data che ne occupa 10 in formato \texttt{yymmddhhmm}. (\textbf{TODO} possibile ottimizzazione accorpando alcune caratteristiche e gestendo pi\`u vetrine in parallelo, se consentito dagli standard)
Durante la lettura/scrittura delle vetrine, vengono usati due array (\texttt{toRead} e \texttt{toWrite}) che contengono gli id dei valori da leggere/scrivere (anche utilizzati come indici nell'array degli handle), le variabili \texttt{reading} e \texttt{writing} vengono incrementate ad ogni passo e rappresentano il valore attualmente richiesto al dispositivo ble. Quando queste arrivano al termine (fine dell'array) la procedura \`e terminata e si pu\`o passare alla prossima operazione (per quanto riguarda la lettura esiste una seconda variabile di indice incrementata nel \textit{callback} all'interno di \texttt{HCI\_Event\_CB}, dove avviene effettivamente la lettura).
Qualora una vetrina non sia disponibile, nonostante il database online la contenga, la scheda tenta di connettersi ma entra ben presto in timeout rendendosi conto di non ricevere risposta. A questo punto ignora la vetrina e passa a quella successiva. Nessuna operazione viene effettuata per tener conto di questa condizione, si fa sempre fede al database ricevuto via ETH, se questo dovesse contenere una vetrina in pi\`u o si fosse verificato un guasto, ogni ripetizione del processo andrebbe in timeout a quel punto, senza comunque bloccare l'esecuzione per le altre vetrine.
Il led blu (\texttt{LD2}) viene attivato all'inizio della comunicazione con la prima vetrina e spento alla fine dell'ultima, per ogni operazione, quello rosso (\texttt{LD3}) si attiva per ogni errore o timeout.
\subsubsection{Upload del firmware sulle vetrine}
Quando viene scaricato un aggiornamento firmware per le vetrine dal server, viene abilitata la procedura per poterlo passare ai vari dispositivi. Al momento questo viene effettuato settando una flag all'interno della funzione \texttt{ETH\_Process()} (dove viene gestito il download). A questo punto il processo analogo per il bluetooth, finite le eventuali attivit\`a rimaste, \`e in grado di effettuare il caricamento. Vengono prima scritte la grandezza del firmware e il checksum in una caratteristica a parte (solita notazione in \textit{big-endian} per 4+4 byte), cos\`i il dispositivo connesso si prepara a ricevere l'aggiornamento e questo viene inviato a pacchetti ordinati su una specifica caratteristica (la grandezza massima di un singolo pacchetto \`e 20 byte). Questa esecuzione, al momento, non scrive correttamente il firmware, forse per problemi di velocit\`a della scrittura in flash, sar\`a comunque da irrobustire il protocollo.
\subsection{Collegamento Ethernet STM32F429ZI}
\subsubsection{Crittografia con protocolli TLS/HTTPS}
Per migliorare la sicurezza della comunicazione, il sistema implementa la libreria di cifratura \texttt{mbedtls.h} (selezionabile da STM32Cube), abbastanza leggera per poter svolgere il suo lavoro con poche risorse e abbastanza avanzata nei metodi e protocolli. La comunicazione HTTP viene dunque `filtrata' attraverso questa libreria, che la rende dunque accessibile solo a server e client. Durante la procedura di \textit{handshake}, entrambi gli attori concordano un metodo di cifratura (vengono supportate ciphersuite con \texttt{ECHDE} e algoritmi \texttt{RSA} o \texttt{ECDSA}, che dovranno essere implementati sul server) e il certificato del server viene controllato (non ne sono stati utilizzati lato client). La scheda \`e in grado di autorizzare certificati \textit{self signed} solo se il certificato della CA (ente reale o fittizio utilizzato per certificare un server) \`e salvato all'interno del firmware (come stringa in \texttt{srv\_cert.c}, \textbf{TODO} implementare un filesystem e caricare l\`i il certificato).
Nello specifico ogni trasmissione inizia come connessione TCP, viene dunque effettuato il \textit{three-way handshake} dove il client chiede di stabilire la connessione attraverso un segmento (vuoto) di \texttt{SYN}, questo viene riconosciuto con un pacchetto \texttt{SYN,ACK} che verr\`a a sua volta confermato da una \texttt{ACK} dal client (questa flag viene utilizzata per confermare la ricezione di ogni pacchetto all'interno del protocollo TCP). A questo punto pu\`o iniziare la procedura di handshake per la connessione criptata (\texttt{TLS1.2}), che in maniera analoga utilizzer\`a un \textit{Client Hello} per segnalare l'intenzione di iniziare la connessione (includendo i parametri necessari a concordare la cifratura), seguito da un \textit{Server Hello} che include il certificato utilizzato e da una (eventuale) conferma lato client di corretta inizializzazione del tunnel TLS (figura \ref{fig:https_tcp}). Ora i dati possono essere passati in tutta sicurezza come normali pacchetti HTTP che, criptati, saranno leggibili solo dal diretto destinatario, inoltre qualunque pacchetto ricevuto al di fuori dell'ambito di tale connessione sar\`a scartato (risulterebbe illeggibile dopo una decodifica, non essendo stato creato con la chiave corretta).
\subsubsection{Funzionamento delle librerie}
La connessione ad internet della board attraverso le librerie \texttt{mbedtls} \`e effettuata esclusivamente con chiamate procedurali, dunque l'esecuzione \`e il pi\`u possibile consecutiva. Durante l'inizializzazione, vengono impostati i parametri generali necessari alla crittografia (numeri casuali, certificati e varie configurazioni), questo capita solamente quando la scheda viene accesa. Ad ogni esecuzione la connessione viene aperta, la funzione crea un nuovo \textit{socket} ed inizia la connessione al server tramite questa struttura, utilizzando le configurazioni tls precedentemente impostate, questo inizia la procedura di handshake (accordi riguardo autenticazioni e crittografia) con il server. Ogni comunicazione avviene tramite normali richieste http criptate secondo i criteri stabiliti durante l'\textit{handshake} (semplici chiamate della libreria si assicurano che questo avvenga), in maniera analoga vengono ricevute e gestite le risposte. Al termine della procedura la connessione e il relativo \textit{socket} vengono chiusi. Per consentire una connessione unica per le diverse trasmissioni \`e stata sfruttata l'opzione \textit{Keep-alive} implementata dalla versione 1.1 di http, in questa maniera il server non chiuder\`a la connessione finch\'e questa non sar\`a entrata in timeout o non sar\`a stata chiusa da lato client. Va abilitata l'opzione \texttt{SO\_KEEPALIVE} a livello di \textit{socket} per questa funzione.
\subsubsection{Comunicazione come client web}
\textdesc{funzione \textit{ETH\_Process()} e file \textit{Src/mbedtls.c}, \textit{Inc/mbedtls.h}}
Anche qui le operazioni disponibili sono lettura, per i dati dal server, scrittura, di dati ricevuti sul server e sincronizzazione, per la data corrente presa dal server. Sono disponibili anche funzionalit\`a di download del firmware.
Le interazioni (r/w) con il server trattano prima i dati del negozio (id, versione e stato) e successivamente i dati di ciascuna vetrina. Quando la connessione \`e stata stabilita si utilizza la funzione \texttt{PollEthData()} per mandare la richiesta e leggerne il responso, restituendo il corpo del messaggio e eventualmente un codice di errore.
Le richieste \texttt{HTTP} utilizzano il metodo \texttt{POST} (la query string si trova dentro il corpo del pacchetto) e viaggiano all'interno della stessa connessione \texttt{TCP} creata all'inizio del processo (pressione del bottone) e chiusa quando la comunicazione \`e terminata. La prima richiesta che viene effettuata (query \texttt{mode=syn}) richiede dal server data e ora aggiornate (se necessario), successivamente con \texttt{mode=shp} si richiedono i dati specifici del negozio e la versione del database presente sul server, se questi dati sono corretti vengono fatte successive richieste per gli effettivi dati delle vetrine. Questi vengono richiesti con \texttt{mode=ent} e nella risposta il numero di vetrine precede gli altri dati (per conoscere a priori il contenuto del pacchetto). Nella scrittura su server i dati sono direttamente inclusi nel corpo del pacchetto e vengono inviati a pagine specifiche (per evitare di utilizzare una query string insieme ai dati). Tutti i pacchetti contenenti dati di negozio o vetrine sono in formato binario, dove ogni bit contiene un numero relativo ad un campo, per i campi a 16 bit \`e utilizzata la notazione \textit{big-endian}.
Ipotizzando che ogni vetrina contiene 17 bit con 2 bit aggiuntivi di checksum, un massimo di 50 vetrine possono essere scritte su pacchetti con corpo 1000 byte, che rientra nel limite imposto per il buffer di ricezione (1200, dove c'\`e da considerare anche l'\textit{header}). I dati di accesso al database su server sono inclusi nell'\textit{header} del pacchetto come campi appositi (risultano comunque criptati).
Ogni volta che durante la trasmissione viene registrato un errore non critico (ad esempio un checksum sbagliato), si ritenta la medesima procedura, fino ad un massimo di \texttt{MAX\_RETRY} (impostato a 5), se questo limite viene superato l'intera procedura si interrompe con un errore. Per implementare una ritrasmissione \`e sufficiente incrementare il valore della variabile \texttt{retry\_num} (statica e utilizzabile solo per \texttt{ETH}) e ritornare dalla funzione, durante la successiva esecuzione (in ogni caso) ci sar\`a un controllo per verificare se il limite \`e stato superato, in modo da lanciare l'errore. \`E importante ri-inizializzare la variabile a 0 ogni volta che la procedura ha successo (essendo statica manterrebbe il valore).
Quando una funzione di connessione ritorna un errore, il led rosso (\texttt{LD3}) si attiva, mentre il led blu (\texttt{LD2}) rimane attivo tra una trasmissione e una ricezione.
\subsubsection{Scaricamento dal server del firmware}
\textdesc{funzione \textit{FotaEthUpdate()} in \textit{Src/mbedtls.c}}
Il download del firmware viene eseguito sempre tramite https, ma viste le notevoli dimensioni non pu\`o essere bufferizzato in ram e successivamente scritto in flash, \`e quindi necessario salvare direttamente in flash ogni pacchetto quando questo viene ricevuto. La scrittura viene effettuata in una partizione apposita della memoria. Per come \`e configurata \texttt{mbedTLS}, i segmenti tcp hanno un limite di grandezza molto conservativo, utile per mantenere un ridotto utilizzo di RAM, ma problematico in questo caso. A tal proposito il valore di \texttt{SSL\_MAX\_CONTENT\_LEN} andrebbe allargato o disabilitato (di default \`e 2kB mentre il massimo \`e intorno ai 16kB ma tale valore introduce un notevole aumento di memoria utilizzata).
Per un trasferimento ottimale \`e stata utilizzata la codifica di tipo chunked (\texttt{Transfer-encoding: chunked}, dall'inglese \textit{a pezzi}), il che significa che i dati mandati dal server (sempre nello stesso pacchetto http) vengono divisi in pezzi, ognuno preceduto dalla propria grandezza in formato esadecimale e da \texttt{\textbackslash{r}\textbackslash{n}} per separare dall'effettivo \textit{chunk}, che a sua volta termina con \texttt{\textbackslash{r}\textbackslash{n}}. Il server cos\`i ha tempo di preparare progressivamente ogni \textit{chunk} e il client riesce a gestire correttamente i pacchetti ricevuti senza introdurre troppo ritardo. Questo \`e possibile perch\'e il client non chiede direttamente la risorsa (fota\_update.bin) ma una pagina php che, dopo aver controllato le credenziali di accesso, invia tale firmware. Per favorire la divisione in \textit{chunk}, lo script utilizza \texttt{fread()} su una grandezza ridotta (intorno ai 2kB alla volta) all'interno dello script php, evitando dunque di servire l'intero file in una volta.
Le letture da \textit{socket} (sul client) avvengono a blocchi grandi al massimo \texttt{MAX\_ETH\_LEN}, ma la lettura (per impostazione automatica) si ferma quando incontra dei fine riga. Questo fa s\`i che parti del pacchetto che non fanno effettivamente parte del firmware (come \textit{header} e \textit{chunk size}) sono lette separatamente, rendendone pi\`u semplice l'interpretazione. In ogni caso, per evitare problemi con particolari sequenze riscontrate in un firmware, il valore di grandezza del \textit{chunk} viene letto dal \textit{socket} (un byte alla volta, fino a \texttt{\textbackslash{r}\textbackslash{n}}) e poi viene letto esattamente lo stesso numero di byte dal \textit{socket} (questa volta a blocchi grandi al massimo 1200 B per limitare l'uso di memoria). Questa sezione far\`a sicuramente parte del firmware e quindi potr\`a essere direttamente salvata in flash, calcolando i relativi checksum e dopo questa si potr\`a passare al \textit{chunk} successivo.
Utilizzando questo metodo di codifica, non viene passato inizialmente l'\textit{header} \texttt{Content-size}, per il client \`e dunque impossibile capire quando sar\`a arrivato l'ultimo \textit{chunk} (il \textit{socket} non andr\`a mai in \texttt{EOF}), il protocollo quindi prevede che al termine del download la connessione html venga chiusa, il client cio\`e ricever\`a un messaggio di \texttt{PEER\_CLOSE\_NOTIFY} (per questa ragione il download viene effettuato in una connessione a s\'e stante). Al termine vengono eseguiti i controlli di dimensione e checksum. Si procede sia facendo riferimento ai byte ricevuti e scritti che sommando i valori di \textit{chunk-size} e si confrontano entrambi i risultati con un dato ricevuto dal server all'interno dell'\textit{header}. In maniera analoga il checksum viene calcolato e confrontato con il valore ricevuto alla fine del firmware, calcolato sul server. Visto che il dato \`e calcolato sul momento questo non pu\`o essere incluso nell'\textit{header} (non \`e ancora conosciuto in quel momento) e si utilizzano quindi gli ultimi 2 byte per contenere tale checksum in notazione \textit{big-endian}. Per avere la certezza che tutti i byte siano correttamente scritti, visto che sulla flash vengono scritte solo parole intere (4 byte), viene aggiunto un \textit{padding} di 3 byte vuoti (\texttt{0xff}) cos\`i da far rientrare anche gli ultimi byte spaiati del firmware all'interno dell'ultima parola scritta in flash (con buona probabilit\`a un firmware non soffre di questo problema in quando le istruzioni sono generalmente contenute in word).
Sono possibili due tipologie di download di firmware via \textit{OTA}, quello abilitato dallo stato \texttt{FW\_UP} (all'interno di \texttt{ETH\_Process()}) che rappresenta l'aggiornamento del firmware locale e quello relativo a \texttt{FW\_DL}, destinato al download del firmware per le vetrine. Entrambe le esecuzioni sono uguali per quanto concerne il download, eccetto che riguardo alle vetrine, la query string \texttt{dl=ble} \`e aggiunta al pacchetto per richiedere al server il firmware corretto (in questo caso \texttt{fota\_update\_ble.bin}). Il file binario viene scaricato e salvato in flash (in entrambi i casi nella stessa posizione), se si tratta dell'aggiornamento locale, un reset della board viene invocato, cos\`i da eseguire il codice del \textit{bootloader} che installer\`a e lancer\`a il nuovo firmware.
\begin{figure}[ht]
\center
%\begin{subfigure}{\textwidth}
\includegraphics[width=\textwidth]{https_tcp}
\caption{Apertura della connessione HTTPS-TCP}
%\end{subfigure}
%\hfill FIXME
%\caption{protocollo HTTPS}
\label{fig:https_tcp}
\end{figure}
\newpage
\subsection{Note}
\begin{itemize}
\item Il debug attraverso la console (utilizzando printf) pu\`o essere effettuato utilizzando la console \texttt{SWD} (accessibile dal debugger di Atollic) o usando l'\texttt{UART} (necessaria la connessione seriale e un applicazione esterna in grado di leggerne i dati). Nel primo caso basta abilitarla attraverso la configurazione di debug della toolchain, impostando il clock corretto reperibile in STM32Cube come \texttt{HCLOCK}. Va modificata la funzione \texttt{\_write()}, utilizzata da printf ma definita come \texttt{\_weak\_} all'interno delle librerie per consentirne l'override in fase di linking con una funzione con lo stesso nome. La si pu\`o trovare in \texttt{Src/syscalls.c}, anche se pu\`o essere direttamente aggiunta in altre sorgenti senza dover includere l'intero file. In alternativa si pu\`o mantenere la definizione di default in \texttt{syscalls.c}, che chiama a sua volta la funzione \texttt{\_\_io\_putchar()} (che definisce la scrittura per carattere invece che per stringa) e sovrascrivere quella con i metodi per SWD/UART.
\item Il debug \`e abilitato attraverso la costante \texttt{DEBUG}, che definisce la funzione \texttt{PRINTF} come \texttt{printf} (altrimenti definita come vuota), \`e bene disabilitare tale funzione quando si passer\`a ad un ambiente di \textit{release}, in quanto introduce funzionalit\`a inutilizzate che potrebbero rallentare il sistema.
\item La comunicazione bluetooth viaggia in formato testuale, una possibile ottimizzazione pu\`o essere passare al binario, riducendo cos\`i la grandezza dei pacchetti e le istruzioni necessarie alla gestione (gi\`a implementato nella connessione via http).
\item La scrittura su server web \`e in po' pi\`u delicata perch\'e nello spedire uno stream binario nel pacchetto HTTP, \`e molto facile utilizzare caratteri particolari che invaliderebbero il parsing della query string. A tal proposito si pu\`o gestire il dato ricevuto come puro binario su pagine apposite (invece di utilizzare la stessa pagina e cambiare in base al valore di \texttt{\$\_REQUEST[mode]}).
\item Bisogna prestare particolare attenzione alla configurazione del server HTTPS per garantire l'autenticazione col client, la board ha un supporto limitato di ciphersuite, una normale configurazione di \textit{Apache} con \textit{OpenSSL} dovrebbe funzionare. Il certificato pu\`o essere \textit{self-signed}, in quel caso bisogna installare tutta la \textit{chain} o anche solo la \texttt{CA} sul dispositivo, nel test \`e stato generato con chiave \texttt{RSA} ma dovrebbe essere supportata anche \texttt{ECDSA}.
\item Utilizzando questi metodi di cifratura non \`e possibile leggere il contenuto del pacchetto (decrittato) da programmi come \textit{wireshark}.
\item Per la connessione HTTPS non vengono utilizzati certificati lato client in quanto non espressamente richiesto dallo standard, potrebbe essere un'ulteriore sicurezza per controllare gli accessi al server (in aggiunta al controllo della password).
\item Indipendentemente dal metodo effettivamente implementato nel sistema, ogni \textit{stream} binario all'interno di questa applicazione che prevede byte multipli, utilizza una notazione \textit{big-endian}, dove i byte pi\`u significativi precedono quelli meno significativi (viene gestito tutto via software, perci\`o \`e indipendente dall'architettura), dunque una grandezza a 16 bit con valore \texttt{0xabcd} viene trasmessa separando i byte come \texttt{0xab} e \texttt{0xcd}, la notazione contraria (\textit{little-endian}) viene invece utilizzata a livello di firmware.
\item Le azioni r/w con ble, vengono gestite per singolo attributo e ognuno corrisponde ad un campo nella struct definita per le vetrine, per identificarla dall'esterno si usano le macro \texttt{FIELD\_*}, utilizzate anche come indici nell'array degli \textit{handle} (\texttt{CH\_HANDLES[FIELD\_FOO]==FOO\_HANDLE}), per questa ragione \`e bene che vengano tenute in ordine, consecutive e che partano da 0.
\item La sincronizzazione della data viene ripetuta ad ogni connessione, questo pu\`o essere cambiato in base alla modalit\`a (\texttt{active\_shop.status}) esattamente come l'ordine e la frequenza delle operazioni che vengono eseguite. Per fare ci\`o si devono modificare le funzioni \texttt{*\_Process} in \texttt{main.c}.
\item Le variabili del database locale riguardanti le vetrine sono impostate a 0 sfruttando il fatto che la memoria allocata staticamente non pu\`o essere parzialmente inizializzata, dunque basta settare alcuni byte (in questo caso gli id dei primi 3 record, il loro valore \`e ininfluente) per avere il resto della struttura inizializzata automaticamente a 0.
\item Considerando che la variabile che contiene la versione del database (\texttt{*\_shop->version}) occupa soltanto un bit, la probabilit\`a di \textit{overflow} dopo un certo periodo \`e alta. Si suppone dunque che se la versione locale \`e sufficientemente maggiore di quella ricevuta, allora \`e avvenuto un \textit{overflow} e si considera la versione locale come minore.
\item Per come sono configurate ora, sia vetrine che negozi contengono il proprio id all'interno del firmware (attraverso un \texttt{\#define}), questo fa si che ogni board \`e programmata per essere una specifica vetrina e il suo firmware \`e unico. Una configurazione di questo tipo pu\`o risultare scomoda quando si tratta di effettuare aggiornamenti \textit{OTA}, perch\'e, in tal caso, si renderebbe necessario un download diverso per ogni vetrina, una soluzione pi\`u ottimale sarebbe avere lo stesso firmware che si adatta in base ad un valore salvato in flash (che pu\`o essere configurato al primo avvio o programmato prima della distribuzione del dispositivo.
\item Gli indirizzi virtuali per la eeprom sono definiti in \texttt{db\_struct.h}, l'indirizzo iniziale \`e del tutto arbitrario, da l\`i inizia il negozio, sono poi definiti i numeri di \textit{half-word} necessari per contenere il negozio e ciascuna vetrina, con questi si compone l'indirizzo finale, dal quale si pu\`o capire lo spazio di indirizzi utilizzato (conoscendo anche quante vetrine possono essere salvate). \`E importante che siano tutti consecutivi cos\`i da evitare una enumerazione che sarebbe poco pratica (considerando un numero elevato di vetrine), \`e quindi necessario modificare anche queste costanti qualora la struttura delle tabelle venisse alterata.
\item Nella flash i dati scritti devono essere allineati, il che vuol dire che possono essere scritte parole (32 bit), mezze parole e byte singoli, ma non \`e possibile scrivere una parola subito dopo un singolo byte, perch\'e il suo allineamento prevede un indirizzo di partenza multiplo di 4 (per questa ragione le flag di inizio partizione occupano un'intera parola anzi che un singolo bit).
\item Con l'utilizzo di \textit{stream} binari nella comunicazione, non \`e pi\`u possibile utilizzare le funzioni legate alle stringhe, poich\'e il valore \texttt{'\textbackslash 0'} che termina le stringhe \`e un valore perfettamente lecito all'interno di un pacchetto binario e non ne determina dunque la fine.
\item Le query string utilizzate per le richieste al server sono nella forma \texttt{mode=abc} per poter occupare una dimensione fissa di 8 bit, necessaria alla funzione che compone il pacchetto http e non sempre ricavabile con \texttt{strlen()} (vedi sopra).
\item Per ridurre la grandezza dei pacchetti http ricevuti \`e possibile eliminare o accorciare alcuni \textit{header}, che comunque non vengono interpretati dalla board. Ad esempio all'interno degli script php si pu\`o rimuovere l'\textit{header} \texttt{X-Powered-By}, che contiene dati sull'interprete utilizzato (qui php). Attraverso le configurazioni del server apache invece, \`e possibile ridurre i dati presentati nell'\textit{header} \texttt{Server} alla sola dicitura \textit{Apache} aggiungendo al file di configurazione (\texttt{httpd.conf}) la linea \texttt{ServerTokens Prod}.
\item I nomi utente per i singoli negozi (necessari per accedere al database) vanno scelti con cautela, nel php il nome viene filtrato per estrapolarne un contenuto numerico e questo viene usato come id del negozio, deve dunque essere l'unico numero presente nel nome (in questa fase vengono usati nomi del tipo \texttt{shopX}).
\item L'operazione di \textit{jump} del bootloader \`e delicata, \`e importante che l'indirizzo per lo stack pointer (\texttt{\_\_set\_MSP()}) sia messo all'inizio della partizione in flash, quello del \textit{program counter} (chiamato attraverso la funzione \texttt{Jump()}, definita a partire dall'indirizzo) sar\`a invece impostato 4 byte dopo (al termine della vector table). \textit{[progetto bootloader]}
\item L'applicazione, che verr\`a flashata nella partizione dedicata, deve essere programmata adeguatamente, va quindi modificato il linker script \texttt{STM32F429ZI\_FLASH.ld} includendo una corretta \texttt{ORIGIN} per la flash e nel file \texttt{Src/system\_stm32f4xx.c} va settato l'offset per la vector table. Visto che quest'ultima viene inizializzata nell'applicazione, non c'\`e bisogno di impostarla anche nel bootloader, la flag \texttt{SET\_VECTOR\_TABLE} pu\`o dunque essere disabilitata (ripeterebbe l'inizializzazione di \texttt{SCB->VTOR}).
\end{itemize}