mirror of
https://github.com/lemmingDev/ESP32-BLE-Gamepad.git
synced 2026-03-06 00:04:11 +01:00
Now, each axis/hat can be set independently setLeftThumb takes 2 int16_t parameters for x and y axes setRightThumb takes 2 int16_t parameters for z and rZ axes setLeftTrigger takes 1 char parameter for rX axis setRightTrigger takes 1 char parameter for rY axis setHat takes a hat position as above (or 0 = centered and 1~8 are the 8 possible directions) Axes/hat can still be set all at once with setAxes Library can now disable the aotoReport feature (enabled by default), and manually call the sendReport() function when wanted
259 lines
7.0 KiB
C++
259 lines
7.0 KiB
C++
#include <BLEDevice.h>
|
|
#include <BLEUtils.h>
|
|
#include <BLEServer.h>
|
|
#include "BLE2902.h"
|
|
#include "BLEHIDDevice.h"
|
|
#include "HIDTypes.h"
|
|
#include "HIDKeyboardTypes.h"
|
|
#include <driver/adc.h>
|
|
#include "sdkconfig.h"
|
|
|
|
#include "BleConnectionStatus.h"
|
|
#include "BleGamepad.h"
|
|
|
|
#if defined(CONFIG_ARDUHAL_ESP_LOG)
|
|
#include "esp32-hal-log.h"
|
|
#define LOG_TAG ""
|
|
#else
|
|
#include "esp_log.h"
|
|
static const char* LOG_TAG = "BLEDevice";
|
|
#endif
|
|
|
|
static const uint8_t _hidReportDescriptor[] = {
|
|
USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop)
|
|
USAGE(1), 0x05, // USAGE (Gamepad)
|
|
COLLECTION(1), 0x01, // COLLECTION (Application)
|
|
USAGE(1), 0x01, // USAGE (Pointer)
|
|
COLLECTION(1), 0x00, // COLLECTION (Physical)
|
|
|
|
// ------------------------------------------------- Buttons (1 to 32)
|
|
USAGE_PAGE(1), 0x09, // USAGE_PAGE (Button)
|
|
USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (Button 1)
|
|
USAGE_MAXIMUM(1), 0x20, // USAGE_MAXIMUM (Button 32)
|
|
LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0)
|
|
LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1)
|
|
REPORT_SIZE(1), 0x01, // REPORT_SIZE (1)
|
|
REPORT_COUNT(1), 0x20, // REPORT_COUNT (32)
|
|
HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;32 button bits
|
|
// ------------------------------------------------- X/Y position, Z/rZ position
|
|
USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop)
|
|
COLLECTION(1), 0x00, // COLLECTION (Physical)
|
|
USAGE(1), 0x30, // USAGE (X)
|
|
USAGE(1), 0x31, // USAGE (Y)
|
|
USAGE(1), 0x32, // USAGE (Z)
|
|
USAGE(1), 0x35, // USAGE (rZ)
|
|
0x16, 0x01, 0x80,//LOGICAL_MINIMUM (-32767)
|
|
0x26, 0xFF, 0x7F,//LOGICAL_MAXIMUM (32767)
|
|
REPORT_SIZE(1), 0x10, // REPORT_SIZE (16)
|
|
REPORT_COUNT(1), 0x04, // REPORT_COUNT (4)
|
|
HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs)
|
|
// ------------------------------------------------- Triggers
|
|
USAGE(1), 0x33, // USAGE (rX) Left Trigger
|
|
USAGE(1), 0x34, // USAGE (rY) Right Trigger
|
|
LOGICAL_MINIMUM(1), 0x81, // LOGICAL_MINIMUM (-127)
|
|
LOGICAL_MAXIMUM(1), 0x7f, // LOGICAL_MAXIMUM (127)
|
|
REPORT_SIZE(1), 0x08, // REPORT_SIZE (8)
|
|
REPORT_COUNT(1), 0x02, // REPORT_COUNT (2)
|
|
HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;4 bytes (X,Y,Z,rZ)
|
|
END_COLLECTION(0), // END_COLLECTION
|
|
|
|
USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop)
|
|
USAGE(1), 0x39, // USAGE (Hat switch)
|
|
USAGE(1), 0x39, // USAGE (Hat switch)
|
|
LOGICAL_MINIMUM(1), 0x01, // LOGICAL_MINIMUM (1)
|
|
LOGICAL_MAXIMUM(1), 0x08, // LOGICAL_MAXIMUM (8)
|
|
REPORT_SIZE(1), 0x04, // REPORT_SIZE (4)
|
|
REPORT_COUNT(1), 0x02, // REPORT_COUNT (2)
|
|
HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;1 byte Hat1, Hat2
|
|
|
|
END_COLLECTION(0), // END_COLLECTION
|
|
END_COLLECTION(0) // END_COLLECTION
|
|
};
|
|
|
|
BleGamepad::BleGamepad(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) :
|
|
_buttons(0),
|
|
_x(0),
|
|
_y(0),
|
|
_z(0),
|
|
_rZ(0),
|
|
_rX(0),
|
|
_rY(0),
|
|
_hat(0),
|
|
_autoReport(false),
|
|
hid(0)
|
|
{
|
|
this->deviceName = deviceName;
|
|
this->deviceManufacturer = deviceManufacturer;
|
|
this->batteryLevel = batteryLevel;
|
|
this->connectionStatus = new BleConnectionStatus();
|
|
}
|
|
|
|
void BleGamepad::begin(bool autoReport)
|
|
{
|
|
_autoReport = autoReport;
|
|
xTaskCreate(this->taskServer, "server", 20000, (void *)this, 5, NULL);
|
|
}
|
|
|
|
void BleGamepad::end(void)
|
|
{
|
|
}
|
|
|
|
void BleGamepad::setAxes(int16_t x, int16_t y, int16_t z, int16_t rZ, char rX, char rY, signed char hat)
|
|
{
|
|
if(x == -32768) { x = -32767; }
|
|
if(y == -32768) { y = -32767; }
|
|
if(z == -32768) { z = -32767; }
|
|
if(rZ == -32768) { rZ = -32767; }
|
|
|
|
_x = x;
|
|
_y = y;
|
|
_z = z;
|
|
_rZ = rZ;
|
|
_rX = rX;
|
|
_rY = rY;
|
|
_hat = hat;
|
|
|
|
if(_autoReport){ sendReport(); }
|
|
}
|
|
|
|
void BleGamepad::sendReport(void)
|
|
{
|
|
if (this->isConnected())
|
|
{
|
|
uint8_t m[15];
|
|
m[0] = _buttons;
|
|
m[1] = (_buttons >> 8);
|
|
m[2] = (_buttons >> 16);
|
|
m[3] = (_buttons >> 24);
|
|
m[4] = _x;
|
|
m[5] = (_x >> 8);
|
|
m[6] = _y;
|
|
m[7] = (_y >> 8);
|
|
m[8] = _z;
|
|
m[9] = (_z >> 8);
|
|
m[10] = _rZ;
|
|
m[11] = (_rZ >> 8);
|
|
m[12] = (signed char)(_rX - 128);
|
|
m[13] = (signed char)(_rY - 128);
|
|
m[14] = _hat;
|
|
if (m[12] == -128) { m[12] = -127; }
|
|
if (m[13] == -128) { m[13] = -127; }
|
|
this->inputGamepad->setValue(m, sizeof(m));
|
|
this->inputGamepad->notify();
|
|
}
|
|
}
|
|
void BleGamepad::buttons(uint32_t b)
|
|
{
|
|
if (b != _buttons)
|
|
{
|
|
_buttons = b;
|
|
|
|
if(_autoReport){ sendReport(); }
|
|
}
|
|
}
|
|
|
|
void BleGamepad::press(uint32_t b)
|
|
{
|
|
buttons(_buttons | b);
|
|
}
|
|
|
|
void BleGamepad::release(uint32_t b)
|
|
{
|
|
buttons(_buttons & ~b);
|
|
}
|
|
|
|
void BleGamepad::setLeftThumb(int16_t x, int16_t y)
|
|
{
|
|
_x = x;
|
|
_y = y;
|
|
|
|
if(_autoReport){ sendReport(); }
|
|
}
|
|
void BleGamepad::setRightThumb(int16_t z, int16_t rZ)
|
|
{
|
|
_z = z;
|
|
_rZ = rZ;
|
|
|
|
if(_autoReport){ sendReport(); }
|
|
}
|
|
|
|
void BleGamepad::setLeftTrigger(char rX)
|
|
{
|
|
_rX = rX;
|
|
|
|
if(_autoReport){ sendReport(); }
|
|
}
|
|
|
|
void BleGamepad::setRightTrigger(char rY)
|
|
{
|
|
_rY = rY;
|
|
|
|
if(_autoReport){ sendReport(); }
|
|
}
|
|
|
|
void BleGamepad::setHat(signed char hat)
|
|
{
|
|
_hat = hat;
|
|
|
|
if(_autoReport){ sendReport(); }
|
|
}
|
|
|
|
void BleGamepad::setAutoReport(bool autoReport)
|
|
{
|
|
_autoReport = autoReport;
|
|
}
|
|
|
|
bool BleGamepad::isPressed(uint32_t b)
|
|
{
|
|
if ((b & _buttons) > 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool BleGamepad::isConnected(void)
|
|
{
|
|
return this->connectionStatus->connected;
|
|
}
|
|
|
|
void BleGamepad::setBatteryLevel(uint8_t level)
|
|
{
|
|
this->batteryLevel = level;
|
|
if (hid != 0)
|
|
this->hid->setBatteryLevel(this->batteryLevel);
|
|
}
|
|
|
|
void BleGamepad::taskServer(void* pvParameter)
|
|
{
|
|
BleGamepad* BleGamepadInstance = (BleGamepad *) pvParameter; //static_cast<BleGamepad *>(pvParameter);
|
|
BLEDevice::init(BleGamepadInstance->deviceName);
|
|
BLEServer *pServer = BLEDevice::createServer();
|
|
pServer->setCallbacks(BleGamepadInstance->connectionStatus);
|
|
|
|
BleGamepadInstance->hid = new BLEHIDDevice(pServer);
|
|
BleGamepadInstance->inputGamepad = BleGamepadInstance->hid->inputReport(0); // <-- input REPORTID from report map
|
|
BleGamepadInstance->connectionStatus->inputGamepad = BleGamepadInstance->inputGamepad;
|
|
|
|
BleGamepadInstance->hid->manufacturer()->setValue(BleGamepadInstance->deviceManufacturer);
|
|
|
|
BleGamepadInstance->hid->pnp(0x01,0x02e5,0xabcd,0x0110);
|
|
BleGamepadInstance->hid->hidInfo(0x00,0x01);
|
|
|
|
BLESecurity *pSecurity = new BLESecurity();
|
|
|
|
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
|
|
|
|
BleGamepadInstance->hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor));
|
|
BleGamepadInstance->hid->startServices();
|
|
|
|
BleGamepadInstance->onStarted(pServer);
|
|
|
|
BLEAdvertising *pAdvertising = pServer->getAdvertising();
|
|
pAdvertising->setAppearance(HID_GAMEPAD);
|
|
pAdvertising->addServiceUUID(BleGamepadInstance->hid->hidService()->getUUID());
|
|
pAdvertising->start();
|
|
BleGamepadInstance->hid->setBatteryLevel(BleGamepadInstance->batteryLevel);
|
|
|
|
ESP_LOGD(LOG_TAG, "Advertising started!");
|
|
vTaskDelay(portMAX_DELAY); //delay(portMAX_DELAY);
|
|
}
|