From 884ddba40966e11c13ce60d9c2dc1f91f134380e Mon Sep 17 00:00:00 2001 From: lemmingDev Date: Tue, 27 Sep 2022 09:54:51 +1000 Subject: [PATCH] Add more configurable BLE characteristics --- BleConnectionStatus.cpp | 4 +- BleGamepad.cpp | 88 ++++++++++++++++--- BleGamepadConfiguration.cpp | 17 +++- BleGamepadConfiguration.h | 16 +++- README.md | 4 +- .../CharacteristicsConfiguration.ino | 49 +++++++++++ keywords.txt | 13 ++- library.properties | 4 +- 8 files changed, 172 insertions(+), 23 deletions(-) create mode 100644 examples/CharacteristicsConfiguration/CharacteristicsConfiguration.ino diff --git a/BleConnectionStatus.cpp b/BleConnectionStatus.cpp index 61076b0..5d11694 100644 --- a/BleConnectionStatus.cpp +++ b/BleConnectionStatus.cpp @@ -4,10 +4,10 @@ BleConnectionStatus::BleConnectionStatus(void) { } -void BleConnectionStatus::onConnect(NimBLEServer *pServer, ble_gap_conn_desc* desc){ +void BleConnectionStatus::onConnect(NimBLEServer *pServer, ble_gap_conn_desc* desc) +{ pServer->updateConnParams(desc->conn_handle, 6, 7, 0, 600); this->connected = true; - } void BleConnectionStatus::onDisconnect(NimBLEServer *pServer) diff --git a/BleGamepad.cpp b/BleGamepad.cpp index 4ddbc58..cba102a 100644 --- a/BleGamepad.cpp +++ b/BleGamepad.cpp @@ -19,17 +19,30 @@ static const char *LOG_TAG = "BLEGamepad"; #endif +#define SERVICE_UUID_DEVICE_INFORMATION "180A" // Service - Device information + +#define CHARACTERISTIC_UUID_MODEL_NUMBER "2A24" // Characteristic - Model Number String - 0x2A24 +#define CHARACTERISTIC_UUID_SOFTWARE_REVISION "2A28" // Characteristic - Software Revision String - 0x2A28 +#define CHARACTERISTIC_UUID_SERIAL_NUMBER "2A25" // Characteristic - Serial Number String - 0x2A25 +#define CHARACTERISTIC_UUID_FIRMWARE_REVISION "2A26" // Characteristic - Firmware Revision String - 0x2A26 +#define CHARACTERISTIC_UUID_HARDWARE_REVISION "2A27" // Characteristic - Hardware Revision String - 0x2A27 + + uint8_t tempHidReportDescriptor[150]; int hidReportDescriptorSize = 0; uint8_t reportSize = 0; uint8_t numOfButtonBytes = 0; uint16_t vid; -uint16_t pid; +uint16_t pid; uint16_t axesMin; uint16_t axesMax; uint16_t simulationMin; uint16_t simulationMax; - +std::string modelNumber; +std::string softwareRevision; +std::string serialNumber; +std::string firmwareRevision; +std::string hardwareRevision; BleGamepad::BleGamepad(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) : _buttons(), _specialButtons(0), @@ -67,18 +80,24 @@ void BleGamepad::resetButtons() void BleGamepad::begin(BleGamepadConfiguration *config) { configuration = *config; // we make a copy, so the user can't change actual values midway through operation, without calling the begin function again - + + modelNumber = configuration.getModelNumber(); + softwareRevision = configuration.getSoftwareRevision(); + serialNumber = configuration.getSerialNumber(); + firmwareRevision = configuration.getFirmwareRevision(); + hardwareRevision = configuration.getHardwareRevision(); + vid = configuration.getVid(); pid = configuration.getPid(); - + uint8_t high = highByte(vid); uint8_t low = lowByte(vid); - + vid = low << 8 | high; - + high = highByte(pid); low = lowByte(pid); - + pid = low << 8 | high; uint8_t buttonPaddingBits = 8 - (configuration.getButtonCount() % 8); @@ -244,7 +263,7 @@ void BleGamepad::begin(BleGamepadConfiguration *config) // USAGE (Home) tempHidReportDescriptor[hidReportDescriptorSize++] = 0x0A; tempHidReportDescriptor[hidReportDescriptorSize++] = 0x23; - tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; } if (configuration.getIncludeBack()) @@ -252,7 +271,7 @@ void BleGamepad::begin(BleGamepadConfiguration *config) // USAGE (Back) tempHidReportDescriptor[hidReportDescriptorSize++] = 0x0A; tempHidReportDescriptor[hidReportDescriptorSize++] = 0x24; - tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; } if (configuration.getIncludeVolumeInc()) @@ -316,7 +335,7 @@ void BleGamepad::begin(BleGamepadConfiguration *config) tempHidReportDescriptor[hidReportDescriptorSize++] = highByte(configuration.getAxesMin()); //tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; // Use these two lines for 0 min //tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; - //tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; // Use these two lines for -32767 min + //tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; // Use these two lines for -32767 min //tempHidReportDescriptor[hidReportDescriptorSize++] = 0x80; // LOGICAL_MAXIMUM (+32767) @@ -325,7 +344,7 @@ void BleGamepad::begin(BleGamepadConfiguration *config) tempHidReportDescriptor[hidReportDescriptorSize++] = highByte(configuration.getAxesMax()); //tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF; // Use these two lines for 255 max //tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; - //tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF; // Use these two lines for +32767 max + //tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF; // Use these two lines for +32767 max //tempHidReportDescriptor[hidReportDescriptorSize++] = 0x7F; // REPORT_SIZE (16) @@ -963,6 +982,7 @@ void BleGamepad::setLeftThumb(int16_t x, int16_t y) sendReport(); } } + void BleGamepad::setRightThumb(int16_t z, int16_t rZ) { if (z == -32768) @@ -1325,16 +1345,55 @@ void BleGamepad::setBatteryLevel(uint8_t level) void BleGamepad::taskServer(void *pvParameter) { BleGamepad *BleGamepadInstance = (BleGamepad *)pvParameter; // static_cast(pvParameter); + + // Use the procedure below to set a custom Bluetooth MAC address + // Compiler adds 0x02 to the last value of board's base MAC address to get the BT MAC address, so take 0x02 away from the value you actually want when setting + //uint8_t newMACAddress[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF - 0x02}; + //esp_base_mac_addr_set(&newMACAddress[0]); // Set new MAC address + NimBLEDevice::init(BleGamepadInstance->deviceName); NimBLEServer *pServer = NimBLEDevice::createServer(); pServer->setCallbacks(BleGamepadInstance->connectionStatus); BleGamepadInstance->hid = new NimBLEHIDDevice(pServer); + BleGamepadInstance->inputGamepad = BleGamepadInstance->hid->inputReport(BleGamepadInstance->configuration.getHidReportId()); // <-- input REPORTID from report map BleGamepadInstance->connectionStatus->inputGamepad = BleGamepadInstance->inputGamepad; BleGamepadInstance->hid->manufacturer()->setValue(BleGamepadInstance->deviceManufacturer); + NimBLEService *pService = pServer->getServiceByUUID(SERVICE_UUID_DEVICE_INFORMATION); + + BLECharacteristic* pCharacteristic_Model_Number = pService->createCharacteristic( + CHARACTERISTIC_UUID_MODEL_NUMBER, + NIMBLE_PROPERTY::READ + ); + pCharacteristic_Model_Number->setValue(modelNumber); + + BLECharacteristic* pCharacteristic_Software_Revision = pService->createCharacteristic( + CHARACTERISTIC_UUID_SOFTWARE_REVISION, + NIMBLE_PROPERTY::READ + ); + pCharacteristic_Software_Revision->setValue(softwareRevision); + + BLECharacteristic* pCharacteristic_Serial_Number = pService->createCharacteristic( + CHARACTERISTIC_UUID_SERIAL_NUMBER, + NIMBLE_PROPERTY::READ + ); + pCharacteristic_Serial_Number->setValue(serialNumber); + + BLECharacteristic* pCharacteristic_Firmware_Revision = pService->createCharacteristic( + CHARACTERISTIC_UUID_FIRMWARE_REVISION, + NIMBLE_PROPERTY::READ + ); + pCharacteristic_Firmware_Revision->setValue(firmwareRevision); + + BLECharacteristic* pCharacteristic_Hardware_Revision = pService->createCharacteristic( + CHARACTERISTIC_UUID_HARDWARE_REVISION, + NIMBLE_PROPERTY::READ + ); + pCharacteristic_Hardware_Revision->setValue(hardwareRevision); + BleGamepadInstance->hid->pnp(0x01, vid, pid, 0x0110); BleGamepadInstance->hid->hidInfo(0x00, 0x01); @@ -1343,8 +1402,9 @@ void BleGamepad::taskServer(void *pvParameter) uint8_t *customHidReportDescriptor = new uint8_t[hidReportDescriptorSize]; memcpy(customHidReportDescriptor, tempHidReportDescriptor, hidReportDescriptorSize); - for (int i = 0; i < hidReportDescriptorSize; i++) - Serial.printf("%02x", customHidReportDescriptor[i]); + // Testing + //for (int i = 0; i < hidReportDescriptorSize; i++) + // Serial.printf("%02x", customHidReportDescriptor[i]); BleGamepadInstance->hid->reportMap((uint8_t *)customHidReportDescriptor, hidReportDescriptorSize); BleGamepadInstance->hid->startServices(); @@ -1359,4 +1419,4 @@ void BleGamepad::taskServer(void *pvParameter) ESP_LOGD(LOG_TAG, "Advertising started!"); vTaskDelay(portMAX_DELAY); // delay(portMAX_DELAY); -} +} \ No newline at end of file diff --git a/BleGamepadConfiguration.cpp b/BleGamepadConfiguration.cpp index 78e0a3f..c60f600 100644 --- a/BleGamepadConfiguration.cpp +++ b/BleGamepadConfiguration.cpp @@ -13,7 +13,12 @@ BleGamepadConfiguration::BleGamepadConfiguration() : _controllerType(CONTROLLER_ _axesMin(0x0000), _axesMax(0x7FFF), _simulationMin(0x0000), - _simulationMax(0x7FFF) + _simulationMax(0x7FFF), + _modelNumber("1.0.0"), + _softwareRevision("1.0.0"), + _serialNumber("0123456789"), + _firmwareRevision("0.5.2"), + _hardwareRevision("1.0.0") { } @@ -107,6 +112,11 @@ bool BleGamepadConfiguration::getIncludeAccelerator() { return _whichSimulationC bool BleGamepadConfiguration::getIncludeBrake() { return _whichSimulationControls[BRAKE]; } bool BleGamepadConfiguration::getIncludeSteering() { return _whichSimulationControls[STEERING]; } const bool *BleGamepadConfiguration::getWhichSimulationControls() const { return _whichSimulationControls; } +char *BleGamepadConfiguration::getModelNumber(){ return _modelNumber; } +char *BleGamepadConfiguration::getSoftwareRevision(){ return _softwareRevision; } +char *BleGamepadConfiguration::getSerialNumber(){ return _serialNumber; } +char *BleGamepadConfiguration::getFirmwareRevision(){ return _firmwareRevision; } +char *BleGamepadConfiguration::getHardwareRevision(){ return _hardwareRevision; } void BleGamepadConfiguration::setWhichSpecialButtons(bool start, bool select, bool menu, bool home, bool back, bool volumeInc, bool volumeDec, bool volumeMute) { @@ -173,3 +183,8 @@ void BleGamepadConfiguration::setAxesMin(int16_t value) { _axesMin = value; } void BleGamepadConfiguration::setAxesMax(int16_t value) { _axesMax = value; } void BleGamepadConfiguration::setSimulationMin(int16_t value) { _simulationMin = value; } void BleGamepadConfiguration::setSimulationMax(int16_t value) { _simulationMax = value; } +void BleGamepadConfiguration::setModelNumber(char *value) { _modelNumber = value; } +void BleGamepadConfiguration::setSoftwareRevision(char *value) { _softwareRevision = value; } +void BleGamepadConfiguration::setSerialNumber(char *value) { _serialNumber = value; } +void BleGamepadConfiguration::setFirmwareRevision(char *value) { _firmwareRevision = value; } +void BleGamepadConfiguration::setHardwareRevision(char *value) { _hardwareRevision = value; } \ No newline at end of file diff --git a/BleGamepadConfiguration.h b/BleGamepadConfiguration.h index 679af0d..75d8d6f 100644 --- a/BleGamepadConfiguration.h +++ b/BleGamepadConfiguration.h @@ -216,7 +216,11 @@ class BleGamepadConfiguration int16_t _axesMax; int16_t _simulationMin; int16_t _simulationMax; - + char *_modelNumber; + char *_softwareRevision; + char *_serialNumber; + char *_firmwareRevision; + char *_hardwareRevision; public: BleGamepadConfiguration(); @@ -261,6 +265,11 @@ class BleGamepadConfiguration int16_t getAxesMax(); int16_t getSimulationMin(); int16_t getSimulationMax(); + char *getModelNumber(); + char *getSoftwareRevision(); + char *getSerialNumber(); + char *getFirmwareRevision(); + char *getHardwareRevision(); void setControllerType(uint8_t controllerType); void setAutoReport(bool value); @@ -297,6 +306,11 @@ class BleGamepadConfiguration void setAxesMax(int16_t value); void setSimulationMin(int16_t value); void setSimulationMax(int16_t value); + void setModelNumber(char *value); + void setSoftwareRevision(char *value); + void setSerialNumber(char *value); + void setFirmwareRevision(char *value); + void setHardwareRevision(char *value); }; #endif diff --git a/README.md b/README.md index 6cb41d4..e714c4b 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,8 @@ It would be great however if any improvements are fed back into this version. - [x] Special buttons (start, select, menu, home, back, volume up, volume down, volume mute) all disabled by default - [x] Configurable HID descriptor - [x] Configurable VID and PID values - - [ ] Report optional battery level to host <-- currently disabled - - [x] Customize Bluetooth device name/manufacturer + - [x] Configurable BLE characteristics (name, manufacturer, model number, software revision, serial number, firmware revision, hardware revision) + - [ ] Report optional battery level to host <-- currently disabled <-- awaiting NimBLE support - [x] Uses efficient NimBLE bluetooth library - [x] Compatible with Windows - [x] Compatible with Android (Android OS maps default buttons / axes / hats slightly differently than Windows) diff --git a/examples/CharacteristicsConfiguration/CharacteristicsConfiguration.ino b/examples/CharacteristicsConfiguration/CharacteristicsConfiguration.ino new file mode 100644 index 0000000..4d5c7f4 --- /dev/null +++ b/examples/CharacteristicsConfiguration/CharacteristicsConfiguration.ino @@ -0,0 +1,49 @@ +/* + * Sets BLE characteristic options + * Also shows how to set a custom MAC address + * Use BLE Scanner etc on Android to see them + */ + +#include +#include + +BleGamepad bleGamepad("Custom Contoller Name", "lemmingDev", 100); // Set custom device name, manufacturer and initial battery level +BleGamepadConfiguration bleGamepadConfig; // Create a BleGamepadConfiguration object to store all of the options + +// Use the procedure below to set a custom Bluetooth MAC address +// Compiler adds 0x02 to the last value of board's base MAC address to get the BT MAC address, so take 0x02 away from the value you actually want when setting +// I've noticed the first number is a little picky and if set incorrectly don't work and will default to the board's embedded address +// 0xAA definately works, so use that, or experiment +uint8_t newMACAddress[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF - 0x02}; + +void setup() +{ + Serial.begin(115200); + Serial.println("Starting BLE work!"); + bleGamepadConfig.setAutoReport(false); + bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD); // CONTROLLER_TYPE_JOYSTICK, CONTROLLER_TYPE_GAMEPAD (DEFAULT), CONTROLLER_TYPE_MULTI_AXIS + bleGamepadConfig.setVid(0xe502); + bleGamepadConfig.setPid(0xabcd); + + bleGamepadConfig.setModelNumber("1.0"); + bleGamepadConfig.setSoftwareRevision("Software Rev 1"); + bleGamepadConfig.setSerialNumber("9876543210"); + bleGamepadConfig.setFirmwareRevision("2.0"); + bleGamepadConfig.setHardwareRevision("1.7"); + + // Some non-Windows operating systems and web based gamepad testers don't like min axis set below 0, so 0 is set by default + //bleGamepadConfig.setAxesMin(0x8001); // -32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal + bleGamepadConfig.setAxesMin(0x0000); // 0 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal + bleGamepadConfig.setAxesMax(0x7FFF); // 32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal + + bleGamepad.begin(&bleGamepadConfig); // Begin gamepad with configuration options + esp_base_mac_addr_set(&newMACAddress[0]); // Set new MAC address +} + +void loop() +{ + if (bleGamepad.isConnected()) + { + + } +} \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index 43c4cca..fd7c21b 100644 --- a/keywords.txt +++ b/keywords.txt @@ -4,7 +4,7 @@ # Class ####################################### -BleGamepad KEYWORD1 +BleGamepad KEYWORD1 BleGamepadConfiguration KEYWORD1 ####################################### @@ -134,12 +134,23 @@ getAxesMin KEYWORD2 getAxesMax KEYWORD2 getSimulationMin KEYWORD2 getSimulationMax KEYWORD2 +getModelNumber KEYWORD2 +getSoftwareRevision KEYWORD2 +getSerialNumber KEYWORD2 +getFirmwareRevision KEYWORD2 +getHardwareRevision KEYWORD2 setVid KEYWORD2 setPid KEYWORD2 setAxesMin KEYWORD2 setAxesMax KEYWORD2 setSimulationMin KEYWORD2 setSimulationMax KEYWORD2 +setModelNumber KEYWORD2 +setSoftwareRevision KEYWORD2 +setSerialNumber KEYWORD2 +setFirmwareRevision KEYWORD2 +setHardwareRevision KEYWORD2 + ####################################### # Constants diff --git a/library.properties b/library.properties index 5b289bf..ce2a879 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP32-BLE-Gamepad -version=0.5.1 +version=0.5.2 author=lemmingDev maintainer=lemmingDev sentence=Bluetooth LE Gamepad library for the ESP32. @@ -7,4 +7,4 @@ paragraph=Bluetooth LE Gamepad library for the ESP32. category=Communication url=https://github.com/lemmingDev/ESP32-BLE-Gamepad architectures=esp32 -depends=NimBLE-Arduino +depends=NimBLE-Arduino \ No newline at end of file