Capire il concetto di Buffer nelle Comunicazioni - Fondamentale per NOOB prt 1

Prima di scrivere questo thread avevo provato a riaprire questo senza successo.
Dal 18 Marzo ho continuato a studiare da autodidatta sul Purdum, cercando anche su blog e Stack. Purtroppo abito in un paesello e persone fisiche a cui chiedere e con cui scambiarsi informazioni è praticamente impossibile.

Il funzionamento del buffer e della seriale mi è ancora poco chiaro.

  • Qual è il materiale che vi ha permesso meglio di capire questo argomento?
  • Ho provato a studiare questo concetto, ho fatto una sorta di sunto di tutto quello che ho imparato, in grassetto ho evidenziato le parti che purtroppo faccio difficoltà a capire :frowning:

Grazie per la pazienza :slight_smile:

Da questa domanda su stack ho capito che per buffer si intende “Una parte di memoria utilizzata per conservare dei dati “. In generale è una sorta di bolla, di sacca che viene caricata in una operazione, mentre viene riempita in una o più operazioni. Un po’ come il carrellino della miniera.

Un esempio in C non proprio entry level che, da quello che ho capito, serve a "costruire un buffer, è il seguente:

#define BUFSIZE 1024
char buffer[BUFSIZE];
size_t len = ;

// ... later
while((len=read(STDIN, &buffer, BUFSIZE)) > 0)
    write(STDOUT, buffer, len);

Dove l’autore ha definito un buffer di 1024 byte di caratteri, che avrà quindi al suo interno 511 elementi /caratteri più l’elemento null .

Il ciclo while contiene al suo interno la funzione “read” che vuole come argomenti un canale standard di input, la reference (quindi il left value del buffer/il suo indirizzo di memoria) e la dimensione del buffer.

La condizione è “finche la lunghezza che è stata dichiarata come un size_t, un tipo intero senza segno di almeno 16 bit, è >0”
Scrivi (canale standard di output, rvalue del buffer e lunghezza)

Purtroppo non capisco perchè in lettura ci sia il left value attraverso la reference ed in scrittura un valore pass-by-value del buffer

Da questa domanda ho capito che
il buffer è sfruttato per la comunicazione tra il sensore gyro+acc e il microcontrollore.

In questo caso non capisco perché la funzione readFrom contenga solo due indirizzi formato Ascii e non tre (x,y,z) ne perché ci sia quel 6

//Function for reading the accelerometers
void getAccelerometerReadings(int accelResult[]) {
  byte buffer[6];
  readFrom(0x53,0x32,6,buffer);
  accelResult[0] = (((int)buffer[1]) << 8 ) | buffer[0]; //Yes, byte order different from gyros'
  accelResult[1] = (((int)buffer[3]) << 8 ) | buffer[2];
  accelResult[2] = (((int)buffer[5]) << 8 ) | buffer[4];
}

Traducendo la domanda:
Il protocollo di comunicazione seriale I2C è impostato per utilizzare segmenti di informazioni di 8 bit, quindi se io voglio inviare un valore più grande di 8 bits questo deve essere scisso in più parti, e poi essere ricomposto.

(((int)buffer[0]) << 8 ) | buffer[1];

