Newsgroup: it.hobby.elettronica.digitale
Titolo: Stream binario

Ciao,
chiedo scusa per il secondo post di richiesta nella stessa giornata...
Ho uno stream binario di dati che contiene dei pacchetti di informazione 
di lunghezza variabile. Devo riuscire a isolare correttamente tali 
pacchetti. Il protocollo è proprietario (mio) quindi posso adeguarlo 
come necessario.
Fermo restando che vorrei mantenerlo binario anziché testuale il 
problema sorge ovviamente nel sincronismo: non essendo di lunghezza 
fissa devo usare dei marcatori per stabilire l'inizio e la fine. Ma dal 
momento che i dati sono binari (e realisticamente casuali) posso avere 
occorrenze di tali marcatori anche nell'informazione stessa.
So che ci sono delle tecniche per mantenere la coerenza (tipo 
raddoppiare il marcatore se presente nell'informazione o usare sequenze 
poco probabili).
Prima di avventurarmi però in una strada senza uscita vorrei domandare a 
chi ha più esperienza se vi è davvero una soluzione efficiente al 
problema. Efficiente per me significa che l'overhead (nello stream e nel 
processo di elaborazione) deve essere minore rispetto a uno stream 
testuale, altrimenti non ne vale la pena...
Qualche dato: i pacchetti possono avere lunghezze comprese tra una 
decina di byte e alcune centinaia. Contengono quasi esclusivamente 
valori numerici a 8 e 16 bit. Quindi se in binario un int16 mi occupa 2 
byte, in modalità testo come minimo mi raddoppia (hex).
Grazie anticipate!
--
Marco / iw2nzm

 byte, in modalità testo come minimo mi raddoppia (hex).
Ah, ora ho capito: per modalità testo intendi dire codificata in ASCII.
In pratica hai bisogno di qualcosa che ti dica se il byte ricevuto è un
dato a 8 bit o se è la metà di un 16 bit?
Mi sembra però strano che questa sia la sola informazione che ti serve per
interpretare correttamente i dati.
Devi sapere meglio che genere di dati vuoi spedire: è più importante che
siano affidabili, ovvero che possano essere ri-trasmessi in caso di errore
o che siano in real-time?
Proprietario per proprietario, se l'hardware te lo permette puoi
trasmettere a 9 bit, col MSb che ti dice se è il primo byte di un 16 bit o
un 8 bit oppure se è il secondo byte di un 16 bit.
Se il flusso è bidirezionale e puoi ordinare i dati potresti inviare prima
i byte singoli, precedduti di un byte o due di header. Se sono meno di 127
valori, ne scrivi il numero, se sono meno di 32768 ne scrivi il numero, ma
con il MSb settato a 1. A fine pacchetto il ricevente ti dovrà rispondere
con un ack.
Per il controllo errori la parità è un sistema poco efficiente e sicuro. Ti
conviene forse trasmettere senza e spedire, alla fine, il CRC della
sequenza completa. Se al ricevente la CRC non torna, invierà un NAK.
Insomma, io copierei i pacchetti di TCP/IP e buonanotte al secchio. ;-)

 quindi posso adeguarlo come necessario.
E' un problema annoso... :-) In cui mi sono imbattuto
diverse volte (ad esempio succede spesso quando
usi l'USB...). La soluzione dipende dal tipo di flusso
dati e dalle sue caratteristiche.
Una soluzione usata a volte (ad esempio negli
stream MIDI) è riservare un bit di ciascun byte
per indicare se si tratta di dati o inizio messaggio
(o comando). Ovviamente devi poi provvedere
ad alloggiare i bit rimanenti da qualche parte...
Questo metodo è abbastanza semplice ed
efficiente e non necessita dell'inserimento di
un header con la lunghezza del pacchetto.
Un altro metodo consiste nell'inserire un piccolo
header composto da un carattere identificativo,
la lunghezza del pacchetto ed un controllo di
correttezza alla fine del pacchetto. Inizialmente
attendi il carattere identificativo,  quando ne
ricevi uno inizi a memorizzare il pacchetto, ti fermi
alla lunghezza specificata e controlli la correttezza.
Se il tutto va a buon fine sei sincronizzato con
lo stream: ti rimetterai ad attendere il prossimo
header e lo riceverai correttamente... Se il
controllo non va a buon fine, butti via tutto ed
attendi di nuovo il carattere identificativo. Dopo
un pò di tentativi ti sincronizzerai. E' importante
implementare un controllo sulla lunghezza massima
dei pacchetti per evitare errori o perdite di tempo.
Una volta che ti sincronizzi, a meno che non
succedano cose strane (interruzioni o alterazioni
dello stream) rimani sincronizzato.
Un terzo metodo è quello a cui accennavi tu: usare
un indentificativo unico, e se questo appare anche
nei dati raddoppiarlo (o meglio segnalarlo in qualche
modo). In questo modo puoi distinguere se si tratta
dell'inizio o di un dato.
Buona fortuna,
A.D.

 Per il controllo errori la parità [...]
Mi rendo conto di essere stato equivoco, ho parlato genericamente di 
stream ma non ho detto che fosse seriale. In effetti non lo è :)
Si tratta di un file letto da una SDIO. Quindi ho solo 8 bit per 
carattere, nessuna parità e flusso unidirezionale.
Ci ho pensato su stanotte: mi sto complicando la vita per nulla. 
Converto tutti i dati in hex (ascii) e così posso usare senza problemi i 
marcatori che preferisco (comodo anche il \r\n per fine riga/pacchetto).
Il discorso rimane aperto, ma per questa implementazione direi che posso 
accettare una maggiore lunghezza dei pacchetti a fronte di una maggiore 
semplicità di gestione.
Ciao e grazie degli interventi come sempre!
Marco / iw2nzm

 dell'inizio o di un dato.
