Codice non funzionante dopo alcuni giorni

Ciao,
Ho questo codice che praticamente attiva un relè da un altro arduino attraverso un antenna radio NRF24L01. Il codice funziona egregiamente ma dopo qualche giorno che l'arduino sta acceso smette di funzionare, riavviandolo poi riprende a funzionare! Perché?

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
                    
#define PIN_RELAY 2  
#define DEVICE_ID "00001" 
#define DELIMITER "§"                      
const byte address[6] = "00001";
char rawData[10] = "";
char *container;

RF24 radio(7, 8);


void setup() { 
  // configuring relay 
  pinMode(PIN_RELAY, OUTPUT);  
  // configuring radio  
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_250KBPS);
  radio.setCRCLength(RF24_CRC_8) ; 
  radio.setRetries(15,15); 
  radio.openReadingPipe(0, address);
  radio.startListening();
}

void loop() {
  if ( radio.available() ) {
    // reading data
    radio.read(&rawData, sizeof(rawData));
    // detecting command
    container = strtok(rawData, DELIMITER);
    if ( strcmp(container, DEVICE_ID) == 0 ) {
      container = strtok(NULL, DELIMITER);
      if ( container[0] == '0' ) {
        digitalWrite(PIN_RELAY, 0);
      }
      else {
        digitalWrite(PIN_RELAY, 1);
      }
    }
    free(container);
  }
  delay(300);
}

Buonasera,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

fatto!

Non sono sicuro, ma l'uso delle free(), è proprio necessario? non puoi semplicemente sovrascrive il contenuto con una serie di valori a zero?
se hai un pin libero, invece, potresti provare a far lampeggiare un led a cadenza regolare, che se vedi che smette di lameggiare sai che è impinatato il SW, se non risponde ma continua a lmapeggiare è la radio....

la free non libera memoria allorata o riallocata con calloc, malloc, or realloc?
chi fa queste allocazioni?
la libreria RF24?
eventualmente richiamarla "impropriamente" può creare effetti collaterali?
A parte questa cosa un po' stiracchiata, non mi salta all'occhio roba strana sul codice.

Nemmeno a me
Serve loggare un pochino
Cominciare con un led lampeggiante
Comunque la Free proprio non ci va
Container punta ad una porzione della rawdata, che è globale non ha senso liberarla
Ci vorrebbe un intervento di sukkopera, che sa molto bene queste cose

in teoria dovrebbe far finta di fare qualcosa ma non fare nulla la free su una cosa non allocata per cui mi sa che crea solo un po' di calore e basta.
Si, direi che il test con il led vada bene per capire cosa effettivamente si pianta, se si pianta.

Il relè è connesso correttamente? diodo in antiparallelo, isolamento dell'altra alimentazione, ecc. ecc. ecc.?
Perchè potrebbe anche essere un ritorno di un disturbo di un qualche tipo (il terzo?).

Poi ho un altro dubbio
Non sono sicuro che la read() garantisca che il buffer sia terminato da zeri, non ho trovato nella documentazione

D'accordissimo col led che potrebbe lampeggiare lentamente quando a riposo e lampeggiare velocemente quando trasmette (così hai i tre stati del programma: funzionante, trasmittente e... bloccato se rimane fisso acceso o spento).
Una volta che sai cosa succede diventa tutto più semplice

FrancoScala:
Ho questo codice che praticamente attiva un relè da un altro arduino attraverso un antenna radio NRF24L01. Il codice funziona egregiamente ma dopo qualche giorno che l'arduino sta acceso smette di funzionare, riavviandolo poi riprende a funzionare! Perché?

Cercando di capire come funzioni questa cosa, mi pare di capire che tu attendi che ti arrivi un pacchetto con un device ID di 5 caratteri seguito da un '§' e da un carattere. Se il device ID è il tuo (DEVICE_ID) allora leggi il carattere dopo il '§' e se è '0' disattivi il relè (quindi logica inversa, esatto?) altrimenti lo attivi.

Primo, perché complicarti la vita ed usare strtok()? Per capire se l'ID è il tuo usa strncmp() per confrontare i primi 5 caratteri, e se sono quelli che ti aspetti allora attivi il relè se il settimo byte del buffer è il carattere '0':

    // detecting command
    if ( strncmp(rawData, DEVICE_ID, 5) == 0 ) {
      digitalWrite(PIN_RELAY, rawData[6] == '0');
    }

