4. Codice Coordinatore e nodo generico - Giachelli/Apio-RSSI1 GitHub Wiki

Come agisce il coordinatore

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).

Codice del coordinatore

#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();
    }
}

Come agisce il nodo generico

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)).

Apio.setup

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;

  }
}

Apio.Loop

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;
    }
  }
}

Apio.send

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.

⚠️ **GitHub.com Fallback** ⚠️