.toString(radix) ?

Posted on
  • Hello,
    i'm working with Voice module from DFRobot

    if i use an array of command i'm supposed to receive some datas
    i'm trying to convert the data in hexa value...
    when i'm trying .toString(radix), console displays always the same char, not bin or oct or hex value...

    sorry, where i'm wrong?

    s.setup(9600,{rx:A8, tx:B7});
      s.on('data', function(d) {
        console.log(d.toString(2),d.toString(8),­d.toString(16));
      });
    

    it display

    ª ª ª
    $ $ $
    
  • Assuming d is an array of numbers / bytes - not String or array of strings:

    Reference doc http://www.espruino.com/Reference#l_Arra­y_toString says:

    Parameter - radix: unused

    Referred-to detail reference on MDN - https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Global_Objects­/Array/toString - does not have any parameter for Array.toString(). May be that having a parameter is something @Gordon has in mind for future purposes...

    ...on the other hand it make perfect sense:

    You apply .toString() to the array object and not to the individual items in the array. If you do so, it just works. Did some messing around in the browser debugger console - you get there by ctrl-click and inspect, where you can enter JavaScript expressions when not being connected to an Espruino board:

    [11,12,9].toString(16)
    --> "11,12,9,32"
    [11,12,9].forEach(function(b){ console.log(b.toString(16)); })
    VM3935:1--> b
    VM3935:1--> c
    VM3935:1--> 9
    VM3935:1--> 20
    --> undefined
    [11,12,9,32].reduce(function(r,b){ return r+b.toString(16); },"")
    --> "bc920"
    [11,12,9,32].reduce(function(r,b){ return r+("0"+b.toString(16)).substr(-2); },"")
    --> "0b0c0920"
    

    Use Array.reduce(...) and you get what you are looking for... just make sure that you always get a 2-digit value for values less than 16 when talking hex, otherwise you cannot read it 'back' (talking octal, you need to bump it up to 3-digit).

    Just validated in Espruino (on an Espruino-Wifi w/ Espruino 2v00). What though is clear is that the array elements have to be numbers / bytes, and NOT Strings or Chars.

    >reset()
    =undefined
     ____                 _
    |  __|___ ___ ___ _ _|_|___ ___
    |  __|_ -| . |  _| | | |   | . |
    |____|___|  _|_| |___|_|_|_|___|
             |_| espruino.com
     2v00 (c) 2018 G.Williams
    >[11,12,9,32].reduce(function(r,b){ return r+("0"+b.toString(16)).substr(-2); },"")
    ="0b0c0920"
    > 
    

    BUT d is not an array of numbers or bytes, as I wrongly assumed: data return from Serial is always a String... where as from others, such as I2C, SPI, etc. it is a byte array...

    THEREFORE , we have to get a byte array from the string. This is the final answer:

    >new Uint8Array(E.toArrayBuffer("012 abc"))
    =new Uint8Array([48, 49, 50, 32, 97, 98, 99])
    >(new Uint8Array(E.toArrayBuffer("012 abc"))).reduce(function(r,b){ return r+("0"+b.toString(16)).substr(-2); },"")
    ="30313220616263"
    > 
    

    ...and with variable d being the String:

    console.log((new Uint8Array(E.toArrayBuffer(d))).reduce(f­unction(r,b){ return r+("0"+b.toString(16)).substr(-2); },""));
    

    This is for hex... the others are similar.

    PS: @Gordon, could this parameter - if present - be used to trigger the alternate interpretation which is applying .toString(...) to the individual elements and still return a string rather than to the array as a whole? ...and even extend it to work on a String? ...I know, it is not standard JavaScript... so better not doing it, but finding other ways that to it fast.

  • Hello Markus,
    a Happy new Year.

    i've found that in the forum and it do the job as i expect.

    console.log("hex:",d.charCodeAt().toStri­ng(16));
    

    the module send some char and the last one is the SUM of the transmitted string.
    i wrote something like that (i did not test it on the espruino)

    let sum=0;
    let buf = new Uint8Array();
    
    function checkAnswer(buff) {
      console.log(buff.toString(16));
     switch (buff[1]) {
       case 0x01: // status
         console.log("status:",buff[3]);
         break;
       case 0x0C: //total audios
         console.log("total audios:",buff[3],buff[4]);
         break;
       case 0x0D: //current audio
         console.log("current audio:",buff[3],buff[4]);
         break;
       default:
         break;
      }
      // reset first buffer
      buf = new Uint8Array();
    }
    
    s.setup(9600,{rx:B6, tx:B5});
      s.on('data', function(d) {
        console.log("hex",d.charCodeAt().toStrin­g(16).toUpperCase());
        let nd = d.charCodeAt();
        buf.push(nd);
        sum+= nd;
        if (sum == nd && buf.length >1) {
          // fin de la transmission
          buf.pop(); // efface le sum du buffer
          sum = 0;
          checkAnswer(buf);
        }
      });
    
    

    regards

  • Happy New Year to you too, Eric!

    I assume that your anonymous function in s(erial).on("data",function(d){...}) is not complete yet (because String.charCodeAt(index) needs an index into the string to indicate from which char you want the code (ascii value). For the interpretation of the complete response, you can go directly after each character's code in the response string ( switch response.charAt(1) { ... case 0x0C: ... }; and do not have to go through the buffer of numbers business...

    Composing the response though may change too, because data received my contain (parts) of more than one response (I do not know if this is possible with your device, but even then, when responses back up / congest for what ever reason, you will get there). Extract response one by one from composed received data and interpret only the extracted one.

    Checkout the gps module. It does this, because it receives multiple sentences and each has to be interpreted standalone.

  • i give you an example of a frame

    //Check Playback Status(01)
    //Command: AA 01 00 AB
    let command= [0xAA,0x01,0x00,0xAB];
    s.write(command)
    //Return: AA 01 01 Playback status SuM
    

    if i've read and kept the good part in the gps module, it use an object and fill the "line" until it's more than 80chars or until \n char.

     var gps = {line:""};
      serial.on('data', function(data) {
        gps.line += data;
      });
    

    i do not have this '\n' in the frame module.
    the length is not always the same. between 5 and 7 chars.
    The last char is always a sum of the values sent...
    I could :
    evaluate continiously the frame to know when it is end (the sum)
    or
    evaluate the second char received to determine the length of the frame (the command),
    or
    anticipate the length (5,6,7) of the response by the command sent.

    'Status', send back 5 chars
    'duration of the current audio', send back 7 chars.

    thanks

    i'll try.

  • oh and a simple question about Upper-byte and Lower-Byte

    Return: AA 11 02 Upper-byte Lower-byte SM
    

    to add these upper and lower bytes...

    should i do like this result = upperByte<<8 ^ lowerByte ?

  • i've written something like that

    var reponse= {trame:"",longueur:0};
    
    s.setup(9600,{rx:B6, tx:B5});
    s.on('data', function(data) {
      reponse.trame+= data;
      if (reponse.trame.length >= reponse.longueur) {
        switch (reponse.trame.charCodeAt(1)) {
          case 0x01: // status
            console.log("status:",reponse.trame.char­CodeAt(3));
            break;
          case 0x09: // status
            console.log("check Drive:",reponse.trame.charCodeAt(3));
            break;
          case 0x12: //Check the total numbers of audio in all folders(12)
            console.log("nbr total audios:",(reponse.trame.charCodeAt(3)<<8­ ^ reponse.trame.charCodeAt(4)));
            break;
          case 0x0C: //Check the total audios(0C)
            console.log("nbr total audios:",(reponse.trame.charCodeAt(3)<<8­ ^ reponse.trame.charCodeAt(4)));
            break;
          case 0x0D: //current audio
            console.log("nom fichier audio:",reponse.trame.charCodeAt(3),repo­nse.trame.charCodeAt(4));
            break;
          case 0x24: //duration audio
            console.log("Duréé: "+reponse.trame.charCodeAt(3)+"H "+reponse.trame.charCodeAt(4)+"mn "+reponse.trame.charCodeAt(5)+"s");
            break;
          default:
            break;
          }
      }
    });
    

    and each command sent, fill the reponse.longeur with the appropriate value...

    function Duration() {
     var command = [0xAA, 0x24, 0x00, 0xCE];
      // Return: AA 24 03 hour minute second SM
      reponse.longueur = 7;
      reponse.trame = "";
      s.write(command);
    }
    

    Not Tested

    Thanks for your help @allObjects.

  • I know that you do not have responses ending with /n. But there is or are some thing(s) equivalent from which you can derive when a response is completely received.

    I took a look at the wiki of the device: https://www.dfrobot.com/wiki/index.php/V­oice_Module_SKU:_DFR0534

    The response is always: <0xAA><cmd><noOfResponseBytes><rspByte0>­<rspByte1>...

    Together with the pre-amble of 0xAA we can detect begins of a new command response in any string (We can safely assume that no response value has AA w/ a valid command as next byte in the response value(s), and to start with, we omit checking for valid command valid response data lengths against lookup tables).

    I can see something like this:

    // --- process response
    function proc(rsp) {
      // response processing code goes here...
    }
    
    // [0] [1] [2] [3]
    // AA  01  01  <statusValueByte> - status response
    var cAA = String.fromCharCode(0xAA); // hex AA char
      , pAA = 0   // pos of AA +1 (+1 to make check easy)
      , dta = "", // received but not yet processed data
      , dL        // dta length
      , rDL       // response's data length
      , rsp       // response
      ;
    s.setup(9600,{rx:B6, tx:B5});
    s.on('data', function(d) {
      dta += d;
      if (    (pAA=dta.indexOf(cAA)+1)  // --> cmd byte if contains 0xAA
           && ((dL=dta.length)>(++pAA)) // --> response length byte
           && (dL>=pAA+1+(rDL=dta.charCodeAt(pAA))) // contains resp
         ) { 
        rsp = dta.substr(pAA-2,3+rDL); // complete response
        dta = dta.substr(pAA+1+rDL);
        proc(rsp);                     // process response
      }
    });
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

.toString(radix) ?

Posted by Avatar for Mrbbp @Mrbbp

Actions