Valore di char* sovrascritto/perso

Ciao a tutti,
per il progetto che vi illustrerò sto utilizzando dei cloni di arduino Pro Micro with ATMEGA32U4, 5 V, 16 MHz.

Sto cercando di scrivere un protocollo per far comunicare 2 arduino (ma poi diventranno X) con dei moduli a 433 Mhz, la comunicazione sarà half-duplex e uno degli arduino sarà master mentre gli altri saranno tutti slave.
Il protocollo è abbastanza semplice e lo trovate in allegato.
Un esempio è questo:

  1. Arduino master segnalala sua presenza trasmettendo il suo id M2.
  2. Arduino slave sente l'id del Master e si presenta inviando contenente il proprio id(S2): M2IS2
  3. Il master invia un ACK a S2
  4. Periodicamente il master interroga gli slaves per vedere se sono ancora raggiungibili.

Ora, il problema è che nel momento in cui lo slave riceve l'id del master lo memorizza nella variabile char* masterId che verrà poi passata alle varie funzioni per costruire i pacchetti, ma poi ad un certo punto lo perde come se venisse sovrascritto o cancellato in memoria.

Questo si può vedere chiaramente dal log dello slave:

Looking for master...
Master found: M2
SizeofTosend:6
[1]IndexofTosend:
[1]IndexofTosend:
[2]IndexofTosend:I
[2]IndexofTosend:S
[2]IndexofTosend:2

dovrebbe essere:

Looking for master...
Master found: M2
SizeofTosend:6
[1]IndexofTosend:M
[1]IndexofTosend:2
[2]IndexofTosend:I
[2]IndexofTosend:S
[2]IndexofTosend:2

ma quell'M2 si è perso durante il tragitto ma non capisco dove.

Qui il codice del ricevitore:

//Receiver Code (Leonardo)
#include <VirtualWire.h>


uint8_t buflen = VW_MAX_MESSAGE_LEN;

char ACK = 'K';
char INIT_SLAVE = 'I';
char SLAVE_PREF = 'S';
char SLAVE_NEW_ID = 'N';

char* EMPTY = "ER";
char* slaveIdentifier = "S2";
char* masterId ="M2";
void setup() {
  delay(2000);
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

  vw_setup(2000);
  vw_set_tx_pin(8);
  vw_set_rx_pin(7);
  vw_rx_start();
  randomSeed(42);
}

void loop() {
  //Cerco un master
  masterId = lookForMaster();

  //Chiedo al master di darmi un id
  requestNewSlaveID(masterId);
  return;
  //Aspetto che mi venga assegnato un id
  slaveIdentifier = getNewIDFromMaster(masterId);
  delay(99999);
}

char* lookForMaster() {
  Serial.println(F("Looking for master..."));
  boolean masterFound = false;
  do {
    uint8_t buf[buflen];
    vw_wait_rx();
    if (vw_get_message(buf, &buflen)) {
      char masterId[buflen + 1];
      int i = 0;
      for (i = 0; i < buflen; i++) {
        masterId[i] = (char) buf[i];
      }
      masterId[i] = '\0';
      if (masterId[0] == 'M' && sizeof(masterId) == 3) {
        Serial.print(F("Master found: "));Serial.println(masterId);
        return masterId;
      }
    }
  } while (true);

  return slaveIdentifier;
}

void requestNewSlaveID(char* masterId) {
  //char *masterId1 = "M2";
  send(slaveIdentifier, masterId, INIT_SLAVE);
}

char* getNewIDFromMaster(char* masterId) {
  Serial.println(F("Waiting new slaveID from master..."));
  char* message;
  do {
    message = listenMessagesForMe();
  } while (sizeof(message) == 0 || message == EMPTY);
  Serial.print(F("New slaveIdentifier: "));
  Serial.println(message);
  Serial.println(F("Confirming to master my new id..."));
  return message;
}

char* listenMessagesForMe() {
  //delay(25);
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  vw_wait_rx_max(300);
  if (vw_get_message(buf, &buflen)) { // Non-blocking
    char sender[3];
    char command;
    char recipient[3];
    char message[buflen  + 1 ];
    int i;
    // Message with a good checksum received, dump it.
    for (i = 0; i < buflen; i++) {
      message[i] = (char) buf[i];
    }
    for (i = 0; i < buflen; i++) {
      if ( (message[i] >= '0' && message[i] <= '9') || (message[i] >= 'A' && message[i] <= 'Z')) {

        //Controllo se il messaggio è per me, altrimenti esco
        if (i < sizeof(slaveIdentifier) && message[i] != slaveIdentifier[i]) {
          Serial.println(F("Messaggio per altri: ")); Serial.println(message);
          return EMPTY;
        }
        if (i == sizeof(slaveIdentifier)) {
          command = message[i];
        }
        else if (i > sizeof(slaveIdentifier)) {
          recipient[i - sizeof(slaveIdentifier) - 1] = message[i];
          recipient[i - sizeof(slaveIdentifier)] = '\0';
        }
      } else {
        Serial.println(F("Carattere non valido: "));
        return EMPTY;
      }
    }
    message[i] = '\0';

    Serial.println(message);
    Serial.print(F("Command: ")); Serial.println(command);
    Serial.print(F("Recipient: ")); Serial.println(recipient);
    if (command != ACK) {
      received(slaveIdentifier, recipient);
    }
    return message;
  }
  Serial.println(F("Messaggio vuoto "));
  return EMPTY;
}

void send(char* sender, char* receiver, char command) {
  char tosend[(sizeof(sender) ) + (sizeof(receiver) ) + 1 + 1];
  Serial.print(F("SizeofTosend:")); Serial.println(sizeof(tosend));
  int i = 0;

  for (int r = 0; r < sizeof(receiver) ; ++r, ++i) {
    tosend[i] = receiver[r];
    Serial.print(F("[1]IndexofTosend:")); Serial.println(tosend[i]);
  }
  tosend[i] = command;
  Serial.print(F("[2]IndexofTosend:")); Serial.println(tosend[i]);
  i++;
  for (int r = 0; r < sizeof(sender); ++r, ++i) {
    tosend[i] = sender[r];
    Serial.print(F("[2]IndexofTosend:")); Serial.println(tosend[i]);
  }

  tosend[i] = '\0';
  Serial.print(F("ToSend: ")); Serial.println(tosend); 
  do {
    send(tosend);
    delay(random(50, 500));
  } while (!isReceived(sender, receiver) );
  free(tosend);
}

boolean isReceived(char* sender, char* receiver) {
  char ackMessage[sizeof(sender)  + sizeof(receiver)  + 1 + 1];
  Serial.print(F("SizeofackMessage:")); Serial.println(sizeof(ackMessage)); 
  int i = 0;

  for (int r = 0; r < sizeof(receiver) ; ++r, ++i) {
    ackMessage[i] = receiver[r];
    Serial.print(F("[1]IndexofackMessage:")); Serial.println(ackMessage[i]); 
  }
  ackMessage[i] = ACK;
  Serial.print(F("[2]IndexofackMessage:")); Serial.println(ackMessage[i]);
  i++;
  for (int r = 0; r < sizeof(sender); ++r, ++i) {
    ackMessage[i] = sender[r];
    Serial.print(F("[2]IndexofackMessage:")); Serial.println(ackMessage[i]);
  }
  ackMessage[i] = '\0';
  Serial.print(F("ackMessage: ")); Serial.println(ackMessage); 
  char* message = "M2KS2";//listenMessagesForMe();
  Serial.print(F("ackMessage: ")); Serial.println(message); 
  if (message == EMPTY) {
    return false;
  }
  if (sizeof(ackMessage) - 1 != strlen(message)) {
    Serial.print(F("Different size ")); Serial.print(strlen(message) -1); Serial.println(sizeof(ackMessage));
    //free(ackMessage);
    //free(message);
    return false;
  }
  for (int i = 0; i < sizeof(ackMessage) && i < sizeof(message); ++i) {
    if (ackMessage[i] != message[i]) {
      Serial.println(F("Caratteri diversi"));
      //free(ackMessage);
      //  free(message);
      return false;
    }
  }
  Serial.println(F("RECEIVED!"));
  //free(ackMessage);
  //free(message);
  return true;
}

void extractElements(char srcArray[], char subArray[], int n)
{
  for (char i = 0; i < n; i++)
  {
    subArray[i] = srcArray[i];
  }
}
void received(char* sender, char* receiver) {
  send(sender, receiver, ACK);
}

void send(char* message) {
  waitChannelFree();
  vw_send((uint8_t *)message, strlen(message));
  vw_wait_tx(); // Wait until the whole message is gone
}

void waitChannelFree() {
  uint8_t buf[buflen];
  do {
    delay(random(150, 800));
  } while (vw_get_message(buf, &buflen)) ;
}

Grazie a chi cercherà di aiutarmi e a chi mi darà qualche consiglio utile per migliorare il codice :slight_smile:

Il consiglio è ... NON reinventare l'acqua calda quando c'è gente che ci ha speso anni per fare cose semplici, efficienti, funzionanti e ... affidabili :slight_smile:

