Elaborato Parricelli Francesco N46001992

Transcript

Elaborato Parricelli Francesco N46001992
Scuola Politecnica e delle Scienze di Base
Corso di Laurea in Ingegneria Informatica
Elaborato finale in Calcolatori Elettronici I
Gestione dei flussi dati in una rete di
sensori basata su piattaforma Arduino
Anno Accademico 2015/2016
Candidato:
Francesco Parricelli
matr. N46/001992
Alla Mia dolce metà,
Alla mia famiglia,
Ai miei amici.
Indice
Prefazione e Ringraziamenti
ix
1 Introduzione ai Sistemi Embedded
1
1.1
Principi generali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2
Componenti dei sistemi embedded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.2.1
Componenti comuni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.2.2
Componenti specifici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
1.3
Classificazione dei sistemi embedded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
1.4
Performance nei sistemi embedded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.4.1
5
Requisiti di sviluppo e Scelte di Design . . . . . . . . . . . . . . . . . . . . . . . .
2 La piattaforma Arduino
2.1
2.2
2.3
7
Cenni generali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.1.1
8
Arduino IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Aspetti Hardware della piattaforma
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2.1
Arduino Mega 2560 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2.2
Arduino Ethernet Shield 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.3
Arduino GSM Shield 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.4
WiFi Module - ESP8266 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.5
Transceiver RS485 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.6
Arduino UNO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.7
Display compatibile Hitachi HD44780 e Keypad numerico . . . . . . . . . . . . . . 16
Prototipo di debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3 Descrizione e sviluppo del progetto
3.1
Panoramica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.1
3.2
17
Componenti del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Soluzioni di sviluppo del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2.1
Sviluppo con Protocollo RS485 - Architettura semplificata . . . . . . . . . . . . . . 19
3.2.2
Sviluppo con Protocollo RS485 - Architettura raffinata . . . . . . . . . . . . . . . . 27
3.2.3
Sviluppo con Protocollo TCP/IP - Ethernet . . . . . . . . . . . . . . . . . . . . . . 30
iv
3.2.4
3.3
Sviluppo con Protocollo TCP/IP - WiFi . . . . . . . . . . . . . . . . . . . . . . . . 36
Scheduling delle Richieste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.3.1
Design dello scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.3.2
Esempio di utilizzo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4 Conclusioni
45
Riferimenti
46
v
Elenco delle tabelle
1.1
Requisiti di Design per Sistemi Embedded . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1
Tabella riassuntiva ATmega2560 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
vi
6
Elenco delle figure
1.1
Esempio di Sistema di ABS, adattato da [1] . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2
Schema generico di un sistema embedded . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.3
Architettura di un sistema embedded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2.1
Componenti fondamentali architettura Arduino . . . . . . . . . . . . . . . . . . . . . . . .
7
2.2
Arduino IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.3
Arduino Board Mega 2560 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.4
Atmel ATmega2560 - Diagrammi dei blocchi, adattato da [6] . . . . . . . . . . . . . . . . 10
2.5
Arduino Ethernet Shield 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.6
Wiznet W5500 - Schema a blocchi, adattato da [7] . . . . . . . . . . . . . . . . . . . . . . 12
2.7
Arduino GSM Shield 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.8
Schema Quectel M10, adottato da [8] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.9
Schema a blocchi ESP8266, adottato da [9] . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.10 Configurazione dei Pin - SN75HVD08, adottato da [10] . . . . . . . . . . . . . . . . . . . . 14
2.11 Arduino UNO - Board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.12 Arduino UNO - Diagramma a blocchi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.13 Snapshot del prototipo di testing e debugging . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.1
Schema Architetturale realizzativo del sistema - adattato da [12] . . . . . . . . . . . . . . 18
3.2
Schema Architetturale Semplificativo del sistema - adattato da [12] . . . . . . . . . . . . . 19
3.3
Modalità di Indirizzamento adottata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.4
Estratto del file di intestazione: mappingStructure.h . . . . . . . . . . . . . . . . . . . . 21
3.5
Estratto dello sketch Centrale.ino relativo allo sviluppo con protocollo RS485 . . . . . . 22
3.6
Estratto dello sketch Gateway.ino relativo allo sviluppo con protocollo RS485
. . . . . . 23
3.7
Estratto dello sketch Sensore.ino relativo allo sviluppo con protocollo RS485
. . . . . . 25
3.8
Scambio indirizzo tra Centrale (a sinistra) e Gateway (a destra) . . . . . . . . . . . . . . . 25
3.9
Scambio valori dei sensori tra Centrale (a sinistra) e Gateway (a destra) . . . . . . . . . . 26
3.10 Comunicazione tra Gateway (a sinistra) e Concentratore (a destra) . . . . . . . . . . . . . 26
3.11 Esempio di testing della piattaforma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.12 Schema Architetturale Raffinato del sistema - adattato da [12]
. . . . . . . . . . . . . . . 28
3.13 Modalità di Indirizzamento a tre livelli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
vii
3.14 Estratto dello sketch Concentratore.ino relativo allo sviluppo con protocollo RS485
Raffinato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.15 Comunicazione tra Gateway (a sinistra) e Concentratore (di primo livello) (a destra) . . . 31
3.16 Estratto dello sketch Centrale.ino relativo allo sviluppo con protocollo Ethernet . . . . 32
3.17 Estratto dello sketch Gateway.ino relativo allo sviluppo con protocollo Ethernet . . . . . 33
3.18 Estratto dello sketch Concentratore.ino relativo allo sviluppo con protocollo Ethernet . 34
3.19 Comunicazione tra Centrale (a sinistra) e Gateway (a destra) con Ethernet . . . . . . . . 35
3.20 Estratto dello sketch Concentratore.ino relativo alla funzione ReadMySensor() - Ethernet
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.21 Esempio di testing della piattaforma con Ethernet . . . . . . . . . . . . . . . . . . . . . . 36
3.22 Estratto dello sketch Centrale.ino relativo allo sviluppo con WiFi . . . . . . . . . . . . . 37
3.23 Estratto dello sketch Centrale.ino relativamente alle funzioni SendRequest() (a sinistra)
e pollingToGateway() (a destra) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.24 Implementazione della procedura sendData() . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.25 Modalità di invio dati, estratto dallo sketch Concentratore.ino . . . . . . . . . . . . . . 39
3.26 Estratto dello sketch Concentratore.ino relativo alla funzione readMySensor() - WiFi
40
3.27 Esempio di testing della piattaforma con WiFi . . . . . . . . . . . . . . . . . . . . . . . . 41
3.28 Estratto del file myScheduler.h - Descrittore del task (a sinistra) e Struttura dello scheduler (a destra) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.29 Estratto del file myScheduler.h - Procedure di Utility dello Scheduler . . . . . . . . . . . 42
3.30 Estratto dello sketch (inizializzazione) Gateway.ino utilizzato come centrale nel testing
dello scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.31 Estratto dello sketch Gateway.ino utilizzato come centrale nel testing dello scheduler . . 43
3.32 Screenshot del monitor seriale del Gateway utilizzato come centrale . . . . . . . . . . . . . 44
viii
Prefazione e Ringraziamenti
Il presente elaborato si pone l’obiettivo di sviluppare un sistema di gestione di dati sensoriali attraverso la
piattaforma Arduino. In particolare, al fine di poter definire un progetto così descritto, risulta necessario
conoscere i dispositivi utilizzati, in termini di caratteristiche e funzionalità. A tal proposito, l’elaborato
si suddivide in tre parti, corrispondenti ai primi tre capitoli, sinteticamente presentati di seguito:
• il primo capitolo si occupa di fornire una panoramica introduttiva circa i sistemi embedded da
un punto di vista hardware e software, caratterizzando le differenze rispetto ai classici e comuni
sistemi general-purpose riportando esempi celebri di applicazione degli stessi.
• il secondo capitolo introduce la piattaforma Arduino, soffermandosi da un punto di vista hardware
sui componenti base e addizionali della stessa, presentando, infine, un prototipo fisico di sviluppo
utilizzato nel testing del progetto realizzato.
• il terzo capitolo è il cuore dell’elaborato e descrive l’architettura del sistema, gli aspetti implementativi, le scelte di design ed i motivi ad esse correlate.
I primi due capitoli sono, quindi, rivolti a fornire uno strato teorico di base, necessario a comprendere
le scelte di progetto adoperate nello sviluppo del sistema.
La presentazione del progetto da sviluppare è condotta seguendo un approccio step-by-step aumentando,
gradualmente, la complessità di realizzazione, in accordo al risultato finale da ottenere.
Prima di proseguire, è doveroso porgere un ringraziamento al Professore Alessandro Cilardo per
l’opportunità da egli offertami di operare attivamente nel settore dei sistemi embedded e per il supporto
fornitomi durante lo sviluppo di questo elaborato.
ix
Capitolo 1
Introduzione ai Sistemi Embedded
1.1
Principi generali
Che cos’è un sistema embedded? A tal riguardo si possono fornire differenti definizioni. Tipicamente,
in una maniera fortemente semplicistica, si può definire un sistema embedded come un qualunque dispositivo che include un computer programmabile, il cui utilizzo non è inteso ad essere di tipo general purpose
[1]. Procedendo in una direzione di maggior dettaglio, un sistema embedded lo possiamo descrivere come
una combinazione di componenti hardware e software, ed eventualmente periferiche addizionali, nonché
meccanismi elettronici e meccanici, atti a definire una funzione dedicata [2].
È evidente che, quindi, mentre i comuni calcolatori, tipicamente commerciali, sono predisposti ad un
utilizzo generico, questa particolare classe di sistemi è invece dedicata all’esecuzione di una funzionalità
specifica. Altresì, è fondamentale chiarire che, alla luce di quanto evidenziato, un normale calcolatore
può essere utilizzato per la costruzione di un sistema integrato, programmandolo in maniera opportuna.
Frequentemente, un sistema embedded è un componente incluso in un generico sistema più grande. A tal
proposito possiamo illustrare differenti esempi; se consideriamo il settore automotive, si può facilmente
corrispondere alla visione dell’autoveicolo come un insieme di sistemi integrati che definiscono ciascuno
una differente funzionalità, e che concorrono nell’obiettivo di controllo del mezzo. In particolar modo
la figura 1.1 illustra il componente ABS1 .
Figura 1.1.
Esempio di Sistema di ABS, adattato da [1]
1 Antilocking Braking System, è un sistema di sicurezza che evita il bloccaggio delle ruote dei veicoli garantendone la
guidabilità durante le frenate
1
1 – Introduzione ai Sistemi Embedded
Può essere, inoltre, interessante notare che un computer general-purpose si interfaccia a diversi sistemi integrati: esempi banali possono corrispondere alla tastiera, al mouse e alla stampante.
L’esistenza di un processore e di uno strato software all’interno di un sistema embedded può non essere
ravvisato da un utente utilizzatore. In alcuni casi ciò può corrispondere alla realtà, in quanto si preferisce, piuttosto che dotare il device della coppia software-processore, progettare una circuiteria integrata
dedicata all’esecuzione della funzione del sistema in hardware. Tuttavia, è utile osservare che il primo
approccio risulta essere più flessibile, talvolta anche meno costoso e più semplice, rispetto alla definizione
di un circuito integrato (IC).
1.2
1.2.1
Componenti dei sistemi embedded
Componenti comuni
Così come osservato nel paragrafo 1.1, secondo una definizione non-hardwired, si può stabilire che ogni
sistema integrato contenga un processore e un software [2]. Tali componenti rappresentano, dunque,
delle features comuni per essi. È utile osservare, che affinché un sistema di questo tipo possa eseguire
un certo programma è necessario che tale sia provvisto di un’area ove memorizzare il codice eseguibile, e
un’area ove memorizzare temporaneamente dati relativamente all’esecuzione dello stesso. Per tale motivo
è necessario che ogni dispositivo embedded abbia a disposizione una memoria a sola lettura (ROM, Read
Only Memory) e una memoria RAM (Random Access Memory). Per sistemi integrati su piccola scala,
per i quali necessita solo una memoria di piccole dimensioni, essa è, tipicamente, immersa all’interno
dello stesso chip del processore.
Figura 1.2.
Schema generico di un sistema embedded
Tutti i sistemi embedded reagiscono ad un insieme di dati d’ingresso con una o più azioni di uscita.
Ad esempio consideriamo il sistema di antibloccaggio delle ruote in frenata (ABS) in figura 1.1.
In questo caso, su ogni ruota del veicolo è posto un Encoder, formato da un trasduttore e da una ruota
fonica, che è costituita da una ruota dentata simile ad un ingranaggio che gira con la ruota del veicolo ed
un sensore di prossimità induttivo fisso che rileva il passaggio dei denti di suddetta ruota. La centralina
elettronica, contando il numero di denti che passano in una data unità di tempo, calcola la velocità di
rotazione della ruota e se rileva che una o più ruote sono bloccate in fase di frenata comanda la pompa
idraulica in modo da diminuire la forza di frenata, evitando il bloccaggio [13].
2
1 – Introduzione ai Sistemi Embedded
1.2.2
Componenti specifici
Ad eccezione di quanto appena specificato, un sistema embedded lo si può caratterizzare da una circuiteria
hardware esclusiva, su cui esegue un software esclusivo. Sia la struttura software che hardware sono
strettamente legate al campo di utilizzo, e, dunque, dalla funzione da esso implementata; ad esempio,
un sistema di controllo di un aeromobile necessita di uno strato operativo real-time, al fine di assicurare
il soddisfacimento dei vincoli temporali.
Nel tempo, la richiesta di tali sistemi è stata spesso accompagnata dall’esigenza di definire dei dispositivi
sempre di dimensioni minori. In tale ottica, la nascita dei microcontrollori ha permesso di conseguire
un risultato ottimo, rispetto ad un punto di vista dimensionale, fornendo, allo stesso tempo, un elevata
potenza, in termini di capacità di calcolo. A questo proposito è importante sottolineare la differenza
tra microprocessore e microcontrollore; in particolare, il primo è un singolo chip VLSI2 che include solo
la logica di elaborazione mentre richiede sempre delle unità esterne per poter scambiare informazioni e
interagire con l’esterno.
Il microcontrollore è invece un sistema completo, che integra in uno stesso chip il processore, la memoria
permanente, la memoria volatile e i canali (pin) di I/O, oltre ad eventuali altri blocchi specializzati.
Seguendo una tale ottica, un sistema embedded lo si può anche associare ad un sistema basato su
microprocessore costruito per il controllo di una funzione o un insieme di funzioni [3].
I microcontrollori possono essere classificati secondo differenti livelli di sofisticatezza. Tale classificazione
è tipicamente condotta in base alla dimensione della parola (word). Considerando un dettaglio maggiore,
i microcontrollori a 8-bit vengono impiegati attraverso altri componenti (ad esempio dispositivi di I/O),
in sistemi low-cost; microcontrollori a 16-bit vengono utilizzati in applicazioni più sofisticate. Infine, sono
da citare i microprocessori RISC3 a 32-bit, che offrono alte performance per applicazioni CPU-intensive.
A seguire, in figura 1.3 è rappresentato un esempio di architettura hardware di un sistema embedded
[4].
In virtù di ciò, è necessario, quindi, illustrare l’importanza delle periferiche in un sistema integrato
nell’interazione dello stesso con l’ambiente esterno in cui è immerso. Ciò avviene attraverso dispositivi
collegati mediante delle porte di comunicazione seriale. Esempi di devices di input possono risultar essere
sensori, tastierini numerici e parallelamente devices di output possono identificarsi con display, memorie,
output seriali.
1.3
Classificazione dei sistemi embedded
Come già accennato, tipicamente, un sistema embedded è esclusivo, nel senso che esso viene progettato
e distribuito per l’esecuzione di una funzione dedicata, In tale eterogeneità è possibile definire una
classificazione, che suddivide questi sistemi in:
2
Very Large Scale Integration, indica una elevata integrazione di transistor all’interno di un singolo chip
3
L’acronimo RISC, dall’inglese Reduced Instruction Set Computing, indica una filosofia di progettazione di architetture
per microprocessori che predilige lo sviluppo di un’architettura semplice e lineare
3
1 – Introduzione ai Sistemi Embedded
Figura 1.3.
Architettura di un sistema embedded
1. Sistemi a Piccola Scala: si tratta di sistemi dotati di un singolo microcontrollore a 8-bit o
16-bit. Tipicamente si tratta di dispositivi semplici, con hardware poco sofisticato, su cui viene
eseguito un software non complesso. Per tale tipo di sistema, vengono messi a disposizione, spesso,
dei tool di svliuppo, comprensivi di IDE4 , compilatori e interfacce di programmazione (API); il
linguaggio utilizzato per la programmazione dei suddetti devices è, usualmente, il C. Esempi di
sistemi embedded di questo tipo sono:
• Keyboard Controller;
• Controller HDD o CD-Drive;
• Telecomando per TV;
• Smartphone;
• Elettrodomestici (Lavatrici, Forni elettrici, ...).
2. Sistemi a Media Scala: sono sistemi dotati di uno o più microcontrollori a 16-bit o 32-bit. A
differenza dei primi, sono più complessi sia da un punto di vista software che hardware. Poiché,
dunque, risultano adatti allo sviluppo di applicazioni complesse, tipicamente, lo sviluppo software
è guidato dalla presenza di RTOS, simulatori, debugger e ambienti di sviluppo integrati. Anche in
questo caso sono presenti delle librerie che semplificano il developing, permettendo di mascherare
la complessità circuitale del device. Esempi di sistemi embedded di questo tipo sono:
• Computer Network Systems (router, switch, bridge,...);
• Sistemi Bancari (ATM);
• Smartphone;
4
Integrated Developing Envivorment, ambiente di sviluppo integrato
4
1 – Introduzione ai Sistemi Embedded
• Sistemi di Intrattenimento (Video Games, ...).
Sistemi Sofisticati: sono sistemi fortemente sofisticati, con enormi complessità hardware e
3.
software, che possono avere la necessità di utilizzare processori configurabili o scalabili. É possibile
che tali sistemi prevedano la definizione di alcune funzionalità complesse, come ad esempio la DCT,
Discrete Cosine Transformation, a livello hardware, attraverso una circuiteria dedicata, al fine di
migliorare le prestazioni. Anche in questo caso sono messe a disposizione dello sviluppatore API e
strumenti di supporto. Esempi di sistemi embedded di questo tipo sono:
• Sistemi Embedded per la wireless LAN;
• Sistemi Embedded per il video Real-Time;
• Prodotti per la sicurezza;
• Sistemi di Network Security.
1.4
Performance nei sistemi embedded
Il concetto di performance è un qualcosa di relativo allo specifico ambito di applicazione del sistema.
A titolo di esempio, in un comune PC, general-purpose, si vuole ridurre al minimo il tempo medio di
risposta dei task, al fine di ottenere un buon compromesso circa la reattività del sistema. Ciò non è,
invece, vero per il campo dei sistemi integrati. Per comprendere ciò, consideriamo il cuore di questa
classe di sistemi, ossia il settore real-time.
I sistemi in tempo reale sono quei sistemi di calcolo per i quali la correttezza di funzionamento non
dipende solo dalla validità dei risultati ottenuti, ma anche dal tempo in cui tali risultati sono prodotti[5].
La caratteristica di questi sistemi è la presenza di una deadline, che rappresenta, per un certo task (o
istanza di esso) il tempo massimo entro cui tale deve terminare la propria esecuzione. A seconda della
classe di criticità, un superamento di deadline può invalidare l’intero sistema o definire un degradamento
della QoS (Quality of Service). È evidente, quindi, che, per questi sistemi non ha senso minimizzare
il tempo medio di risposta delle applicazioni; risulta, invece, essenziale, garantire che ogni task possa
terminare entro il proprio limite massimo temporale. Ciò viene ottenuto attraverso l’utilizzo di tecniche
di scheduling appositamente definite per garantire il rispetto delle deadline.
1.4.1
Requisiti di sviluppo e Scelte di Design
Sulla base di quanto detto, è evidente che ad ogni singolo sistema integrato debba corrispondere ad
uno specifico set di requisiti. È importante notare che, spesso, il soddisfacimento di questi requisiti,
contemporaneamente, non è possibile, e per tale motivo risulta necessario definire un trade-off, ossia un
compromesso, antecedente lo sviluppo del prodotto. Ad esempio, un tipico vincolo che spesso occorre è
il budget a disposizione; in questo caso il soddisfacimento di altri requisiti è, ovviamente, subordinato al
suddetto. Si specifica che tale non rappresenta l’unico possibile vincolo che può presentarsi all’atto di
sviluppo di questa classe di prodotti. A seguire vengono descritti altri possibili requisiti.
5
1 – Introduzione ai Sistemi Embedded
• Potenza di calcolo: rappresenta la massima domanda di calcolo che il chip riesce a gestire.
Tipicamente, un metodo utilizzato per la valutazione della potenza di calcolo è il fattore MIPS,
Million Instructions Per Second, rappresentante il numero (in ordine 106 ) di istruzioni che vengono
eseguite in un secondo dal chip. Ovviamente, il MIPS non è l’unico fattore che influenza la potenza
di calcolo; si fa riferimento ad altre features, quali, ad esempio, la dimensione dei registri del
processore: ad oggi i sistemi embedded vengono costruiti con processori, tipicamente, a 16-bit.
• Storage: intesa come la quantità di memoria richiesta per l’archiviazione del software da eseguire
e dei dati da esso manipolati. Si nota come la quantità di memoria a disposizione influenzi anche la
scelta del processore. Infatti un processore a 16-bit può indicizzare fino a 216 locazioni di memoria.
• Numero di unità: rappresenta il numero di unità di produzione del prodotto atteso. Tale fattore
influenza in particolar modo il budget a disposizione per lo sviluppo.
• Consumo di energia: è la quantità di energia richiesta per l’elaborazione, di particolare importanza per i dispositivi alimentati da batteria. Ovviamente, si cerca sempre di ottenere un
basso consumo, al fine di aumentare l’autonomia energetica del dispositivo, ma anche limitare le
dimensioni e il riscaldamento dello stesso.
• Tempo di Vita: rappresenta il tempo atteso di utilizzo del dispositivo. Ciò va a influenzare la
scelta dei componenti hardware e, dunque, il costo di sviluppo del progetto.
• Affidabilità: rappresenta quanto deve essere affidabile il prodotto. Ad esempio un giocattolo può anche non funzionare il 100 percento delle volte, mentre se l’ABS di un auto ha un
malfunzionamento, ciò può arrecare danno a persone o cose (sistema safety-critical).
In tabella 1.1 è presente uno schema sintetico di quanto specificato.
Requisito/Criterio
Basso
Medio
Alto
Processore
4-bit o 8-bit
16-bit
32-bit o 64-bit
Memoria
<64KB
da 64KB a 1MB
>1MB
Costo di Sviluppo
<$100.000
da $100K a $1M
>$1M
Costo di Produzione
<$10
da $10 a $1000
>$1000
Numero di Unità
<100
da 100 a 10000
>10000
Consumo di Energia
>10mW/MIPS
da 1 a 10mW/MIPS
<1mW/MIPS
Tempo di Vita
Giorni, settimane o mesi
Anni
Decadi
Affidabilità
Può occasionalmente fallire
Deve essere affidabile
Non deve fallire
Tabella 1.1.
Requisiti di Design per Sistemi Embedded
6
Capitolo 2
La piattaforma Arduino
2.1
Cenni generali
Arduino è una piattaforma prototipale di sviluppo open-source, caratterizzata dalla presenza di una
semplice board di input/output. Questa si basa su un circuito stampato che integra un microcontrollore
con pin connessi alle porte I/O, un regolatore di tensione e quando necessario un’interfaccia USB che
permette la comunicazione con il computer. A questo hardware viene affiancato un ambiente di sviluppo
integrato (IDE) multipiattaforma (per Linux, Apple MacOS e Windows). Tale ambiente permette di
creare dei programmi (sketch) ed eseguirli sulla piattaforma.
(a) Arduino PRIMO Board
Figura 2.1.
(b) Arduino NFC Shield
Componenti fondamentali architettura Arduino
L’hardware Arduino originale viene prodotto in Italia dalla Smart Project, una società di proprietà
di uno dei co-fondatori del progetto. Ad oggi, sono messe a disposizione differenti tipologie di schede,
ognuna delle quali rientra in una determinata categoria di utilizzo, similmente a quanto specificato
nel paragrafo 1.3. Tali schede sono dotate, tipicamente, di un microcontrollore Atmel; sono presenti in
realtà anche schede dotate di microcontrollori STMicroelectronics o Nordic. In generale i chip Atmel sono
progettati secondo l’architettura AVR, mentre i chip Nordic o STMicroelectronics secondo l’architettura
ARM-Cortex.
In particolare la definizione di un prototipo Arduino necessita della presenza di una board, che rappresenta
7
2 – La piattaforma Arduino
il blocco fondamentale di sviluppo per il progetto, caratterizzato da un microcontrollore e altre features
a seconda della classe.
Ad esempio in figura 2.1(a) è rappresentata una board Arduino Primo.
Arduino Primo include la presenza di un microcontrollore Nordic nRF52832, di un modulo ESP8266
per la comunicazione WiFi, un insieme di sensori e un caricatore di batteria. Il microcontrollore Nordic
include l’NFC, e Bluetooth Smart.
Per fornire delle features aggiuntive alla board è possibile utilizzare le Shield. Arduino mette a disposizione un grosso numero di shields, a partire dall’Ethernet Shield fino ad arrivare all’NFC, in figura
2.1(b), e GSM Shield.
2.1.1
Arduino IDE
Come già accennato, Arduino mette a disposizione per lo sviluppo, un ambiente integrato, Arduino
IDE, costituito da un editor di testo, un’area messaggi, una console testuale, una toolbar con funzioni
comuni e un menu. Tramite questo ambiente è possibile collegarsi direttamente alla board, effettuare
l’upload dello sketch ed eseguirlo.
Figura 2.2.
Arduino IDE
In figura 2.2 è illustrato uno screenshot del tool. Si nota che la definizione dello sketch, in ambiente
Arduino, è caratterizzato da due procedure fondamentali:
8
2 – La piattaforma Arduino
1. void setup(), che contiene il codice di inizializzazione della board, che viene eseguito una sola
volta, all’inizio.
2. void loop(), che contiene il codice relativo alle azioni da effettuare, eseguito ciclicamente dalla
board.
2.2
Aspetti Hardware della piattaforma
Poiché nel prosieguo dell’elaborato, così come specificato nella prefazione, sarà presentato un progetto
di sviluppo prototipale con la piattaforma Arduino, è necessario riportare le caratteristiche delle schede
utilizzate, al fine di comprendere le scelte di progetto operate. Senza entrare nel dettaglio, si è scelto
di utilizzare come prototipo una piattaforma costituita da una board Arduino Mega 2560, uno shield
Arduino Ethernet Shield 2, un ulteriore shield Arduino GSM Shield 2, un modulo WiFi ESP8266, e
infine una scheda con transceiver RS485. Si aggiunge inoltre, in ottica di debugging, la presenza di
una ulteriore board Arduino UNO, di un display LCD compatibile HD44780, a 4 righe e 20 colonne e
infine di un keypad numerico di dimensioni 4x3. Di seguito si dettagliano le caratteristiche hardware dei
componenti sopra elencati.
2.2.1
Arduino Mega 2560
Arduino Mega 2560 è una board basata sul microcontrollore Atmel ATmega2560. È dotato di 54 pin
digitali di input/output di cui 15 possono essere utilizzati come output PWM1 , 16 input analogici, 4
UART2 , un clock a 16 MHz, una interfaccia USB e un jack di alimentazione. Questa board differisce dai
modelli Arduino Mega precedenti in quanto utilizza come convertitore USB-to-serial un ATmega16U2.
In particolare la Revision 3 possiede anche pin per la comunicazione I2C, SDA e SCL.
Figura 2.3.
Arduino Board Mega 2560
1 Pulse
Width Modulation, è una tecnica per ottenere un risultato analogico attraverso un mezzo digitale. Il controllo
digitale è utilizzato per definire un’onda quadra. La tecnica simula il comportamento analogico, ossia tutte le tensioni tra
0 e 5V cambiando la porzione di tempo per cui un segnale è on oppure è off. Definito l’on-time, ossia il tempo in cui il
segnale è alto, come pulse width, la modifica di questo valore permette di ottenere valori analogici
2 Porte
hardware seriali
9
2 – La piattaforma Arduino
Per la programmazione della board, Arduino mette a disposizione delle librerie in virtù di astrarre
lo sviluppo dai dettagli hardware del dispositivo. In figura 2.3 è rappresentata la board Arduino Mega
2560.
Atmel ATmega2560
L’ ATmega2560 è un microcontrollore CMOS, a 8-bit, facente parte della famiglia AVR, e, dunque basato
su una tecnologia RISC. È caratterizzato dalla presenza di 32 registri interni general-purpose, tutti
collegati direttamente all’unità logico-aritmetica (ALU), inclusi due registri indipendenti che possono
essere acceduti attraverso una singola istruzione eseguita in un solo ciclo di clock.
Figura 2.4.
Atmel ATmega2560 - Diagrammi dei blocchi, adattato da [6]
È presente una memoria flash programmabile da 256KB, una EEPROM da 4KB, una SRAM da 8KB
86 pin di I/O general purpose. Oltre a ciò figurano altre features, come la presenza di Timer, USART3 ,
porta SPI seriale, una interfaccia seriale byte-oriented 2-wire e 16 canali ADC.
3 Universal Synchronous/Asynchronous Receiver/Transmitter è un chip che facilita la comunicazione tramite una porta
seriale utilizzando il protocollo RS-232C. A differenza dell’UART permette una comunicazione sincrona
10
2 – La piattaforma Arduino
Device
Flash
EEPROM
SRAM
Pin I/O
Canali PWM
USART Seriali
Canali ADC
ATmega2560
256KB
4KB
8KB
86
12
4
16
Tabella 2.1.
2.2.2
Tabella riassuntiva ATmega2560
Arduino Ethernet Shield 2
Così come prima accennato, Arduino permette di aggiungere funzionalità alla main board attraverso
un approccio modulare tramite l’utilizzo di shield. In particolare, il modulo in questione permette il
collegamento alla rete tramite un classico cavo RJ45, e in più supporta il PoE4 , al fine di alimentarsi
direttamente dal cavo ethernet.
Figura 2.5.
Arduino Ethernet Shield 2
In questo caso, ai fini di semplificare lo sviluppo, Arduino mette a disposizione un insieme di API
raccolti nella libreria Ethernet2.h. In più, come si nota anche in figura 2.5 è presente uno slot per
MicroSD, come supporto di memorizzazione esterna. Il chip utilizzato è il Wiznet W5500.
Wiznet W5500
Il chip W5500 è un controllore embedded TCP/IP hardwired, che è tipicamente utilizzato in sistemi
embedded per permettere la connessione alla rete Internet. Per tale motivo esso implementa il protocollo
TCP/IP e aderisce allo standard Ethernet 802.3 10/100 Mbit/s.
In virtù di ciò offre pieno supporto ai protocolli TCP, UDP, IPv4, ICMP, ARP, IGMP, PPPoE. È
dotato di un buffer di memoria interna da 32KB per il processing dei pacchetti Ethernet. Il collegamento
al microcontrollore avviene attraverso l’interfaccia SPI; a tal riguardo, il chip raggiunge frequenze di
80Mhz al fine di comunicare in maniera veloce con la board. Infine, per il risparmio energetico adotta
il power down mode e lo standard WoL (Wake on LAN), che permette di risvegliare un dispositivo
remotamente tramite la conoscenza dell’indirizzo MAC.
4 Power over Ethernet, tecnica molto utilizzata al fine di alimentare il dispositivo con lo stesso cavo utilizzato per la
rete dati
11
2 – La piattaforma Arduino
Figura 2.6.
2.2.3
Wiznet W5500 - Schema a blocchi, adattato da [7]
Arduino GSM Shield 2
L’Arduino GSM Shield 2 fornisce alla board la funzionalità di connettersi ad internet tramite la rete
wireless GPRS. In particolare questo modulo è dotato di uno slot per SIM Card, in modo tale da
permettere al prototipo la connessione alla rete cellulare. È possibile, dunque, anche ricevere/effettuare
chiamate (è infatti presente un jack per microfono e speaker esterno) e inviare/ricevere messaggi di testo
(SMS).
Figura 2.7.
Arduino GSM Shield 2
Tale scheda è dotata di un chip Quectel M10.
Quectel M10
Il Quectel M10 è una soluzione Quad-band GSM/GPRS che può essere utilizzato in applicazioni embedded. Fornisce il supporto a tecnologie GSM/GPRS 850/900/1800/1900 MHz ed è utilizzabile per
voce, SMS, Data Network e Fax. L’M10 supporta una tecnologia chiamata QuecFOTA, che permette un
semplice update del firmware tramite il microcontrollore attraverso l’UART.
12
2 – La piattaforma Arduino
Figura 2.8.
Schema Quectel M10, adottato da [8]
In figura 2.8 è presente uno schema a blocchi del chip. Notiamo la presenza di una flash memory
e di una RAM statica, oltre al baseband GSM e la parte dedicata alla frequenza radio. Inoltre il
chip è dotato di un insieme di interfacce per il collegamento con l’esterno. In particolare si noti la
presenza dell’interfaccia UART, la fondamentale presenza dell’interfaccia SIM Card e dell’interfaccia
Audio, necessari per poter sfruttare a pieno le potenzialità del chip.
2.2.4
WiFi Module - ESP8266
L’ESP8266 è il nome di un microcontrollore progettato dalla Espressif Systems. È descritto come una
soluzione di networking WiFi self-contained che può essere utilizzata sia per permettere il collegamento
WiFi ad un pre-esistente microcontrollore, sia come microcontrollore a sé stante.
Figura 2.9.
Schema a blocchi ESP8266, adottato da [9]
Come modulo WiFi aderisce al protocollo standard 802.11 b/g/n. Per tale ragione ha piena compatibilità con i protocolli IPv4, TCP/UDP, supporta la security WPA/WPA2 e come algoritmo crittografico
WEP, TKIP e AES. Il modulo può funzionare sia come Access Point, sia come stazione e infine, anche
13
2 – La piattaforma Arduino
in entrambe le modalità. La programmazione avviene attraverso l’utilizzo di comandi AT5 .
Ad esempio il comando per il restart del modulo è AT+RST. Ad ogni comando corrisponde una risposta;
nell’esempio precedente tale può essere OK. Per dettagli maggiori circa i comandi si rimanda al capitolo
successivo.
2.2.5
Transceiver RS485
Un transceiver, in italiano ricetrasmettitore, è un buffer driver bidirezionale che viene utilizzato per
collegare, tipicamente, microprocessori. L’RS485 è uno standard EIA, del livello fisico (Modello OSI) di
una connessione seriale a due fili, half-duplex6 e multi-punto. Secondo questo standard, il segnale viene
gestito in maniera differenziale, ossia il bit in transito viene definito rispetto alla differenza di potenziale
presente tra i due fili. Si noti che tale standard specifica esclusivamente le caratteristiche elettriche del
trasmettitore e del ricevitore, ma non definisce alcun protocollo per la trasmissione dei dati. Per tale
motivo è compito del programmatore adottare opportuni accorgimenti per verificare il corretto transito
dei dati. Sebbene ciò sia un punto a sfavore, lo standard permette il raggiungimento di velocità di
trasmissioni molto elevate: fino a 10 metri si raggiungono i 35Mbit/s; a 1200 metri si raggiungono i
100Kbit/s. In particolare, nel caso in esame, si fa riferimento al transceiver SN75HVD08, prodotto dalla
Texas Instruments.
Figura 2.10.
Configurazione dei Pin - SN75HVD08, adottato da [10]
Come si nota in figura, le linee A e B sono utilizzate per la comunicazione differenziale. Per il
prosieguo dell’elaborato ci serve conoscere il DE (Driver Output Enable): se alto, il chip viene attivato
come output (invio dati), viceversa quando è basso, il chip funziona da ricevente. Per completezza si
cita la funzionalità dei pin rimanenti: sul pin R arrivano i dati letti dalla linea differenziali quindi va
collegato alla linea RX della board; il pin D, invece, riceve i dati da inviare, quindi va collegato alla linea
TX della board; RE, quando è basso, il chip è in grado di ricevere i dati dalla linea differenziale.
Per quanto riguarda la programmazione, il transceiver va gestito semplicemente come una porta seriale.
2.2.6
Arduino UNO
Come prima accennato, in fase di debugging si è utilizzata, in aggiunta, anche una board Arduino UNO.
Si tratta di un microcontrollore basato sul chip Atmel ATmega328, ed è caratterizzata da 14 pin
di I/O digitale, di cui 6 possono essere utilizzati con la tecnica del PWM, 6 input analogici, una porta
USB e un jack di alimentazione. Così come l’Arduino Mega 2560 utilizza un chip ATmega16U2 come
5
Sono comandi consistenti in semplici stringhe.
6
La trasmissione è bidirezionale ma alternata
14
2 – La piattaforma Arduino
Figura 2.11.
Arduino UNO - Board
convertitore USB-to-serial. Anche in questo caso sono presenti i pin per l’utilizzo del protocollo I2C,
SDA e SCL.
ATmega328
A testimonianza della sua minor potenza rispetto all’Arduino Mega 2560 è la presenza del chip ATmega328 caratterizzato dai seguenti fattori: una memoria flash da soli 32KB, una SRAM da 2KB, una
EEPROM da 1 KB e una frequenza di clock di 16MHz. A ciò si aggiungono un insieme di 32 registri
general-purpose direttamente collegati all’ALU, così come caratteristico dell’architettura AVR.
Figura 2.12.
Arduino UNO - Diagramma a blocchi
15
2 – La piattaforma Arduino
In figura 2.12 è rappresentato il diagramma a blocchi del chip.
2.2.7
Display compatibile Hitachi HD44780 e Keypad numerico
Il chip HD44780 è un cosiddetto “standard de facto”, dunque non è uno standard ufficialmente riconosciuto ma è largamente utilizzato tale per cui gode di elevata popolarità e ampia diffusione. A tal
proposito Arduino mette a disposizione un set di API contenute nella libreria LiquidCrystal.h, permettendo l’astrazione dai dettagli interni del chip per la sua programmazione. In maniera analoga, per
il keypad numerico 4x3 si utilizza una libreria analoga, Keypad.h che permette alla board di leggere il
carattere premuto sul tastierino.
2.3
Prototipo di debugging
Utilizzando i componenti descritti nel paragrafo 2.2, si è assemblato un prototipo al fine di effettuare il
testing e il debugging del progetto definito nel capitolo successivo. Si presenta, a titolo illustrativo, una
istantanea del suddetto.
Figura 2.13.
Snapshot del prototipo di testing e debugging
16
Capitolo 3
Descrizione e sviluppo del progetto
3.1
Panoramica
Il progetto si pone il fine di andare a definire un sistema composito di tre tipi di nodi:
• Centrale;
• Concentratore;
• Gateway;
L’obiettivo è quello di realizzare una rete sensoriale, caratterizzata da concentratori, collegati tra di
loro attraverso una rete wired o wireless che aderisca allo stack protocollare TCP/IP. In tale insieme di
nodi, se ne contraddistinguono due fondamentali, il nodo centrale e il nodo gateway.
Il nodo centrale ha il compito di definire ciclicamente le richieste di ottenimento dei dati sensoriali, mentre
il gateway ha il compito di smistare le richieste provenienti dalla centrale verso i vari concentratori
presenti sulla rete. In realtà, è possibile anche che un determinato concentratore sia dotato di un
collegamento wired attraverso il protocollo EIA RS485 ad un bus su cui si interfacciano un certo numero
di concentratori. Quindi, ogni concentratore può comportarsi come gateway verso la sottorete ad esso
associata. Per tale motivo, il gateway, effettivamente, perde l’esclusività nel suo ruolo. È possibile, allora,
adoperare la logica di smistamento richieste all’interno della centrale e lasciare al gateway la generica
funzione di concentratore, aggiungendogli l’onere relativo al rilevamento delle richieste effettuate dalla
centrale al fine di verificare eventuali malfunzionamenti. Se, infatti, il gateway non rileva più richieste
gli si reca l’obbligo di instaurare una connessione dati (GSM/GPRS) con la centrale. In figura 3.1 è
presente uno schema dell’architettura da realizzare.
3.1.1
Componenti del sistema
Così come specificato, il sistema è composito di nodi, collegati tra di loro attraverso una rete TCP/IP. È
opportuno richiedere, quindi che ciascun nodo sia caratterizzato dalla presenza di un modulo Ethernet
e/o WiFi, oltre che da un modulo RS485.
17
3 – Descrizione e sviluppo del progetto
Figura 3.1.
Schema Architetturale realizzativo del sistema - adattato da [12]
In più, il gateway e la centrale saranno dotati di un modulo GSM, per l’instaurazione di una connessione
dati. Sotto tali requisiti, si considerano, a livello hardware, i nodi caratterizzati dalla seguente struttura:
1. Board Arduino Mega 2560, con chip ATmega2560 ;
2. Shield Arduino Ethernet Shield 2, con chip Wiznet W5500 ;
3. Modulo WiFi ESP8266;
4. Scheda con Transceiver RS485, con chip SN75HVD08 ;
In aggiunta, così come specificato, sarà necessaria la presenza, nel gateway e nella centrale, di
un componente:
5. Shield Arduino GSM Shield 2, con chip Quectec M10 ;
3.2
Soluzioni di sviluppo del sistema
Per quanto riguarda lo sviluppo del sistema, l’idea adottata è stata quella di utilizzare un approccio di
tipo bottom-up. In quest’ottica si aggiunge la necessità, data la complessità del sistema, di procedere
per passi. In particolare, si osservi la natura modulare del sistema: ciò permette di dominare il livello di
complessità progettuale, promuovendo uno sviluppo individuale dei singoli moduli.
Innanzitutto notiamo, dal paragrafo 3.1, che il progetto include l’utilizzo di tre meccanismi di comunicazione:
1. Ethernet 802.3 o WiFi 802.11 (protocolli del livello fisico e MAC dello stack TCP/IP);
18
3 – Descrizione e sviluppo del progetto
2. RS485;
3. GSM/GPRS.
Per tale motivo si è deciso di strutturare lo sviluppo del sistema incentrandolo, singolarmente, su
ciascuno di questi tre protocolli. Sfruttando lo schema in figura 3.1, si va, dunque, a considerare come
protocollo di comunicazione tra tutti i nodi, l’RS485. In tal senso, l’utilizzo del gateway come punto
di smistamento delle richieste provenienti dalla centrale può risultare utile, in quanto ciò consente di
incapsulare all’interno della centrale esclusivamente la logica di invio delle richieste.
3.2.1
Sviluppo con Protocollo RS485 - Architettura semplificata
Così come accennato, in questa soluzione si fa riferimento ad un utilizzo esclusivo del protocollo RS485. In
ottica semplificativa, inoltre, si preferisce, per il momento, escludere la possibilità di dotare i concentratori
del collegamento verso una ulteriore sottorete. Ciò è riassunto nella figura 3.2.
Figura 3.2.
Schema Architetturale Semplificativo del sistema - adattato da [12]
In questo caso quindi si considerano le seguenti assunzioni:
• Il nodo centrale e il gateway sono legati tramite un collegamento fisico diretto sfruttante il protocollo
RS485. Per tale motivo ambo i nodi dovranno essere in possesso di un transceiver RS485.
• In riferimento al punto precedente, in questo esempio di comunicazione, la centrale si comporta
come master mentre il gateway come slave. Quindi, il gateway attende di ricevere comandi dalla
centrale per poter operare.
19
3 – Descrizione e sviluppo del progetto
• Il gateway è collegato fisicamente alla rete di concentratori attraverso un bus condiviso, ove esso
opera da master e i concentratori da slave. Per tale motivo, una volta ricevuto il comando, il
gateway attiverà uno degli slave richiedendo l’acquisizione dei dati dai sensori. A tal fine si ritiene
necessario che il gateway sia dotato aggiuntivamente di un collegamento RS485 verso il bus, allo
scopo di poter comunicare con i concentratori.
Indirizzamento
Al fine di permettere al nodo centrale di richiedere dati sensoriali da un singolo oppure da un insieme
di concentratori, si è definito, a livello applicazione, un tecnica di indirizzamento gerarchica. In virtù
dello schema in figura 3.2, in questo ambito è sufficiente una gerarchia a due livelli: l’indirizzo, di 16-bit,
viene suddiviso in due sotto-indirizzi di 8-bit. Definita come parte più significativa dell’indirizzo i primi
8-bit, tale identifica un gruppo di concentratori. Definita come parte meno significativa dell’indirizzo i
rimanenti 8-bit, tale identifica il concentratore singolo nel gruppo. Ciò è schematizzato in figura 3.3.
0
0
| 1 0 1{z0 1 0 1}
| 1 0 1{z0 1 0 1}
Gruppo
Concentratore nel gruppo
Figura 3.3.
Modalità di Indirizzamento adottata
Inoltre, si definiscono le seguenti assunzioni:
• un indirizzo la cui parte meno significativa è composita di tutti 1 mentre differisce nella parte più significativa, è equivalente ad un indirizzo di broadcast del gruppo.
Ad esempio, l’in-
dirizzo 1010101011111111 è un indirizzo di broadcast per il gruppo identificato dall’indirizzo
10101010xxxxxxxx.
• un indirizzo interamente caratterizzato dalla presenza di bit alti, identifica un indirizzo di broadcast.
In tal caso, la centrale richiederà ad ogni concentratore interfacciante il bus i dati sensoriali.
Registrazione concentratori
Così come definito precedentemente nel paragrafo 3.1, in riferimento alle assunzioni elencate in questa
prima fase di sviluppo, sia il gateway che la centrale hanno necessità di conoscere l’eventuale presenza dei
concentratori, e, in particolar modo, dei rispettivi propri indirizzi. Per tale motivazione è sorta l’esigenza
di considerare la presenza di una struttura statica contenente l’insieme degli indirizzi dei concentratori
attualmente presenti all’interno del sistema. La soluzione adottata è basata, in virtù della condivisione
della stessa tra differenti devices, sul concetto di libreria. Nel dettaglio è stato definito un header file
mappingStructure.h, contenente la struttura dati racchiudente l’insieme di indirizzi (applicazione e
IPv4 secondo un mapping uno-a-uno), e un insieme di procedure, richiamabili su di essa la cui utilità
risulterà più chiara nel prosieguo dell’elaborato. In figura 3.4 è rappresentato un estratto del file di
intestazione della struttura.
Come si nota, tale struttura è composita di tre campi:
20
3 – Descrizione e sviluppo del progetto
1
/* Definizione Struttura */
2
3
typedef struct {
4
char *addresses[NUM_SENSORS];
5
6
int ipAddresses[NUM_SENSORS][4];
7
8
int size;
9
10
11
}MappingAddress;
12
13
/* Procedure di Utility */
14
15
16
17
18
void initialize_addresses(MappingAddress*);
void insert_row(MappingAddress*, char*, int , int , int , int );
int getIPfromAddress(MappingAddress* , char* , int* );
int getAddressFromIP(MappingAddress* , char* , int , int , int , int );
Figura 3.4.
Estratto del file di intestazione: mappingStructure.h
1. char *addresses[NUM_SENSORS]: tale campo è un vettore di indirizzi, con dimensione pari al
valore NUM_SENSORS.
2. int ipAddresses[NUM_SENSORS][4]: tale campo è un vettore di indirizzi IPv41 , con indicizzazione
concorde al campo precedente. La memorizzazione dell’indirizzo è suddivisa per byte. Ciascun byte
è rappresentato da un intero (anche se il tipo intero memorizza un valore di 2 bytes).
3. int size: è una variabile di conteggio, utilizzata per valutare il riempimento dei vettori staticamente definiti.
Su di essa sono definite delle procedure di utility, in particolare quelle di interesse sono:
• void initialize_addresses(MappingAddress*): è una procedura il cui obiettivo è l’inizializzazione della struttura. Deve, quindi, essere chiamata al momento della dichiarazione della stessa.
Riceve come parametro di input un puntatore alla struttura MappingAddress precedentemente
definita;
• int getIPfromAddress(MappingAddress* , char* , int* ): è una procedura che ricevendo in
ingresso l’indirizzo a livello applicativo restituisce il corrispondente indirizzo IP sotto forma di
vettore di interi. Riceve come parametri di input un puntatore alla struttura MappingAddress e
l’indirizzo a livello applicazione sotto forma di stringa, mentre come parametro di output richiede
un vettore di interi di dimensione pari a 4. Se l’operazione va a buon fine, la procedura ritorna un
valore intero 0, altrimenti -1.
1È
necessario considerare questo campo in quanto il progetto finale prevede l’utilizzo di una rete TCP/IP
21
3 – Descrizione e sviluppo del progetto
Struttura della Centrale
Così come accennato nel paragrafo 2.1, lo sketch che viene caricato sulla piattaforma Arduino è caratterizzato da due procedure fondamentali, una di inizializzazione void setup(), e una di azione ciclica
void loop(). In questo caso l’azione della centrale consiste, semplicemente, nel richiedere la lettura dei
dati sensoriali rispetto ad un concentratore e attenderne la ricezione. Pertanto lo sketch si riduce alle
poche righe di codice in figura 3.5.
1
/********** Setup ***********/
2
3
void setup() {
4
Serial.begin(9600);
Serial.println("Central");
Serial.println("Send an Address to Gateway");
5
6
7
8
pinMode(SSerialTxControl, OUTPUT);
9
10
Serial2.begin(4800);
11
12
initialize_addresses(&sensorAddresses);
13
14
15
}
16
17
/********** Loop ***********/
18
19
void loop() {
20
getSensorToCall(address);
21
22
sendRequest(address);
23
24
readValues();
25
26
27
}
Figura 3.5.
Estratto dello sketch Centrale.ino relativo allo sviluppo con protocollo RS485
In questo estratto è possibile verificare come la funzione di setup() si limiti a inizializzare il data-rate
delle interfacce Serial (per l’USB) e Serial2 (ai cui pin è collegata la scheda con il transceiver RS485)
e la struttura statica contenente il mapping degli indirizzi applicazione-IP prima definita.
Relativamente all’effettiva operazione effettuata dalla centrale, come già accennato, essa si riduce a tre
operazioni fondamentali, richiamate ciclicamente:
1. getSensorToCall(): è una procedura che serve per ottenere l’indirizzo del concentratore da cui
ottenere i dati;
2. sendRequest(): serve per inviare la richiesta di prelievo dati al concentratore tramite il gateway;
3. readValues(): attende l’arrivo dei dati dal gateway e li legge.
22
3 – Descrizione e sviluppo del progetto
Struttura del Gateway
Il gateway, come abbiamo visto, anche da un punto di vista schematico in figura 3.2, ha l’obiettivo
di intercettare le richieste della centrale per smistarle correttamente ai concentratori presenti sul bus
condiviso. Per tale motivo si richiede ad esso l’onere di gestire la comunicazione tra la centrale e i
concentratori per il prelievo dei dati sensoriali. Anche in questo caso la funzione di setup() provvede
all’inizializzazione del data-rate delle interfacce Serialx; in particolare, in questo caso viene inizializzato
anche il Serial3, utilizzato per il collegamento con il bus RS485 del gateway (supponendo, dunque, un
transceiver i cui pin TX e RX vengano collegati, rispettivamente, ai pin 14 e 15 della board).
1
/********** Setup ***********/
2
3
void setup() {
4
Serial.begin(9600);
Serial.println("Gateway");
Serial.println("[DEBUG] Write an Address, then press ENTER ");
5
6
7
8
pinMode(SSerialTxControl, OUTPUT);
pinMode(CSerialTxControl, OUTPUT);
9
10
11
digitalWrite(SSerialTxControl, RS485Transmit);
digitalWrite(CSerialTxControl, RS485Receive);
12
13
14
Serial2.begin(4800);
Serial3.begin(4800);
15
16
17
initialize_addresses(&sensorAddresses);
18
19
20
}
21
22
/********** Loop ***********/
23
24
void loop() {
25
getSensorFromSerial(address); //Per interazione con la Centrale: getSensorFromCentral();
26
27
int type = getAddressType(address);
28
29
if (type == ISSINGLE)
sendSingleRequest(address);
30
31
32
else if (type == ISGROUP)
sendGroupRequest(address);
33
34
35
else
sendBroadcastRequest(address);
36
37
38
/**** Per interazione con la Centrale ****
sendEndToCentral();
**************************/
digitalWrite(CSerialTxControl, RS485Receive);
39
40
41
42
43
}
Figura 3.6.
Estratto dello sketch Gateway.ino relativo allo sviluppo con protocollo RS485
Relativamente alla funzione di loop() invece, in questo caso, essa consiste nell’attendere un comando
23
3 – Descrizione e sviluppo del progetto
dalla centrale e inviare la richiesta ai concentratori interfaccianti il bus. In particolare:
• getSensorFromCentral(): mette in attesa il gateway di un comando da parte della centrale.
Ritorna quando viene rilevato un indirizzo valido.
• getAddressType(): prelevato l’indirizzo, in virtù delle considerazioni effettuate precedentemente,
è necessario valutare se l’indirizzo sia rivolto ad un singolo concentratore, ad un gruppo oppure
all’intero set di concentratori.
• send[Single/Group/Broadcast]Request(): racchiude la logica di invio delle richieste e ricezione
dei dati dalla centrale.
• sendEndToCentral(): inoltra i dati alla centrale.
In figura 3.6 è rappresentato il codice di sviluppo del Gateway.
Struttura del Concentratore (Sensore)
Anche in questo caso il setup() inizializza i data-rate oltre che settare opportunamente il livello di
tensione e il modo di utilizzo dei pin. Per ciò che riguarda, invece, la funzione di loop(), essa contiene la
logica del concentratore. In particolare esso deve attendere di essere svegliato dal gateway e rispondere
alle richieste.
Come si nota nel codice in figura 3.7, tale logica è racchiusa nelle seguenti procedure:
• WaitForRequest(): mette in attesa il concentratore di ricevere l’indirizzo applicativo. Se tale
coincide con il proprio indirizzo, viene settata una variabile active ad un valore maggiore di zero.
• AnswerRequest(): gestisce la logica di risposta ad una richiesta del gateway. Si noti che tale
funzione viene richiamata esclusivamente se la variabile active corrisponde ad un valore maggiore
di zero.
Protocollo di comunicazione Centrale-Gateway
Come abbiamo specificato nel paragrafo 2.2, il protocollo RS485 è uno standard del livello fisico relativo al
modello ISO/OSI e per tale ragione non specifica alcuna regola circa lo scambio dei dati tra trasmettitore
e ricevente. È, dunque, necessario stabilire a livello applicazione dei vincoli che devono rispettare la
centrale e il gateway durante la loro comunicazione. In figura 3.8 sono presenti estratti di codice circa lo
scambio dell’indirizzo tra le due entità in questione.
Come si può notare, la centrale invia l’indirizzo utilizzando la porta seriale 2 (quindi il pin TX del
transceiver è collegato al pin 16 della board, mentre l’RX al pin 17). D’altra parte, la centrale si mette
in attesa (attiva) dell’indirizzo; non appena il numero di bytes presenti sulla porta seriale in lettura è
pari alla dimensione dell’indirizzo, legge i bytes presenti sulla porta, li elimina dal buffer di input e li
memorizza nel vettore di caratteri address, costruendo una stringa.
Una volta ottenuto l’indirizzo, tramite la funzione getAddressType(), descritta precedentemente, il
24
3 – Descrizione e sviluppo del progetto
1
/***** Setup *****/
2
3
void setup() {
4
Serial.begin(9600);
Serial.println("Sensor ");
5
6
7
pinMode(SSerialTxControl, OUTPUT);
8
9
digitalWrite(SSerialTxControl, RS485Receive);
10
11
RS485Serial.begin(4800);
12
13
14
}
15
16
/***** Loop *****/
17
18
void loop() {
19
WaitForRequest();
20
21
if (active) {
22
23
AnswerRequest();
24
25
} else {
26
27
Serial.println("Address doesn’t match! \nWaiting For Command");
waitForTransmit();
active = FALSE;
28
29
30
31
}
digitalWrite(SSerialTxControl, RS485Receive);
32
33
}
Figura 3.7.
1
Estratto dello sketch Sensore.ino relativo allo sviluppo con protocollo RS485
void sendRequest(char* address) {
1
2
2
Serial2.write(address);
Serial2.flush();
3
4
3
4
5
5
...
6
6
7
8
7
}
8
Figura 3.8.
void getSensorFromCentral(char* address) {
...
if (Serial3.available() >= ADDRESS_SIZE) {
for (int i = 0; i < ADDRESS_SIZE; i++)
address[i] = (char)Serial3.read();
...
}
Scambio indirizzo tra Centrale (a sinistra) e Gateway (a destra)
gateway ne ottiene il tipo (singolo, broadcast o gruppo) e a seconda di esso richiama la funzione
send[Single/Group/Broadcast]Request().
In figura 3.9 è rappresentato uno stralcio di codice, caratterizzante il caso in cui venga richiesto un indirizzo singolo di un concentratore. In particolare si noti che la centrale rimane in attesa mentre il gateway
attende i dati dal/i concentratore/i. Non appena rileva un byte disponibile nel buffer di input, inizia a
prelevare dati (ciò in corrispondenza con l’invocazione, da parte del gateway, di sendToCentral()). In
particolare la centrale entra in un ciclo che termina quando riceve un carattere speciale, ossia "#". Tale
simbolo è inviato dal gateway tramite la procedura sendEndToCentral().
25
3 – Descrizione e sviluppo del progetto
1
2
3
void readValues() {
...
while (true) {
1
2
3
4
4
if (Serial2.available())
{
5
6
5
6
7
7
c = (char)Serial2.read();
8
8
9
9
if (c == ’#’){
...
return;
}
10
11
12
13
10
11
12
13
14
14
...
15
15
16
16
}
17
19
17
}
18
18
}
19
Figura 3.9.
void loop() {
...
sendSingleRequest();
...
sendEndToCentral();
...
}
void sendSingleRequest(char address[]) {
...
sendToCentral(sensors);
...
}
void sendToCentral(int* sensorValues){
...
for(int i = 0; i<NUM_ADC; i++){
Serial3.write(sensorValues[i]);
Serial3.flush();
}
}
Scambio valori dei sensori tra Centrale (a sinistra) e Gateway (a destra)
Protocollo di comunicazione Gateway-Concentratori
Nella figura 3.10 sono presenti i passi fondamentali che descrivono la comunicazione tra il Gateway e i
concentratori. In particolare si consideri anche il codice in figura 3.7.
1
2
3
4
5
6
7
8
void sendSingleRequest(char address[]) {
sendWakeUPCmd();
Serial2.write(address);
Serial2.flush();
...
int* sensors = receiveSensorValue();
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
9
void sendWakeUPCmd() {
Serial2.write("WAKEU");
...
}
10
11
12
13
14
15
16
17
18
19
20
21
22
23
14
int* receiveSensorValue() {
...
while (true) {
if (Serial2.available() >= NUM_ADC) {
...
for (int i = 0 ; i < NUM_ADC; i++)
sensors[i] = Serial2.read();
...
}
Figura 3.10.
15
16
17
18
19
20
21
22
23
void WaitForRequest(){
command = getCommand();
...
address = getAddress();
isMyAdd = compareString(address,ADDRESS,16);
if (isMyAdd == 0)
active = TRUE;
}
void AnswerRequest(){
...
RS485Serial.write(sensorReading);
...
RS485Serial.write("#");
RS485Serial.flush();
...
active = FALSE;
}
void waitForTransmit() {
...
if (RS485Serial.available()){
if ((char)RS485Serial.read() == ’#’)
return;
...}
Comunicazione tra Gateway (a sinistra) e Concentratore (a destra)
Si osservi che il concentratore è in attesa di essere risvegliato tramite la procedura getCommand();
allo stesso tempo il gateway avrà utilizzato la funzione sendWakeUpCmd() per inviare il comando e
successivamente l’indirizzo. Dopo aver recepito l’indirizzo, il concentratore verifica se coincide con il
proprio e, dunque, setta opportunamente la variabile active. Nel caso in cui recepisca un indirizzo non
26
3 – Descrizione e sviluppo del progetto
conforme con il proprio si mette in attesa richiamando la funzione WaitForTransmit(), che attende la
fine della trasmissione in corso. Nel caso contrario, ottenuti i valori dai sensori, il concentratore li invierà
al gateway effettuando una scrittura sulla porta seriale. Quest’ultimo stanzierà in attesa attiva fintanto
che non riceva i valori, attraverso la procedura receiveSensorValue().
Esempio di Testing
Sfruttando il prototipo a disposizione, descritto in figura 2.13, si va ad effettuare un test circa la comunicazione tra il Gateway e il Concentratore. In questo caso rappresentiamo il Gateway attraverso la board
Arduino Mega 2560 mentre il Concentratore attraverso la board Arduino UNO. Entrambi sono dotati di
una scheda con transceiver RS485 mediante la quale comunicano.
(a) Monitor Seriale Gateway
Figura 3.11.
(b) Monitor Seriale Concentratore
Esempio di testing della piattaforma
In figura 3.11 è illustrato un esempio di comunicazione tra tali componenti, utilizzando per il debug
l’interfaccia Serial e dunque il monitor seriale.
3.2.2
Sviluppo con Protocollo RS485 - Architettura raffinata
Così come chiarito nel paragrafo 3.1, il progetto finale prevede una complessità maggiore rispetto allo
sviluppo appena effettuato nel paragrafo 3.2.1, consistente in un’estensione gerarchica dei concentratori. Continuando lo sviluppo attraverso il protocollo wired RS485, osserviamo la necessità di modifica
di alcuni meccanismi affinché il progetto rispecchi l’architettura desiderata, raffigurata in figura 3.12.
Riconsiderando le assunzioni precedentemente fatte, notiamo che tali non possano considerarsi più vere
a causa di differenti aspetti.
In questo caso, infatti, bisogna tener traccia delle seguenti problematiche:
1. L’indirizzamento gerarchico a due livelli, definito nell’architettura precedentemente sviluppata, non
può considerarsi più valido perché impossibilita l’opportunità di sollecitare un concentratore non
direttamente collegato al bus principale;
2. I singoli concentratori sono essi stessi dei gateway verso il bus più esterno.
27
3 – Descrizione e sviluppo del progetto
Figura 3.12.
Schema Architetturale Raffinato del sistema - adattato da [12]
Ciò implica modifiche nel sistema di indirizzamento e nella logica di smistamento dei messaggi dei
gateway/concentratori.
Indirizzamento
La soluzione adottata per risolvere il problema dell’indirizzamento nell’architettura in figura 3.12 è risolto
adottando un indirizzo suddiviso in tre livelli. Supponendo di avere a disposizione un indirizzo di 16bit, l’idea richiede di suddividerlo in tre parti, ottenendo, dunque, due sotto-indirizzi da 5-bit e uno da
6-bit. Ciò permette di indirizzare fino a 32 gruppi, ciascuno contenente fino a 32 concentratori e ogni
concentratore può essere collegato ad un bus secondario con al più 64 concentratori aggregati. In tale
ottica la parte più significativa dell’indirizzo individua il gruppo di concentratori, la parte di intermezzo
individua il concentratore nel gruppo ed infine, la parte meno significativa individua il concentratore
aggregato al bus secondario rispetto al singolo individuato nella parte centrale.
0
|
1
0
1
{z
Gruppo
0}
1
0
1
0
1} 0
1
0 {z 1
0
1}
|
{z
|
Concentratore nel gruppo Concentratore II livello
Figura 3.13.
Modalità di Indirizzamento a tre livelli
In virtù di una tale ripartizione, si definiscono le seguenti assunzioni:
• un indirizzo la cui parte meno significativa corrisponde ad un insieme di 1 e la rimanente parte
risulta composita di bit non necessariamente unitari è un indirizzo di broadcast per il sottogruppo,
ossia per l’insieme dei concentratori collegati al bus secondario rispetto ad un concentratore legato
al bus principale. Ad esempio, l’indirizzo 1010101010111111 sollecita tutti i concentratori che sono
collegati al concentratore individuato nel gruppo 10101 dal sotto-indirizzo 01010.
28
3 – Descrizione e sviluppo del progetto
• un indirizzo le cui parti di intermezzo e meno significativa sono costituite da tutti 1 è un indirizzo
di broadcast per il gruppo individuato dalla parte di indirizzo più significativa.
• un indirizzo costituito interamente da bit alti è un indirizzo di broadcast per l’intero insieme di
concentratori.
• un indirizzo la cui parte meno significativa è costituita da tutti bit 0 localizza il gateway individuato dall’indirizzo corrispondente alla parte di intermezzo nel gruppo individuato dalla parte più
significativa.
In questo caso la struttura memorizzante gli indirizzi dei concentratori rimane invariata, in quanto si
modifica solo la modalità di rappresentazione degli stessi. Analogamente, non si modifica la logica della
centrale che, dunque, si limita a trasmettere comandi al gateway e ad attendere risposta come nel codice
in figura 3.5. Riscontriamo cambiamenti, invece, sia nella logica del concentratore e sia nella logica del
gateway, in conseguenza al problema dell’indirizzamento.
Struttura del Concentratore
Come già accennato, nell’architettura a tre livelli presentata in figura 3.12, il ruolo del concentratore si
amplia in virtù della presenza di un bus secondario a cui vengono collegati ulteriori concentratori. In tale
ottica esso può essere rappresentato alla stessa stregua di un gateway di secondo livello, incapsulando
sia la logica di ottenimento dell’indirizzo dal gateway di primo livello, sia la logica di smistamento delle
richieste ai concentratori secondari.
Così come definito in figura 3.14, notiamo che differentemente dalla funzione di inizializzazione valutata nel precedente progetto, in questo caso vengano utilizzate due porte seriali. In particolare, la porta
Serial2 è utilizzata per la comunicazione del concentratore con il gateway, coerentemente con il progetto
precedente, mentre la porta Serial3 è utilizzata per la comunicazione con il set di concentratori legati
al bus secondario. Per quanto riguarda la funzione di loop(), tale si limita ad attendere l’arrivo di una
richiesta dal gateway e a rispondere ad essa. Nel dettaglio:
• WaitForRequest(): mette il concentratore in attesa di ricevere il comando di Wake-Up e poter,
dunque, ricevere l’indirizzo;
• AnswerRequest(): verifica se l’indirizzo è relativo al concentratore d’interesse e in caso affermativo
risponde alla richiesta.
Struttura del Concentratore (Sensore), del Gateway e della Centrale
In questa architettura, è bene sottolineare che il ruolo del concentratore di secondo livello è analogo al
ruolo del concentratore nello sviluppo considerato nel paragrafo 3.2.1. Ciò si ripete anche per quanto
riguarda la struttura del gateway e della centrale, che ad eccezione di lievi modifiche riguardanti la logica,
rimangono pressoché invariate.
29
3 – Descrizione e sviluppo del progetto
/***** SETUP *****/
1
2
3
void setup() {
4
Serial.begin(9600);
Serial.println("Concentratore ");
5
6
7
8
pinMode(SSerialTxControl, OUTPUT);
pinMode(CSerialTxControl, OUTPUT);
9
10
11
digitalWrite(SSerialTxControl, RS485Receive);
digitalWrite(CSerialTxControl, RS485Transmit);
12
13
14
delay(10);
15
16
initialize_addresses(&m);
17
18
Serial2.begin(4800);
Serial3.begin(4800);
19
20
21
}
22
23
/**** LOOP *****/
24
25
void loop() {
26
WaitForRequest();
27
28
AnswerRequest();
29
30
31
}
Figura 3.14.
Estratto dello sketch Concentratore.ino relativo allo sviluppo con protocollo RS485 Raffinato
Protocollo di comunicazione Gateway-Concentratore
Per ciò che riguarda il protocollo di comunicazione utilizzato tra Gateway e Concentratore (di primo
livello) è utile osservare che tale rimane invariato ad eccezione di due aspetti, rispettivamente relativi
alla gestione dell’indirizzo e all’invio/ricezione dei dati.
In particolare, considerando lo spezzone di codice in figura 3.15, si noti che il numero di dati che può
ricevere il gateway non è deterministico e dipende dal numero di concentratori collegati al concentratore
primario. Per tale motivo si utilizza una variabile size al fine di memorizzare la dimensione del vettore
di valori. D’altra parte, considerando il concentratore di primo livello, esso deve verificare se l’indirizzo
sollecitato dalla centrale è di un membro collegato al bus secondario, oppure se è riferito a sé stesso,
oppure se è un indirizzo broadcast. Si sottolinea che, per convenzione, un indirizzo avente gli ultimi 6-bit
bassi individua il concentratore di primo livello individuato nel gruppo dallo specifico indirizzo.
3.2.3
Sviluppo con Protocollo TCP/IP - Ethernet
Seguendo l’approccio bottom-up, si è partiti da una struttura rispecchiante un’architettura semplificata
del sistema da progettare e si è visto che con qualche opportuna modifica si è potuto ottenere la struttura
complessiva desiderata. In realtà, osservando lo schema in figura 3.1, l’interazione tra la centrale e il
30
3 – Descrizione e sviluppo del progetto
1
int* receiveSensorValue(int* size) {
1
2
2
int sensors[NUM_ADC*64+1];
*size = 0;
while (1) {
3
4
5
3
4
5
6
6
if (Serial2.available() >= NUM_ADC) {
Serial.println("Getting Sensors... ");
while(Serial2.peek()!=’#’){
sensors[*size] = Serial2.read();
(*size)++;
}
7
8
9
10
11
12
7
8
9
10
11
12
13
13
Serial.println("Sensors Obtained!");
break;
14
15
14
15
}
16
16
17
17
}
18
18
19
19
return sensors;
20
20
21
22
21
}
22
Figura 3.15.
int getAddressType(char* address) {
int isGrpBrdcst = 1;
int isSingleGrp = 1;
int isMe = 1;
for (int i = 10; i < 16; i++) {
if (address[i] != ’1’) {
isGrpBrdcst = 0;
break;
}
}
for (int i = 10; i < 16; i++) {
if (address[i] != ’0’) {
isMe = 0;
break;
}
}
if (isGrpBrdcst == 0 && isMe == 0)
return ISME;
if (isGrpBrdcst == 1)
return ISGRPBROADCAST;
return ISGRPSINGLE;
}
Comunicazione tra Gateway (a sinistra) e Concentratore (di primo livello) (a destra)
gateway e tra il gateway e i concentratori dovrebbe essere effettuata attraverso lo standard TCP/IP.
In questa prima parte ci si concentra sul protocollo wired Ethernet 802.3 utilizzando, nell’architettura
prototipale, un Arduino Shield Ethernet 2. Nell’ottica di progetto adoperata, i cambiamenti rispetto
agli sviluppi presenti nei paragrafi 3.2.1 e 3.2.2 sono pochi e non modificanti la logica implementata, in
quanto relativi al differente protocollo adoperato. Si noti, d’altro canto, che, in riferimento alla figura 3.1,
è necessario che il gateway e la centrale siano dotati di connettività GSM/GPRS al fine di evidenziare
malfunzionamenti (attraverso un meccanismo di poling), così come specificato nella sezione 3.1.
Struttura della Centrale
In virtù di quanto specificato, notiamo che la funzione di setup() si arricchisce con l’insieme dei comandi
necessari per l’inizializzazione del modulo Ethernet e GSM, così come riscontrabile in figura 3.16.
A differenza dello sviluppo con RS485, inoltre, vengono a mancare le operazioni di inizializzazione
delle interfacce seriali, non più utilizzate (eccetto l’USB). Notiamo, inoltre, che in questa architettura,
così come preannunciato, il gateway perde le sue funzionalità. In tal senso la logica di smistamento delle
richieste è immersa nella centrale. È possibile verificare che la centrale, infatti, effettua ciclicamente tre
azioni, consistenti nelle procedure:
1. lookForGsmRequest(): verifica l’eventuale presenza di una richiesta di connessione da parte del
gateway;
2. getSensorToCall(): mira ad ottenere l’indirizzo applicativo del concentratore da sollecitare;
3. AnswerRequest(): verifica la natura dell’indirizzo, invia la richiesta e pone la centrale in attesa di
ricevere risposta.
31
3 – Descrizione e sviluppo del progetto
1
/**** SETUP *****/
2
3
4
5
6
7
8
void setup() {
Ethernet.begin(mac, ip);
delay(1000);
Serial.begin(9600);
Serial.println("Gateway");
Serial.println("[DEBUG] Write an Address, then press ENTER ");
9
initialize_addresses(&sensorAddresses);
10
11
boolean notConnected = true;
12
13
while (notConnected) {
if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &
(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
notConnected = false;
} else {
Serial.println("Not connected");
delay(1000);
}
}
14
15
16
17
18
19
20
21
22
23
24
}
25
26
/**** LOOP *****/
27
28
29
30
31
32
void loop() {
lookForGsmRequest();
getSensorToCall();
AnswerRequest();
}
Figura 3.16.
Estratto dello sketch Centrale.ino relativo allo sviluppo con protocollo Ethernet
Struttura del Gateway
Per quanto riguarda il gateway, così come affermato precedentemente, esso perde alcune delle sue funzionalità a scapito di altre. In particolare esso si comporta come un semplice concentratore, con l’aggiunta
che viene utilizzato anche per verificare la corretta funzione del sistema, attraverso il meccanismo di
polling.
In particolare oltre alle classiche operazioni di inizializzazione, la funzione setup() memorizza il
valore in millisecondi del tempo trascorso dall’accensione del sistema attraverso la primitiva millis().
Tale primitiva viene utilizzata per verificare l’inattività della centrale. In alternativa, opportunamente
commentata, è utilizzata una libreria esterna, TimerThree.h, da [18], che sfrutta il meccanismo delle
interruzioni del Timer.
D’altra parte la funzione di loop() si limita a verificare eventuali richieste (anche polling) e fornirne
risposta. In più, nel caso in cui occorra l’inattività della centrale, stabilisce una connessione GPRS con
essa. In particolare, tutto ciò è realizzato attraverso le procedure:
1. AnswerRequest(): non bloccante, risponde ad una eventuale richiesta (o polling) della centrale;
2. createGPRSConnection(): stabilisce una connessione GPRS con la centrale.
32
3 – Descrizione e sviluppo del progetto
1
2
3
4
5
6
/**** SETUP ****/
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
delay(1000);
Serial.println("Gateway ");
7
8
9
10
11
12
13
14
15
16
17
18
19
digitalWrite(CSerialTxControl, RS485Transmit);
delay(10);
initialize_addresses(&m);
/* Opzione Timer3 *
Timer3.initialize(500000);
Timer3.attachInterrupt(createGPRSConnection);
Timer3.start();
*/
Serial3.begin(4800);
server.begin();
start = millis();
}
20
21
/*** LOOP ***/
22
23
24
25
26
27
28
29
30
void loop() {
client = server.available();
AnswerRequest();
checkpoint = millis();
if(checkpoint - start >= MAX_TIME)
createGPRSConnection();
}
}
Figura 3.17.
Estratto dello sketch Gateway.ino relativo allo sviluppo con protocollo Ethernet
Struttura del Concentratore
Il concentratore si discosta, in termini implementativi, di poco dallo sviluppo effettuato attraverso il
protocollo RS485. In sostanza vengono a modificarsi solo le porzioni di codice relative all’interazione
con la centrale (che fa le veci del gateway per quanto specificato precedentemente). Il protocollo utilizzato per l’interazione con i concentratori di secondo livello rimane l’RS485, quindi le porzioni di codice
corrispondenti rimangono intatte.
Notiamo che la funzione di setup() rimane pressoché identica rispetto all’implementazione del gateway, eccezion fatta per l’inizializzazione dei parametri relativi al polling. La funzione di loop(), d’altra
parte, risulta effettuare le stesse operazioni effettuate dal gateway, ad eccezione del richiamo della procedura di creazione della connessione GPRS con la centrale.
Infine, è bene sottolineare che, in accordo alla figura 3.1, rappresentante l’architettura complessiva e definitiva del sistema, la struttura del sensore rimanga invariata rispetto a quella presentata nel paragrafo
3.2.2.
Protocollo di comunicazione Centrale-Gateway
In figura 3.19 sono riportati dei frammenti rispetto alle procedure che definiscono la comunicazione tra
cemtrale e gateway.
33
3 – Descrizione e sviluppo del progetto
1
/***** SETUP ******/
2
3
4
5
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
6
delay (1000);
7
8
Serial.println("Concentratore ");
9
10
pinMode(CSerialTxControl, OUTPUT);
digitalWrite(CSerialTxControl, RS485Transmit);
11
12
13
delay(10);
14
15
initialize_addresses(&m);
16
17
Serial3.begin(4800);
server.begin();
18
19
20
21
}
22
23
24
25
26
27
28
29
/***** LOOP ******/
void loop() {
client = server.available();
if (client) {
AnswerRequest();
}
}
Figura 3.18.
Estratto dello sketch Concentratore.ino relativo allo sviluppo con protocollo Ethernet
Innanzitutto notiamo che la la funzione lookForGsmRequest() verifica l’eventuale presenza di richieste di connessione da parte del gateway pervenute in conseguenza all’assenza del polling. In tale ottica
si constata che il gateway poiché è anche un concentratore, e dunque, anch’esso può ricevere richieste
di prelievo dati dai sensori, è necessario separare le sollecitazioni di polling da quelle di richieste. Per
tale motivo, quando la centrale effettua il polling, invia un carattere speciale al gateway, ossia "*"; lato
ricevente, ad ogni sollecitazione, il gateway verifica, attraverso la procedura getAddress() la natura
della sollecitazione, definendo l’azione da intraprendere. A conclusione notiamo, dunque, che grazie all’approccio di progettazione adoperato, le modifiche da effettuare allo sviluppo presentato nella sezione
3.2.2 sono minimali, riguardanti per lo più le primitive di gestione della comunicazione.
Protocollo di comunicazione Centrale-Concentratore
In questo caso si ripetono esattamente tutte le considerazioni effettuate nella descrizione del protocollo
di comunicazione tra la centrale e il gateway, escludendo, però, quelle relative all’insieme di operazioni
necessarie all’effettuazione del polling e alla conseguente instaurazione di una connessione GPRS.
Esempio di Testing
Così come descritto nel paragrafo 3.2.1, anche in questo caso si riporta un esempio di messa in esercizio
del sistema, simulata attraverso la circuiteria a disposizione. In particolare l’esempio di testing prevede
34
3 – Descrizione e sviluppo del progetto
1
void lookForGsmRequest() {
1
2
GSMClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
//do something
...
3
4
5
6
7
8
9
3
4
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
29
30
31
32
33
34
7
8
}
9
10
void sendRequest(char* address) {
...
if(compareString(address,GATEWAY_ADD,16)!=0)
pollingToGateway();
...
if(client.connect(server, PORT)) {
client.write(address);
client.flush();
int size;
sensors = getDataSensor(&size);
printResult(sensors, size);
while(client.connected());
client.stop();
}
}
}
11
12
13
14
15
16
17
18
20
start = millis();
}
21
22
23
}
24
25
26
27
void pollingToGateway() {
IPAddress server(192, 168, 1, 100);
if (client.connect(server, PORT))
{
client.write("*");
while(client.connected());
client.stop();
28
29
30
31
void sendRequest(char address[]) {
...
int* sensors = receiveSensorValue();
...
waitForEnd();
...
Serial.println("Send to Central");
32
33
34
35
}
36
}
19
35
37
int type = getAddressType(address);
if (type == ISME)
{
readSensor();
sendEnd();
}
else if (type == ISGRPBROADCAST) {
...
}
else {
sendRequest(address);
sendEnd();
}
6
27
28
if (client) {
if (getAddress() == 0) {
5
10
11
void AnswerRequest(){
2
for (int i = 0; i < NUM_ADC; i++)
server.write(sensors[i]);
...
36
}
37
Figura 3.19.
}
Comunicazione tra Centrale (a sinistra) e Gateway (a destra) con Ethernet
l’utilizzo della piattaforma prototipale come un concentratore e l’utilizzo di un comune browser come
centrale. Poiché nello sviluppo appena concluso non si è utilizzato alcun protocollo HTTP, al fine di
permettere la comunicazione con il browser è necessario, all’interno dell’implementazione della centrale,
specificarlo. Ciò si riduce all’aggiunta di stringhe costituenti l’intestazione HTTP. In via semplificativa
si assume che le richieste effettuate dal browser riguardino esclusivamente il concentratore a disposizione.
Sotto tali assunzioni, la funzione readMySensor() si modifica come illustrato in figura 3.20.
In questo modo, attraverso i comandi specificati nell’intestazione HTTP, il contenuto nella pagina
del browser verrà formattato come html.
Per effettuare un test di messa in esercizio del sistema occorre semplicemente collegare la porta Ethernet della scheda Arduino Ethernet Shield 2 ad uno switch Ethernet o ad un router che possiede tale
caratteristica attraverso un cavo RJ45. A questo punto, una volta caricato lo sketch sulla piattaforma,
collegandosi attraverso un browser all’indirizzo IPv4 del concentratore è possibile ottenere l’output così
come specificato in figura 3.21.
35
3 – Descrizione e sviluppo del progetto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void readMySensor() {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("Lettura Sensore: <br> <br>");
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
client.print(sensorReading);
client.print("<br>");
}
Serial.println("Value Sent");
}
Figura 3.20.
Estratto dello sketch Concentratore.ino relativo alla funzione ReadMySensor() - Ethernet
(a) Browser Web - 192.168.1.101
Figura 3.21.
3.2.4
(b) Monitor Seriale Concentratore
Esempio di testing della piattaforma con Ethernet
Sviluppo con Protocollo TCP/IP - WiFi
In questa sezione si va a presentare una prototipazione del progetto esposto in figura 3.1, attraverso lo
standard IEEE WiFi 802.11. Si noti che poiché viene a modificarsi esclusivamente il mezzo di comunicazione, le uniche modifiche da effettuare, rispetto al progetto di sviluppo attraverso lo standard Ethernet,
implementato nel paragrafo 3.2.3, sono relative alle primitive necessarie all’utilizzo del mezzo. Nel dettaglio si ricordi, dalla sezione 2.2, che il modulo utilizzato nel prototipo per usufruire della connessione
WiFi è un ESP8266, il cui funzionamento è legato all’impiego di comandi AT.
Struttura della Centrale
In figura 3.22 è rappresentato un’estratto della struttura dello sketch relativo all’implementazione della
centrale. In particolare si noti come il flusso logico delle operazioni effettuate da essa rimanga invariato
rispetto allo sviluppo presentato con lo standard Ethernet e che le differenze sono visibili nella funzione
di inizializzazione. Come possiamo osservare, nella funzione di setup() sono evidenziati l’insieme dei
comandi necessari alla messa in esercizio del modulo WiFi. In particolare, tali comandi sono invocati
36
3 – Descrizione e sviluppo del progetto
1
/**** SETUP *****/
2
3
4
5
6
7
8
9
void setup() {
...
String cwjap="AT+CWJAP=\"";
cwjap+=SSID;
cwjap+="\",\"";
cwjap+=PASS;
cwjap+="\"\r\n";
10
String cipsta="AT+CIPSTA_CUR=\"";
cipsta+=myIp;
cipsta+="\",\"192.168.1.1\",\"255.255.255.0\"";
cipsta+="\"\r\n";
11
12
13
14
15
sendData("AT+RST\r\n",2000);
sendData("AT+CWMODE=1\r\n",1000);
sendData(cwjap,2000);
sendData(cipsta,5000);
sendData("AT+CIFSR\r\n",5000); //Per Debug
sendData("AT+CIPMUX=1\r\n",1000);
16
17
18
19
20
21
22
}
23
24
/**** LOOP *****/
25
26
27
void loop() {
lookForGsmRequest();
28
getSensorToCall();
29
30
AnswerRequest();
31
32
}
Figura 3.22.
Estratto dello sketch Centrale.ino relativo allo sviluppo con WiFi
attraverso l’utilizzo della routine sendData(), di cui si discuterà a seguire. Le operazioni effettuate in
fase di inizializzazione prevedono:
1. Restart del modulo attraverso il comando AT+RST;
2. Setting della modalità di funzionamento stazione ottenuto attraverso il comando AT+CWMODE=1;
3. Join all’Access Point attraverso il comando AT+CWJAP="SSID","PASS";
4. Setting dell’IP Statico attraverso il comando AT+CIPSTA_CUR = "IP", "GATEWAY", "SUBNET-MASK";
5. Setting della connessione multipla attraverso il comando AT+CIPMUX = 1.
Per quanto riguarda, invece, la struttura della procedura loop(), essa rimane inalterata. Vengono
a modificarsi esclusivamente le istruzioni necessarie alla comunicazione con i concentratori ma non la
logica della stessa. Ricordando quanto esposto nella sezione 3.2.3, la funzione AnswerRequest() ha il
compito di inviare la richiesta al/i concentratore/i e attendere la ricezione dei dati. In figura 3.23 sono
presenti degli estratti dello sketch Centrale.ino che illustrano l’invio della richiesta di prelievo dati e
del polling al gateway. In particolare si noti che la centrale, affinché sia in grado di comunicare con i
concentratori deve stabilire con essi una connessione TCP, e, di conseguenza, ad essa devono essere noti
37
3 – Descrizione e sviluppo del progetto
sia l’indirizzo IPv4 sia il porto in cui il server è in ascolto. La comunicazione, ovviamente, avviene solo se
è possibile instaurare la connessione. Ciò viene eseguito attraverso il comando AT+CIPSTART. Una volta
terminate le operazioni, viene richiesta la chiusura della connessione attraverso il comando AT+CIPCLOSE.
1
2
3
4
5
6
7
8
9
10
void SendRequest(){
...
String server = String(ip[0]);
...
String cipStart = "AT+CIPSTART=";
cipStart += connectionId;
cipStart += ",TCP,";
cipStart += server;
cipStart += ",";
cipStart+= PORT;
1
String gateway = "192.168.1.100";
3
4
String cipStart = "AT+CIPSTART=";
cipStart += connectionId;
cipStart += ",TCP,";
cipStart += gateway;
cipStart += ",";
cipStart += PORT;
5
6
7
8
9
10
11
11
String res = sendData(cipStart, 2000);
12
String res = sendData(cipStart, 2000);
12
13
13
if(res.compareTo("OK") == 0) {
14
if (res.compareTo("OK") == 0)
{
String charForPolling = "*";
String cipSend = "AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend += charForPolling.length();
cipSend += "\r\n";
sendData(cipSend, 1000);
sendData(charForPolling, 1000);
14
15
15
String cipSend = "AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend +=server.length();
cipSend +="\r\n";
sendData(cipSend,1000);
sendData(address,1000);
int size;
sensors = getDataSensor(&size);
printResult(sensors, size);
String closeCommand = "AT+CIPCLOSE=";
closeCommand+=connectionId;
closeCommand+="\r\n";
sendData(closeCommand,3000);
}
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
16
17
18
19
20
21
22
23
24
sendData("AT+CIPCLOSE", 1000);
String closeCommand = "AT+CIPCLOSE=";
closeCommand += connectionId;
closeCommand += "\r\n";
sendData(closeCommand, 3000);
25
26
27
28
29
30
}
31
32
void pollingToGateway() {
2
}
31
}
32
}
Figura 3.23. Estratto dello sketch Centrale.ino relativamente alle funzioni SendRequest() (a
sinistra) e pollingToGateway() (a destra)
Struttura del Gateway e Concentratore
In riferimento alla figura 3.1 si osserva come, utilizzando una rete TCP/IP, il gateway e il concentratore
si comportano, rispetto alla centrale, alla stregua dei server. È pertanto necessario definire, attraverso
comandi AT, rispetto alla implementazione della centrale, oltre all’indirizzo IP anche il porto di listening.
Ciò avviene attraverso il comando seguente che registra, nel caso in esempio, il server sul porto 8080:
sendData("AT+CIPSERVER=1,8080\r\n",1000);
È importante osservare che, così come nello sviluppo tramite Ethernet, anche in questo caso la struttura del concentratore (sensore) rimane invariata in quanto esso continua a comunicare con il concentratore
che abbiamo definito di primo livello attraverso un collegamento a bus RS485.
38
3 – Descrizione e sviluppo del progetto
Procedura di invio comandi e dati
Così come si è accennato poc’anzi, l’invio del comandi AT viene effettuato attraverso l’utilizzo della
procedura String sendData(String cmd, int timeout) che utilizza come parametri di input:
• String cmd che rappresenta il comando AT;
• int timeout che rappresenta il tempo massimo di attesa di una risposta;
Tale procedure ritorna la risposta, ossia l’esito del comando.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String sendData(String command, const int timeout)
{
String response = "";
Serial1.print(command); // send the read character to the esp8266
long int time = millis();
while( (time+timeout) > millis())
{
while(Serial1.available())
{
char c = Serial1.read();
response+=c;
}
}
return response;
}
Figura 3.24.
Implementazione della procedura sendData()
In figura 3.24 è rappresentata l’implementazione della procedura di invio comandi. Per quanto riguarda l’invio di dati è importante osservare che, in riferimento all’utilizzo del modulo ESP8266, prima
dell’invio effettivo degli stessi è necessario, tramite il comando AT+CIPSEND, definire la lunghezza della
stringa che s’intende trasmettere e fornire l’id della connessione. Si consideri l’esempio, in figura 3.25,
dove è possibile notare l’invio del comando AT+CIPSEND specificante il numero di bytes da trasmettere e
successivamente il carattere trasmesso.
1
void sendEnd() {
2
String endChar = "#";
String cipSend = "AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend += endChar.length();
cipSend += "\r\n";
3
4
5
6
7
8
9
sendData(cipSend, 1000);
sendData(endChar, 1000);
10
11
12
String closeCommand = "AT+CIPCLOSE=";
...
13
14
15
}
Figura 3.25.
Modalità di invio dati, estratto dallo sketch Concentratore.ino
39
3 – Descrizione e sviluppo del progetto
Esempio di Testing
Analogamente a quanto definito nei paragrafi 3.2.1 e 3.2.3, si riporta un esempio di messa in opera del sistema. Anche in questo caso si simula una versione semplificata del sistema, eseguibile sulla
piattaforma a disposizione, che agirà da concentratore. Analogamente all’esempio di testing tramite
Ethernet, il client sarà rappresentato da un browser web e per tale motivo, al fine di permettere la
comunicazione, è necessario aggiungere le stringhe relative all’intestazione HTTP. Sotto tali assunzioni,
la funzione readMySensor() si modifica come illustrato in figura 3.26 con l’aggiunta della procedura
sendHTTPHeader().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void sendHTTPHeader(int connectionId){
String http[6];
String cipSend = "";
http[0] = "HTTP/1.1 200 OK\r\n";
http[1] = "Content-Type: text/html\r\n\r\n";
http[2] = "<!DOCTYPE html>\r\n";
http[3] = "<html>\r\n";
http[4] = "<body>\r\n";
http[5] = "Lettura Sensori: <br><br>";
for(int i = 0 ; i < 6; i++)
{
cipSend = "AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend +=http[i].length();
cipSend +="\r\n";
sendData(cipSend,1000);
18
sendData(http[i],1000);
}
19
20
}
21
22
23
void readMySensor() {
24
connectionId = Serial1.read()-48;
delay(1);
sendHTTPHeader(connectionId);
25
26
27
28
String breakLine = "<br>";
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
29
30
31
String sensorReading = (String)analogRead(analogChannel);
...
32
33
34
}
String closeCommand = "AT+CIPCLOSE=";
...
Serial.println("Value Sent");
35
36
37
38
}
Figura 3.26.
Estratto dello sketch Concentratore.ino relativo alla funzione readMySensor() - WiFi
L’intestazione HTTP così descritta permetterà la visualizzazione dell’output all’interno del browser
attraverso una formattazione html.
Per effettuare un test di messa in esercizio del sistema occorre semplicemente disporre di un access
point oppure di un router che integra tale funzione. A questo punto, una volta caricato lo sketch sulla
40
3 – Descrizione e sviluppo del progetto
piattaforma, collegandosi attraverso un browser all’indirizzo IPv4 del concentratore è possibile ottenere
l’output così come specificato in figura 3.27.
(a) Browser Web - 192.168.1.101
Figura 3.27.
3.3
(b) Monitor Seriale Concentratore
Esempio di testing della piattaforma con WiFi
Scheduling delle Richieste
Al fine di prevedere un meccanismo di invio periodico delle richieste ai concentratori, è stato realizzato,
con l’intento di governare la logica della centrale, un semplice scheduler, principalmente basato sull’algoritmo di scheduling per task periodici EDF2 , non preemptive, con supporto anche per task aperiodici.
Poiché non supporta la prelazione dei task, l’algoritmo non può essere considerato ottimo nel senso dello
scheduling [5].
Esso è implementato come una libreria Arduino, e può essere facilmente utilizzato in un qualunque sketch
per il quale sia necessario temporizzare le operazioni definite nella funzione di loop().
3.3.1
Design dello scheduler
Nello stralcio di codice in figura 3.28 è definita una struttura rappresentante, nel contesto dell’algoritmo,
un descrittore del task. Tale struttura consta di diversi campi descritti di seguito:
• taskF_ptr *function: rappresenta un puntatore alla funzione che deve eseguire il task;
• void *fun_args: sono gli argomenti, ossia i parametri della funzione al punto precedente;
• int task_type: rappresenta il tipo di task: periodico, aperiodico, idle oppure non settato.
• long period: è il periodo del task, espresso in millisecondi.
2 Earliest
Deadline First, schedula i processi dinamicamente, relativamente alla deadline più imminente
41
3 – Descrizione e sviluppo del progetto
• unsigned long nextJobTime: è compilato solo per task periodici, rappresenta il tempo di attivazione dell’istanza successiva del task;
• int status: è lo stato del task, che può essere: pronto, in attesa del periodo, fine esecuzione o
reset.
• long release: definisce il release time, ossia il tempo di arrivo, del task.
1
typedef struct {
1
2
3
4
5
6
7
8
9
typedef struct {
2
taskF_ptr *function;
void *fun_args;
int task_type;
long period;
unsigned long nextJobTime;
int status;
long release;
task_str task_list[MAX_TASK_NUM];
3
4
5
}sched_str;
10
11
}task_str;
Figura 3.28. Estratto del file myScheduler.h - Descrittore del task (a sinistra) e Struttura
dello scheduler (a destra)
La coda di scheduling è visualizzata come un vettore di descrittori di task. Tale è utilizzata al fine
di definire il meccanismo di scelta del processo da eseguire.
1
/****** Funzioni di Utility ******/
2
3
4
5
6
7
8
void task_str_reset(task_str*);
void sched_init(sched_str*);
void task_set(task_str*, taskF_ptr*, void*, long, int, long);
int make_task_ready(task_str*, sched_str*);
void sched_set_tasks(sched_str*);
void _schedule(sched_str*);
Figura 3.29.
Estratto del file myScheduler.h - Procedure di Utility dello Scheduler
L’insieme delle operazioni che devono essere effettuate per la configurazione e utilizzo dello scheduler
sono riportate in figura 3.29 e di seguito vengono descritte nel dettaglio, anche in relazione al loro utilizzo:
• void task_str_reset(task_str*): è una funzione che viene utilizzata per resettare il descrittore
del task; tipicamente può essere utilizzata quando un task aperiodico termina la sua esecuzione o
in fase di inizializzazione;
• void sched_init(sched_str*): tale funzione è utilizzata per inizializzare la struttura di scheduling, e, in particolare, il vettore dei task della struttura sched_str descritta poc’anzi;
• void task_set(task_str*, taskF_ptr*, void*, long, int, long): è una funzione utilizzata
per settare le caratteristiche di un task attraverso il proprio descrittore (nell’ordine, il puntatore
alla struttura del task, il puntatore alla funzione da eseguire, eventuali argomenti, il periodo, il
tipo e il tempo di arrivo) . È richiamata prima dell’inserimento del task nella coda di scheduling;
42
3 – Descrizione e sviluppo del progetto
• int make_task_ready(task_str*, sched_str*): è la funzione che, effettivamente, registra il
task all’interno della coda di scheduling, registrandolo come pronto. Ritorna un valore che contrassegna l’esito dell’operazione;
• void sched_set_tasks(sched_str*): è una operazione che viene effettuata per settare, in presenza di un task periodico, per la sua prima istanza, il valore della prima deadline assoluta, e quindi
della sua prossima attivazione (analogamente, per task aperiodici definisce la deadline assoluta).
• void _schedule(sched_str*): tale funzione richiama lo scheduler, e deve essere eseguita come
unica azione all’interno della procedura di loop() di uno sketch Arduino.
3.3.2
Esempio di utilizzo
Utilizzando l’architettura prototipale presentata nel paragrafo 2.2 e, allo stesso tempo, lo sviluppo del progetto presentato nella sezione 3.2.1 si costruisce di seguito una centrale che invia richieste periodicamente
all’unico sensore (per motivi di testing) presente nel sistema.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void setup() {
Serial.begin(9600);
Serial.println("Gateway");
pinMode(SSerialTxControl, OUTPUT);
pinMode(CSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, RS485Transmit);
digitalWrite(CSerialTxControl, RS485Receive);
Serial2.begin(4800);
Serial3.begin(4800);
initialize_addresses(&sensorAddresses);
/*** ISTRUZIONE PER L’INIZIALIZZAZIONE DELLO SCHEDULER ***/
scheduler = (sched_str*)malloc(sizeof(sched_str));
myTask = (task_str*)malloc(sizeof(task_str));
sched_init(scheduler);
task_set(myTask, (taskF_ptr*) fun , (void*)0, 2000, PERIODIC,0);
make_task_ready(myTask, scheduler);
sched_set_tasks(scheduler);
}
Figura 3.30. Estratto dello sketch (inizializzazione) Gateway.ino utilizzato come centrale
nel testing dello scheduler
1
2
3
4
5
6
7
8
9
10
11
12
void fun(void* arg) {
...
int type = getAddressType(address);
if (type == ISSINGLE)
sendSingleRequest(address);
else
...
}
/********* Loop ***********/
void loop(){
_schedule(scheduler);
}
Figura 3.31.
Estratto dello sketch Gateway.ino utilizzato come centrale nel testing dello scheduler
43
3 – Descrizione e sviluppo del progetto
In figura 3.30 è rappresentata la funzione di inizializzazione del gateway che, in questo caso, lo
si fa operare da centrale simulando sempre la richiesta dello stesso indirizzo. In particolare si nota
l’insieme delle istruzioni che permettono l’inizializzazione dello scheduler; nel dettaglio è utile osservare
la definizione di un unico task periodico di periodo pari a 2 secondi con tempo di arrivo pari a 0, a cui
è assegnata la funzione fun, descritta in figura 3.31. Tutta la logica della centrale è quindi incapsulata
all’interno della funzione fun. La procedura loop() si limita a richiamare la primitiva _schedule()
dello scheduler, atta a verificare la presenza di eventuali task pronti e ad eseguirli nel rispetto dei vincoli.
In figura 3.32 è presentato uno screenshot dell’output di esecuzione del Gateway utilizzato come centrale.
Figura 3.32.
Screenshot del monitor seriale del Gateway utilizzato come centrale
44
Capitolo 4
Conclusioni
L’elaborato ha presentato un progetto volto allo sviluppo di una rete sensoriale, utilizzando sia tecnologie
wired che wireless. A tal fine si è reso necessario introdurre diversi concetti preliminari, atti a fornire
una base teorica alla realizzazione del sistema. In particolare, si è iniziato con un breve studio dei sistemi
embedded, richiamando delle definizioni fondamentali, caratteristiche, fini e scopi di utilizzo. Si sono
descritte problematiche di realizzazione hardware e di sviluppo software, caratterizzando le differenze
rispetto ad un sistema general-purpose, considerando come esempio il sistema di antibloccaggio delle
ruote (ABS) presente, ormai, in tutto il settore automotive. Si è osservato che il core di un sistema
embedded è il microcontrollore e che, a seconda della complessità del sistema da realizzare, vadano
utilizzati differenti livelli di sofisticatezza di esso. Si è citato una importante classe di sistemi integrati,
ossia il settore real-time, che introduce vincoli temporale rispetto alle esecuzioni delle operazioni del
sistema. Infine si sono considerati e classificati, a seconda della complessità del sistema, dei requisiti
generali di sviluppo per i sistemi in questione.
Con questa breve introduzione, si è passati allo studio della piattaforma Arduino. In particolare, a tal
proposito, è stato presentato il prototipo fisico utilizzato per il testing del sistema, e si sono dettagliate
le sue parti componenti da un punto di vista hardware.
Tutto ciò è stato da introduzione per lo sviluppo effettivo del progetto, che è stato condotto con un
approccio modulare a complessità crescente, considerando dapprima l’utilizzo di protocolli wired e, in
un secondo momento, di protocolli wireless. La prima architettura presentata ha utilizzato un protocollo
RS485, che come abbiamo potuto constatare, non definisce alcuna regola di comunicazione, ed è stato,
quindi, compito dello sviluppatore definire un protocollo in tal senso. Lo stesso è stato utilizzato,
con opportune modifiche, anche nello sviluppo wired tramite lo standard Ethernet e nello sviluppo
wireless tramite lo standard 802.11. Si è presentata, infine, un’implementazione di uno scheduler per lo
smistamento delle richieste sensoriali temporizzato ed un corrispondente esempio di utilizzo nel sistema
progettato, evidenziandone l’efficacia. Per concludere, è importante sottolineare il fondamentale supporto
di Arduino allo sviluppo embedded attraverso la definizione di un set di API organizzate in librerie.
Con quanto specificato è bene constatare che non si è chiuso in alcun modo lo sviluppo del sistema, in
quanto tale rimane comunque aperto a estensioni e ottimizzazioni.
45
Riferimenti
[1] M. Wolf, " Computers as Components, Third Edition: Principles of Embedded Computing System
Design ", Morgan Kaufmann, 2012.
[2] M. Barr, " Programming Embedded Systems in C and C++ ", O’Reilly Media, 1st Ed., 1999.
[3] F. Vahid & T. Givargis, " Embedded System Design: A Unified Hardware/Software Introduction ",
John Wiley & Sons, 2nd Ed., 2003.
[4] R. Kamal, " Embedded Systems: Architecture, Programming and Design ", McGraw-Hill, 2nd Ed.,
2009.
[5] G. Buttazzo, " Sistemi in tempo reale ", Pitagora Editrice, 3rd Ed., 2006.
[6] Datasheet Atmel ATmega640/V-1280/V-1281/V-2560/V-2561/V, 2014.
[7] W5500 Datasheet Version 1.0.6, 2013.
[8] M10 Hardware Design, 2010.
[9] ESP8266EX Datasheet Version 4.3, 2015.
[10] ESNx5HVD08 Wide Supply Range RS-485 Transceiver, 2015.
[11] Datasheet ATmega48A/PA/88A/PA/168A/PA/328/P, 2015.
[12] Dispense Prof. Alessandro Cilardo.
[13] Wikipedia - ABS, https://it.wikipedia.org/wiki/Sistema_anti_bloccaggio.
[14] Arduino, http://arduino.org.
[15] Quectel, http://www.quectel.com.
[16] ESP8266-Comandi AT,
http://www.electrodragon.com/w/index.php?title=Category:ESP8266.
[17] Texas Instruments, http://www.ti.com.
[18] TimerThree Library, https://github.com/PaulStoffregen/TimerThree.
[19] Simple Scheduler Arduino,
https://www.cyphar.com/blog/post/making-a-simple-scheduler-for-arduino
46