Advertising with 128-bit and 16-bit UUID?

Posted on
  • Hi,
    I'm trying to put together a system that has its own 128-bit UUID as well as battery service. I'd like to keep the UART for now (probably removing once everything is good). I'd also like to add the Device Information service, but first things first.

    I can't seem to get both the 128-bit UUID and the battery service working at the same time.

    Thoughts?

    Here's my code:

    NRF.setAdvertising({}, {name: "XXX"});
    
    
    pinMode(D28, "output");
    pinMode(D29, "analog");
    pinMode(D30, "output");
    
    NRF.setServices({
      0x180F : {
        0x2A19 : {
          value : Puck.getBatteryPercentage(),  readable : true
        }
      }
    });
    setInterval(function() {
      NRF.updateServices({
        0x180F : {
          0x2A19 : {
           value : Puck.getBatteryPercentage()
          }
        }
      });
    }, 60000);
    
    
    NRF.setServices({
      "8093A600-DC1B-4C75-A61C-37BB61E00F1B" : {
        "8093A601-DC1B-4C75-A61C-37BB61E00F1B" : { // **
          value : 0x00, // optional
          broadcast : false, // optional, default is false
          readable : true,   // optional, default is false
          writable : false,   // optional, default is false
          notify : true,   // optional, default is false
        },
    
        "8093A602-DC1B-4C75-A61C-37BB61E00F1B" : { // **
          value : 0x0, // optional
          broadcast : false, // optional, default is false
          readable : true,   // optional, default is false
          writable : false,   // optional, default is false
          notify : true,   // optional, default is false
         },
        
        "8093A603-DC1B-4C75-A61C-37BB61E00F1B" : { // **
          value : 0x0, // optional
          broadcast : false, // optional, default is false
          readable : true,   // optional, default is false
          writable : true,   // optional, default is false
          notify : false,   // optional, default is false
        },
    
      }
    }, { advertise: ['180F', '8093A600-DC1B-4C75-A61C-37BB61E00F1B'],­ uart: true } );
    
  • Hi! You don't want to be calling setServices twice - since the second will overwrite the first, so you want to just put the two sets of services together:

    NRF.setServices({
      0x180F : {
        0x2A19 : {
          value : Puck.getBatteryPercentage(),  readable : true
        }
      },
      "8093A600-DC1B-4C75-A61C-37BB61E00F1B" : {
        "8093A601-DC1B-4C75-A61C-37BB61E00F1B" : { // **
          value : 0x00, // optional
          broadcast : false, // optional, default is false
          readable : true,   // optional, default is false
          writable : false,   // optional, default is false
          notify : true,   // optional, default is false
        },
        "8093A602-DC1B-4C75-A61C-37BB61E00F1B" : { // **
          value : 0x0, // optional
          broadcast : false, // optional, default is false
          readable : true,   // optional, default is false
          writable : false,   // optional, default is false
          notify : true,   // optional, default is false
         },
        
        "8093A603-DC1B-4C75-A61C-37BB61E00F1B" : { // **
          value : 0x0, // optional
          broadcast : false, // optional, default is false
          readable : true,   // optional, default is false
          writable : true,   // optional, default is false
          notify : false,   // optional, default is false
        },
      }
    } 
    ...
    

    However the advertising services is a problem. The issue is that there's just too much data. 128 bit services are 16 bytes long. The UART is 128 bits, so you're trying to fit 2+16+16=34 bytes into an advertising scan response packet which can only be 31 bytes.

    At that point Puck.js should error, but it only knows there's a problem when it restarts the BLE stack which it does when you disconnect from BLE - so you can't see it (the lack of reporting is a bug which I'll try and fix).

    So you have some options, none of which are great:

    • Use setScanResponse to overwrite the scan response packet and remove the UART service UUID. You can still access the UART, it just won't be advertised as being there. You'll have to manually construct the scan response packet as an array though.
    • Use setAdvertising with a fully manually constructed advertising packet which contains your 128 bit UUID, then only advertise the 16 bit one in setServices.

    Hope that's some help!

  • Thanks Gordon -- I forgot the UART service is a 128-bit UUID. Now that makes perfect sense. Same with overwriting with the two calls.

    I'm a bit confused about the interaction between NRF.setServices(..., {advertise:[ ... ]}) and the scan response package. What is normally/automatically put in the scan response? The documentation is kind of thin on this.

    I'm fine with not advertising the UART service (but having it useable). I'm actually fine with not advertising my service either, but having it show up once I connect. How can I control this a bit better?

    Maybe a short example if you have one?

    Thanks!
    Bill

  • @Gordon, I think I got it by using your suggestion and disabling the UART advertisement with NRF.setServices({}, { uart: false });.

    I don't need to advertise my custom service, so I'll let the UART advertise instead.

    Odd question: IF I decide not to advertise the UART service (but leave it active), is there a way I can have the espruino Chrome IDE to try to connect to device that isn't advertising the UART service (but has it)?

    Thanks!!!
    Bill

  • Ahh, well setServices({...},{advertise: will set the services in the scan response packet, and setScanResponse will overwrite them. There's a very small note about it here: http://www.espruino.com/Reference#l_NRF_­setScanResponse

    Basically while you can advertise services outside the scan response, it's not really worth it with 128 bit UUIDs like the UART because there's no room for anything else.

    The IDE will try and show you anything with the UART service or that starts with 'Espruino', 'Puck.js', and some others.

    However specifying uart:false should totally disable the UART, which isn't what you want. As far as I know there's no way to disable the advertising of UART but not the UART except by using NRF.setScanResponse with your own manually constructed advertising packet after having called setServices.

  • Thanks @Gordon! Yet another question somewhat related. It seems I can't use a const in NRF.setServices(). Is there a reason; I'd really rather not have to use a literal each time for the UUID strings?

    This works:

    NRF.setServices({
      "00001523-1212-EFDE-1523-785FEABCD123" : {
        "00001524-1212-EFDE-1523-785FEABCD123" : { // button
          value : 0x00, // optional
    ...
    

    This doesn't (and doesn't throw an error to the IDE when loaded):

    const  LBS_UUID  = "00001523-1212-EFDE-1523-785FEABCD123";
    const  LBS_BUTTON = "00001524-1212-EFDE-1523-785FEABCD123";
    const  LBS_LED = "00001525-1212-EFDE-1523-785FEABCD123";
    
    NRF.setServices({
      LBS_UUID : {
        "00001524-1212-EFDE-1523-785FEABCD123" : { // button
          value : 0x00, // optional
      ...
    
  • That's just normal JavaScript :) You're not referencing the constant, you're creating a field called LBS_UUID - so the constant isn't being referenced at all!

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

Advertising with 128-bit and 16-bit UUID?

Posted by Avatar for billsalt @billsalt

Actions