Lettura Dati con o senza PipeTo
Mettiamo a confronto due approcci diversi per leggere dati in arrivo dalla porta seriale. Qui sotto abbiamo un esempio di uso del pipeTo:
const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
reader = textDecoder.readable.getReader(); |
-
Dati binari da Arduino: port.readable riceve dati binari dalla porta seriale di Arduino.
-
Pipeline di decodifica:
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
- port.readable: Questo è lo stream leggibile che fornisce dati binari dalla porta seriale.
- textDecoder.writable: Questo è lo stream scrivibile del TextDecoderStream, che accetta dati binari e li decodifica in testo.
- pipeTo(): Incanala (pipe) i dati binari dallo stream leggibile della porta seriale allo stream scrivibile del TextDecoderStream.
-
Lettore per leggere dati decodificati:
reader = textDecoder.readable.getReader();
- textDecoder.readable: Questo è lo stream leggibile del TextDecoderStream, che ora contiene dati di testo decodificati.
- getReader(): Crea un lettore (reader) per leggere i dati dallo stream leggibile del TextDecoderStream.
Chiarimenti aggiuntivi
-
textDecoder.writable: Questo rappresenta la parte scrivibile del TextDecoderStream. I dati binari incanalati qui attraverso pipeTo vengono automaticamente decodificati in testo. Anche se non lo usi direttamente nel codice successivo, è fondamentale per il processo di decodifica. Una volta che i dati binari vengono incanalati in textDecoder.writable, non hai più bisogno di interagire direttamente con questo stream. Il suo ruolo è finito, in quanto ha già decodificato i dati che poi leggi dallo stream leggibile (textDecoder.readable).
-
writer = port.writable.getWriter(): Questo è per scrivere dati binari sulla porta seriale di Arduino. Serve per inviare comandi o valori dallo slider ad Arduino.
Flusso dei dati
- Dati binari da Arduino: port.readable.
- Decodifica: port.readable.pipeTo(textDecoder.writable). Questo processo decodifica i dati binari in testo.
- Lettura dei dati decodificati: reader = textDecoder.readable.getReader().
Il lettore (reader) che ottieni da textDecoder.readable.getReader() serve per leggere i dati di testo decodificati.
Quando leggi i dati:
const { value, done } = await reader.read();
value contiene il testo decodificato proveniente da Arduino.
Differenza tra lettore di dati binari e decodificati
- Lettore di dati binari: port.readable.getReader() ti darebbe un lettore per leggere direttamente i dati binari dalla porta seriale.
- Lettore di dati decodificati: textDecoder.readable.getReader() ti dà un lettore per leggere i dati di testo decodificati dal TextDecoderStream.
Uso di textDecoder.writable
Sebbene non interagisca direttamente con textDecoder.writable dopo aver incanalato i dati con pipeTo, è essenziale per la pipeline di decodifica. Senza di esso, i dati binari non verrebbero trasformati in testo.
Conclusione
textDecoder.writable viene usato implicitamente attraverso pipeTo per decodificare i dati binari in testo. Non hai bisogno di interagire direttamente con textDecoder.writable dopo la decodifica. Invece, leggi i dati decodificati dallo stream leggibile di TextDecoderStream usando un lettore (reader).
Che cosa è: readableStreamClosed
E' una promessa che si risolve quando il textDecoder.writable si chiude. Può essere usato per:
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
readableStreamClosed.then(() => {
console.log('La pipeline è stata completata con successo.');
}).catch((error) => {
console.error('Errore nella pipeline:', error);
});
Qui sotto vediamo come leggere dati dalla seriale con questo approccio
Come si può notare non abbia nessuna decodifica dei dati, perchè i dati sono già decodificati. Infatti il reader che viene usato è quello reader = textDecoder.readable.getReader(); cioè quello che legge i dati dal textDecoder.writable percui value contiene testo legibile e non byte.
async function readSerialData() {
let buffer = '';
while (potActive) {
const { value, done } = await reader.read();
if (done) {
console.log('Reader closed');
break;
}
if (value) {
buffer += value;
let lines = buffer.split('\n');
buffer = lines.pop();
for (let line of lines) {
line = line.trim();
if (line) {
const potValue = parseInt(line);
const voltage = (potValue / 1023.0 * 1.8).toFixed(2);
document.getElementById('potValue').innerText = voltage;
}
}
}
}
} |
Se invece non facessimo uso di pipeTo come in questo caso:
reader = port.readable.getReader(); |
Qui il reader è un normale reader che leggedati binari dallaporta seriale.
E sotto dobbiamo aggiungere: const textDecoder = new TextDecoder(); che è diverso da:
const textDecoder = new TextDecoderStream();
e quando leggiamo:
const { value, done } = await reader.read(); value contiene byte e non testo percui bisognerà fare il decode prima di visualizzarli in potValue: buffer += textDecoder.decode(value, { stream: true }); Importante aggiungere l'attributo: { stream: true } che permette di non perdere i dat tronchi.
async function readSerialData() {
let buffer = '';
const textDecoder = new TextDecoder();
while (potActive) {
const { value, done } = await reader.read();
if (done) {
console.log('Reader closed');
break;
}
if (value) {
buffer += textDecoder.decode(value, { stream: true });
let lines = buffer.split('\n');
buffer = lines.pop();
for (let line of lines) {
line = line.trim();
if (line) {
const potValue = parseInt(line);
const voltage = (potValue / 1023.0 * 1.8).toFixed(2);
console.log("Voltage: " + voltage);
document.getElementById('potValue').innerText = voltage;
}
}
}
}
} |
Tutto sommato preferisco il secondo metodo
|