4. Codice Coordinatore e nodo generico - Giachelli/Apio-RSSI1 GitHub Wiki
L'Apio Dongle coordinatore ha il compito di creare, controllare e mantenere la rete Mesh. Questo vuol dire che tutte le informazioni che le General si inviano vengono centralizzate in esso. Quindi, esso acquisisce tutti i vari valori di RSSI che le General ricevono. E' il responsabile del passaggio dei dati sulla piattaforma (essendo il "capo" della rete Mesh).
#include <avr/wdt.h>
#include "Apio.h"
#include "property.h"
int RX=9;
int TX=10;
int RF = 15;
int T = 13;
int E = 14;
int S = 12;
int Tf = 11;
void setup() {
wdt_disable();
pinMode(RX,OUTPUT);
pinMode(TX,OUTPUT);
pinMode(RF,OUTPUT);
pinMode(T,OUTPUT);
pinMode(E,OUTPUT);
pinMode(S,OUTPUT);
pinMode(Tf,OUTPUT);
Apio.setup("Coordinatore", "1,0", 0, 0x01);
wdt_enable(WDTO_4S);
//UBRR0H = 0;
//UBRR0L = 0;
}
int flagP = 0;
unsigned long previousM = 0;
unsigned long previousM1 = 0;
int t = 0;
void loop(){
Apio.loop();
wdt_reset();
digitalWrite(RX,LOW);
digitalWrite(TX,LOW);
if(millis()-previousM>150){
digitalWrite(RX,LOW);
digitalWrite(TX,LOW);
previousM = millis();
}
if(millis()-previousM1>800){
digitalWrite(RF,LOW);
digitalWrite(T,LOW);
digitalWrite(E,LOW);
digitalWrite(S,LOW);
digitalWrite(Tf,LOW);
previousM1 = millis();
}
}
Per analizzare il comportamento del nodo generico bisogna fare una suddivisione tra quei nodi che sono le porte e quei nodi che invece sono in movimento. Infatti, ogni nodo porta riceve ed invia solo ai nodi in movimento e mostra il suo valore di RSSI relativo ai segnali che gli altri nodi gli inviano. Inoltre, appena ha ricevuto tutti i valori di RSSI che si aspetta, invia al coordinatore tutti i valori che ha ricevuto. Stesso discorso per i nodi in movimento, che inviano e ricevono solo ai nodi porta e poi inviano il tutto al coordinatore.
/* Ogni nodo generico invia e riceve dagli altri nodi e mostra il suo valore di RSSI relativo ai segnali che gli altri nodi gli inviano. Inoltre, appena ha ricevuto tutti i valori di RSSI che si aspetta, invia al coordinatore tutti i valori che ha ricevuto. */
Nello specifico analizziamo il codice del nodo della porta1 (gli altri 3 nodi delle porte hanno il medesimo codice con alcune ovvie differenze sull'assegnazione di alcune variabili).
#include "Apio.h"
#include "property.h"
int pin20=20;
int pin21=21;
int pin0=0;
int pin9=9;
int addressNodo = 1; //il nodo 2 avrà 2, il nodo 3 avrà 3, il nodo 4 avrà 4
int maxNode = 10; //è il numero totale dei nodi( ossia i nodi a cui devo inviare)
void setup() {
Apio.setup("Porta1", "1,0", addressNodo, 0x01);
pinMode(pin20,OUTPUT);
digitalWrite(pin20,LOW);
pinMode(pin21,OUTPUT);
digitalWrite(pin21,LOW);
pinMode(pin9,OUTPUT);
digitalWrite(pin9,LOW);
}
int ping = 0;
unsigned long preMillis1 = 0;
unsigned long preMillis = 0;
int index = 5; //lo faccio partire da 5 essendo la 5 il primo nodo in movimento a cui inviare
int value = 0;
void loop(){
Apio.loop();
if(millis()-preMillis>500){ // ogni mezzo secondo invio al nodo a cui devo inviare
SYS_TaskHandler();
Apio.sendTo = String(index); //stabilisco chi deve essere il destinatario di quello che sto per inviare
Apio.mex = "1:ping:"+String(value)+"-"; //questo è il messaggio di conferma che voglio dopo ogni invio
Apio.send(); //invio(non specifico alcun parametro in quanto devo solo inviare un segnale, nient'altro)
//al nodo preso in considerazione
Serial.println(index);
preMillis = millis();
index++;
if(index>maxNode){
index=5;
}
if(value==0){
value=1;
} else {
value = 0;
}
}
if(millis()-preMillis1>3000){ //ogni 3 secondi invio al coordinatore
Apio.send("12:update:Persone:"+String(Apio.rssi[5])+"0"+String(Apio.rssi[6])+"0"+String(Apio.rssi[7])+"0"+String(Apio.rssi[8])+"0"+String(Apio.rssi[9])+"0"+String(Apio.rssi[10])+"-"); //questo è quello che invio al coordinatore
//che poi mi permetterà la visualizzazione
//dei risultati sull'app
ping++; // lo incremento ogni volta che invio al coordinatore
preMillis1 = millis();
Serial.println("ping");
Serial.println(ping);
}
Invece, il codice relativo ad un nodo in movimento: ( analizziamo il codice del nodo5 tanto gli altri 5 nodi che rappresentano il nodo in movimento hanno il medesimo codice con alcune ovvie differenze sull'assegnazione di alcune variabili).
#include "Apio.h"
#include "property.h"
int pin20=20;
int pin21=21;
int pin0=0;
int pin9=9;
int addressNodo = 5; //il nodo 6 avrà 6, il nodo 7 avrà 7 e così via
int maxNode = 4; //è il numero totale delle porte( ossia i nodi a cui devo inviare)
void setup() {
Apio.setup("nodo5", "1,0", addressNodo, 0x01);
pinMode(pin20,OUTPUT);
digitalWrite(pin20,LOW);
pinMode(pin21,OUTPUT);
digitalWrite(pin21,LOW);
pinMode(pin9,OUTPUT);
digitalWrite(pin9,LOW);
}
int ping = 0;
unsigned long preMillis1 = 0;
unsigned long preMillis = 0;
int index = 1; //lo faccio partire da 1 essendo la prima porta
int value = 0;
void loop(){
Apio.loop();
if(millis()-preMillis>500){ // ogni mezzo secondo invio al nodo a cui devo inviare
SYS_TaskHandler();
Apio.sendTo = String(index); //stabilisco chi deve essere il destinatario di quello che sto per inviare
Apio.mex = "1:ping:"+String(value)+"-"; //questo è il messaggio di conferma che voglio dopo ogni invio
Apio.send(); //invio(non specifico alcun parametro in quanto devo solo inviare un segnale, nient'altro)
//al nodo preso in considerazione
Serial.println(index);
preMillis = millis();
index++;
if(index>maxNode){
index=1;
}
if(value==0){
value=1;
} else {
value = 0;
}
}
if(millis()-preMillis1>5000){ //ogni 5 secondi invio al coordinatore
Apio.send("16:update:Porte:"+String(Apio.rssi[1])+"0"+String(Apio.rssi[2])+"0"+String(Apio.rssi[3])+"0"+String(Apio.rssi[4])+"-"); //questo è quello che invio al coordinatore che poi mi permetterà la visualizzazione dei
//risultati sull'app
ping++; //ogni qualvolta invio al coordinatore lo incremento
preMillis1 = millis();
Serial.println("ping");
Serial.println(ping);
}
}
Le parti fondamentali che necessitano di uno sguardo più da vicino sono Apio.setup e Apio.loop. Questi due metodi sono definiti all'interno della libreria Apio.h (implementata seguendo lo schema del Lightweight Mesh (3.Apio Mesh)).
Alla funzione setup vengono passati 4 parametri che sono (in ordine):
- nome dell'applicazione a cui vogliamo legare tale sketch;
- la revisione di tale sketch;
- l'indirizzo del nodo a cui è legato tale sketch;
- il Pan ID (personal area network identifier) del nodo;
Nel caso specifico del coordinatore, il suo indirizzo è 0 e il passaggio di tale parametro alla funzione è fondamentale in quanto mi permette di accedere a funzioni che sono costruite apposta per il coordinatore all'interno del setup o delle funzioni che in esso sono richiamate. Nel caso dei nodi è importante che abbiano l'indirizzo diverso da 0 altrimenti accedono, erroneamente, alle funzioni del coordinatore.
void ApioClass::setup(const char *sketchName, const char *sketchRevision, const uint16_t theAddress, const uint16_t thePanId) {
this->sketchName = sketchName;
this->sketchRevision = sketchRevision;
this->hi = 0;
SYS_Init();
PHY_RandomReq();
NWK_Init();
Serial.begin(BAUDRATE); //il Baudrate impostato per il coordinatore è un 1000000, quello dei nodi generici è
//115200
theAdd= theAddress;
if(theAddress==0)
{
this->isDongle=1;
Serial.println("COORDINATOR ACTIVE");
} else {
this->isDongle=0;
Serial.println("Sono una General");
send(String(theAddress)+":hi::-");
}
int pan = getPanId();
//int pan = (int)thePanId;
Serial.println("Pan ID vale "+String(pan));
meshSetRadio(theAddress, pan, 0x1a);
//Canale di ascolto di default messaggi Apio
meshListen(1, receive); //la receive è una funzione che permette al nodo di prepararsi alla ricezione del dato,
//è la callback di indicazione dei dati di cui parlavamo in 2.Apio Mesh (nell'
//Application endpoint o nella sezione: "Ricezione del dato")
for(int j=0; j<10; j++){
codaInvio[j]="";
}
}
static bool receive(NWK_DataInd_t *ind) {
if(Apio.isDongle) //entriamo se siamo il coordinatore
{ //il coordinatore si prepara alla ricezione del dato da un generico nodo
digitalWrite(9,HIGH);
int message_size=ind->size;
char bufferL[62]=" ";
for(int i=0; i<message_size; i++)
{
//Serial.print(ind->data[i]);
bufferL[i] = ind->data[i];
}
Serial.println(String(bufferL));
//questa concatenazione di if e di digitalWrite mi permette di vedere sul Dongle (tramite
//i led)
if(ind->rssi<= 5){
//the worst
digitalWrite(11,HIGH);
} else if(ind->rssi> 5 && ind->rssi <= 10){
digitalWrite(12,HIGH);
digitalWrite(11,HIGH);
} else if(ind->rssi > 10 && ind->rssi <= 15){
digitalWrite(14,HIGH);
digitalWrite(12,HIGH);
digitalWrite(11,HIGH);
} else if(ind->rssi >15 && ind->rssi <= 23){
digitalWrite(13,HIGH);
digitalWrite(14,HIGH);
digitalWrite(12,HIGH);
digitalWrite(11,HIGH);
} else {
//the best
digitalWrite(15,HIGH);
digitalWrite(13,HIGH);
digitalWrite(14,HIGH);
digitalWrite(12,HIGH);
digitalWrite(11,HIGH);
}
return true;
} else { //entro qui se sono un nodo generico
//Serial.println("Ciao ho ricevuto questo");
int message_size=ind->size;
int i;
char Buffer[110];
String receivedL="";
for(i=0; i<message_size; i++)
{
Buffer[i] = ind->data[i];
}
NWK_SetAckControl(ind->rssi); //questa funzione mi permette di rimandare, da chi ho ricevuto, oltre al
//ack anche il valore di RSSI ricevuto
Serial.println("Questo è l'rssi");
Serial.println(String(ind->rssi));
Serial.println(String(ind->srcAddr));
Apio.rssi[ind->srcAddr] = ind->rssi; // RSSI è un vettore di interi e nel indice ( coincidente con l'indirizzo
// di chi invia) salvo il valore dell'RSSI del nodo che sto analizzando
// rispetto al nodo che mi ha inviato
divide_string(String(Buffer)); //è una funzione che mi permette di scompattare il messaggio che mi arriva in
//deviceAddress, messageId, proprietà e valore che mi servono poi per
//l'applicazione all'interno del sistema
for(int i=0; i<100; i++)
{
Buffer[i]=NULL;
}
return true;
}
}
ApioLoop () consente di ricevere messaggi e di selezionare la coppia corrente"proprietà: valore" da elaborare nel corrente ciclo principale. Ciò è dovuto al fatto che lo sketch ha la possibilità di eseguire una coda di comandi multipli dal server, ma è necessario preoccuparsi solo di controllare il valore delle variabili denominate 'proprietà' e 'valore' perché in ciascun loop la funzione Apio.loop () memorizza in queste variabili un elemento della coda (solo se vengono inviati più comandi o il ciclo principale non ha avuto tempo di eseguire la precedente prima dell'arrivo dei comandi successivi)
void ApioClass::loop() {
SYS_TaskHandler();
if(this->isDongle){
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
// mi salva l'ultimo istante in cui ha lampeggiato il LED
previousMillis = currentMillis;
Serial.println("c");
running_hearth = !running_hearth; //questo è un booleano che inizialmente è settato come false mi permette
//il lampeggio del LED
digitalWrite(15,running_hearth);
}
if(currentMillis-previousTable>10000){ //previousTable è un long inizializzato a 0
Serial.println("Here");
NWK_RouteTableEntry_t *table = NWK_RouteTable(); // NWK_RouteTable() – get a pointer to the entire Routing Table
for (int i=0; i < NWK_ROUTE_TABLE_SIZE; i++) { //NWK_ROUTE_TABLE_SIZE - numero di entrate nella tabella di
//di routing
if (table[i].dstAddr == NWK_ROUTE_UNKNOWN) { //questo NWK_ROUTE_UNKNOWN è definito di default come 0xffff
continue; // di default i dstAddr delle tabelle sono settati a 65535
}
}
previousTable = millis();
}
if(Serial.available()){
char c = readFromSerial();
//if(this->isVerbose) Serial.println(c+this->sendTo+":"+this->mex);
if(c=='l') {
flagSendInLoop=1;
send();
}else if(c=='s') {
//Serial.println(Apio.mex);
int i = 0;
int flagAddPropertyValue=0;
int len = Apio.mex.length();
String p = "";
String v = "";
for(i=0;i<len; i++){
if(Apio.mex.charAt(i)==':'){
flagAddPropertyValue++;
i++;
}
if(flagAddPropertyValue==1){
p+=Apio.mex.charAt(i);
}
else if(flagAddPropertyValue==2){
if(Apio.mex.charAt(i)!='-')
v+=Apio.mex.charAt(i);
}
}
Serial.println(p);
if(p=="panId"){
if(v!=""){
setPanId(v.toInt());
meshSetRadio(0, v.toInt(), 0x1a);
Serial.println("Cambio panId "+v);
} else if(v==""){
int pan = getPanId();
Serial.println("0:update:panId:"+String(pan));
}
} else if(p=="hi"){
Serial.println("Invio l'hi");
this->sendTo="65535";
this->mex = "65535:hi:m-";
this->hi=1;
send();
}
} else if(c=='p'){
Serial.println("Here");
NWK_RouteTableEntry_t *table = NWK_RouteTable();
for (int i=0; i < NWK_ROUTE_TABLE_SIZE; i++) {
if (table[i].dstAddr == NWK_ROUTE_UNKNOWN) {
continue;
}
Serial.print(String(i)+"|Fixed:");
Serial.print(table[i].fixed);
Serial.print("|Multicast:");
Serial.print(table[i].multicast);
Serial.print("|Score:");
Serial.print(table[i].score);
Serial.print("|dstAddr:");
Serial.print(table[i].dstAddr);
Serial.print("|nextHp:");
Serial.println(table[i].nextHopAddr);
}
}
}
}
if(!this->isDongle)
{
if(ack!=1 && contatoreInvii<6){
contatoreInvii++;
} else if (contatoreInvii>=6){
if(isVerbose) Serial.println("Invio avvenuto correttamente o impossibile inviare");
contatoreInvii = 0;
ack=1;
}
}
}
Questa funzione è quella che mi permette l'invio del segnale agli altri nodi e l'invio delle informazioni al coordinatore. Le strutture base per questa funzione sono contenute all'interno del capitolo 2.Apio Mesh nella sezione relativa all'invio del dato.