Bene, è comunque un'alternativa da avere nel bagaglio!
Grazie anche a te e buona domenica!
Marco / iw2nzm

 poco probabili).
Infatti mi sembra la tecnica migliore, se sei proprio convinto ad 
abbandonare l'ASCII.
Questa tecnica funziona ed è usata ampiamente in moltissime situazioni, 
soprattutto quando devi creare, in un collegamento punto-punto (com'è 
quella di una RS232), più porte virtuali. Ho visto da qualche parte una 
intera funzione di libreria che permetteva di aprire, sullo stesso 
canale punto-punto, più porte seriali virtuali e trattarle in modo 
indipendente. La libreria si occupava di multiplexare e demultiplexar i 
vari pacchetti delle diverse porte seriali virtuali nell'unico canale 
fisico.
Lo stesso PPP usato dai modem PSTN nella connessione ad Internet 
utilizzano tecniche simili.
Un esempio per tutti è l'HDLC che, in molti micro, è gestito 
direttamente via hardware, ma non è così complicato da implementare via 
software.
http://en.wikipedia.org/wiki/High-Level_Data_Link_Control
Ci sono anche dei pacchetti utilizzati per riconfigurare la linea 
punto-punto.
Comunque sia, non scarterei la soluzione del Bertolazzi, anche se, 
probabilmente, non è molto portabile. Trasmetti sempre a 9 bit (quindi 
hai un overhead di 1/9) e il non bit indica l'inizio di un pacchetto.

 testuale, altrimenti non ne vale la pena...
Confermo che è un tecnica molto efficace, il caso peggiore ce l'hai 
quando devi inviare una pacchetto contenente una sfilza di soli 
marcatori, in quel caso la dimensione del pacchetto inviata raddoppia.
Però questa eventualità è poco probabile, quindi la lunghezza dello 
stream inviato è mediamente molto ridotta, limitata a quello che serve.
Anche per quanto riguarda l'overhead in elaborazione posso confermarti 
che è molto limitato: durante l'invio basta cambiare la funzione di 
send/scrittura in modo che quando trova un marcatore esegua l'escape.
Durante la ricezione è necessario un flag che ti dica se sei o meno in 
escape, ma anche questa è roba da poco.
Per avere un'idea puoi guardare il loop di "snocciolamento" fatto per 
il nostro pocketbus, è abbastanza generico anche da adattarsi a un file:
http://www.bertos.org/browser/trunk/bertos/net/pocketbus.c#L165
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org

 funzionare perché devo leggere *tutti* i pacchetti, nessuno escluso.
Allora dove sta' il problema? se e' un file, basta  precedere i 
pacchetti con un header tipo:
STX, LEN_OF_DATA, [block_of_data],  STX,STX, LEN_OF_DATA,[....], ...EOT
Siccome non c'e' il problema della ricezione asincrona nel bel  mezzo di un
frame, ma sei sequenziale, basta trovare il carattere di STX (o quello 
che vuoi),
leggere la lunghezza del blocco dati, leggere il blocco, controllare di 
avere un
altro STX (o EOT, se serve chiudere), determinare la lunghezza dei dati 
e via....
Devi solo determinare quanti byte ti servono per la lunghezza del pacchetto.
Volendo sofisticare puoi anche aggiungere un controllo di sequenza ciclico:
STX, [sequence], Lengh........
dove sequence = 0,1,2...255, 0 etc....
B.

 STX, LEN_OF_DATA, [block_of_data],  STX,STX, LEN_OF_DATA,[....], ...EOT
Giusto. E dire che ci avevo anche pensato ma l'avevo scartata per non so 
quali motivi.
Perché a volte sono così ottuso? :-/
Marco / iw2nzm