Skip to content

Commit cdf05b3

Browse files
committed
Add Output Report Function
Added Output Report function and provided examples.
1 parent 11ee6e9 commit cdf05b3

7 files changed

+203
-1
lines changed

BleGamepad.cpp

+70
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ std::string serialNumber;
4747
std::string firmwareRevision;
4848
std::string hardwareRevision;
4949

50+
bool enableOutputReport = false;
51+
uint16_t outputReportLength = 64;
5052
BleGamepad::BleGamepad(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) : _buttons(),
5153
_specialButtons(0),
5254
_x(0),
@@ -94,6 +96,8 @@ void BleGamepad::begin(BleGamepadConfiguration *config)
9496
pid = configuration.getPid();
9597
guidVersion = configuration.getGuidVersion();
9698

99+
enableOutputReport = configuration.getEnableOutputReport();
100+
outputReportLength = configuration.getOutputReportLength();
97101
uint8_t high = highByte(vid);
98102
uint8_t low = lowByte(vid);
99103

@@ -568,6 +572,49 @@ void BleGamepad::begin(BleGamepadConfiguration *config)
568572
tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0;
569573
}
570574

575+
if (configuration.getEnableOutputReport()){
576+
// Usage Page (Vendor Defined 0xFF00)
577+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x06;
578+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00;
579+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF;
580+
581+
// Usage (Vendor Usage 0x01)
582+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09;
583+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
584+
585+
// Usage (0x01)
586+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09;
587+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01;
588+
589+
// Logical Minimum (0)
590+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15;
591+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00;
592+
593+
// Logical Maximum (255)
594+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x26;
595+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF;
596+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00;
597+
598+
// Report Size (8 bits)
599+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75;
600+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x08;
601+
602+
if(configuration.getOutputReportLength()<=0xFF){
603+
// Report Count (0~255 bytes)
604+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95;
605+
tempHidReportDescriptor[hidReportDescriptorSize++] = configuration.getOutputReportLength();
606+
}else{
607+
// Report Count (0~65535 bytes)
608+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x96;
609+
tempHidReportDescriptor[hidReportDescriptorSize++] = lowByte(configuration.getOutputReportLength());
610+
tempHidReportDescriptor[hidReportDescriptorSize++] = highByte(configuration.getOutputReportLength());
611+
}
612+
613+
// Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
614+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x91;
615+
tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02;
616+
}
617+
571618
// END_COLLECTION (Application)
572619
tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0;
573620

@@ -1357,6 +1404,22 @@ void BleGamepad::setBatteryLevel(uint8_t level)
13571404
}
13581405
}
13591406

