21#if CONFIG_NIMBLE_ENABLED
30#include <initializer_list>
33#include "host/ble_att.h"
34#include "host/ble_gatt.h"
35#include "host/ble_uuid.h"
36#include "host/ble_gap.h"
37#include "host/ble_gap.h"
38#include "os/os_mbuf.h"
39#include "esp32-hal-log.h"
47#define HID_REPORT_COUNT 10
49#define EMPTY_ble_gatt_cpfd { \
56#define EMPTY_ble_gatt_dsc_def { \
60 .access_cb = nullptr, \
63#define EMPTY_ble_gatt_chr_def { \
65 .access_cb = nullptr, \
67 .descriptors = nullptr, \
70 .val_handle = nullptr, \
73#define EMPTY_ble_gatt_svc_def { \
76 .includes = nullptr, \
77 .characteristics = nullptr}
92 constexpr ApiResult() noexcept {};
94 constexpr ApiResult(
int value) noexcept : code{value} {};
96 constexpr ApiResult(
const ApiResult &)
noexcept =
default;
98 constexpr ApiResult(ApiResult &&) noexcept = default;
106 constexpr operator
bool() const noexcept {
return (code == 0); }
113 constexpr explicit operator int() const noexcept {
return code; }
120 constexpr ApiResult &operator=(
const ApiResult &)
noexcept =
default;
127 constexpr ApiResult &operator=(ApiResult &&) noexcept = default;
135 constexpr ApiResult &operator=(
int value) noexcept;
142 void abort_if(const
char *txt) const;
149 void log_if(const
char *txt) const noexcept;
158 int to_attr_rc(
bool readOrWrite) const noexcept;
167 friend struct BLEDevice;
170 using OnConnectionStatus = ::std::function<void(
bool)>;
173 inline static OnConnectionStatus onConnectionStatus;
179 static void stop() noexcept;
183 static
bool connected() noexcept {
return _connected; }
186 static void disconnect() noexcept;
190 inline static const ble_gap_adv_params adv_params{
191 .conn_mode = BLE_GAP_CONN_MODE_UND,
192 .disc_mode = BLE_GAP_DISC_MODE_GEN,
197 .high_duty_cycle = 0,
201 inline static bool _connected =
false;
204 inline static int16_t _conn_handle = BLE_HS_CONN_HANDLE_NONE;
210 static int ble_gap_event_fn(ble_gap_event *event,
void *arg);
222 friend class BLEAdvertising;
230 static bool initialized() {
return _initialized; };
237 static void init(
const std::string &deviceName);
241 inline static uint8_t address_type = 0;
244 inline static bool ready =
false;
247 inline static bool _initialized =
false;
250 static void init_gatt_server();
254 static void onReset(
int reason);
257 static void onSync();
261 static void host_task(
void *param);
265struct BLEReadCallback
267 virtual int onRead(os_mbuf *buffer) {
return 0; };
271struct BLEWriteCallback
273 virtual int onWrite(
void *data, uint16_t data_size) {
return 0; };
284 bool is_descriptor =
false>
288 static constexpr bool can_read =
289 ::std::is_base_of<BLEReadCallback, T>::value;
291 static constexpr bool can_write =
292 ::std::is_base_of<BLEWriteCallback, T>::value;
295 can_read || can_write,
296 "BLE: Accessor does not read or write");
307 static int access_fn(
308 uint16_t conn_handle,
309 uint16_t attr_handle,
310 ble_gatt_access_ctxt *ctxt,
315 "BLEAccessor::access_fn(%d,%d,...), op=%d",
319 if constexpr (can_read)
321 if constexpr (is_descriptor)
323 if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC)
324 return static_cast<T *
>(arg)->onRead(ctxt->om);
328 if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR)
329 return static_cast<T *
>(arg)->onRead(ctxt->om);
331 log_e(
"Unexpected READ operation on attr_handle %d", attr_handle);
333 if constexpr (can_write)
336 if constexpr (is_descriptor)
338 if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC)
339 return static_cast<T *
>(arg)->onWrite(ctxt->om);
343 if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
344 return static_cast<T *
>(arg)->onWrite(
348 log_e(
"Unexpected WRITE operation on attr_handle %d", attr_handle);
350 return BLE_ATT_ERR_UNLIKELY;
355enum class HIDReportType : uint8_t
363struct BLEDesc2908 : BLEReadCallback
367 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2908);
374 ble_gatt_dsc_def definition();
383 void set(uint8_t report_id, HIDReportType report_type);
385 virtual int onRead(os_mbuf *buffer)
override;
392 uint8_t report_id() {
return _report_id; }
399 HIDReportType report_type() {
return _report_type; }
403 HIDReportType _report_type = HIDReportType::feature;
404 uint8_t _report_id = 0;
408struct BLECharacteristic
410 static constexpr const uint16_t INVALID_HANDLE = 0xFFFF;
418 virtual ble_gatt_chr_def definition() = 0;
435 void setSubscription_if(uint16_t requested_attr_handle,
bool status);
439 bool subscribed =
false;
446 uint16_t attr_handle = INVALID_HANDLE;
450struct BatteryLevelChr : BLECharacteristic, BLEReadCallback
453 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A19);
455 virtual int onRead(os_mbuf *buffer)
override;
456 virtual ble_gatt_chr_def definition()
override;
463 void set(uint8_t new_value);
470 uint8_t get() const noexcept {
return value; }
473 inline static ble_gatt_cpfd _chr_cpfd_def[]{
479 .description = 0x106,
484 ble_gatt_dsc_def dsc_def[2]{};
488struct BatteryStatusChr : BLECharacteristic, BLEReadCallback
491 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2BED);
493 virtual int onRead(os_mbuf *buffer)
override;
494 virtual ble_gatt_chr_def definition()
override;
512struct BLEBatteryService
515 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x180F);
518 inline static BatteryLevelChr batteryLevel{};
520 inline static BatteryStatusChr batteryStatus{};
528 static const ble_gatt_svc_def definition();
541 static void onSubscriptionChange(
542 uint16_t attr_handle,
545 batteryLevel.setSubscription_if(attr_handle, yesOrNo);
546 batteryStatus.setSubscription_if(attr_handle, yesOrNo);
550 inline static ble_gatt_chr_def chr_set[3]{};
554struct PnpInfoChr : BLECharacteristic, BLEReadCallback
557 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A50);
564 virtual int onRead(os_mbuf *buffer)
override;
565 virtual ble_gatt_chr_def definition()
override;
569struct SerialNumberChr : BLECharacteristic, BLEReadCallback
572 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A25);
574 virtual int onRead(os_mbuf *buffer)
override;
575 virtual ble_gatt_chr_def definition()
override;
579struct ManufacturerChr : BLECharacteristic, BLEReadCallback
582 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A29);
584 ::std::string name{};
586 virtual int onRead(os_mbuf *buffer)
override;
587 virtual ble_gatt_chr_def definition()
override;
594struct BLEDeviceInfoService
597 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x180A);
600 inline static PnpInfoChr pnpInfo;
603 inline static SerialNumberChr serialNumber;
606 inline static ManufacturerChr manufacturer;
609 static const ble_gatt_svc_def definition();
615 inline static ble_gatt_chr_def chr_set[4]{};
619struct HIDReportChr : BLECharacteristic
621 friend class BLEHIDService;
624 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A4D);
627 BLEDesc2908 desc2908;
628 ble_gatt_dsc_def desc_def[2]{};
629 size_t report_size = 0;
633struct FeatureReportChr : HIDReportChr
635 FeatureReportChr(uint8_t report_id,
size_t size)
noexcept;
636 FeatureReportChr(
const FeatureReportChr &)
noexcept =
default;
637 FeatureReportChr(FeatureReportChr &&) noexcept = default;
638 FeatureReportChr &operator=(const FeatureReportChr &) noexcept = default;
639 FeatureReportChr &operator=(FeatureReportChr &&) noexcept = default;
641 virtual ble_gatt_chr_def definition() override;
645struct OutputReportChr : HIDReportChr
647 OutputReportChr(uint8_t report_id,
size_t size)
noexcept;
648 OutputReportChr(
const OutputReportChr &)
noexcept =
default;
649 OutputReportChr(OutputReportChr &&) noexcept = default;
650 OutputReportChr &operator=(const OutputReportChr &) noexcept = default;
651 OutputReportChr &operator=(OutputReportChr &&) noexcept = default;
653 virtual ble_gatt_chr_def definition() override;
657struct InputReportChr : HIDReportChr
659 InputReportChr(uint8_t report_id,
size_t size)
noexcept;
660 InputReportChr(
const InputReportChr &)
noexcept =
default;
661 InputReportChr(InputReportChr &&) noexcept = default;
662 InputReportChr &operator=(const InputReportChr &) noexcept = default;
663 InputReportChr &operator=(InputReportChr &&) noexcept = default;
664 virtual ble_gatt_chr_def definition() override;
668struct HIDInfoChr : BLECharacteristic, BLEReadCallback
671 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A4A);
673 virtual int onRead(os_mbuf *buffer)
override;
674 virtual ble_gatt_chr_def definition()
override;
679struct HIDControlChr : BLECharacteristic, BLEWriteCallback
682 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A4C);
684 virtual ble_gatt_chr_def definition()
override;
688struct HIDReportMapChr : BLECharacteristic, BLEReadCallback
691 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A4B);
693 virtual int onRead(os_mbuf *buffer)
override;
694 virtual ble_gatt_chr_def definition()
override;
703struct HIDProtocolModeChr : BLECharacteristic, BLEReadCallback, BLEWriteCallback
706 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x2A4E);
708 virtual int onRead(os_mbuf *buffer)
override;
709 virtual int onWrite(
void *data, uint16_t data_size)
override;
710 virtual ble_gatt_chr_def definition()
override;
714 uint8_t value = 0x01;
723 friend class FeatureReportChr;
724 friend class OutputReportChr;
725 friend class InputReportChr;
728 inline static const ble_uuid16_t uuid = BLE_UUID16_INIT(0x1812);
731 using OnGetFeatureCallback =
734 ::std::function<uint16_t(uint8_t, uint8_t *, uint16_t)>;
736 using OnSetFeatureCallback =
738 ::std::function<void(uint8_t,
const uint8_t *, uint16_t)>;
740 using OnOutputCallback = OnSetFeatureCallback;
742 using OnInputCallback = OnGetFeatureCallback;
745 inline static OnGetFeatureCallback onGetFeatureReport =
nullptr;
747 inline static OnSetFeatureCallback onSetFeatureReport =
nullptr;
749 inline static OnOutputCallback onWriteOutputReport =
nullptr;
751 inline static OnInputCallback onReadInputReport =
nullptr;
754 inline static HIDInfoChr info;
756 inline static HIDControlChr control;
758 inline static HIDReportMapChr report_map;
760 inline static HIDProtocolModeChr protocol_mode;
762 inline static InputReportChr input_report{
765 inline static FeatureReportChr capabilities_report{
768 inline static FeatureReportChr config_report{
771 inline static FeatureReportChr button_map_report{
774 inline static FeatureReportChr hardware_id_report{
777 inline static OutputReportChr powertrain_report{
780 inline static OutputReportChr ecu_report{
783 inline static OutputReportChr race_control_report{
786 inline static OutputReportChr gauges_report{
789 inline static OutputReportChr pixel_report{
798 static const ble_gatt_svc_def definition();
811 static void onSubscriptionChange(
812 uint16_t attr_handle,
815 input_report.setSubscription_if(attr_handle, yesOrNo);
819 inline static ble_gatt_chr_def chr_set[4 + HID_REPORT_COUNT + 1]{};
820 static int report_access_fn(
821 uint16_t conn_handle,
822 uint16_t attr_handle,
823 ble_gatt_access_ctxt *ctxt,
Key definitions of the sim wheel as a HID device. Independent from transport layer.
#define RID_OUTPUT_GAUGES
Gauges report ID.
#define RACE_CONTROL_REPORT_SIZE
Race control report size.
#define RID_FEATURE_CONFIG
Configuration report ID.
#define GAMEPAD_REPORT_SIZE
Input report size.
#define RID_OUTPUT_POWERTRAIN
Powertrain telemetry report ID.
#define BUTTONS_MAP_REPORT_SIZE
Input map report size.
#define PIXEL_REPORT_SIZE
Pixel control report size.
#define ECU_REPORT_SIZE
ECU telemetry report size.
#define RID_OUTPUT_RACE_CONTROL
Race control report ID.
#define RID_INPUT_GAMEPAD
Input report ID.
#define BLE_VENDOR_ID
Default BLE vendor ID.
#define HARDWARE_ID_REPORT_SIZE
Custom VID/PID report size.
#define CONFIG_REPORT_SIZE
Configuration report size.
#define POWERTRAIN_REPORT_SIZE
Powertrain telemetry report size.
#define RID_FEATURE_BUTTONS_MAP
Input map report ID.
#define RID_FEATURE_HARDWARE_ID
Custom VID/PID report ID.
#define BLE_PRODUCT_ID
Default BLE product ID.
#define GAUGES_REPORT_SIZE
Gauges report size.
#define RID_OUTPUT_ECU
ECU telemetry report ID.
#define CAPABILITIES_REPORT_SIZE
Capabilities report size.
#define RID_FEATURE_CAPABILITIES
Capabilities report ID.
#define RID_OUTPUT_PIXEL
Pixel control report ID.
System functionality not exposed to the end user.
void onReset(uint8_t *report)
Resets data for the input report.
Data format for the Battery Level Status characteristic (packed)