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();
  1. Dati binari da Arduino: port.readable riceve dati binari dalla porta seriale di Arduino.

  2. 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.
  3. 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

  1. Dati binari da Arduino: port.readable.
  2. Decodifica: port.readable.pipeTo(textDecoder.writable). Questo processo decodifica i dati binari in testo.
  3. 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