Coda di bit

Salve a tutti,

sto lavorando ad un progetto che consiste nel creare una lista di operazioni da eseguire sequenzialmente. Più nello specifico una lista in cui vado a mettere il numero del relay da attivare (ne ho 4) e il tempo durante il quale deve restare attivo (espresso in ore: 2, 4 o 8 ) garantendo la precedenza sempre all'operazione che richiede maggior tempo. Mi è stato consigliato di farlo con i bit:

2 per rappresentare i relay (00, 01, 10, 11)
e 4 per rappresentare il tempo in ore (0010, 0100, 1000)

Per quanto riguarda la priorità avevo pensato ad una maschera di bit. Il problema è che non so quale struttura dati utilizzare. Un arrayqueue può andare bene? E come tipo di dato "byte" aggiungendo due zeri?

Il byte è un tipo di dati che contiene 8 bit, per cui a te va bene.
Puoi manipolare i singoli bit in modo molto semplice:
bitSet imposta ad 1 un singolo bit
http://arduino.cc/en/Reference/BitSet

bitRead legge lo stato di un singolo bit
http://arduino.cc/en/Reference/BitRead

bitClear pulisce un bit
http://arduino.cc/en/Reference/BitClear

Inoltre se usi le operazioni logiche sui bit

puoi anche leggere gruppi di bit in un unico blocco. Puoi anche manipolare direttamente i pin di una porta logica, trasportando sui pin lo stato dei bit in un unico passaggio:
http://www.leonardomiliani.com/2013/manipoliamo-direttamente-le-porte-logiche-di-una-mcu/

Grazie mille per la risposta, mi è stata di grande aiuto. Ora però è sorto un altro impiccio...
Quando un elemento deve essere inserito in coda, controllo i tre bit che corrispondono alle modalità e li confronto con quelli degli elementi già presenti in coda. Se entrambi hanno la stessa modalità allora giustamente quello che vado ad aggiungere si accoda dietro a quello già presente (sempre se non ce ne sia un altro già accodato con ancora la stessa modalità). Ora il mio dubbio è: usando un Arrayqueue, come posso aggiungere quell'elemento nella posizione in cui deve andare e spostare tutti gli altri di una posizione in avanti?
La mia idea era di fare:

for (i=i+1, coda.size(), i++){
coda[i+1]= coda[i];
}
elemento= coda[i];

Esiste un modo migliore per farlo?

Devi spostare materialmente le varie celle.
Tieni presente però di non inserire le celle oltre la dimensione massima dell'array. Tu leggi la dimensione di coda ma se coda ha già tutte le sue celle occupate, il nuovo valore lo inserisci all'esterno di coda, e la cosa può creare problemi perché quel byte va a inserirsi in RAM in una posizione casuale, anche sopra ad un altro valore.

usa un array circolare.

In pratica tu dai per scontato che l'indice INIZIALE dell'array sia sempre 0.. ma se invece l'indice iniziale è una variabile? allora ti basta incrementare di uno questa variabile per aggirare il problema.

poi quando vuoi la terza cella fai:

array[(indiceSfaso+3)%lunghezzaArray]

Ma esiste una struttura dati per inserire un elemento in mezzo all'array e non in cima o in fondo? Sinceramente finora non ho trovato sketch con la struttura dati QueueArray (Arduino Playground - QueueArray Library) o ArrayList che usano questa funzione...

Strutture dati native non esistono. Se devi inserire un byte in una cella di un array devi fare posto nell'array.

Capisco, ma operativamente parlando, per spostare materialmente le celle il mio ragionamento è errato?

for (i=i+1, coda.size(), i++){

coda[i+1]= coda[i];
}
elemento= coda[i];

Piuttosto che usare .size io userei un indice che mi punta all'ultimo byte usato. Così eviteresti di spostare non solo le celle vuote ma anche di sforare oltre la fine dell'array

è corretto ma è inefficiente. però usare una lista di strutture su arduino è uno spreci di ram enorme

error: no match for 'operator[]' in 'coda*'*
Qual è la sintassi per indicare un elemento della coda?

Metti il codice che stai usando.

Sì scusate, è che sto provando prima su uno sketch grezzo... Ecco il codice brutale:

#include <QueueArray.h>

QueueArray <byte> coda;