Prova a guardare, in questa stessa sezione, tra i primi thread, ovvero QUI ... è una libreria Arduino manutenuta e supportata ... :wink:

Guglielmo

P.S.: ... ovviamente è solo un consiglio ... poi divertiti come più ti piace :wink:

Ciao Gugliemo,
grazie per il consiglio, guardo il topic che mi hai consigliato e guardo come funziona, ma il dubbio rimane. Perchè perdo quella variabile?? Non c'ho quasi dormito sopra :smiley:

catalgiu:
ma quell'M2 si è perso durante il tragitto ma non capisco dove.

Uhm troppi puntatori in giro passati, per i miei gusti...

Ti dico solo la prima cosa che mi pare pericolosa. La variabile globale masterId la inizializzi con "char* masterId ="M2";" che quindi alloca 3 byte in area globale. Ma poi tu la riassegni come valore di ritorno di una funzione in "masterId = lookForMaster();" (tra l'altro quindi perdendo il riferimento al buffer globale iniziale che contiene "M2" ossia 3 char).

Quella funzione a sua volta crea una variabile locale "char masterId[buflen + 1];" che usi per catturare il dato, e poi restituisci il puntatore a questa variabile locale come valore di ritorno.

Per cui temo che all'uscita la variabile sia stata deallocata e quindi distrutta per cui tu quando fai la "requestNewSlaveID(masterId);" che chiama "send(slaveIdentifier, masterId, INIT_SLAVE);" la "masterId" non contiene più nulla.

Invece di restituire il puntatore alla locale masterId, scrivi direttamente nella variabile globale masterId (o prima di tornare fai uno strcpy).

docdoc:
Per cui temo che all'uscita la variabile sia stata deallocata e quindi distrutta per cui tu quando fai la "requestNewSlaveID(masterId);" che chiama "send(slaveIdentifier, masterId, INIT_SLAVE);" la "masterId" non contiene più nulla.

Bingo!

Grazie mille :slight_smile:

Solo per curiosità, mi permetto di porre una domanda allo OP
quando ho cercato di fare io una cosa simile ho trovato anch'io la libreria virtualwire, ma ho anche trovato che viene sconsigliata a favore della sua "sorella maggiore" RadioHead, che già fa nativamente tutto quello che un uomo possa desiderare: indirizzi, ritrasmissioni, reliabledatagram, reti mesh, martini dry, spogliarello...
no, forse a spogliarello e martini dry non ci arriva, ma il resto sì...
perchè non hai deciso di non usarla?
io di mio, per la poca differenza di prezzo, sono passato ai molto più performanti HC12

Standardoil:
Solo per curiosità, mi permetto di porre una domanda allo OP
quando ho cercato di fare io una cosa simile ho trovato anch'io la libreria virtualwire, ma ho anche trovato che viene sconsigliata a favore della sua "sorella maggiore" RadioHead, che già fa nativamente tutto quello che un uomo possa desiderare: indirizzi, ritrasmissioni, reliabledatagram, reti mesh, martini dry, spogliarello...
no, forse a spogliarello e martini dry non ci arriva, ma il resto sì...
perchè non hai deciso di non usarla?
io di mio, per la poca differenza di prezzo, sono passato ai molto più performanti HC12

Perché non sapevo che era poco affidabile e quando l'ho confrontata con radioHead sembrava molto più semplice.
Ora ho abbandonato virtualwire e sto utilizzando radiohead con reliabledatagram :smiley:
I dispositivi RF sono ancora quelli cinesi da pochi euro però...

Ho una domanda, è normale che spesso la trasmissione fallisca, cioè che

 if (manager.sendtoWait((uint8_t*) message, strlen(message), SERVER_ADDRESS)) {

ritorni spesso false?

Purtroppo non ne ho idea
Come ti dicevo sono passato ai moduli hc12
Mi trovo bene

Come detto mi sono convertito a RadioHead e il che mi ha permesso di snellire il codice in quanto non devo più gestire la comunicazione, ma ho notato che il server non riceve mai l'ack, succede anche con i moduli hc12? Mi spiego meglio:
Client invia richiesta
Server risponde
Server rimane in attesa di ack, ma non lo riceve mai.
Questo succede anche se uso lo sketch di esempio che si trova nell'ide.
Succede anche con i moduli hc12 o è un problema di quelli che uso io?

Grazie

Guarda, io, considerando che gli hc12 simulano già una seriale ho fatto diverso....
Ma se vai a vedere il mio "termoremoto non è termometro scritto sbagliato" vedi che avevo fatto rilevamento errore, ack e retry