Skip to content

Commit

Permalink
Bug fix on PNP info
Browse files Browse the repository at this point in the history
Fixed issue h2zero#492
  • Loading branch information
afpineda committed Mar 25, 2023
1 parent 0d9f039 commit 54b2542
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 50 deletions.
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
# Doxygen output

docs/doxydocs

# Arduino's Library development

.development

# Arduino on VSCode

*.svd
debug.cfg
debug_custom.json
138 changes: 88 additions & 50 deletions src/NimBLEHIDDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,45 @@
#include "NimBLEHIDDevice.h"
#include "NimBLE2904.h"

#define PNPVersionField(MajorVersion, MinorVersion, PatchVersion) ((MajorVersion << 16) && 0xFF00) || ((MinorVersion << 8) && 0x00F0) || (PatchVersion && 0x000F)

/**
* @brief Construct a default NimBLEHIDDevice object.
* @param [in] server A pointer to the server instance this HID Device will use.
*/
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer *server)
{
/*
* Here we create mandatory services described in bluetooth specification
*/
m_deviceInfoService = server->createService(NimBLEUUID((uint16_t) 0x180a));
m_hidService = server->createService(NimBLEUUID((uint16_t) 0x1812));
m_batteryService = server->createService(NimBLEUUID((uint16_t) 0x180f));
m_deviceInfoService = server->createService(NimBLEUUID((uint16_t)0x180a));
m_hidService = server->createService(NimBLEUUID((uint16_t)0x1812));
m_batteryService = server->createService(NimBLEUUID((uint16_t)0x180f));

/*
* Mandatory characteristic for device info service
*/
m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, NIMBLE_PROPERTY::READ);
m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t)0x2a50, NIMBLE_PROPERTY::READ);

/*
* Non-mandatory characteristics for device info service
* Will be created on demand
*/
m_manufacturerCharacteristic = nullptr;

/*
* Mandatory characteristics for HID service
*/
m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, NIMBLE_PROPERTY::READ);
m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, NIMBLE_PROPERTY::READ);
m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, NIMBLE_PROPERTY::WRITE_NR);
m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ);
m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4a, NIMBLE_PROPERTY::READ);
m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4b, NIMBLE_PROPERTY::READ);
m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4c, NIMBLE_PROPERTY::WRITE_NR);
m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4e, NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ);

/*
* Mandatory battery level characteristic with notification and presence descriptor
*/
m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
NimBLE2904* batteryLevelDescriptor = (NimBLE2904*)m_batteryLevelCharacteristic->createDescriptor((uint16_t) 0x2904);
m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t)0x2a19, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
NimBLE2904 *batteryLevelDescriptor = (NimBLE2904 *)m_batteryLevelCharacteristic->createDescriptor((uint16_t)0x2904);
batteryLevelDescriptor->setFormat(NimBLE2904::FORMAT_UINT8);
batteryLevelDescriptor->setNamespace(1);
batteryLevelDescriptor->setUnit(0x27ad);
Expand All @@ -56,27 +65,30 @@ NimBLEHIDDevice::NimBLEHIDDevice(NimBLEServer* server) {
* This value is setup here because its default value in most usage cases, its very rare to use boot mode
* and we want to simplify library using as much as possible
*/
const uint8_t pMode[] = { 0x01 };
protocolMode()->setValue((uint8_t*) pMode, 1);
const uint8_t pMode[] = {0x01};
protocolMode()->setValue((uint8_t *)pMode, 1);
}

NimBLEHIDDevice::~NimBLEHIDDevice() {
NimBLEHIDDevice::~NimBLEHIDDevice()
{
}

/**
* @brief Set the report map data formatting information.
* @param [in] map A pointer to an array with the values to set.
* @param [in] size The number of values in the array.
*/
void NimBLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
void NimBLEHIDDevice::reportMap(uint8_t *map, uint16_t size)
{
m_reportMapCharacteristic->setValue(map, size);
}

/**
* @brief Start the HID device services.\n
* This function called when all the services have been created.
*/
void NimBLEHIDDevice::startServices() {
void NimBLEHIDDevice::startServices()
{
m_deviceInfoService->start();
m_hidService->start();
m_batteryService->start();
Expand All @@ -85,17 +97,20 @@ void NimBLEHIDDevice::startServices() {
/**
* @brief Create a manufacturer characteristic (this characteristic is optional).
*/
NimBLECharacteristic* NimBLEHIDDevice::manufacturer() {
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, NIMBLE_PROPERTY::READ);
NimBLECharacteristic *NimBLEHIDDevice::manufacturer()
{
if (m_manufacturerCharacteristic == nullptr)
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t)0x2a29, NIMBLE_PROPERTY::READ);
return m_manufacturerCharacteristic;
}

/**
* @brief Set manufacturer name
* @param [in] name The manufacturer name of this HID device.
*/
void NimBLEHIDDevice::manufacturer(std::string name) {
m_manufacturerCharacteristic->setValue(name);
void NimBLEHIDDevice::manufacturer(std::string name)
{
manufacturer()->setValue(name);
}

/**
Expand All @@ -105,8 +120,18 @@ void NimBLEHIDDevice::manufacturer(std::string name) {
* @param [in] pid The product ID number.
* @param [in] version The produce version number.
*/
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version)
{
//uint8_t pnp[] = {sig, (uint8_t)(vid >> 8), (uint8_t)vid, (uint8_t)(pid >> 8), (uint8_t)pid, (uint8_t)(version >> 8), (uint8_t)version};
uint8_t pnp[] = {
sig,
((uint8_t *)&vid)[0],
((uint8_t *)&vid)[1],
((uint8_t *)&pid)[0],
((uint8_t *)&pid)[1],
((uint8_t *)&version)[0],
((uint8_t *)&version)[1]
};
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
}

Expand All @@ -115,8 +140,9 @@ void NimBLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t vers
* @param [in] country The country code for the device.
* @param [in] flags The HID Class Specification release number to use.
*/
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
uint8_t info[] = { 0x11, 0x1, country, flags };
void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags)
{
uint8_t info[] = {0x11, 0x1, country, flags};
m_hidInfoCharacteristic->setValue(info, sizeof(info));
}

Expand All @@ -125,12 +151,13 @@ void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
* @param [in] reportID input report ID, the same as in report map for input object related to the characteristic
* @return pointer to new input report characteristic
*/
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC);
NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC);
NimBLECharacteristic *NimBLEHIDDevice::inputReport(uint8_t reportID)
{
NimBLECharacteristic *inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC);
NimBLEDescriptor *inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t)0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC);

