How to read directly from Serial1? (baby steps into CASIC)

Posted on
Page
of 2
Prev
/ 2
  • Is it same code used for both watches?

    github has quite nice search, you can go to https://github.com/espruino/Espruino and it topleft corner enter e.g. ublox or casic or nmea and click 'in this repository'

    As for using Serial2 - instead of finding random pins for Serial1 it could also work to configure just rx or tx, so do Serial1.setup with just tx: and then setup Serial2 with just rx: and hook into Serial2 'data' event to get replies and still write to Serial1

  • Both, the github search and the search in Espruino-master.zip returns no results for AT6558.

    For "casic" or "uranus" it finds only one result:
    'GPS' : {

            'device' : 'Casic URANUS',
            'pin_en' : 'D29', # IO expander P0
            'pin_rx' : 'D30', 
            'pin_tx' : 'D31'
    

    May be
    BANGLEJS_F18 is Bangle.js
    BANGLEJS_Q3 is Bangle.js 2
    DTNO1_F5 is ?

  • Yes, there is no code that would handle CASIC binary protocol for AT6558, only NMEA is used so far for bangle2 and also ublox protocol for v1. And almost everything for banglejs watches is in libs/banglejs (and some js stuff in libs/js/banglejs). F5 was something like version 0.

  • Yes, there is no code that would handle CASIC binary protocol for AT6558, only NMEA is used so
    far for bangle2 and also ublox protocol for v1

    Do you mean there is no specific code for either in the firmware. For B1 we send UBLOX commands via serial1.write() via a javascript app called gpssetup:

    https://github.com/espruino/BangleApps/b­lob/master/apps/gpssetup/gpssetup.js

    For Bangle 2 we should be able to do the same approach for but different bits and bytes as per the CASIC protocol. The quest we have is how to setup the AT6558 so that it accepts both CAS and CASIC instructions.

    The problem we have at the moment is that the chip appears to be told not to listen or respond to CASIC instructions and the only way to comfigure it to respond is to send a CASIC instriction.

    As for using Serial2 - instead of finding random pins for Serial1 it could also work to configure just >rx or tx, so do Serial1.setup with just tx: and then setup Serial2 with just rx: and hook into Serial2 >'data' event to get replies and still write to Serial1

    This sounds promising. I would not have a lot of confidence in how to code that; but if someone can get the Bangle 2 AT6558 to respond to CASIC instructions (over Serial1,write(), or Serial2.write()) I'm reasonably confident I could figure out how to put the AT6558 into a power saving mode and reduce its battery drain and build a Bangle 2 version of gpssetup.

  • My understanding BANGLEJS_Q3 means Bangle JS2. And Q3 watch has AT6558 chip for GPS.

    But, main question was - is jswrap_banglejs_gps_character(char ch) function assigned to Serial1 input for all time? Can it be unassigned by Serial1.removeAllListeners(); ?
    For Q3 that C code should be adjusted to CASIC not UBX.

  • For Q3 that C code should be adjusted to CASIC not UBX.

    What C code are you referring to ? The C code just sets up the pipes. What flows through the pipes (UBX or CASIC) is sent via javascript in function calls to Serial1.write(...)- isn't it ?

  • I am not saying about GPS chip input, I am about output, what GPS chip sends to Serial1 and how it is processed.
    The code is in bool jswrap_banglejs_gps_character(char ch) in https://github.com/espruino/Espruino/blo­b/master/libs/banglejs/jswrap_bangle.c
    it checks for a protocol, if it is NMEA or UBX it copyes data into ubloxMsg. Otherwise it just skips the data.
    The way it check if it is UBX is in line 3690

        } else if (ch == 0xB5) {
          inComingUbloxProtocol = UBLOX_PROTOCOL_UBX;
    

    That 0xB5 is specific to UBX, for CASIC it should be two bytes 0xBA 0xCE.
    It also checks for consistency of NMEA at 3707-3719. I do not think it will pass whatever "unknown" binary data as NMEA. It will just skip it.

  • Got it ! Bingo - thats the bug. The firmware assumes the Bangle 2 GPS talks UBLOX and throws the responses away if not. There should be a more generic way of doing this in the future.

    Thats why we get no apparent response when we send CASIC commands.
    We need @Gordon to do a firmware update.

    If you agree I will log an issue and reference this thread.
    Its the firmware thats causing the responses to be chucked away !

  • I agree.
    But also I am still puzzled where is the code that assigns jswrap_banglejs_gps_character(char ch) function to Serial1 input forever? And why it cannot be unassigned by Serial1.removeAllListeners(); ?

  • But also I am still puzzled where is the code that assigns jswrap_banglejs_gps_character(char ch) function to Serial1 input forever?

    interesting, it is the type specifier EV_SERIAL1
    https://github.com/espruino/Espruino/blo­b/c09de7bc3a206760f16fd9482c2152dd73a9f6­05/libs/banglejs/jswrap_bangle.c#L3662
    as per this
    https://github.com/espruino/Espruino/blo­b/62a456e99abd49805599c03602cffa5afeaa11­38/scripts/common.py#L63
    so looks like returning always true from that method makes the character handled so it is not passed further.

    The way it is done is quite complicated, here the jswOnCharEvent method is generated from such EV_XXX JSON comments https://github.com/espruino/Espruino/blo­b/47d22f82e1c5b325f62bdccafb324553dcff76­55/scripts/build_jswrapper.py#L689
    and here it is called https://github.com/espruino/Espruino/blo­b/86eba79a209f32a885e08ad34f688d406b04a8­be/src/jsdevices.c#L419

  • Its the firmware thats causing the responses to be chucked away !

    That's why I was suggesting switching GPS output to Serial2 as a quick workaround to test CASIC commands.

    something like this should work once gps is enabled

    Serial1.setup(9600,{tx:D31});
    Serial2.setup(9600,{rx:D30});
    

    then the data will arrive to Serial2 instead where you can handle it yourself

  • @fanoush. Great! This redirection to Serial2 works!
    I am going to try some CASIC now.
    Yes! After CASIC call GPS spits out some binary output. Most likely NACK.

    D29.write(1); // turn GPS on
    // pause
    Serial2.write(0xBA,0xCE,0x00,0x00,0x06,0­x00,0x00,0x06,0x00,0x00);
    //short pause
    D29.write(0);
    =undefined
    ser: ºÎ
    
    
  • First success! CASIC response received and parsed.

    var h1=0,h2=0, l1=0,l2=0,
        cs1=0,cs2=0,cs3=0,cs4=0,
        protocolType="Unknown",
        casicPos=-1, payloadPos=0,
        inCasicMessage=false, casicIsCompleted=false;
    var casicMsg={};
    
    function parseCASIC(data){
      for(var i=0;i<data.length;i++){
        c=data.charCodeAt(i);
        //print("i:",i,"c:",c, "casicPos:",casicPos,"payloadPos:",paylo­adPos);
        if(c==0xBA && casicPos<0){
          h1=c;
          protocolType="CASIC";
          inCasicMessage=true;
          casicIsCompleted=false;
          casicPos=0; payloadPos=0;
          h2=0; l1=0; l2=0; cs1=0;cs2=0;cs3=0;cs4=0;
          casicMsg={};
        }
        else if(!inCasicMessage) return;
        else if(c==0xCE && casicPos==0){
          h2=c;
          casicPos++;
          casicMsg.hdr = (h1<<8) + h2;
        }
        else if(inCasicMessage && casicPos==1){
          l1=c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==2){
          l2=c;
          casicPos++;
          casicMsg.len = (l2<<8) + l1;
        }
        else if(inCasicMessage && casicPos==3){
          casicMsg.class = c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==4){
          casicMsg.msgId = c;
          casicMsg.payload=[];
          payloadPos=0;
          casicPos++;
        }
        else if(inCasicMessage && casicPos>4 && payloadPos<casicMsg.len){
          casicMsg.payload.push(c);
          payloadPos++;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==casicMsg.len+5){
          cs1 = c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==casicMsg.len+6){
          cs2 = c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==casicMsg.len+7){
          cs3 = c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==casicMsg.len+8){
          cs4 = c;
          casicMsg.checkSum = (cs1<<24)+(cs2<<16)+(cs3<<8)+cs4;
          inCasicMessage = false;
          casicIsCompleted = true;
          casicPos = -1;
          protocolType="Unknown";
          print(casicMsg);
        }
      }//for
    }
    
    D29.write(0);
    Serial2.removeAllListeners();
    Serial2.setup(9600,{rx:D30,tx:D31});
    Serial2.on('data', function(data){parseCASIC(data);});
    D29.write(1);
    

    some pause

    //CFG-PRT query
    Serial2.write([0xBA,0xCE, 0x00,0x00, 0x06,0x00, 0x00,0x00,0x06,0x00]);
    =undefined
    { "hdr": 47822, "len": 8, "class": 6, "msgId": 0,
      "payload": [ 1, 7, 192, 8, 0, 194, 1, 0 ],
      "checkSum": 164218632 }
    { "hdr": 47822, "len": 8, "class": 6, "msgId": 0,
      "payload": [ 0, 119, 192, 8, 128, 37, 0, 0 ],
      "checkSum": -2002991608 }
    { "hdr": 47822, "len": 4, "class": 5, "msgId": 1,
      "payload": [ 6, 0, 0, 0 ],
      "checkSum": 167773441 }
    >
    
  • oh, the Serial2.setup silently steals pins from Serial1, I was expecting it to throw some error instead but this is even easier

  • @Mark_M - brilliant ! I can see you had a late night. Many thanks for sharing. Just about to give it a go. I got bogged down in trying to shut the NMEA output up and failed miserably, so didn't make much progress.

    I have logged the firmware issue at:
    https://github.com/espruino/BangleApps/i­ssues/1200

  • to shut NMEA output you can use CAS06 with 0 for all types.
    I have created module AT6558 that can do it conveniently.
    I need to merge it. You can get from my github https://github.com/markmal/BangleApps/tr­ee/master/modules

    now I am starting working to make some functions. I will try to change mode to Car (CFG-NAVX). I tried GPS during driving, it is very slow, I can drive for like 30 sec at 40kph, but it still shows 18. Stubborn.
    I do not know is it because of its poor reception (no or too small antenna) or because it is configured for pedestrians :)

  • to shut NMEA output you can use CAS06 with 0 for all types.

    I got CAS06 as product information. I think its CAS03 to set the outputs

    None of these attempts worked for me.

    // try and slow the output down 
    function cas02() {
      // example $PCAS02,1000*2E  - 1 second in milliseconds
      sendCommand("CAS02,5000");  // does not work
    }
    
    // try and stop the NMEA output
    function stp() {
      //example:  $PCAS03,1,1,1,1,1,1,1,1,0,0,,,1,1,,,,1*3­3
      // attempt no output - did not work
      //sendCommand("CAS03,0,0,0,0,0,0,0,0,0,0­,,,0,0,,,,0");
      // attempt every 100, does not work
      sendCommand("CAS03,100,100,100,100,100,1­00,100,100,100,100,,,100,100,,,,100");
    }
    

    I can see gnss.setSentencesAll("0"); in your code, so assume that works for you.

     gnss.setSystems(1,0,0);
      gnss.setSentencesAll("0");
      gnss.setSentences({RMC:"1"});
      gnss.setUpdateRate(500);
    

    Not to worry, I'm more interested in the CASIC controls to get the NAV frequency down to once every 2 minutes.

    I'm working on trying to get a checksum function to work.
    I will test it from the output of your parse_casic code.

  • here's my variation of your code. Attempted to print out the checksum in Hex as it makes it
    easier to manually check. I'm concerned about the negative checksum - this should not happen.

    //cs1=0,cs2=0,cs3=0,cs4=0,
    
    var h1=0,h2=0, l1=0,l2=0,
        protocolType="Unknown",
        casicPos=-1, payloadPos=0,
        inCasicMessage=false, casicIsCompleted=false;
    
    var cs1 = new Uint32Array(1);
    var cs2 = new Uint32Array(1);
    var cs3 = new Uint32Array(1);
    var cs4 = new Uint32Array(1);
    
    cs1[0] = 0;
    cs2[0] = 0;
    cs3[0] = 0;
    cs4[0] = 0;
    
    var casicMsg={};
    
    function parseCASIC(data){
      for(var i=0;i<data.length;i++){
        c=data.charCodeAt(i);
        //print("i:",i,"c:",c, "casicPos:",casicPos,"payloadPos:",paylo­adPos);
        if(c==0xBA && casicPos<0){
          h1=c;
          protocolType="CASIC";
          inCasicMessage=true;
          casicIsCompleted=false;
          casicPos=0; payloadPos=0;
          h2=0; l1=0; l2=0; cs1[0]=0;cs2[0]=0;cs3[0]=0;cs4[0]=0;
          casicMsg={};
        }
        else if(!inCasicMessage) return;
        // header byte 2
        else if(c==0xCE && casicPos==0){
          h2=c;
          casicPos++;
          casicMsg.hdr = (h1<<8) + h2;
          casicMsg.hdr = '0x' + (casicMsg.hdr).toString(16).toUpperCase(­);
        }
        // length byte1
        else if(inCasicMessage && casicPos==1){
          l1=c;
          casicPos++;
        }
        // length byte2
        else if(inCasicMessage && casicPos==2){
          l2=c;
          casicPos++;
          casicMsg.len = (l2<<8) + l1;
          //casicMsg.len = '0x' + casicMsg.len.toString(16).toUpperCase();­
        }
        // class 
        else if(inCasicMessage && casicPos==3){
          casicMsg.class = c;
          casicPos++;
        }
        // msg id
        else if(inCasicMessage && casicPos==4){
          casicMsg.msgId = c;
          casicMsg.payload=[];
          payloadPos=0;
          casicPos++;
        }
        // accumulate payload
        else if(inCasicMessage && casicPos>4 && payloadPos<casicMsg.len){
          casicMsg.payload.push(c);
          payloadPos++;
          casicPos++;
        }
        // checksum bytes cs1, cs2, cs3, cs4
        else if(inCasicMessage && casicPos==casicMsg.len+5){
          cs1[0] = c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==casicMsg.len+6){
          cs2[0] = c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==casicMsg.len+7){
          cs3[0] = c;
          casicPos++;
        }
        else if(inCasicMessage && casicPos==casicMsg.len+8){
          cs4[0] = c;
          casicMsg.checkSum = ((cs1[0]<<24)+(cs2[0]<<16)+(cs3[0]<<8)+c­s4[0]);
          casicMsg.checkSum16 = '0x' + casicMsg.checkSum.toString(16).toUpperCa­se();
          inCasicMessage = false;
          casicIsCompleted = true;
          casicPos = -1;
          protocolType="Unknown";
          print(casicMsg);
        }
      }//for
    }
    
    function setup() {
      print("setup()");
      D29.write(0);
      Serial2.removeAllListeners();
      Serial2.setup(9600,{rx:D30,tx:D31});
      Serial2.on('data', function(data){parseCASIC(data);});
    }
    
    function pon() {
      print("power on");
      setup();
      D29.write(1);
    }
    
    
    function pof() {
      print("power off");
      D29.write(0);
    }
    
    function prt() {
      Serial2.write([0xBA,0xCE, 0x00,0x00, 0x06,0x00, 0x00,0x00,0x06,0x00]);
    }
    

    Here's the output

    >prt();
    =undefined
    {
      "hdr": "0xBACE",
      "len": 8, "class": 6, "msgId": 0,
      "payload": [ 1, 7, 192, 8, 0, 194, 1, 0 ],
      "checkSum": 164218632,
      "checkSum16": "0x9C9C708"
     }
    {
      "hdr": "0xBACE",
      "len": 8, "class": 6, "msgId": 0,
      "payload": [ 0, 119, 192, 8, 128, 37, 0, 0 ],
      "checkSum": -2002991608,
      "checkSum16": "0x-776339F8"
     }
    {
      "hdr": "0xBACE",
      "len": 4, "class": 5, "msgId": 1,
      "payload": [ 6, 0, 0, 0 ],
      "checkSum": 167773441,
      "checkSum16": "0xA000501"
     }
    >pof();
    power off
    =undefined
    
  • I'm concerned about the negative checksum - this should not happen.

    https://stackoverflow.com/questions/1908­492/unsigned-integer-in-javascript

  • The only JavaScript operator that works using unsigned 32-bit integers is >>>. You can exploit this >to convert a signed-integer-in-Number you've been working on with the other bitwise operators >to an unsigned-integer-in-Number:

    sounds like need todo >>> 0 at the end of the checksum calculation in parseCasic.

  • or store it to Uint32 array element instead of reading from it (which does nothing helpful)

  • @HughB

    Not to worry, I'm more interested in the CASIC controls to get the NAV frequency down to once every 2 minutes.

    I doubt it is possible.
    I've made code that can set intervals 1000, 500, 200,100,50(yes, 20Hz!). But for other values it returns NACK.

    function ckSum(len,cls,mid, pldDV){
      var cs = (mid<<24)|(cls<<16)|len;
      for(var i=6; i<pldDV.buffer.length; i+=4){
        print(i, pldDV.getUint32(i, true));
        cs += pldDV.getUint32(i, true);
      }
      print(cs.toString(16));
      return cs;
    }
    const UD='undefined';
    function sendCfgRate(cfg){
      const cls=0x06, mid=0x04;
      var len = (typeof(cfg.interval)!=UD)?4:0;
      var msg = new ArrayBuffer(6+len+4);
      var dv = new DataView(msg);
      dv.setUint8(0,0xBA); dv.setUint8(1,0xCE);
      dv.setUint16(2, len, true);
      dv.setUint8(4,cls); dv.setUint8(5,mid);
    
      if(typeof(cfg.interval)!=UD){dv.setUint1­6(6+0,cfg.interval,true);}
      cs = ckSum(len,cls,mid,dv);
      dv.setUint32(6+len,cs, true);
      print(msg);
      Serial2.write(msg);
    }
    
    sendCfgRate({interval:10000})
    6 10000
    10 0
    4062714
    new Uint8Array([186, 206, 4, 0, 6, 4, 16, 39, 0, 0, 20, 39, 6, 4]).buffer
    =undefined
    { "hdr": 47822, "len": 4,
      "payload": new Uint8Array([6, 4, 0, 0]).buffer,
      "payloadBytes": new Uint8Array([6, 4, 0, 0]),
      "class": 5, "msgId": 0, "checkSum": 168035584,
      "name": "ACK-NACK"
     }
    >
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

How to read directly from Serial1? (baby steps into CASIC)

Posted by Avatar for Mark_M @Mark_M

Actions