Bluefruit app - parse incoming

Posted on
  • The adafruit Bluefruit has a control pad the sends strings such as: !B41CRC
    I want to parse this into its component parts such as: [‘!’] [‘B’] [‘4’] [‘1’] [CRC]
    I think I can do this, but I don't know how to set a watch event that actually parses the string once it's received.
    It is not like the bluefruit app calls a function parse(!B41CRC). How do I watch for incoming data then do something with it?

  • It's actually pretty easy - I used it for the robot demo in the KickStarter video and I may have forgotten to post the code up. Basically you treat Bluetooth like any other serial device:

    For instance to handle colours:

    Bluetooth.on('data', function(d) { 
      if (d[0]=="!" && d[1]=="B") {
        var b = d.substr(2,2);
        if (b[0]=="1") LED1.write(0|b[1]);
        if (b[0]=="2") LED2.write(0|b[1]);
        if (b[0]=="3") LED3.write(0|b[1]);
        // 4
      }
      if (d[0]=="!" && d[1]=="C") {
        analogWrite(LED1, d.charCodeAt(2)/800);
        analogWrite(LED2, d.charCodeAt(3)/256);
        analogWrite(LED3, d.charCodeAt(4)/300);
      }
    });
    

    or for the robot itself I did:

    Bluetooth.on('data', function(d) {
      if (d[0]=="!" && d[1]=="B") {
        var b = d.substr(2,2);
        var m = 0;
        if (b[1]=="1") {
          if (b[0]=="5") m=5;
          if (b[0]=="6") m=10;
          if (b[0]=="7") m=9;
          if (b[0]=="8") m=6;
        }
        digitalWrite([D4,D5,D30,D31],m);
      }
    });
    

    Because of the way BLE works, you'll get one big chunk of data received in one go, so you don't have to worry about detecting start and end - each time the handler is called it'll have a complete command in it.

    However: it's not quite that simple. By default, the actual JS interpreter is running on that Bluetooth UART, and will intercept any characters and try and execute them as JS before your code gets to see them.

    You need to force the console to stay on some other device, maybe with LoopbackA.setConsole(1). But, once you do that you can no longer program Puck.js until something like Bluetooth.setConsole() is called, or you reset it!

    So probably what you want is simply:

    setWatch(function() {
      LoopbackA.setConsole()
    }, BTN, {repeat:true, edge:"rising", debounce:50});
    

    That will move the console out of the way temporarily, when you press a button. So now when everything is running you can connect the Adafruit app, press the Puck's button to move the console out the way, and it all works fine.

    When you disconnect and reconnect with the PC, the console will go back to being on Bluetooth so you can program it as normal!

  • Excellent explanation! Thank you for explaining the LoopBack to me, I was really scratching my head over how to stop the JS interpreter intercepting incoming data.

    It works really well with the app, however, I tried to use the WebIDE to pass a command string instead of using the app.
    When I press the button on the puck to activate the LoopBackA the WebIDE console locks up, the console logs -> LookbackA then it does not let me type anymore.


    1 Attachment

    • console_lock.PNG
  • At this point in the web ide disconnect and then connect, and you will be able to type again...

  • I can't do that because the puck will go back to being on Bluetooth instead of being in LoopbackA.

  • As @Wilberforce says, you'd have to reconnect to get control back.

    And if you're wondering why it's not working when you enter characters yourself, it's because they're being sent one by one - so Bluetooth.on('data',... gets called with a single character.

    To make it work properly in that case you'd have to store the whole string, a bit like:

    var data = "";
    Bluetooth.on('data', function(d) {
      data += d;
      // and then handle what's in 'data'
    });
    

    The reason it works for the Adafruit app is that the app is sending the characters all in one chunk, so they're being received in one chunk.

    I guess you might have some luck if you copied and then pasted the command into the Web IDE, but it's not guaranteed :)

  • I get it now thanks @Gordon and sorry @Wilberforce you were correct.
    Gordon you're correct, copy and pasting does allow it to be sent as one packet.

  • How can I detect once a connection has estabilished then run a LoopbackA.setConsole().
    I thinking it should automatically switch to LoopbackA.setConsole() then press the button on the puck to return to Bluetooth.setConsole(). I tried the following but it didn't work and I'm assuming it has something to do with switching to LoopbackA.setConsole() before a Bluetooth connection has been established.

    LoopbackA.setConsole(1);
    
    setWatch(function() {
      Bluetooth.setConsole();
    }, BTN, {repeat:true, edge:"rising", debounce:50});
    
    
    Bluetooth.on('data', function(d) { 
      if (d[0]=="!" && d[1]=="B") {
        var b = d.substr(2,2);
        if (b[0]=="1") LED1.write(0|b[1]);
        if (b[0]=="2") LED2.write(0|b[1]);
        if (b[0]=="3") LED3.write(0|b[1]);
      }
    });
    
  • Yes, it'll be because Bluetooth.setConsole() overwrites LoopbackA.setConsole(1);

    How about:

    NRF.on('connect', function(addr) { 
      LoopbackA.setConsole();
    });
    

    Note that you could check the device's address, so you could avoid calling LoopbackA if your development PC is connecting?

    Check this out for an example: http://forum.espruino.com/comments/13603623/

  • Thanks for your help Gordon. This is a nice little example to do with the puck by itself.
    For anyone else, finished code to be used along with the adafruit bluefruit app is below.

    NRF.on('connect', function(addr) { 
      LoopbackA.setConsole();
    });
    
    setWatch(function() {
      Bluetooth.setConsole();
    }, BTN, {repeat:true, edge:"rising", debounce:50});
    
    
    Bluetooth.on('data', function(d) { 
      if (d[0]=="!" && d[1]=="B") {
        var b = d.substr(2,2);
        if (b[0]=="1") LED1.write(0|b[1]);
        if (b[0]=="2") LED2.write(0|b[1]);
        if (b[0]=="3") LED3.write(0|b[1]);
        if (b[0]=="4") digitalWrite([LED1, LED2, LED3], b[1]*7);
      }
    });
    

    Just remeber to press the btn on the puck if you want to send some new code to the puck

  • Neat - thanks for posting it up!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Bluefruit app - parse incoming

Posted by Avatar for JackJamesHoward @JackJamesHoward

Actions