Richiamare costante utilizzando una stringa... Sto impazzendo!!!

Ciao ragazzi... Sto diventando matto dietro al richiamare una costante che corrisponderebbe a un comando da inviare via ir.
Allora vi spiego.
Ho 5 variabili, e messe in ordine mi vanno a creare il nome della costante, faccio un esempio:

unsigned long AC116A0[]={0x6A2E00,0x000400,0x000000,0x000000,0x000018}; questo è uno dei comandi. E la stringa in questo caso restituisce AC116A0.

void sendcommandcam(){
  String string1 = modecam;
  String string2 = (String) statocamera;
  String string3 = (String)tempcam;
  String string4 = ventolacam;
  String string5 = (String) sleepcamera;
  comandocam = String((string1) + (string2) + (string3) + (string4) + (string5));
  Serial.println(comandocam);
  irsend.sendNEC(comandocam, 5, 24);
  delay(200);
}

Allora, la creazione della stringa funziona regolarmente, perchè con il println sul monitor seriale comandocam equivale proprio a AC116A0. Ma inserito in irsend ecc me lo vede come stringa... Mentre se al posto di comandocam scrivo AC116A0 funziona... Ma a me serve che vari a seconda delle impostazioni, e il modo migliore mi è sembrato creare una stringa, ma non capisco perchè pur risultando AC116A0 da codice seriale, inserito nel irsend non funzioni. Eppure non dovrebbe essere come se io scrivessi AC116A0??? Grrrr.

La sendXXX() qualcosa, vuole come primo parametro una stringa NON una String.
Sono due cose diverse. Le stringhe del C sono vettori di caratteri. String è un oggetto che contiene del testo.
Una volta composta la String devi riportarla in un vettore di char abbastanza grande, usando comandocam.ToCharArray()

Non è certo un bel pezzo di codice, inoltre le String consumano mooolta memoria.
Molto più pratico usare la sprintf() del C che permette di "stampare" dentro a un vettore di caratteri
http://www.cplusplus.com/reference/cstdio/sprintf/
esempio:

char buf[20];
char str="AC";
int val=4;
sprintf(buf,"%2s%20d",str,val);

dentro a buf troverai AC04

EDIT: la sendNEC() vuole unsigned long, mi son confuso con sendRaw() che vuole un vettore/array !!!

nid69ita:
La sendXXX() qualcosa, vuole come primo parametro una stringa NON una String.
Sono due cose diverse. Le stringhe del C sono vettori di caratteri. String è un oggetto che contiene del testo.
Una volta composta la String devi riportarla in un vettore di char abbastanza grande, usando comandocam.ToCharArray()
http://arduino.cc/en/Reference/StringToCharArray

Non è certo un bel pezzo di codice, inoltre le String consumano mooolta memoria.
Molto più pratico usare la sprintf() del C che permette di "stampare" dentro a un vettore di caratteri
http://www.cplusplus.com/reference/cstdio/sprintf/
esempio:

char buf[20];

char str="AC";
int val=4;
sprintf(buf,"%2s%20d",str,val);



dentro a buf troverai AC04

Allora, intanto ti ringrazio infinitamente del chiarimento. E cerco di raccogliere informazioni per la prima prova.
Per quanto riguarda il codice mi rendo conto che è imbarazzante, ma al momento mi interessa che funzioni, giusto per capire come poter inserire la stringa di comando nel send. Dopodichè sicuramente mi butterò nella seconda ipotesi che mi hai dato.
Grazie mille ancora :)))

Sorry mi son spiegato male. E' brutto non il tuo codice ma l'usare String, su piccole MCU come Arduino Uno con soli 2K di SRAM se li mangia in un attimo. Non siamo su un PC con 2 o 4 Gb di RAM

nid69ita:
Sorry mi son spiegato male. E' brutto non il tuo codice ma l'usare String, su piccole MCU come Arduino Uno con soli 2K di SRAM se li mangia in un attimo. Non siamo su un PC con 2 o 4 Gb di RAM

A me non piace nemmeno il mio codice a dirti il vero. Ma sarebbe un bel regalo di Natale se almeno riuscissi a farlo funzionare... :roll_eyes: :roll_eyes:
Con il tuo sistema toCharArray son riuscito a dare alla variabile char data il valore AC120A0 ma inserendolo nella send irsend.sendNEC(data, 5, 24); lo ho scritto giusto??? O va inserito tra delle virgolette??? Non me lo compila ancora, mi dice no matching function for call to IRsend::sendNEC(char[8], int, int)... Infatti la funzione richiede (unsigned long, int, int), però AC120A0 è il nome di quella benedetta Unsigned long, e se al posto di data scrivo AC120A0 funziona... Non capisco.
Grazie mille. :frowning:

void sendcommandcam(){
  String string1 = modecam;
  String string2 = (String) statocamera;
  String string3 = (String)tempcam;
  String string4 = ventolacam;
  String string5 = (String) sleepcamera;
  comandocam = String((string1) + (string2) + (string3) + (string4) + (string5));
  //Serial.println(comandocam);
  char data[8];
  comandocam.toCharArray(data, 8); 
  Serial.println(data);
  irsend.sendNEC(data, 5, 24);
  delay(200);
}

Questo è il codice con il toCharArray. Con il serial print da monitor data mi dà il valore AC120A0 che è il nome corretto del comando (comando di prova).
Sigh.

Ho quella di Shirriff, quella dell'ide la ho tagliata e incollata sul desktop.

nid69ita:
@Lollo, è tutto sbagliato.
esempio: irsend.sendSony(0xa90, 12)

Il primo valore è un numero solo che è scritto in esadecimale
Devi convertire la stringa in numero long:
irsend.sendNEC( atol(data) , 5, 24);

O meglio ancora non usi più data e usi direttamente toInt()
irsend.sendNEC( comandocam.toInt() , 5, 24);

Sisi, è che il sendNec ho dovuto modificarlo perchè il condizionatore che devo controllare ha il telecomando che spara 120 bit, quindi li ho divisi in 5 insiemi da 24 bit e con un ciclo for li invio. Infatti 5 è il numero di insiemi, 24 è il numero di bit che contiene ogni insieme. E infatti son riuscito a inviare i comandi.
Con entrambe le soluzioni non mi compila, mi dà invalid conversion from 'long int' to 'long unsigned int*'.
Non capisco perchè se inserisco direttamente AC120A0 funziona... Data contiene quel valore... Dovrebbe essere la stessa cosa :(.
L'unico modo di farglielo compilare è sostituire nella libreria unsigned long data[] con char data[]. Ma poi non so se mi invierà il comando... Ma non credo. Al momento non ho manco modo di provare.

Ora, i comandi che tu scrivi sono numeri che per comodità TU ti scrivi in esadecimale.
Tu NON scrivi la frase "AC120A0" ma il valore numerico 0xAC120A0
Che equivale al numero 180428960
La conversione che fa atol() è solo tra decimali e testo, NON esadecimale.
Spiega bene quali valori devi inviare e quali "parti" di quel numero esadecimale cambiano a seconda dei parametri. La cosa la si deve fare SENZA stringhe ma semplicemente con numeri e moltiplicazioni.
Anche perchè se hai il numero 4 come testo non verrà mai "04" se deve occupare 2 celle ma solo "4" mentre il numero 10 -> "10" occupa di sicuro 2 celle

Lollo82:
Ho 5 variabili, e messe in ordine mi vanno a creare il nome della costante, faccio un esempio:
unsigned long AC116A0[]={0x6A2E00,0x000400,0x000000,0x000000,0x000018}; questo è uno dei comandi. E la stringa in questo caso restituisce AC116A0.

ANZI scrivi il codice di quando usi un valore unico (non con il tuo tentativo di generalizzarlo) perchè non si capisce nulla.
AC116A0 è il nome di un vettore di long senza segno, come hai scritto sopra. Potevi anche chiamarlo Pippo.

Ora, la sendNEC() vuole solo 2 valori, un unsigned long e un int, non puoi passarli 3 valori:
void sendNEC(unsigned long data, int nbits);
Se vuoi spedire 5 valori DEVI fare un loop e spedire un valore alla volta, prendendo dal tuo vettore AC116A0

for(int i=0;i<=4;i++)
{ irsend.sendNEC( AC116A0[i], 24); 
}

nid69ita:
Ora, la sendNEC() vuole solo 2 valori, un unsigned long e un int, non puoi passarli 3 valori:
void sendNEC(unsigned long data, int nbits);
Se vuoi spedire 5 valori DEVI fare un loop e spedire un valore alla volta, prendendo dal tuo vettore AC116A0

for(int i=0;i<=4;i++)

{ irsend.sendNEC( AC116A0[i], 24);
}

Allora, è meglio che ti spiego bene quello che ho fatto.
Il telecomando che ho clonato è a 120 bit, mentre la send nec per come è strutturata mi consente l'invio di solamente 32 bit e anche scrivendo 120 dove chiedeva Nbits al massimo me ne trovavo comunque 32, infatti dopo aver fatto due conti, unsigned long al max contiene 32 bit. Quindi ho modificato nella libreria la funzione SendNec per far si di inviare tutti i 120 bit semplicimente dividendoli in 5 insiemi che inviati tutti assieme vanno a formare un comando unico. Da qui questa costante:
AC120A0[]={0x6A2E00,0x000400,0x000000,0x000000,0x000018};
Ti faccio vedere la parte di libreria che ho modificato:

void IRsend::sendNEC(unsigned long data[], int insiemi, int nbits)
{
unsigned long temp;
  enableIROut(38);
  mark(NEC_HDR_MARK);
  space(NEC_HDR_SPACE);
for (int datai = 0; datai < insiemi ; datai++) {
temp = data[datai];
  for (int i = 0; i < nbits; i++) {
    if (temp & TOPBIT2) {
      mark(NEC_BIT_MARK);
      space(NEC_ONE_SPACE);
    } 
    else {
      mark(NEC_BIT_MARK);
      space(NEC_ZERO_SPACE);
    }
    temp <<= 1;
}
  }
  mark(NEC_BIT_MARK);
  space(0);
}

ecco il perchè di quel 5 e il 24 che altrimenti non dovrebbero starci.
Il 5 è il numero di insiemi che compone il comando intero, mentre il 24 è il numero di bit che compone ogni insieme.
temp è una variabile in cui viene copiato momentaneamente l'insieme per essere spedito e shiftato senza modificare il comando originale.

Facendo così

for(int i=0;i<=4;i++)
{ irsend.sendNEC( AC116A0[i], 24); 
}

Mi ritroverei che per ogni insieme mi invia il bit di controllo e quello di start, se non sbaglio.

Comunque come ho fatto funziona, mi invia il comando e riesco a controllare il condizionatore.
Il codice che ho usato per testare la modifica e uso per controllare il condizionatore è questo:

/*
 * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend
 * An IR LED must be connected to Arduino PWM pin 3.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

const int buttonPin = 7  ;    // the number of the pushbutton pin

// Variables will change:
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;

unsigned long data[]={0x6A2E00,0x000400,0x000000,0x000000,0x000018};

IRsend irsend;

void setup()
{
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);

  // set initial LED state
}

void loop() {
 int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        
        // set the LED:
  irsend.sendNEC(data, 5, 24);
  Serial.println("Ok");

      }
    }
  }
  
  

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

che è il codice di esempio debounce adattato per far si che alla pressione del pulsante invece di accendere il led invia la sendnec. E con questo funziona, se voglio modificare il comando basta modificare i sei insiemi esadecimali della variabile data.
Quello che io voglio fare è creare una lista di costanti e far si che alla modifica di una variabile che può essere la temperatura, il modo, la ventola ecc corrisponda la stringa che richiami la costante corrispondente a quel comando e la invii. Praticamente invece di chiamarla data, o pippo o chicchesia, chiamarla AC (che corrisponderebbe al mode) (1 o 0 allo stato acceso o spento), (20 la temperatura che non andrebbe mai sotto il 16), (A lo stato della ventola) e (1 o 0 lo stato dello sleep mode).
Spero di essermi spiegato meglio di come mi son spiegato sino ad ora.
I comandi li ho mappati tutti a mano, quindi devo farne una lista che andrebbe richiamata a seconda degli stati di quelle variabili.
Grazie per il tempo che mi stai dedicando. :slight_smile:

Dopo giornate intere passate a studiare il comando, non tanto quello che variava alla modifica dei vari parametri, quanto perchè e come variava il byte di controllo in fondo al codice (scoperto poi essere la somma di tutti i nibble che formano il codice, ma con il peso invertito).
Scoperto ciò mi sono scomposto i 5 insiemi del comando in 6 nibble già col peso invertito, per far si che ad ogni incremento di temperatura corrispondesse un'incremento di unità, e così per gli altri comandi, dopodichè al momento in cui il codice vede un cambiamento dei comandi passa ad una funzione che dapprima mi inverte il peso dei vari nibble, e uno dietro l'altro vado a ricreare il valore esadecimale che permetterà di interpretare il codice. Faccio questo per il secondo, terzo e quarto insieme, mentre per l'ultimo vado a pescare tutti i nibble tranne gli ultimi due e li sommo, inverto il peso del risultato, lo converto in esadecimale a 6 valori e lo piazzo come ultimo insieme. Prendo il comando creato e lo sendo... E... Evvivaaaaa funziona!!! Facendo così ho evitato di mappare una marea di comandi a mano.
Grazie a nid69ita per avermi spinto a trovare una soluzione alternativa.
Scusatemi se vi ho stressato con sta pappardella, ma avendo posto il quesito ho reputato giusto una volta trovata postare anche la soluzione adottata. Non so se mi sono spiegato bene ma spero la abbiate capita.
Vi posto anche un video del tutto funzionante.
Controllo
E ora sbattiamoci sull'altro condizionatore... :grin: :grin: :grin:

Lollo82:
Grazie a nid69ita per avermi spinto a trovare una soluzione alternativa.

Prego ;D