Hi all,
I have been playing around with the BLE APIs in v1.3.0-rc.1 on an Argon, and I am running into some trouble with certain services. I have also tried compiling device-os myself with the ble/fix/v1.3.1-rc.1 changes that have recently been merged into the develop
branch
I am trying to implement the HID over GATT Profile spec which defines an HID service, along with the Device Info service and Battery service.
While I haven’t been able to find documentation of this working for anyone using the Particle device-os APIs, there is an example: hid_keyboard.ino using the Adafruit_nRF52_Arduino core libraries and their implementation of the BLE APIs, so I have been using that as my “documentation” (especially because they’re for the nRF52840 which is the same MCU the argon uses.) The aforementioned core/libraries have even been updated recently with “support for the Particle Xenon”. I have not yet tried this, but I suspect that using their bootloader I could flash and run the above hid_keyboard.ino
on an Argon by replacing device-os with Adafruit’s Arduino core.
I digress, using hid_keyboard.ino
from Adafruit as my guide, I have tried to implement the HID service by replicating the GATT services and characteristics using Particle’s BLE API.
The issue is this: using Nordic’s nRF Connect App I am able to see the device, it is advertising successfully and I can see it advertising the HID service (0x1812) but upon connecting, I am only able to see the battery and device info services, the HID service does not show up. I have read through the HID service XML at Bluetooth SIG GATT Services and I believe I have the mandatory characteristics added, yet I cannot get the HID service to show up. For the battery and device information services, they only show up when I have added their mandatory characteristics, even if I never assign a value to the battery level characteristic or the PnpID characteristic.
Interestingly, iOS always shows the device name in System Settings > Bluetooth as Argon-XXXXXX
but MacOS shows the local name that I set, AKHID
, and even shows a Keyboard Icon. I don’t know how MacOS determines what icon to display for a device but I am also appending the appearance type 961
which corresponds to BLE_APPEARANCE_HID_KEYBOARD
.
This is slightly unrelated, but when I connect in the nRF Connect app I see an additional custom service that starts with UUID prefix 6FA90001
even though I haven’t added this service. Is this service implemented by the device-os? Maybe for mobile setup purposes?
My code is included below, as well as screenshots from the BLE app I am using and a MacOS screenshot. (Keyboard_types.h
only contains the HID report map, and I am using the one from Nordic’s own ble_app_hids_keyboard
example project.
Can anyone offer some advice for what troubleshooting steps I should try next? I have tried assigning values to the characteristics as well but that made no difference as far as I can tell.
Thanks, have a great day.
#include "Keyboard_types.h"
SYSTEM_MODE(MANUAL);
#define DEBUG_BUILD
BleAdvertisingData advData;
BleUuid hogpService(0x1812);
BleUuid deviceInfoService(0x180A);
BleUuid batteryService(0x180F);
#define BLE_WIRING_DEBUG_ENABLED 1
const uint8_t RESPONSE_HID_INFORMATION[] = {0x11, 0x01, 0x00, 0x03};
const uint8_t keyvalue[] = {0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00};
SerialLogHandler serialLogHandler(LOG_LEVEL_TRACE);
BleCharacteristic controlPointChar("control", (BleCharacteristicProperty::WRITE_WO_RSP), BleUuid(0x2A4C), hogpService);
BleCharacteristic reportMapChar("reportMap", BleCharacteristicProperty::READ, BleUuid(0x2A4B), hogpService);
BleCharacteristic bootKeyboardInputCharacteristic("bootInput", (BleCharacteristicProperty)18U, BleUuid(0x2A22), hogpService);
BleCharacteristic bootKeyboardOutputCharacteristic("bootOutput", (BleCharacteristicProperty)14U, BleUuid(0x2A32), hogpService);
// BleCharacteristic reportChar("report", (BleCharacteristicProperty)18, BleUuid(0x2A4D), hogpService);
BleCharacteristic hidInfoChar("hidinfo", BleCharacteristicProperty::READ, BleUuid(0x2A4A), hogpService);
BleCharacteristic pnpIDCharacteristic("pnp", BleCharacteristicProperty::READ, BleUuid(0x2A50), deviceInfoService);
BleCharacteristic battLevelCharacteristic("batt", BleCharacteristicProperty::READ, BleUuid(0x2A19), batteryService);
system_tick_t begin;
void setup() {
Serial.begin(9600);
waitUntil(Serial.isConnected);
BLE.addCharacteristic(battLevelCharacteristic);
BLE.addCharacteristic(pnpIDCharacteristic);
BLE.addCharacteristic(hidInfoChar);
BLE.addCharacteristic(reportMapChar);
BLE.addCharacteristic(bootKeyboardInputCharacteristic);
BLE.addCharacteristic(bootKeyboardOutputCharacteristic);
// BLE.addCharacteristic(reportChar);
BLE.addCharacteristic(controlPointChar);
hidInfoChar.setValue(RESPONSE_HID_INFORMATION, sizeof(RESPONSE_HID_INFORMATION));
//reportMapChar.setValue(hid_map, sizeof(hid_map));
advData.appendLocalName("AKHID");
uint8_t flagsValue = BLE_SIG_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
advData.append(BleAdvertisingDataType::FLAGS, &flagsValue, sizeof(flagsValue));
uint16_t appear = BLE_APPEARANCE_HID_KEYBOARD;
advData.append(BleAdvertisingDataType::APPEARANCE, reinterpret_cast<const uint8_t*>(&appear), sizeof(uint16_t));
advData.appendServiceUUID(hogpService, true);
//BLE.setAdvertisingInterval(32);
//BLE.setPPCP(9, 12, 0, 3000);
uint8_t *data = advData.data();
size_t len = advData.length();
Serial.printf("L: %u, D: ", len);
for(size_t i = 0; i < len; i++) {
Serial.printf("%02X", data[i]);
}
Serial.println();
BLE.advertise(&advData);
begin = millis();
}
void loop() {
if(BLE.connected()) {
if ((millis()-begin) > (6*1000)) {
//protocolChar.setValue((uint8_t)1);
begin = millis();
// reportChar.setValue(value, 8);
}
}
}
MacOS Screenshot: