Avatar for ChristianW

ChristianW

Member since Nov 2016 • Last active Jan 2023
  • 21 conversations
  • 161 comments

German IT developer who found his long lost love for electronics and connected devices...

Most recent activity

    • 25 comments
    • 8,900 views
  • in Puck.js, Pixl.js and MDBT42
    Avatar for ChristianW

    Strange. I tested also with Puck and even the newest release to rule out some Board-specific issue. No luck.
    It gets paired, but no key or volume change gets recognized by either iPhone nor MacBook.

    However, this is not the project I'm working on, just a way to debug things "from the other side".
    My original issue was just solved thanks to a hint by @Gordon :)

  • in Puck.js, Pixl.js and MDBT42
    Avatar for ChristianW

    Yeah - your other comment about bonding from the neighbor thread did the trick.

    This is working now:

    var gatt;
    
    function onInit() {
    
      NRF.requestDevice({
        filters: [{namePrefix: "AB"}]
      }).then((device)=> {
        console.log("FOUND", device.id, device.name);
        return device.gatt.connect();
      }).then((device)=>{
        gatt = device;
        console.log("CONNECTED", device);
        return gatt.startBonding();
      }).then(function() {
        console.log("BONDED", gatt.getSecurityStatus());
        return gatt.getPrimaryService(0x1812);
      }).then((service)=>{
        console.log("SERVICE", service);
        return service.getCharacteristic(0x2a4d);
      }).then((char)=>{
        console.log("CHAR", char);
        char.on("characteristicvaluechanged",(e)­=>{
          console.log("EVENT", e.target.value);
        });
        return char.startNotifications();
      }).then(()=>{
        console.log("DONE");
        return true;
      }).catch((err)=>{
        console.log("ERROR", err);
      });
    }
    
    onInit();
    

    For a button press I get:

    EVENT DataView: {
      "buffer": new Uint8Array([2, 0]).buffer,
      "byteOffset": 0, "byteLength": 2 }
    

    and for a release:

    EVENT DataView: {
      "buffer": new ArrayBuffer(2),
      "byteOffset": 0, "byteLength": 2 }
    

    The only thing is that when I pull the power from Espruino the bonding seems to be lost and the blue LED on the remote begins flashing again.

    This does not happen when bonded to Laptop/Phone. Maybe it's about the whitelisting.

    But I could live with that.
    Thanks @Gordon for the hint!

  • in Puck.js, Pixl.js and MDBT42
    Avatar for ChristianW

    Thanks @Gordon.
    Do I really need this bonding call on the peripheral side?
    This thread here is a test to gain some insight how HID works as a peripheral to use it on the "other side" when Espruino is the Host/Central.

    No Code in iOS needed btw., just a confirmation (Yes/No).

    How do I setup Espruino as HID device?
    I thought that NRF.setServices(undefined, { hid : kb.report }); would do the trick.
    Is there more that is not given in the example code?

  • in Puck.js, Pixl.js and MDBT42
    Avatar for ChristianW

    Just digging into this issue and found this HOGP specification here.

    Chapter 5 explains details about bonding and how to establish a connection.
    I could not find much of that in the Espruino API yet, maybe this is the missing part?

    At some point the Host (normally computer/phone; here: Espruino) writes his address into the HID device (peripheral; here: the remote button) causing a bonding.

  • in Puck.js, Pixl.js and MDBT42
    Avatar for ChristianW

    For investigating in the other HID project I tried to get a MDBT42Q set up as a BLE keyboard or volume control using this example from here

    Strangely, it didn't work.

    Here is my final code (mostly copied, but wrapped in an onInit() so it gets called after PowerUp):

    function onInit() {
    var kb = require("ble_hid_keyboard");
    NRF.setServices(undefined, { hid : kb.report });
    
    function btnPressed() {
      // Send 'a'
      kb.tap(kb.KEY.A, 0, function() {
        // Followed by capital 'A'
        kb.tap(kb.KEY.A, kb.MODIFY.SHIFT);
      });
    }
    
    // trigger btnPressed whenever the button is pressed
    setWatch(btnPressed, BTN, {edge:"rising",repeat:true,debounce:50})­;
    }
    

    Could someone try and confirm my results please?
    I tried both examples: The one with the keyboard and the one with the volumeUp control.
    None worked.

    Some more findings:

    • when I connect a commercial HID remote (remote selfie camera button which sends a volumeUp()) my phone (iOS) shows a confirmation dialog.
    • with Espruino this dialog is missing.
    • also the commercial remote shows up in iOS settings an (i) where I can select to "forget" (disconnect) this device
    • the Espruino does not show up with this option. The only way to disconnect is to pull off the battery.
    • when I pull the battery Espruino is gone from the list and I have to pair it again afterwards
    • the commercial remote stays in the list when switched off and is coming online again right after switching it on again.

    Is this expected behaviour or a bug?

    Thanks in advance.

  • in Puck.js, Pixl.js and MDBT42
    Avatar for ChristianW

    Thanks @Gordon for the hints.

    NRF Connect only shows the Service, no peeking or poking possible (iOS here).

    By the way, this is my code so far:

    var notify = 0;
    var hidService;
    var modeChar, reportChar;
    
    function onInit() {
    
      NRF.requestDevice({
        filters: [{namePrefix: "AB"}]
      }).then((device)=>{
        console.log("FOUND");
        return device.gatt.connect();
      }).then((gatt)=>{
        console.log("CONNECTED", gatt);
        return gatt.getPrimaryService("1812");
      }).then((service)=>{
        hidService = service;
        console.log("SERVICE", hidService);
        return hidService.getCharacteristic(0x2a4e);
        // 2a4e - protocol mode (R-W)
        // 2a4d - report (R-N)
        // 2a4b - report map (R)
        // 2a4a - hid information (R)
        // 2a4c - hid control point (W)    
      }).then((char)=>{
        console.log("MODE", char);
        modeChar = char;
        return char.readValue();
      }).then((d)=>{
        console.log("READ", d.buffer);
        console.log("WRITING 1");
        return modeChar.writeValue(1);
      }).then((d)=>{
        console.log("WRITTEN, GET REPORT");
        return hidService.getCharacteristic(0x2a4d);
      }).then((char)=>{
        console.log("REPORT", char);
        reportChar = char;
        char.on("characteristicvaluechanged",(e)­=>{
          console.log("EVENT", e.targete.value);
        });
        return char.startNotifications();
      }).then((d)=>{
        console.log("DONE");
        return true;
      }).catch((err)=>{
        console.log("ERROR", err);
      }); 
    }
    
    onInit();
    

    And this is the output:

    FOUND
    CONNECTED BluetoothRemoteGATTServer: {
      "device": BluetoothDevice: {
        "id": "2a:07:98:10:35:fb public",
        "rssi": -59,
        "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer,
        "name": "AB Shutter3",
        "services": [
          "1812"
         ],
        "gatt":  ...
       },
      "connected": true, "handle": 1 }
    SERVICE BluetoothRemoteGATTService: {
      "device": BluetoothDevice: {
        "id": "2a:07:98:10:35:fb public",
        "rssi": -59,
        "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer,
        "name": "AB Shutter3",
        "services": [
          "1812"
         ],
        "gatt": BluetoothRemoteGATTServer: {
          "device":  ... ,
          "connected": true, "handle": 1 }
       },
      "uuid": "0x1812",
      "isPrimary": true, "start_handle": 15, "end_handle": 31 }
    MODE BluetoothRemoteGATTCharacteristic: {
      "service": BluetoothRemoteGATTService: {
        "device": BluetoothDevice: {
          "id": "2a:07:98:10:35:fb public",
          "rssi": -59,
          "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer,
          "name": "AB Shutter3",
          "services": [
            "1812"
           ],
          "gatt": BluetoothRemoteGATTServer: {
            "device":  ... ,
            "connected": true, "handle": 1 }
         },
        "uuid": "0x1812",
        "isPrimary": true, "start_handle": 15, "end_handle": 31 },
      "uuid": "0x2a4e",
      "handle_value": 17, "handle_decl": 16,
      "properties": { "broadcast": false, "read": true, "writeWithoutResponse": true, "write": false,
        "notify": false, "indicate": false, "authenticatedSignedWrites": false }
     }
    READ new Uint8Array([1]).buffer
    WRITING 1
    WRITTEN, GET REPORT
    REPORT BluetoothRemoteGATTCharacteristic: {
      "service": BluetoothRemoteGATTService: {
        "device": BluetoothDevice: {
          "id": "2a:07:98:10:35:fb public",
          "rssi": -59,
          "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer,
          "name": "AB Shutter3",
          "services": [
            "1812"
           ],
          "gatt": BluetoothRemoteGATTServer: {
            "device":  ... ,
            "connected": true, "handle": 1 }
         },
        "uuid": "0x1812",
        "isPrimary": true, "start_handle": 15, "end_handle": 31 },
      "uuid": "0x2a4d",
      "handle_value": 19, "handle_decl": 18,
      "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false,
        "notify": true, "indicate": false, "authenticatedSignedWrites": false }
     }
    DONE
    

    Maybe you see something I don't.
    As far as I can see PROTOCOL_MODE already is set to 1:

    READ new Uint8Array([1]).buffer
    

    What about this BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST?

    I will have to look at the sourcecode more in-depth though.
    Any way to log what is going on when Espruino is in the HID role against a phone or computer?

Actions