• @Gordon,

    thanks for taking the time to read and respond... I'll give it a shot, last but not least because I'm not successful yet with 'playing back' the received data, which means that either Espruino is not producing the right bit stream or the modulation/demodulation in the original case added something that was compensated in the device's receiving software.

    Questions - answered them myself by reading the API doc... haha...:

    1. Is the E.setClock(...) also good for Serial2/USART2? - switched over to Serial2 from Serial1
    2. What is the impact of changing this for any other serial communication?

    Btw, I noticed that the protocol is two (2) stop bits... (explaining the 'gap' of one bit between the bytes received).

    I noticed that I never shared the code that does super-soft software serial in JS... Espruino JavaScript is so fast and efficient, that it can handle the 316 baud rate...

    Main line is:

    • have a single object for control and data to minimize scope for / optimize var look up (rather than have individual globals or a bunch of locals w/ multiple parameters passings - does it matter? @Gordon can debunk by thoughts...)
    • setup to wait for first start bit in wSB(), start flank
    • sample start bit sSB() 'half a bit later' (or a tad shorter - 1.47 instead of 1.57 ms... to not be/start late for sure... also trying to compensate not only for the setup of setWatch() but also for the setup of setInterval()... have though no clue if it and what value makes sense... I'm just thinking)
    • keep sampling remaining bits - mainly data bits - in sDB() in intervals of 'a bit later' until including all bits of a byte are done: data, parity and stop bits. Also handle / check parity and keep only 'good' bytes. Key concept used is the bit weight .w that controls everything... (state of 'state machine').
    • start over with waiting and sampling until done - stop stopRecSOD() is invoked from console (when device's transmit LED stops flickering), which sets a flag to not watch for stop bits anymore and clear eventual watch, but let eventual sampling finish.
    • do hex dump for validation of bytes receive after waiting at least for a byte

    Here the code (a bit formatted for legibility...):

    // SWSerialInEspruinoJS.js
    // 20231228ao
    //
    var u; // = undefined constant
    var lon = true; // false; // true; // logging is on
    function log() { if (lon) { console.log.apply(console,arguments); } }
    
    // wire connections (in code use ums view names)
    //  ums=pico view | ums view || ums              pico
    var SOD=A3   // I | SOD   O  || serial out on USART2/1 SERIAL2/1 RX (A3/B7) I
      , SID=A2   // O | SID   I  || serial in  on USART2/1 SERIAL2/1 TX (A2/B6) O
      ;
    
    function setPinModes() {
      //      ums - pico view
      pinMode(SID,"output");
      pinMode(SOD,"input");
    }
    
    function hex(v) { return ((v>15) ?
      hex(v>>4) : "")+"0123456789ABCDEF".charAt(v&15); } // hex...
    function hep(v,ds) { // hex, digits (w/ blank padding up to ds)
      return ("        "+hex(v)).substr(-ds); }
    function lep(v,ds) { // hex, digits (w/ 0 padded up to ds)
      return ("00000000"+hex(v)).substr(-ds); }
    
    var sod =
    { l: 2056 // length of d
    , d:   [] // bytes as u8int array
    , f:    0 // fill level of d
    , wId:  u // stop bit watch id
    , iId:  u // data / parity / stop bit interval id
    , byt:  0 // byte
    , w:    0 // bit weight
    , pC:   0 // parity calculated
    , pR:   0 // parity received
    , pEC:  0 // parity error count
    , fEC:  0 // framing error count
    , r:    0 // running (status)
    };
    sod.d = new Uint8Array(sod.l);
    
    function startRecSOD() { // uses:
      // wSB(): Watch SOD Start Bit
      // sSB(): Sample SOD Start Bit
      // sDB(): Sample SOD Data Bit and others too, incl parity handling
      // sPB(); Sample SOD Parity Bit - part of sDB() - no need, included in sDB
      // sTB(); Sample SOD sTop Bit - part of sDB() - no need, included in sDB
      if (sod.d.length !== sod.l) sod.d=new Uint8Array(sod.l);
      sod.f=0; sod.pEC=0; sod.fEC=0; sod.r=1;
      wSB(sod); // 314,157 ms full bit time / half bit time
    }
    
    function stopRecSOD(sAddr) {
      sod.r=0;
      if (sod.wId) sod.wId=clearWatch(sod.wId);
      setTimeout(function(){
          // console.log(new Uint8Array(sod.buffer,0,_.f));
          console.log("...stopRecSOD.");
          var arr=[], prtd=0, cols=16, addr = sAddr || 0;
          console.log( lep(addr,4) + "..."
                     + lep(addr+sod.f - 1 - 1,4) + " + "
                     + lep(sod.d[sod.f - 1],2) + " check byte: "
                     + sod.f + " bytes ok, "
                     + sod.pEC + " parity errs, "
                     + sod.fEC + " framing errs"
                     );
          while (prtd<sod.f-1) { arr=[]; cols=16;
            arr.push(lep(addr,4)); arr.push(":");
            while (--cols>=0 && prtd<sod.f-1) {
              arr.push(lep(sod.d[prtd++],2)); addr++;
            } console.log(arr.join(" "));
          }
        },11*3.14);
    }
    
    function wSB(_) {
      _.byt=0; _.w=1; _.pC=1;
      if (_.r) {
        _.wId=setWatch(()=>setTimeout(sSB,1.47,_­)
           ,SOD,{repeat:0,edge:"falling"}); } }
    
    function sSB(_) {
      _.iId=(!digitalRead(SOD))
              ? setInterval(sDB,3.14,_)
              : wSB(_); }
    
    function sDB(_) {
      var b=digitalRead(SOD);
      if (_.w<256) {
        if (b) {
          _.byt+=_.w;
          _.pC^=b;
        }
        _.w=_.w<<1;
      } else {
        _.w=_.w<<1;
        if (_.w>512) {
          clearInterval(_.iId);
          if (b) {
            if (_.pC===_.pR) _.d[_.f++]=_.byt; else _.pEC++;
          } else {
            _.fEC++;
          }
          wSB(_);
        } else {
          _.pR=b; } } }
      
    function onInit() {
      setPinModes();
      startRecSOD();
    }
    
    setTimeout(onInit,999); // dev only; remove before upload for save()
    

    Here the console output:

    var t=`
    |  __|___ ___ ___ _ _|_|___ ___
    |  __|_ -| . |  _| | | |   | . |
    |____|___|  _|_| |___|_|_|_|___|
             |_| espruino.com
     2v19 (c) 2021 G.Williams
    >
    startRecSOD...
    >stopRecSOD(0x800);
    =undefined
    ...stopRecSOD.
    0800...080E + FC check byte: 16 bytes ok, 0 parity errs, 0 framing errs
    0800 : 00 01 02 04 08 10 20 40 80 FF 0F F0 00 55 AA
    > 
    `;
    

    The code borrowed ideas from the device's implementation of reading serial input. Something next in line to simulate input for.

    'Formatted' code looks a bit bloated... here the origin:

    function wSB(_) { _.byt=0; _.w=1; _.pC=1; if (_.r)
      _.wId=setWatch(()=>setTimeout(sSB,1.47,_­)
        ,SOD,{repeat:0,edge:"falling"}); }
    function sSB(_) {
      _.iId=(!digitalRead(SOD))?setInterval(sD­B,3.14,_):wSB(_); }
    function sDB(_) { var b=digitalRead(SOD);
      if (_.w<256) { if (b)  { _.byt+=_.w; _.pC^=b; } _.w=_.w<<1;
      } else { _.w=_.w<<1; if (_.w>512) { clearInterval(_.iId);
        if (b) { if (_.pC===_.pR) _.d[_.f++]=_.byt; else _.pEC++; 
        } else { _.fEC++; } wSB(_); } else _.pR=b; } }
    

    Now working on reading the data back: sending the data back to device as received before and stored in a 'file'. Even Espruino Software Serial is not producing a serial data stream accepted by the device. Playing w/ the 330 baud rate and E.setClock(...) gives me some hope until I will take out the 'big guns', like DSO... (My pride to be frugal in material but wasteful in thinking and time gets in my way for moving speedy... but it is somewhat the goal: understanding what's going on and where 'it' leaves the 'happy path'... (I'm part of the 'it'... haha...)...)

    ...so much for (late) Happy New Espruino Year 2024

About

Avatar for allObjects @allObjects started