1407+
bool BleGamepad::isOutputReceived(){
1408+
if(enableOutputReport && outputReceiver){
1409+
if(this->outputReceiver->outputFlag){
1410+
this->outputReceiver->outputFlag=false; // Clear Flag
1411+
return true;
1412+
}
1413+
}
1414+
return false;
1415+
}
1416+
uint8_t* BleGamepad::getOutputBuffer(){
1417+
if(enableOutputReport && outputReceiver){
1418+
memcpy(outputBackupBuffer, outputReceiver->outputBuffer, outputReportLength); // Creating a backup to avoid buffer being overwritten while processing data
1419+
return outputBackupBuffer;
1420+
}
1421+
return nullptr;
1422+
}
13601423
void BleGamepad::taskServer(void *pvParameter)
13611424
{
13621425
BleGamepad *BleGamepadInstance = (BleGamepad *)pvParameter; // static_cast<BleGamepad *>(pvParameter);
@@ -1375,6 +1438,13 @@ void BleGamepad::taskServer(void *pvParameter)
13751438
BleGamepadInstance->inputGamepad = BleGamepadInstance->hid->inputReport(BleGamepadInstance->configuration.getHidReportId()); // <-- input REPORTID from report map
13761439
BleGamepadInstance->connectionStatus->inputGamepad = BleGamepadInstance->inputGamepad;
13771440

1441+
if (enableOutputReport){
1442+
BleGamepadInstance->outputGamepad = BleGamepadInstance->hid->outputReport(BleGamepadInstance->configuration.getHidReportId());
1443+
BleGamepadInstance->outputReceiver = new BleOutputReceiver(outputReportLength);
1444+
BleGamepadInstance->outputBackupBuffer = new uint8_t[outputReportLength];
1445+
BleGamepadInstance->outputGamepad->setCallbacks(BleGamepadInstance->outputReceiver);
1446+
}
1447+
13781448
BleGamepadInstance->hid->manufacturer()->setValue(BleGamepadInstance->deviceManufacturer);
13791449

13801450
NimBLEService *pService = pServer->getServiceByUUID(SERVICE_UUID_DEVICE_INFORMATION);

BleGamepad.h

+8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "NimBLEHIDDevice.h"
1111
#include "NimBLECharacteristic.h"
1212
#include "BleGamepadConfiguration.h"
13+
#include "BleOutputReceiver.h"
1314

1415
class BleGamepad
1516
{
@@ -38,8 +39,13 @@ class BleGamepad
3839

3940
BleConnectionStatus *connectionStatus;
4041

42+
BleOutputReceiver *outputReceiver;
43+
4144
NimBLEHIDDevice *hid;
4245
NimBLECharacteristic *inputGamepad;
46+
NimBLECharacteristic *outputGamepad;
47+
48+
uint8_t *outputBackupBuffer;
4349

4450
void rawAction(uint8_t msg[], char msgSize);
4551
static void taskServer(void *pvParameter);
@@ -105,6 +111,8 @@ class BleGamepad
105111
uint8_t batteryLevel;
106112
std::string deviceManufacturer;
107113
std::string deviceName;
114+
bool isOutputReceived();
115+
uint8_t* getOutputBuffer();
108116

109117
protected:
110118
virtual void onStarted(NimBLEServer *pServer){};

BleGamepadConfiguration.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ BleGamepadConfiguration::BleGamepadConfiguration() : _controllerType(CONTROLLER_
2020
_serialNumber("0123456789"),
2121
_firmwareRevision("0.5.5"),
2222
_hardwareRevision("1.0.0")
23+
_enableOutputReport(false),
24+
_outputReportLength(64)
2325
{
2426
}
2527

@@ -119,7 +121,8 @@ char *BleGamepadConfiguration::getSoftwareRevision(){ return _softwareRevision;
119121
char *BleGamepadConfiguration::getSerialNumber(){ return _serialNumber; }
120122
char *BleGamepadConfiguration::getFirmwareRevision(){ return _firmwareRevision; }
121123
char *BleGamepadConfiguration::getHardwareRevision(){ return _hardwareRevision; }
122-
124+
bool BleGamepadConfiguration::getEnableOutputReport(){ return _enableOutputReport; }
125+
uint16_t BleGamepadConfiguration::getOutputReportLength(){ return _outputReportLength; }
123126
void BleGamepadConfiguration::setWhichSpecialButtons(bool start, bool select, bool menu, bool home, bool back, bool volumeInc, bool volumeDec, bool volumeMute)
124127
{
125128
_whichSpecialButtons[START_BUTTON] = start;
@@ -191,3 +194,5 @@ void BleGamepadConfiguration::setSoftwareRevision(char *value) { _softwareRevisi
191194
void BleGamepadConfiguration::setSerialNumber(char *value) { _serialNumber = value; }
192195
void BleGamepadConfiguration::setFirmwareRevision(char *value) { _firmwareRevision = value; }
193196
void BleGamepadConfiguration::setHardwareRevision(char *value) { _hardwareRevision = value; }
197+
void BleGamepadConfiguration::setEnableOutputReport(bool value) { _enableOutputReport = value; }
198+
void BleGamepadConfiguration::setOutputReportLength(uint16_t value) { _outputReportLength = value; }

BleGamepadConfiguration.h

+6
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ class BleGamepadConfiguration
222222
char *_serialNumber;
223223
char *_firmwareRevision;
224224
char *_hardwareRevision;
225+
bool _enableOutputReport;
226+
uint16_t _outputReportLength;
225227

226228
public:
227229
BleGamepadConfiguration();
@@ -272,6 +274,8 @@ class BleGamepadConfiguration
272274
char *getSerialNumber();
273275
char *getFirmwareRevision();
274276
char *getHardwareRevision();
277+
bool getEnableOutputReport();
278+
uint16_t getOutputReportLength();
275279

276280
void setControllerType(uint8_t controllerType);
277281
void setAutoReport(bool value);
@@ -314,6 +318,8 @@ class BleGamepadConfiguration
314318
void setSerialNumber(char *value);
315319
void setFirmwareRevision(char *value);
316320
void setHardwareRevision(char *value);
321+
void setEnableOutputReport(bool value);
322+
void setOutputReportLength(uint16_t value);
317323
};
318324

319325
#endif

BleOutputReceiver.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "BleOutputReceiver.h"
2+
3+
BleOutputReceiver::BleOutputReceiver(uint16_t outputReportLength)
4+
{
5+
this->outputReportLength = outputReportLength;
6+
outputBuffer = new uint8_t[outputReportLength];
7+
}
8+
9+
BleOutputReceiver::~BleOutputReceiver()
10+
{
11+
// Release memory
12+
if (outputBuffer)
13+
{
14+
delete[] outputBuffer;
15+
}
16+
}
17+
18+
void BleOutputReceiver::onWrite(NimBLECharacteristic *pCharacteristic)
19+
{
20+
// Retrieve data sent from the host
21+
std::string value = pCharacteristic->getValue();
22+
23+
// Store the received data in the buffer
24+
for (int i = 0; i < std::min(value.length(), (size_t)outputReportLength); i++)
25+
{
26+
outputBuffer[i] = (uint8_t)value[i];
27+
}
28+
29+
// Testing
30+
// Serial.println("Received data from host:");
31+
// for (size_t i = 0; i < value.length(); i++) {
32+
// Serial.print((uint8_t)value[i], HEX);
33+
// Serial.print(" ");
34+
// }
35+
// Serial.println();
36+
37+
outputFlag = true;
38+
}

BleOutputReceiver.h

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef BLE_OUTPUT_RECEIVER_H
2+
#define BLE_OUTPUT_RECEIVER_H
3+
#include "sdkconfig.h"
4+
#if defined(CONFIG_BT_ENABLED)
5+
6+
#include "nimconfig.h"
7+
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
8+
9+
#include <NimBLEServer.h>
10+
#include "NimBLECharacteristic.h"
11+
12+
class BleOutputReceiver : public NimBLECharacteristicCallbacks
13+
{
14+
public:
15+
BleOutputReceiver(uint16_t outputReportLength);
16+
~BleOutputReceiver();
17+
void onWrite(NimBLECharacteristic *pCharacteristic) override;
18+
bool outputFlag = false;
19+
uint16_t outputReportLength;
20+
uint8_t *outputBuffer;
21+
};
22+
23+
#endif // CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
24+
#endif // CONFIG_BT_ENABLED
25+
#endif // BLE_OUTPUT_RECEIVER_H
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Test receiving Output Report
3+
*/
4+
#include <BleGamepad.h>
5+
6+
#define numOfButtons 16
7+
8+
BleGamepad bleGamepad;
9+
BleGamepadConfiguration bleGamepadConfig;
10+
11+
void setup() {
12+
Serial.begin(115200);
13+
Serial.println("Starting BLE work!");
14+
15+
bleGamepadConfig.setAutoReport(false);
16+
bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD); // CONTROLLER_TYPE_JOYSTICK, CONTROLLER_TYPE_GAMEPAD (DEFAULT), CONTROLLER_TYPE_MULTI_AXIS
17+
18+
bleGamepadConfig.setEnableOutputReport(true); // (Necessary) Enable Output Report. Default is false.
19+
bleGamepadConfig.setOutputReportLength(128); // (Optional) Set Report Length 128(Bytes). The default value is 64 bytes.
20+
// Do not set the OutputReportLength too large, otherwise it will be truncated. For example, if the hexadecimal value of 10000 in decimal is 0x2710, it will be truncated to 0x710.
21+
22+
bleGamepadConfig.setHidReportId(0x05); // (Optional) Set ReportID to 0x05.
23+
//When you send data from the upper computer to ESP32, you must send the ReportID in the first byte! The default ReportID is 3.
24+
25+
bleGamepadConfig.setButtonCount(numOfButtons);
26+
27+
bleGamepadConfig.setAxesMin(0x0000); // 0 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
28+
bleGamepadConfig.setAxesMax(0x7FFF); // 32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
29+
30+
// Try NOT to modify VID, otherwise it may cause the host to be unable to send output reports to the device.
31+
bleGamepadConfig.setVid(0x3412);
32+
// You can freely set the PID
33+
bleGamepadConfig.setPid(0x0100);
34+
bleGamepad.begin(&bleGamepadConfig);
35+
36+
// changing bleGamepadConfig after the begin function has no effect, unless you call the begin function again
37+
}
38+
39+
void loop() {
40+
if (bleGamepad.isConnected()) {
41+
if (bleGamepad.isOutputReceived()) {
42+
uint8_t* buffer = bleGamepad.getOutputBuffer();
43+
Serial.print("Receive: ");
44+
for (int i = 0; i < 64; i++) {
45+
Serial.printf("0x%X ",buffer[i]); // Print data from buffer
46+
}
47+
Serial.println("");
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)