Se proprio vuoi verificare la correttezza della stringa:

    // detecting command
    if ( strncmp(rawData, DEVICE_ID, 5) == 0 && rawDAta[5] == DELIMITER ) {
      digitalWrite(PIN_RELAY, rawData[6] == '0');
    }

Secondo, la free() non serve a nulla, toglila (tanto se provi il mio metodo non hai più bisogno della variabile "container"...). E per quanto possa vedere, secondo me è quella a far "impicciare" Arduino in qualche modo (non hai mai fatto malloc() che dovrebbe rilasciare?)

docdoc:
... Secondo, la free() non serve a nulla, toglila (tanto se provi il mio metodo non hai più bisogno della variabile "container"...). E per quanto possa vedere, secondo me è quella a far "impicciare" Arduino in qualche modo (non hai mai fatto malloc() che dovrebbe rilasciare?)

Infatti ...
... se si va ad esaminare il codice della free() si vede che comunque, salvo il caso in cui il puntatore passato sia NULL, caso in cui non viene fatto nulla, negli altri casi ... qualcosa viene fatto e ... non ho idea del caos che in memoria la cosa possa produrre :

void free(void *p)
{
	struct __freelist *fp1, *fp2, *fpnew;
	char *cp1, *cp2, *cpnew;

	/* ISO C says free(NULL) must be a no-op */
	if (p == 0)
		return;

	cpnew = p;
	cpnew -= sizeof(size_t);
	fpnew = (struct __freelist *)cpnew;
	fpnew->nx = 0;

	/*
	 * Trivial case first: if there's no freelist yet, our entry
	 * will be the only one on it.  If this is the last entry, we
	 * can reduce __brkval instead.
	 */
	if (__flp == 0) {
		if ((char *)p + fpnew->sz == __brkval)
			__brkval = cpnew;
		else
			__flp = fpnew;
		return;
	}

	/*
	 * Now, find the position where our new entry belongs onto the
	 * freelist.  Try to aggregate the chunk with adjacent chunks
	 * if possible.
	 */
	for (fp1 = __flp, fp2 = 0;
	     fp1;
	     fp2 = fp1, fp1 = fp1->nx) {
		if (fp1 < fpnew)
			continue;
		cp1 = (char *)fp1;
		fpnew->nx = fp1;
		if ((char *)&(fpnew->nx) + fpnew->sz == cp1) {
			/* upper chunk adjacent, assimilate it */
			fpnew->sz += fp1->sz + sizeof(size_t);
			fpnew->nx = fp1->nx;
		}
		if (fp2 == 0) {
			/* new head of freelist */
			__flp = fpnew;
			return;
		}
		break;
	}
	/*
	 * Note that we get here either if we hit the "break" above,
	 * or if we fell off the end of the loop.  The latter means
	 * we've got a new topmost chunk.  Either way, try aggregating
	 * with the lower chunk if possible.
	 */
	fp2->nx = fpnew;
	cp2 = (char *)&(fp2->nx);
	if (cp2 + fp2->sz == cpnew) {
		/* lower junk adjacent, merge */
		fp2->sz += fpnew->sz + sizeof(size_t);
		fp2->nx = fpnew->nx;
	}
	/*
	 * If there's a new topmost chunk, lower __brkval instead.
	 */
	for (fp1 = __flp, fp2 = 0;
	     fp1->nx != 0;
	     fp2 = fp1, fp1 = fp1->nx)
		/* advance to entry just before end of list */;
	cp2 = (char *)&(fp1->nx);
	if (cp2 + fp1->sz == __brkval) {
		if (fp2 == NULL)
			/* Freelist is empty now. */
			__flp = NULL;
		else
			fp2->nx = NULL;
		__brkval = cp2 - sizeof(size_t);
	}
}

Guglielmo

P.S.: Su un sistema che è in grando di gestirlo (es. Linux) una chiamata a free() di un puntatore NON allocato con la malloc() crea un Segmentation fault ... dato che su Arduno NON c'è un sistema operativo, i guai sono assicurati ... ::slight_smile:

gpb01:
... se si va ad esaminare il codice della free() si vede che comunque, salvo il caso in cui il puntatore passato sia NULL, caso in cui non viene fatto nulla, negli altri casi ... qualcosa viene fatto e ... non ho idea del caos che in memoria la cosa possa produrre :

è stato il mio primo pensiero, ma poi, da inguaribile ottimista, pensavo potesse essere indolore :wink:

maubarzi:
la free non libera memoria allorata o riallocata con calloc, malloc, or realloc?
chi fa queste allocazioni?
la libreria RF24?
eventualmente richiamarla "impropriamente" può creare effetti collaterali?
A parte questa cosa un po' stiracchiata, non mi salta all'occhio roba strana sul codice.

Questa free l'ho messa in un secondo memento per provare a vedere se risolveva qualcosa! Inizialmente il codice era senza e comunque non andava!

docdoc:
Cercando di capire come funzioni questa cosa, mi pare di capire che tu attendi che ti arrivi un pacchetto con un device ID di 5 caratteri seguito da un '§' e da un carattere ....

provo questa soluzione e vi aggiorno fra qualche giorno! grazie per ora!

>FrancoScala: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce. Gli utenti da device "mobile" ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: Ho troncato io il "quote" qui sopra alla ... giusta dimensione ... :slight_smile:

    // detecting command

if ( strncmp(rawData, DEVICE_ID, 5) == 0 && rawData[5] == DELIMITER ) {
      digitalWrite(PIN_RELAY, rawData[6] == '0');
    }

Non funziona! Appena provato, arduino non mi riconosce il carattere come 0 o 1 accedendovi cosi rawData[6], sulla console mi stampa questo � !

metti magari il codice completo?
e spieghi chi ti stampa nella console, visto che il frammento che hai mostrato NON ha stampe?

ecco!

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
                    
#define PIN_RELAY 2  
#define DEVICE_ID "00001" 
#define DELIMITER "§"                      
const byte address[6] = "00001";
char rawData[10] = "";

RF24 radio(7, 8);


void setup() { 
  Serial.begin(9600);
    
  // configuring relay 
  pinMode(PIN_RELAY, OUTPUT);  
  // configuring radio  
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_250KBPS);
  radio.setCRCLength(RF24_CRC_8) ; 
  radio.setRetries(15,15); 
  radio.openReadingPipe(0, address);
  radio.startListening();
}

void loop() {
  if ( radio.available() ) {
    // reading data
    radio.read(&rawData, sizeof(rawData));
    Serial.print("-");
    Serial.print(rawData);
    Serial.println("-");
    // detecting command
    if ( strncmp(rawData, DEVICE_ID, 5) == 0 && rawData[5] == DELIMITER ) {
      Serial.println(rawData[6]); // <----- qui non prende il carattere!
      digitalWrite(PIN_RELAY, rawData[6] == '0'); //<---- il confronto non va mai a buon fine e non succede nulla!
    }
  }
  delay(300);
}

Ok, non mi è chiaro
la riga "serial.print(raWdata);"
ti stampa correttamente il valore che dovresti vedere?
esattamente cosa trasmetti?

scrivo liberamente, in attesa della tua risposta
ma perchè fai questa menata?

#define DEVICE_ID "00001" 
#define DELIMITER "§"
.
.
.

 // detecting command
 if ( strncmp(rawData, DEVICE_ID, 5) == 0 && rawData[5] == DELIMITER )

fai direttamente

#define DEVICE_ID "00001§" 
if ( !strncmp(rawData, DEVICE_ID, 6) )

che poi

rawData[5] == DELIMITER

non andrà mai visto che DELIMITER è una stringa "§" mentre rawData[5] è un carattere '§'
poi, e continuo con considerazioni libere, sempre in attesa di tue notizie
che versione di libreria rf24 hai? da ne il prototipo della openreadingpipe è:

  void openReadingPipe(uint8_t number, uint64_t address);

tu le passi una stringa......
anzie nemmeno, le passi un array di 6 byte inizializzata con

const byte address[6] = "00001";

che sembra solo l'inizializzazione di una stringa
e comunque 6 byte da 8 bit fanno seiperottoquarantotto, quando il tipodati è da 64bit
e comunque essendo un array viene passato il "puntatore",
insomma una bella zuppa di tipodati