void setup() {
  byte elemento = 60; 
  coda.push(elemento);
   elemento = 45;
  coda.push(elemento);
   elemento = 90;
  coda.push(elemento);
  Serial.begin(9600); // inizializzazione della comunicazione serial monitor a 9600 baud
  coda.setPrinter(Serial);
  Serial.print("coda: ");
  int i;
  for (i=0; i<=3; i++){
    Serial.print(i);
    Serial.print(": ");
    Serial.println(coda[i];
  }
  posizionaElemento(87);
  for (i=0; i<=4; i++){
    Serial.print(i);
    Serial.print(": ");
    Serial.println(coda[i]);
  }
}

void loop() {
  
  // put your main code here, to run repeatedly: 
  
}

void posizionaElemento(int daPosizionare) {
  boolean posizionato = false;
  while (posizionato==false){  // finchè non posiziono
    for (i=0; i<=coda.length(); i++){ // scorre gli elementi della coda fino alla sua ampiezza
              if (daPosizionare > coda{i}){ // presa con priorità 
              for (i; i<=coda.length(); i++){
                coda[i++] = coda[i];
              }
              elemento=coda[i];
              posizionato=true;
              }
    }
  }
}

Ma se usi quella funzione non credo tu possa accedere a "coda" come ad un normale array.
Devi usare i metodi messi a disposizione dalla lib.

Purtroppo nella documentazione non c'è nessun metodo per accedere ad un elemento (Arduino Playground - QueueArray Library). Perciò chiedevo un'altra struttura dati che ce l'avesse. Se devo fare tutto a mano, almeno devo sapere qual è quella giusta che mi consenta di fare questa cosa. Qualche cosa seguita da documentazione, magari con qualche esempio perché non sono molto esperto in programmazione e per me è un grosso scoglio questo problema...

Forse stai usando lo strumento sbagliato. Quella lib serve ad implementare una struttura di tipo FIFO, First In-First Out. A te serve un comune array dove andare a mettere i valori nelle celle che desideri.

Forse, allora cerco di spiegare meglio il problema. Ho 4 pulsanti che corrispondono a 4 relay. Premendo una sola volta ogni pulsante si scorre il menu e tenendo premuto si seleziona la voce. Selezionare la voce vuol dire attivare i relay per un certo periodo di tempo che varia a seconda della voce che si sceglie: 2, 4+4 o 8 ore. Attivare il relay per 8 ore ha più priorità del farlo per 4+4 o 2, 4+4 ha più priorità del 2. 4+4 significa che fa 4 ore e poi vede se gli altri 3 relay sono stati anche essi programmati per 8 o 4 e nel caso fa prima quelli per poi tornare a fare le sue altre 4 ore. Quindi serve una coda per gestire tutto questo, ma una coda che mi vada a inserire l'elemento che aggiungo nella giusta posizione, perché altrimenti si perderebbero le priorità. Gli elementi all'interno della coda sono byte che ho suddiviso in: primi due bit per etichettare i relay e gli altri 6 per le ore. Siccome la priorità è per le ore, devo tenere conto per l'ordine che andrò a fare sulla coda degli ultimi 6 bit che devono quindi essere in ordine decrescente. Dovrebbe essere questo lo scopo della struttura dati che mi serve... Non so se sia fattibile...

Ma i relay essendo 4, alla fine solo quattro valori devi al massimo memorizzare, giusto?
Cioè se da menu ti riselezionano es. rele2->tempo 8 mentre tu avevi già in code rele2->tempo 2 in questo caso devi togliere quel rele2->2 e mettere rele2->8 verificando anche la priorità in base al tempo?

Se i valori da memorizzare sono tutti, non solo quattro allora ti suggerisco di usare 3 code, una per ogni priorità.
Il programma servirà prima la coda ad alta priorità, se vuota la seconda, altrimenti la terza.
Se metti qualcosa in coda lo fai in quella con priorità giusta. A questo punto nelle varie code non devi più ordinare ma sono solo degli stack code (primo che entra primo che esce per essere servito)
mentre per i valori da memorizzare sono solo gli id dei rele (non devi più avere quella strutturazione dei bits)

Io dico che un semplice array va più che bene. Ci sono solo 3 casi da controllare:

  1. verificare se l'inserimento di un elemento porta l'array a crescere oltre la dimensione massima (e questo è facile da fare, basta usare un indice che punta all'ultima cella dell'array e quando l'indice è uguale alla dimensione, vuol dire che siamo alla situazione limite);
  2. se il punto 1) è soddisfatto, controllare se la priorità dell'elemento e posizionarlo dove deve andare. Se va posto in fondo, basta aggiungerlo nella cella puntata dall'indice di cui sopra ed incrementarlo;
  3. se va infilato tra gli altri elementi, basta localizzare la cella dove deve andare, spostare in avanti tutte quelle che seguono e mettere poi l'elemento nella cella.

Scrivendo un algoritmo fatto bene, i punti 2 e 3 possono diventare uno solo, dato che il caso dell'elemento da porre nell'ultima cella è identico al caso di un elemento da porre in mezzo alla lista dove, per far posto, va spostato un numero di elementi pari a 0.