Quello che succede è che buffer [0] è convertito in un intero quindi un valore di16 bit che viene traslato di 8 bits
Questo significa che gli 8 bit nel buffer iniziale buffer [0] adesso sono localizzati in cima agli 8 bits dell’intero e gli 8 bit inferiori sono zeri.
Infine gli 8 bit inferiori sono definiti dall’operatore bitwise-or |
Che che “turn on” qualsiasi bit che era definito nel buffer [1]
Poiché la fine degli 8 bits erano 0 dalla traslazione, questo copia sempicemente il buffer [1]
(faccio fatica a capire questa affermazione
Alla fine otteniamo un valore di 16bit che contiene entrambi gli 8 bit e può essere interpretato come un numero singolo.

Grazie per aver letto fino a qui e per la pazienza ci sonon dietro tante ore di studio, ho anche un secondo thread che vorrei aprire perchè ho letto e studiato anche qui ma non ho abbastanza caratteri :slight_smile:

Stai facendo un sacco di confusione e ti stai facendo fuorviare da codice che non riesci ad interpretare.
Prima cosa, un buffer è semplicemente una porzione di memoria che fa da “contenitore” temporaneo per dei dati, non a caso la corretta traduzione in italiano di buffer è memoria tampone.
Per definizione un buffer può benissimo essere un singolo byte, p.e. una variabile unsigned char (uint8_t) chiamata “tmp”, come può essere qualunque altro tipo base di variabile, oppure un array mono, o pluri, dimensionale con le celle composte da uno dei possibili tipi di variabile base.
Esempio pratico, devo memorizzare temporaneamente, per poi poterli elaborare, i sei byte che indicano la lettura dei tre assi un accelerometro, quindi sei uint8_t, pertanto creo un array di sei elementi con “uint8_t tmp[6]”, ovvero ho un array di sei elementi a 8 bit che si chiama tmp, questo è il tuo buffer.
Prendendo la linea di codice “readFrom(0x53,0x32,6,buffer);” la funzione “readFrom” dovrebbe usare il primo valore hex come address I2C, il secondo valore è il numero del primo registro, sul device, da leggere, 6 è il numero di registri complessivi da leggere, da 0x32 a 0x37, e buffer è il nome del buffer dove vengono caricati i sei byte acquisiti dal device I2C.
Una volta che hai i sei byte nel buffer li converti in valori interi, e carichi nelle reale variabili da usare nel tuo codice con: "accelResult[0] = (((int)buffer[1]) << 8 ) | buffer[0]; in questo caso usano un array di tre elementi a 16 bit (interi) bit dove tramite shift a sinistra di 8 posizioni, con casting a int, si carica il secondo byte negli 8 bit alti dell’intero, e il primo byte negli otto bit bassi tramite or e autocasting a byte.
La cosa poteva essere scritta anche in questo modo, probabilmente più leggibile ma meno efficiente come codice compilato, richiede più cicli macchina.

accelResult[0] = buffer[0]; // carico il byte basso nell'intero.
accelResult[0] +=  (int)buffer[1] << 8; // sommo all'intero il byte previa promozione a int e shift a sinistra di 8

astrobeed:
Stai facendo un sacco di confusione e ti stai facendo fuorviare da codice che non riesci ad interpretare.
Prima cosa, un buffer è semplicemente una porzione di memoria che fa da “contenitore” temporaneo per dei dati, non a caso la corretta traduzione in italiano di buffer è memoria tampone.

Pienamente d’accordo purtroppo mi sono arrivate tante informazioni frammentante ed ho provato a mettere ordine con scarsi risultati :slight_smile:

astrobeed:
Prendendo la linea di codice “readFrom(0x53,0x32,6,buffer);” la funzione “readFrom” dovrebbe usare il primo valore hex come address I2C, il secondo valore è il numero del primo registro, sul device, da leggere, 6 è il numero di registri complessivi da leggere, da 0x32 a 0x37, e buffer è il nome del buffer dove vengono caricati i sei byte acquisiti dal device I2C.

Tutto chiaro

  • 0x53 indirizzo I2C del sensore
  • 0x32 è l’inizio dei registri del sensore dove sono le info sulle accelerazioni (ognuno dei tre composto da 2 byte?)
  • Capito anche la questione buffer, grazie :slight_smile:

astrobeed:
Una volta che hai i sei byte nel buffer li converti in valori interi, e carichi nelle reale variabili da usare nel tuo codice con: "accelResult[0] = (((int)buffer[1]) << 8 ) | buffer[0]; in questo caso usano un array di tre elementi a 16 bit (interi) bit dove tramite shift a sinistra di 8 posizioni, con casting a int, si carica il secondo byte negli 8 bit alti dell’intero, e il primo byte negli otto bit bassi tramite or e autocasting a byte.
La cosa poteva essere scritta anche in questo modo, probabilmente più leggibile ma meno efficiente come codice compilato, richiede più cicli macchina.

accelResult[0] = buffer[0]; // carico il byte basso nell'intero.

accelResult[0] +=  (int)buffer[1] << 8; // sommo all’intero il byte previa promozione a int e shift a sinistra di 8

Mi chiedevo se gli schemi che mi sono fatto per capire la risposta fossero corretti, ma non li carica qui ci sono i link :slight_smile:


Primo schema

Secondo schema

Grazie :slight_smile: