Avatar for tom.gidden

tom.gidden

Member since Jan 2014 • Last active Jun 2017
  • 9 conversations
  • 67 comments

Most recent activity

  • in Porting to new Devices
    Avatar for tom.gidden

    Mmm.. it's like a Puck, but huge and ugly.

    They've posted some Node.js code to operate with the default firmware: https://github.com/NordicSemiconductor/N­ordic-Thingy52-Nodejs/blob/master/lib/th­ingy.js

    It might be good to try to match the same services and characteristics they're using for their sensor, to get a Puck acting like a Thingy:52 as far as their official App is concerned.

  • in Puck.js
    Avatar for tom.gidden

    Hmm. Okay, I'll try to take a look at this when I next get a chance, if no-one else gets there first: a fresh install of Raspbian without my usual install.

  • in Puck.js
    Avatar for tom.gidden

    Hi,
    Well, from the error log it looks like this line of the script is failing:

    sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)
    

    readlink isn't getting a parameter, and so is returning nothing; and so setcap is missing that parameter too. The most likely answer to this is that which node is failing, ie. node can't be found.

    Since you say start.sh run manually is working, I'd say that it's not that node (and npm, since you're having trouble with that too) isn't installed at all, but that it's not in the path for the user under which node-red is being run. That'd imply a slightly non-standard installation of Node, at least as far as the assumptions of this script are concerned (...or perhaps we've been using a non-standard Node!)

    Did you start with a Raspbian that has Node and Node-RED preinstalled? If not, I'd start by redoing the installation of Node. If so, maybe there's a problem with our script and that start.sh should be a little more aggressive about finding it, rather than just assuming it's in $PATH.

    Please can you try:
    which node
    whereis node
    nave ls (might fail)

  • in Puck.js
    Avatar for tom.gidden

    Another day, another rewrite :)

    I've actually got it working now, although I'm still not sure what I changed. I stripped out pretty much everything, rewrote, and then rigged it so on('disconnect') executes NRF.sleep()... the idea being that when the Puck disconnects (for whatever reason), it won't reconnect until manually woken by a keypress.

    I don't mess with advertising or services beyond the initial setup, which unfortunately loses the battery monitor; however, that doesn't seem to make much difference anyway: the device is either connected (no advertising?) or disconnected and sleeping (no advertising)

    I'm also not sure what the drain on this is. Next I'll have to rig it up to test power consumption while sleeping, as that's the ultimate aim. I also have to solve the auto-switch-off that triggered this whole matter in the first place; I'm hoping it's just a case of setTimeout(...NRF.disconnect()..., 1000*60*10) ... clearTimeout().

    For the benefit of anyone else attempting this - https://gist.github.com/tomgidden/875b5a­5522deeabd9d1ef389607e434a :

    var hid = require("ble_hid_keyboard");
    
    var is_connected = false;
    
    var ad_values = {};
    var ad_options = { name: "Page-Turn-o-Matic 4000" };
    
    
    var sleep_timeout;
    
    
    // Object to handle multiple-clicking and long-clicking on
    // a button, using EventEmitter.
    function Btn(btn) {
      var o = this;
      o.es = [0,'click','double','triple','quadruple'­];
    
      o.br = function (e) {
        if ( 2.0 < e.time - e.lastTime) {
          if (o.h)
            clearTimeout(o.h);
          o.i = o.h = o.l = undefined;
          o.emit('long', 0);
        }
        else {
          // If there's no previous click or it's more than
          // a second ago, it's a new chain of clicks.
          if (!o.i || !o.l || 1.0 < e.time - o.l)
            o.i = 1;
          else
            o.i ++;
    
          o.l = e.time;
    
          if (o.h)
            clearTimeout(o.h);
    
          o.h = setTimeout(function () {
            o.h = undefined;
            if (o.es[o.i]) o.emit(o.es[o.i], o.i);
            o.i = 0;
          }, 400);
        }
      };
    
      o.w = setWatch(o.br, btn, { repeat:true, edge:'falling', debounce : 50 });
    
      return o;
    }
    
    var btn;
    
    function blinken (colour, count)
    {
      digitalWrite([LED1,LED2,LED3], colour);
      setTimeout(function(){
        digitalWrite([LED1,LED2,LED3], 0);
        if (count > 1) {
          setTimeout(function () {
            blinken(colour, --count);
          }, 50);
        }
      }, 25);
    }
    
    function set_sleep_timeout() {
      if (sleep_timeout)
        clearTimeout(sleep_timeout);
    
      sleep_timeout = setTimeout(function () {
        clear_sleep_timeout();
        NRF.disconnect();
      }, 1000*60*5);
    }
    
    function clear_sleep_timeout() {
      if (sleep_timeout) {
        clearTimeout(sleep_timeout);
        sleep_timeout = undefined;
      }
    }
    
    // Connection tracking
    
    function on_connect () {
      blinken(0b011);
      is_connected = true;
    }
    
    function on_disconnect() {
      clear_sleep_timeout();
      blinken(0b101);
      is_connected = false;
      NRF.sleep(); // Prevent reconnection until manually woken
    }
    
    
    // Button click events
    
    function on_click (c) {
      set_sleep_timeout();
      
      if (is_connected) {
        // Single flash - move right
        blinken(0b010, 1);
        hid.tap(hid.KEY.RIGHT, 0);
      }
      else {
        NRF.wake();
        blinken(0b001);
      }
    }
    
    function on_double (c) {
      set_sleep_timeout();
      
      if (is_connected) {
        // Double flash - move left
        blinken(0b010, 2);
        hid.tap(hid.KEY.LEFT, 0);
      }
      else {
        NRF.wake();
        blinken(0b001);
      }
    }
    
    function on_triple (c) {
      NRF.disconnect(); // on('disconnect') causes NRF.sleep
    }
    
    function on_quadruple (c) {
      blinken(0b110);
      NRF.wake();
    }
    
    
    
    // Initialisation
    
    function init () {
      NRF.on('connect', on_connect);
      NRF.on('disconnect', on_disconnect);
    
      NRF.setAdvertising({}, ad_options);
      NRF.setServices(undefined, { hid : hid.report });
    
      btn = new Btn(BTN);
      btn.on('click', on_click);
      btn.on('double', on_double);
      btn.on('triple', on_triple);
      btn.on('quadruple', on_quadruple);
      
      console.log("Note: to activate, either disconnect manually, or NRF.disconnect();"); 
    }
    
    E.on('init', init);
    

    (updated with auto-sleep)

  • in Puck.js
    Avatar for tom.gidden

    The delay during init is really so it can do a disconnect -- and hence do the set* calls without queueing -- without interfering with the upload loop. I've found that if onInit immediately disconnects, it can confuse the IDE.

    I've run out of batteries for the pucks right now -- I've been away from home this weekend -- but I think the code works fine until sleep and wake get involved. After that, it's all a bit unpredictable. Now I've got a barebones implementation, I'll try to add them back in.

  • in Puck.js
    Avatar for tom.gidden

    Hmm. Something's getting stuck, I think.

    With this stripped-down code on 1v92.91; after a power cycle and an E.setBootCode("");, an upload and a refresh, I get Error 13313 when clicking. However, if I Remove (ie. unpair and forget) the Puck with Opt-click on the menu bar, it works okay.

    var hid = require("ble_hid_keyboard");
    
    var is_connected = false;
    
    var ad_values = {};
    var ad_options = { name: "Page-Turn-o-Matic 4000" };
    
    function on_connect () {
      digitalPulse(LED3, true, 100);
      is_connected = true;
    }
    
    function on_disconnect() {
      digitalPulse(LED1, true, 100);
      is_connected = false;
    }
    
    function btn_released() {
      if (is_connected) {
        digitalPulse(LED2, true, 100);
        hid.tap(hid.KEY.RIGHT, 0);
      }
      else
        digitalPulse(LED1, true, 500);
    }
    
    
    
    function init () {
      NRF.on('connect', on_connect);
      NRF.on('disconnect', on_disconnect);
    
      clearWatch();
    
      setTimeout(function () {
        setWatch(btn_released, BTN, { repeat:true, edge:'falling', debounce : 50 });
    
        NRF.disconnect();
    
     //   ad_values[0x180F] = Math.round(Puck.getBatteryPercentage());­
        NRF.setAdvertising(ad_values, ad_options);
        NRF.setServices(undefined, { hid : hid.report });
      }, 3000);
    }
    
    E.on('init', init);
    

    I'll start putting stuff back in, bit-by-bit, and unpair if/when it goes bad. It's times like these I really wish Puck had a USB port.

  • in Puck.js
    Avatar for tom.gidden

    I haven't tried having a delay per se., but when it's connected to the IDE and producing 13313 errors, it'll do it whenever the button is pressed, repeatedly for as long as you like.

    I have been running setServices and setAdvertising whenever it comes out of sleep with NRF.wake() too... I wasn't sure if doing NRF.sleep() wiped the existing records. Regardless, I was trying to do setAdvertising() to update the battery level, so it would need to be called repeatedly.

    To be honest, the lack of an isConnected() and an isSleeping() method is a bit inconvenient. Getting the status of the softdevice would be useful, rather than trying to track it manually.

  • in Puck.js
    Avatar for tom.gidden

    The Error 13313s seem to come when hid.tap() calls are made on a HID connection while also doing NRF.disconnect(), NRF.sleep(), NRF.wake() in various combinations. I'm not entirely sure yet. I think it might be a case of the service characteristics getting lost after an NRF.wake(), but redoing them fails too. I'm seeing these 13313 errors in the Espruino IDE when connected with Web Bluetooth, so there is a connection open with the computer, albeit UART.

    BLE_ERROR_GATTS_SYS_ATTR_MISSING composes to 13313. Pertinent? https://devzone.nordicsemi.com/question/­6085/strange-error-code-13313-0x3401-ret­urned-by-sd_ble_gatts_hvx/?answer=6106#p­ost-id-6106

    The context: the script sets timeouts to make it execute NRF.disconnect(); ... NRF.sleep() after a set time (5 mins) of inactivity; each button press will clearTimeout() and start a new 5 minute timeout. Then, when the button is pressed, an NRF.wake() call is made if necessary, before hid.tap() is called subsequently on release.

    When this behaviour works (it has sporadically worked in random hack versions along the way) it works really well - the Puck disconnects and shuts down when idle, and then wakes up and posts a keypress when it's activated with a click (forward) or a double-click (back)

    And, if the on-screen keyboard is wanted, you can prematurely disconnect and sleep the Puck with a triple-click. That also acts as a manual "Off" when you remember to do so rather than idling it for five minutes.

    A long click does a disconnect without a sleep, allowing Web Bluetooth to see the Puck for long enough to connect to it for maintenance.

    Anyway, I wouldn't analyse that too much: part of the problem of getting you a neat little test case is the unpredictability, and the limitation of debugging while also having connects and disconnects, sleep and wake happen at the same time... I'm mainly working on cryptic LED flashes. I am still trying to isolate it though. My weekend's packed, unfortunately.

  • in Puck.js
    Avatar for tom.gidden

    Thanks… that does seem better as far as the ERROR 0x8 fatal crashes are concerned. I'm still having trouble with a lot of BLE error 13313s, though... looks like my services are getting munged, or something like that.

    I'm not really too sure about the order of execution here, and what's necessary in what order; such as whether NRF.setAdvertising() needs to be called after an NRF.wake(), whether NRF.setServices() needs to be called after a NRF.setAdvertising(). A simple test rig seems to work fine, but as soon as I start introducing a) HID and b) NRF.sleep/wake, it all starts going horribly wrong.

    I expect this would be easier if I wasn't trying to do HID and UART through Web Bluetooth (which is hinky at the best of times) but finding a USB-to-Serial or rigging a Pico to do the same job and then trying to connect to the Puck non-destructively is a big PITA. I'm also suspicious of connecting to Espruinos via serial because whenever I've tried the different redirection of the console seems to change behaviour subtly.

    Anyhoo. I'll soldier on. Thanks

Actions