uint8_t desc1_val[] = { reportID, 0x01 };
inputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
uint8_t desc1_val[] = {reportID, 0x01};
inputReportDescriptor->setValue((uint8_t *)desc1_val, 2);

return inputReportCharacteristic;
}
Expand All @@ -140,12 +167,13 @@ NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
* @param [in] reportID Output report ID, the same as in report map for output object related to the characteristic
* @return Pointer to new output report characteristic
*/
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
NimBLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
NimBLECharacteristic *NimBLEHIDDevice::outputReport(uint8_t reportID)
{
NimBLECharacteristic *outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
NimBLEDescriptor *outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t)0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);

uint8_t desc1_val[] = { reportID, 0x02 };
outputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
uint8_t desc1_val[] = {reportID, 0x02};
outputReportDescriptor->setValue((uint8_t *)desc1_val, 2);

return outputReportCharacteristic;
}
Expand All @@ -155,56 +183,63 @@ NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
* @param [in] reportID Feature report ID, the same as in report map for feature object related to the characteristic
* @return Pointer to new feature report characteristic
*/
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
NimBLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
NimBLECharacteristic *NimBLEHIDDevice::featureReport(uint8_t reportID)
{
NimBLECharacteristic *featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
NimBLEDescriptor *featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t)0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);

uint8_t desc1_val[] = { reportID, 0x03 };
featureReportDescriptor->setValue((uint8_t*) desc1_val, 2);
uint8_t desc1_val[] = {reportID, 0x03};
featureReportDescriptor->setValue((uint8_t *)desc1_val, 2);

return featureReportCharacteristic;
}

/**
* @brief Creates a keyboard boot input report characteristic
*/
NimBLECharacteristic* NimBLEHIDDevice::bootInput() {
return m_hidService->createCharacteristic((uint16_t) 0x2a22, NIMBLE_PROPERTY::NOTIFY);
NimBLECharacteristic *NimBLEHIDDevice::bootInput()
{
return m_hidService->createCharacteristic((uint16_t)0x2a22, NIMBLE_PROPERTY::NOTIFY);
}

/**
* @brief Create a keyboard boot output report characteristic
*/
NimBLECharacteristic* NimBLEHIDDevice::bootOutput() {
return m_hidService->createCharacteristic((uint16_t) 0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
NimBLECharacteristic *NimBLEHIDDevice::bootOutput()
{
return m_hidService->createCharacteristic((uint16_t)0x2a32, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR);
}

/**
* @brief Returns a pointer to the HID control point characteristic.
*/
NimBLECharacteristic* NimBLEHIDDevice::hidControl() {
NimBLECharacteristic *NimBLEHIDDevice::hidControl()
{
return m_hidControlCharacteristic;
}

/**
* @brief Returns a pointer to the protocol mode characteristic.
*/
NimBLECharacteristic* NimBLEHIDDevice::protocolMode() {
NimBLECharacteristic *NimBLEHIDDevice::protocolMode()
{
return m_protocolModeCharacteristic;
}

/**
* @brief Set the battery level characteristic value.
* @param [in] level The battery level value.
*/
void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
void NimBLEHIDDevice::setBatteryLevel(uint8_t level)
{
m_batteryLevelCharacteristic->setValue(&level, 1);
}
/*
* @brief Returns battery level characteristic
* @ return battery level characteristic
*/
NimBLECharacteristic* NimBLEHIDDevice::batteryLevel() {
NimBLECharacteristic *NimBLEHIDDevice::batteryLevel()
{
return m_batteryLevelCharacteristic;
}

Expand All @@ -227,21 +262,24 @@ BLECharacteristic* BLEHIDDevice::hidInfo() {
/**
* @brief Returns a pointer to the device information service.
*/
NimBLEService* NimBLEHIDDevice::deviceInfo() {
NimBLEService *NimBLEHIDDevice::deviceInfo()
{
return m_deviceInfoService;
}

/**
* @brief Returns a pointer to the HID service.
*/
NimBLEService* NimBLEHIDDevice::hidService() {
NimBLEService *NimBLEHIDDevice::hidService()
{
return m_hidService;
}

/**
* @brief @brief Returns a pointer to the battery service.
*/
NimBLEService* NimBLEHIDDevice::batteryService() {
NimBLEService *NimBLEHIDDevice::batteryService()
{
return m_batteryService;
}

Expand Down

0 comments on commit 54b2542

Please sign in to comment.