HID-RP

The hid-rp component provides a wrapper around https://github.com/intergatedcircuits/hid-rp and also provides an example implementation of a configurable HID Gamepad using hid-rp.

It also implements Playstation DualSense, Playstation DualShock 4, Nintendo Switch Pro, and Xbox gamepad reports.

API Reference

Header File

Header File

Unions

espp::gamepad::Accelerometer.__unnamed9__

Public Members

struct espp::gamepad::Accelerometer
std::int16_t raw[3]
espp::gamepad::Gyroscope.__unnamed13__

Public Members

struct espp::gamepad::Gyroscope
struct espp::gamepad::Gyroscope
std::int16_t raw[3]

Header File

Header File

Classes

template<size_t BUTTON_COUNT = 15, typename JOYSTICK_TYPE = std::uint16_t, typename TRIGGER_TYPE = std::uint16_t, JOYSTICK_TYPE JOYSTICK_MIN = 0, JOYSTICK_TYPE JOYSTICK_MAX = 65535, TRIGGER_TYPE TRIGGER_MIN = 0, TRIGGER_TYPE TRIGGER_MAX = 1023, uint8_t REPORT_ID = 1>
class GamepadInputReport : public hid::report::base<hid::report::type::INPUT, 1>

HID Gamepad Input Report This class implements a HID Gamepad with a configurable number of buttons, a hat switch, 4 joystick axes and two trigger axes. It supports setting the buttons, hat switch, joysticks, and triggers, as well as serializing the input report and getting the report descriptor.

HID-RP Gamepad Example

  static constexpr uint8_t input_report_id = 1;
  static constexpr uint8_t battery_report_id = 4;
  static constexpr size_t num_buttons = 15;
  static constexpr int joystick_min = 0;
  static constexpr int joystick_max = 65535;
  static constexpr int trigger_min = 0;
  static constexpr int trigger_max = 1023;

  using GamepadInput =
      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
                               joystick_max, trigger_min, trigger_max, input_report_id>;
  GamepadInput gamepad_input_report;

  using XboxInput = espp::XboxGamepadInputReport<input_report_id>;
  XboxInput xbox_input_report;

  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
  BatteryReport battery_input_report;

  static constexpr uint8_t led_output_report_id = 2;
  static constexpr size_t num_leds = 4;
  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, led_output_report_id>;
  GamepadLeds gamepad_leds_report;

  static constexpr uint8_t rumble_output_report_id = 3;
  using RumbleReport = espp::XboxRumbleOutputReport<rumble_output_report_id>;
  RumbleReport rumble_output_report;

  using namespace hid::page;
  using namespace hid::rdf;
  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
                                   collection::application(gamepad_input_report.get_descriptor(),
                                                           rumble_output_report.get_descriptor(),
                                                           battery_input_report.get_descriptor(),
                                                           gamepad_leds_report.get_descriptor()));

  // Generate the report descriptor for the gamepad
  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());

  logger.info("Report Descriptor:");
  logger.info("  Size: {}", descriptor.size());
  logger.info("  Data: {::#04X}", descriptor);

  using SwitchProInput = espp::SwitchProGamepadInputReport<>;
  SwitchProInput switch_pro_input_report;
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
  logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());

  auto sp_raw_descriptor = espp::switch_pro_descriptor();
  auto sp_descriptor = std::vector<uint8_t>(sp_raw_descriptor.begin(), sp_raw_descriptor.end());

  logger.info("Switch Report Descriptor:");
  logger.info("  Size: {}", sp_descriptor.size());
  std::string str = "";
  for (auto &byte : sp_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
  PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
  using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
  PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
  logger.info("Playstation Dualsense BLE Report Descriptor:");
  auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
  auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
  logger.info("  Size: {}", ps_descriptor.size());
  str = "";
  for (auto &byte : ps_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PS4DualShock4Input = espp::PS4DualShock4GamepadInputReport<>;
  PS4DualShock4Input ps4_input_report;
  logger.info("{}", ps4_input_report);
  logger.info("PS4 DualShock 4 Input Report Size: {}", ps4_input_report.get_report().size());
  logger.info("PS4 DualShock 4 Input Report Data: {::#04X}", ps4_input_report.get_report());

  auto ps4_raw_descriptor = espp::ps4_dualshock4_descriptor();
  auto ps4_descriptor = std::vector<uint8_t>(ps4_raw_descriptor.begin(), ps4_raw_descriptor.end());

  logger.info("PS4 DualShock 4 Report Descriptor:");
  logger.info("  Size: {}", ps4_descriptor.size());
  str = "";
  for (auto &byte : ps4_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
  int button_index = 5;
  float angle = 2.0f * M_PI * button_index / num_buttons;

  // reset all reports
  gamepad_input_report.reset();
  xbox_input_report.reset();
  switch_pro_input_report.reset();
  dualsense_simple_input_report.reset();
  dualsense_complex_input_report.reset();
  ps4_input_report.reset();

  // print out the reports in their default states
  logger.info("{}", gamepad_input_report);
  logger.info("{}", xbox_input_report);
  logger.info("{}", switch_pro_input_report);
  logger.info("{}", dualsense_simple_input_report);
  logger.info("{}", dualsense_complex_input_report);
  logger.info("{}", ps4_input_report);

  // update the gamepad input report
  logger.info("{}", gamepad_input_report);
  gamepad_input_report.set_hat(hat);
  gamepad_input_report.set_button(button_index, true);
  // joystick inputs are in the range [-1, 1] float
  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
  // trigger inputs are in the range [0, 1] float
  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
  gamepad_input_report.set_brake(std::abs(cos(angle)));

  switch_pro_input_report.set_button(button_index, true);
  switch_pro_input_report.set_dpad(false, true, false, true); // down-right
  switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
  switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
  switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
  switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));

  dualsense_simple_input_report.set_button(button_index, true);
  dualsense_simple_input_report.set_hat(hat);
  dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));

  dualsense_complex_input_report.set_button(button_index, true);
  dualsense_complex_input_report.set_hat(hat);
  dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));

  ps4_input_report.set_hat(hat);
  ps4_input_report.set_button_cross(button_index == 1);
  ps4_input_report.set_button_circle(button_index == 2);
  ps4_input_report.set_button_square(button_index == 3);
  ps4_input_report.set_button_triangle(button_index == 4);
  ps4_input_report.set_left_joystick(128 + 127 * sin(angle), 128 + 127 * cos(angle));
  ps4_input_report.set_right_joystick(128 + 127 * cos(angle), 128 + 127 * sin(angle));
  ps4_input_report.set_l2_trigger(std::abs(cos(angle)) * 255);
  ps4_input_report.set_r2_trigger(std::abs(sin(angle)) * 255);
  ps4_input_report.set_battery_level(8);

  button_index = (button_index % num_buttons) + 1;

  // send an input report
  auto report = gamepad_input_report.get_report();
  logger.info("{}", gamepad_input_report);
  logger.info("Gamepad Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = switch_pro_input_report.get_report();
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_simple_input_report.get_report();
  logger.info("{}", dualsense_simple_input_report);
  logger.info("Playstation Dualsense BLE Simple Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_complex_input_report.get_report();
  logger.info("{}", dualsense_complex_input_report);
  logger.info("Playstation Dualsense BLE Complex Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  // update the battery input report
  battery_input_report.reset();
  battery_input_report.set_rechargeable(true);
  battery_input_report.set_charging(false);
  battery_input_report.set_rechargeable(true);
  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
  battery_input_report.set_battery_level(50);

  // send a battery report
  report = battery_input_report.get_report();
  logger.info("Battery report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

Subclassed by espp::XboxGamepadInputReport< REPORT_ID >

Public Functions

constexpr GamepadInputReport() = default

Construct a new Gamepad Input Report object.

inline constexpr void reset()

Reset the gamepad inputs.

inline constexpr void get_left_joystick(float &lx, float &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value, in the range [-1, 1]

  • ly[out] left joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_joystick(JOYSTICK_TYPE &lx, JOYSTICK_TYPE &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value

  • ly[out] left joystick y axis value

inline constexpr void get_right_joystick(float &rx, float &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value, in the range [-1, 1]

  • ry[out] right joystick y axis value, in the range [-1, 1]

inline constexpr void get_right_joystick(JOYSTICK_TYPE &rx, JOYSTICK_TYPE &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value

  • ry[out] right joystick y axis value

inline constexpr void set_left_joystick(float lx, float ly)

Set the left joystick X and Y axis values

Parameters:
  • lx – left joystick x axis value, in the range [-1, 1]

  • ly – left joystick y axis value, in the range [-1, 1]

inline constexpr void set_right_joystick(float rx, float ry)

Set the right joystick X and Y axis values

Parameters:
  • rx – right joystick x axis value, in the range [-1, 1]

  • ry – right joystick y axis value, in the range [-1, 1]

inline constexpr void get_brake(float &value) const

Get the brake trigger value

Parameters:

value – brake trigger value, in the range [0, 1]

inline constexpr void get_brake(TRIGGER_TYPE &value) const

Get the brake trigger value

Parameters:

value – brake trigger value

inline constexpr void get_left_trigger(float &value) const

Get the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void set_brake(float value)

Set the brake trigger value

Parameters:

value – brake trigger value, in the range [0, 1]

inline constexpr void set_left_trigger(float value)

Set the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void get_accelerator(float &value) const

Get the accelerator trigger value

Parameters:

value – accelerator trigger value, in the range [0, 1]

inline constexpr void get_accelerator(TRIGGER_TYPE &value) const

Get the accelerator trigger value

Parameters:

value – accelerator trigger value

inline constexpr void get_right_trigger(float &value) const

Get the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_accelerator(float value)

Set the accelerator trigger value

Parameters:

value – accelerator trigger value, in the range [0, 1]

inline constexpr void set_right_trigger(float value)

Set the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_hat(Hat hat)

Set the hat switch (d-pad) value

Parameters:

hat – Hat enum / direction to set

inline constexpr void set_hat(bool up, bool down, bool left, bool right)

Set the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr Hat get_hat() const

Get the hat switch (d-pad) value

Returns:

Hat enum / direction

inline constexpr void get_hat(bool &up, bool &down, bool &left, bool &right) const

Get the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr void set_button(int button_index, bool value)

Set the button value

Parameters:
  • button_index – The button for which you want to set the value. Should be between 1 and BUTTON_COUNT, inclusive.

  • value – The true/false value you want to se the button to.

inline constexpr void set_joystick_axis(size_t index, JOYSTICK_TYPE value)

Set the joystick axis value

Note

The value should be in the range [joystick_min, joystick_max].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void set_joystick_axis(size_t index, float value)

Set the joystick axis value

Note

The value should be in the range [-1, 1].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void set_trigger_axis(size_t index, TRIGGER_TYPE value)

Set the trigger axis value

Note

The value should be in the range [trigger_min, trigger_max].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr void set_trigger_axis(size_t index, float value)

Set the trigger axis value

Note

The value should be in the range [0, 1].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr bool get_button(int button_index) const

Get the button value

Parameters:

button_index – The button for which you want to get the value.

Returns:

The true/false value of the button.

inline constexpr void set_hat_switch(Hat hat)

Set the hat switch value

Parameters:

hat – The hat switch value to set.

inline constexpr void set_hat_switch(std::uint8_t value)

Set the hat switch value

Note

The value should match the values within the Hat enum.

Parameters:

value – The hat switch value to set.

inline constexpr bool get_consumer_record() const

Get the consumer record button value

Returns:

The consumer record button value.

inline constexpr void set_consumer_record(bool value)

Set the consumer record button value

Parameters:

value – The true/false value you want to se the consumer record button to.

inline constexpr auto get_report() const

Get the input report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The input report as a vector of bytes.

inline constexpr void set_data(const std::vector<uint8_t> &data)

Set the output report data from a vector of bytes

Parameters:

data – The data to set the output report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
using namespace hid::rdf;
auto gamepad_descriptor = gamepad_input_report.get_descriptor();
auto rdf_descriptor = descriptor(
    usage_page<generic_desktop>(),
    usage(generic_desktop::GAMEPAD),
    collection::application(
        gamepad_descriptor
    )
);
auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());

Returns:

The report descriptor as a hid::rdf::descriptor.

template<size_t LED_COUNT = 4, uint8_t REPORT_ID = 2>
class GamepadLedOutputReport : public hid::report::base<hid::report::type::OUTPUT, 2>

HID Gamepad LED Output Report This class implements a HID Gamepad with a configurable number of LEDs. It supports setting the LEDs, as well as serializing the output report and getting the report descriptor.

Public Functions

inline constexpr void set_led(int led_index, bool value)

Set the LED value

Parameters:
  • led_index – The LED for which you want to set the value. Should be between 1 and LED_COUNT, inclusive.

  • value – The true/false value you want to se the LED to.

inline constexpr auto get_min_led()

Get the minimum led usage

Returns:

The minimum led usage

inline constexpr auto get_max_led()

Get the maximum led usage

Returns:

The maximum led usage

inline constexpr bool get_led(hid::page::leds led)

Get the LED value

Parameters:

led – The LED for which you want to get the value.

Returns:

The true/false value of the LED.

inline constexpr bool get_led(int led_index)

Get the LED value

Parameters:

led_index – The LED for which you want to get the value. Should be between 1 and LED_COUNT, inclusive.

Returns:

The true/false value of the LED.

inline constexpr auto get_report()

Get the output report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The output report as a vector of bytes.

inline constexpr void set_data(const std::vector<uint8_t> &data)

Set the output report data from a vector of bytes

Parameters:

data – The data to set the output report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
using namespace hid::rdf;
auto led_descriptor = gamepad_led_report.get_descriptor();
auto rdf_descriptor = descriptor(
    usage_page<generic_desktop>(),
    usage(generic_desktop::GAMEPAD),
    collection::application(
        led_descriptor
    )
);
auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());

Returns:

The report descriptor as a hid::rdf::descriptor.

Header File

Unions

union PlaystationDualsenseGamepadButtons
#include <hid-rp-playstation.hpp>

Playstation DualSense Gamepad Buttons Used in input reports (0x01, 0x31) when used over BLE.

Public Members

std::array<std::uint8_t, 3> raw

Buttons as bytes.

struct espp::PlaystationDualsenseGamepadButtons
union PlaystationDualsenseVendorDefinedData
#include <hid-rp-playstation.hpp>

Playstation DualSense Vendor Defined Data. Used for IMU, touchpad, battery, etc. in input report 0x31 (49) over Bluetooth.

Public Types

using Accelerometer = espp::gamepad::Accelerometer

Accelerometer type.

using Gyroscope = espp::gamepad::Gyroscope

Gyroscope type.

Public Members

std::array<std::uint8_t, 65> raw

Vendor defined data.

struct espp::PlaystationDualsenseVendorDefinedData
espp::PlaystationTouchpadData.__unnamed21__

Public Members

std::uint8_t raw[9]

Raw data array.

struct espp::PlaystationTouchpadData
espp::PlaystationDualsenseVendorDefinedData.__unnamed27__.__unnamed29__

Public Members

std::array<std::int16_t, 6> imu

IMU data as array.

struct espp::PlaystationDualsenseVendorDefinedData
espp::PlaystationDualsenseVendorDefinedData.__unnamed27__.__unnamed31__

Public Members

std::array<std::uint8_t, 2> battery_raw
struct espp::PlaystationDualsenseVendorDefinedData

Classes

template<uint8_t REPORT_ID = 1>
class PlaystationDualsenseBLESimpleInputReport : public hid::report::base<hid::report::type::INPUT, 1>

HID Playstation DualSense Bluetooth Gamepad Input Report

This class implements a HID Playstation DualSense Bluetooth Gamepad Report. It supports 14 buttons, a d-pad, 4 joystick axes, and 2 trigger axes.

This is the simple report which is used by default when connecting the controller over bluetooth and matches report ID 0x01.

HID-RP Playstation Gamepad Example

  static constexpr uint8_t input_report_id = 1;
  static constexpr uint8_t battery_report_id = 4;
  static constexpr size_t num_buttons = 15;
  static constexpr int joystick_min = 0;
  static constexpr int joystick_max = 65535;
  static constexpr int trigger_min = 0;
  static constexpr int trigger_max = 1023;

  using GamepadInput =
      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
                               joystick_max, trigger_min, trigger_max, input_report_id>;
  GamepadInput gamepad_input_report;

  using XboxInput = espp::XboxGamepadInputReport<input_report_id>;
  XboxInput xbox_input_report;

  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
  BatteryReport battery_input_report;

  static constexpr uint8_t led_output_report_id = 2;
  static constexpr size_t num_leds = 4;
  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, led_output_report_id>;
  GamepadLeds gamepad_leds_report;

  static constexpr uint8_t rumble_output_report_id = 3;
  using RumbleReport = espp::XboxRumbleOutputReport<rumble_output_report_id>;
  RumbleReport rumble_output_report;

  using namespace hid::page;
  using namespace hid::rdf;
  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
                                   collection::application(gamepad_input_report.get_descriptor(),
                                                           rumble_output_report.get_descriptor(),
                                                           battery_input_report.get_descriptor(),
                                                           gamepad_leds_report.get_descriptor()));

  // Generate the report descriptor for the gamepad
  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());

  logger.info("Report Descriptor:");
  logger.info("  Size: {}", descriptor.size());
  logger.info("  Data: {::#04X}", descriptor);

  using SwitchProInput = espp::SwitchProGamepadInputReport<>;
  SwitchProInput switch_pro_input_report;
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
  logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());

  auto sp_raw_descriptor = espp::switch_pro_descriptor();
  auto sp_descriptor = std::vector<uint8_t>(sp_raw_descriptor.begin(), sp_raw_descriptor.end());

  logger.info("Switch Report Descriptor:");
  logger.info("  Size: {}", sp_descriptor.size());
  std::string str = "";
  for (auto &byte : sp_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
  PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
  using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
  PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
  logger.info("Playstation Dualsense BLE Report Descriptor:");
  auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
  auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
  logger.info("  Size: {}", ps_descriptor.size());
  str = "";
  for (auto &byte : ps_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PS4DualShock4Input = espp::PS4DualShock4GamepadInputReport<>;
  PS4DualShock4Input ps4_input_report;
  logger.info("{}", ps4_input_report);
  logger.info("PS4 DualShock 4 Input Report Size: {}", ps4_input_report.get_report().size());
  logger.info("PS4 DualShock 4 Input Report Data: {::#04X}", ps4_input_report.get_report());

  auto ps4_raw_descriptor = espp::ps4_dualshock4_descriptor();
  auto ps4_descriptor = std::vector<uint8_t>(ps4_raw_descriptor.begin(), ps4_raw_descriptor.end());

  logger.info("PS4 DualShock 4 Report Descriptor:");
  logger.info("  Size: {}", ps4_descriptor.size());
  str = "";
  for (auto &byte : ps4_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
  int button_index = 5;
  float angle = 2.0f * M_PI * button_index / num_buttons;

  // reset all reports
  gamepad_input_report.reset();
  xbox_input_report.reset();
  switch_pro_input_report.reset();
  dualsense_simple_input_report.reset();
  dualsense_complex_input_report.reset();
  ps4_input_report.reset();

  // print out the reports in their default states
  logger.info("{}", gamepad_input_report);
  logger.info("{}", xbox_input_report);
  logger.info("{}", switch_pro_input_report);
  logger.info("{}", dualsense_simple_input_report);
  logger.info("{}", dualsense_complex_input_report);
  logger.info("{}", ps4_input_report);

  // update the gamepad input report
  logger.info("{}", gamepad_input_report);
  gamepad_input_report.set_hat(hat);
  gamepad_input_report.set_button(button_index, true);
  // joystick inputs are in the range [-1, 1] float
  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
  // trigger inputs are in the range [0, 1] float
  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
  gamepad_input_report.set_brake(std::abs(cos(angle)));

  switch_pro_input_report.set_button(button_index, true);
  switch_pro_input_report.set_dpad(false, true, false, true); // down-right
  switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
  switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
  switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
  switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));

  dualsense_simple_input_report.set_button(button_index, true);
  dualsense_simple_input_report.set_hat(hat);
  dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));

  dualsense_complex_input_report.set_button(button_index, true);
  dualsense_complex_input_report.set_hat(hat);
  dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));

  ps4_input_report.set_hat(hat);
  ps4_input_report.set_button_cross(button_index == 1);
  ps4_input_report.set_button_circle(button_index == 2);
  ps4_input_report.set_button_square(button_index == 3);
  ps4_input_report.set_button_triangle(button_index == 4);
  ps4_input_report.set_left_joystick(128 + 127 * sin(angle), 128 + 127 * cos(angle));
  ps4_input_report.set_right_joystick(128 + 127 * cos(angle), 128 + 127 * sin(angle));
  ps4_input_report.set_l2_trigger(std::abs(cos(angle)) * 255);
  ps4_input_report.set_r2_trigger(std::abs(sin(angle)) * 255);
  ps4_input_report.set_battery_level(8);

  button_index = (button_index % num_buttons) + 1;

  // send an input report
  auto report = gamepad_input_report.get_report();
  logger.info("{}", gamepad_input_report);
  logger.info("Gamepad Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = switch_pro_input_report.get_report();
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_simple_input_report.get_report();
  logger.info("{}", dualsense_simple_input_report);
  logger.info("Playstation Dualsense BLE Simple Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_complex_input_report.get_report();
  logger.info("{}", dualsense_complex_input_report);
  logger.info("Playstation Dualsense BLE Complex Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  // update the battery input report
  battery_input_report.reset();
  battery_input_report.set_rechargeable(true);
  battery_input_report.set_charging(false);
  battery_input_report.set_rechargeable(true);
  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
  battery_input_report.set_battery_level(50);

  // send a battery report
  report = battery_input_report.get_report();
  logger.info("Battery report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

Note

I have tested the playstation dualsense report descriptor and input reports over BLE with iOS, MacOS, Windows, and Android and found that:

  • iOS, MacOS, and Windows only parse the complex report (0x31) and ignore the simple report (0x01). This means that the simple report is effectively unused fields in the report descriptor.

  • Android seems to require Audio support, which it cannot find over BLE, so it does not work at all.

Public Types

using Hat = PlaystationHat

The type used for the hat switch.

using JOYSTICK_TYPE = std::uint8_t

The type used for the joystick axes.

using TRIGGER_TYPE = std::uint8_t

The type used for the trigger axes.

Public Functions

constexpr PlaystationDualsenseBLESimpleInputReport() = default

Construct a new PlaystationPDualSenseBLE Gamepad Input Report object.

inline constexpr void reset()

Reset the gamepad inputs.

template<PlaystationDualsenseButtonStruct T>
inline constexpr void set_buttons(const T &buttons)

Set the buttons

Parameters:

buttons – The struct containing the button values

template<PlaystationDualsenseButtonStruct T>
inline constexpr void get_buttons(T &t) const

Get the button values

Parameters:

t – The struct to fill with the button values

inline constexpr void get_left_joystick(float &lx, float &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value, in the range [-1, 1]

  • ly[out] left joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_joystick(JOYSTICK_TYPE &lx, JOYSTICK_TYPE &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value

  • ly[out] left joystick y axis value

inline constexpr void get_right_joystick(float &rx, float &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value, in the range [-1, 1]

  • ry[out] right joystick y axis value, in the range [-1, 1]

inline constexpr void get_right_joystick(JOYSTICK_TYPE &rx, JOYSTICK_TYPE &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value

  • ry[out] right joystick y axis value

inline constexpr void set_left_joystick(float lx, float ly)

Set the left joystick X and Y axis values

Parameters:
  • lx – left joystick x axis value, in the range [-1, 1]

  • ly – left joystick y axis value, in the range [-1, 1]

inline constexpr void set_right_joystick(float rx, float ry)

Set the right joystick X and Y axis values

Parameters:
  • rx – right joystick x axis value, in the range [-1, 1]

  • ry – right joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_trigger(float &value) const

Get the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void set_left_trigger(float value)

Set the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void get_right_trigger(float &value) const

Get the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_right_trigger(float value)

Set the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_joystick_axis(size_t index, JOYSTICK_TYPE value)

Set the joystick axis value

Note

The value should be in the range [joystick_min, joystick_max].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void set_joystick_axis(size_t index, float value)

Set the joystick axis value

Note

The value should be in the range [-1, 1].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void get_joystick_axis(size_t index, float &value) const

Get the joystick axis value

Parameters:
  • index – The index of the joystick axis to get. Should be between 0 and 3, inclusive.

  • value – The variable to store the joystick axis value in.

inline constexpr void get_joystick_axis(size_t index, JOYSTICK_TYPE &value) const

Get the joystick axis value

Parameters:
  • index – The index of the joystick axis to get. Should be between 0 and 3, inclusive.

  • value – The variable to store the joystick axis value in.

inline constexpr void set_trigger_axis(size_t index, TRIGGER_TYPE value)

Set the trigger axis value

Note

The value should be in the range [trigger_min, trigger_max].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr void set_trigger_axis(size_t index, float value)

Set the trigger axis value

Note

The value should be in the range [0, 1].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr void get_trigger_axis(size_t index, float &value) const

Get the trigger axis value

Parameters:
  • index – The index of the trigger axis to get. Should be between 0 and 1, inclusive.

  • value – The variable to store the trigger axis value in.

inline constexpr void get_trigger_axis(size_t index, TRIGGER_TYPE &value) const

Get the trigger axis value

Parameters:
  • index – The index of the trigger axis to get. Should be between 0 and 1, inclusive.

  • value – The variable to store the trigger axis value in.

inline constexpr bool get_button(int button_index) const

Get the button value

Parameters:

button_index – The button for which you want to get the value.

Returns:

The true/false value of the button.

inline constexpr void set_button(int button_index, bool value)

Set the button value

Parameters:
  • button_index – The button for which you want to set the value. Should be between 1 and 14, inclusive.

  • value – The true/false value you want to se the button to.

inline constexpr void set_hat_switch(espp::gamepad::Hat hat)

Set the hat switch value from espp::gamepad::Hat

Parameters:

hat – The espp::gamepad::Hat value to set.

inline constexpr void set_hat_switch(Hat hat)

Set the hat switch value

Parameters:

hat – The hat switch value to set.

inline constexpr void set_hat_switch(std::uint8_t value)

Set the hat switch value

Note

The value should match the values within the Hat enum.

Parameters:

value – The hat switch value to set.

inline constexpr void set_hat(espp::gamepad::Hat hat)

Set the hat switch (d-pad) value

Parameters:

hat – Hat enum / direction to set

inline constexpr void set_hat(Hat hat)

Set the hat switch (d-pad) value

Parameters:

hat – Hat enum / direction to set

inline constexpr void set_hat(bool up, bool down, bool left, bool right)

Set the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr Hat get_hat() const

Get the hat switch (d-pad) value

Returns:

Hat enum / direction

inline constexpr void get_hat(bool &up, bool &down, bool &left, bool &right) const

Get the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr auto get_report() const

Get the input report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The input report as a vector of bytes.

inline constexpr void set_data(const std::vector<uint8_t> &data)

Set the output report data from a vector of bytes

Parameters:

data – The data to set the output report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
using namespace hid::rdf;
auto gamepad_descriptor = gamepad_input_report.get_descriptor();
auto rdf_descriptor = descriptor(
    usage_page<generic_desktop>(),
    usage(generic_desktop::GAMEPAD),
    collection::application(
        gamepad_descriptor
    )
);
auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());

Returns:

The report descriptor as a hid::rdf::descriptor.

Public Static Attributes

static constexpr size_t button_count = 14

Number of buttons supported.

static constexpr JOYSTICK_TYPE joystick_min = 0

Minimum value for the joystick axes.

static constexpr JOYSTICK_TYPE joystick_max = 255

Maximum value for the joystick axes.

static constexpr JOYSTICK_TYPE joystick_center = (joystick_min + joystick_max) / 2

Center value for the joystick axes.

static constexpr size_t joystick_value_range = joystick_max - joystick_min

Range of values for the joystick axes.

static constexpr JOYSTICK_TYPE joystick_range = joystick_value_range / 2

Half the range of values for the joystick axes.

static constexpr size_t num_joystick_bits = num_bits(joystick_value_range)

Number of bits needed to represent the joystick axes.

static constexpr TRIGGER_TYPE trigger_min = 0

Minimum value for the trigger axes.

static constexpr TRIGGER_TYPE trigger_max = 255

Maximum value for the trigger axes.

static constexpr TRIGGER_TYPE trigger_center = trigger_min

Center value for the trigger axes.

static constexpr size_t trigger_range = trigger_max - trigger_min

Range of values for the trigger axes.

static constexpr size_t num_trigger_bits = num_bits(trigger_range)

Number of bits needed to represent the trigger axes.

static constexpr std::size_t BTN_SQUARE_INDEX = {1}

The index of the SQUARE button.

static constexpr std::size_t BTN_CROSS_INDEX = {2}

The index of the CROSS button.

static constexpr std::size_t BTN_CIRCLE_INDEX = {3}

The index of the CIRCLE button.

static constexpr std::size_t BTN_TRIANGLE_INDEX = {4}

The index of the TRIANGLE button.

static constexpr std::size_t BTN_L1_INDEX = {5}

The index of the L1 button.

static constexpr std::size_t BTN_R1_INDEX = {6}

The index of the R1 button.

static constexpr std::size_t BTN_L2_INDEX = {7}

The index of the L2 button.

static constexpr std::size_t BTN_R2_INDEX = {8}

The index of the R2 button.

static constexpr std::size_t BTN_L3_INDEX = {11}

The index of the L3 button.

static constexpr std::size_t BTN_R3_INDEX = {12}

The index of the R3 button.

static constexpr std::size_t BTN_HOME_INDEX = {13}

The index of the Home button.

static constexpr std::size_t BTN_MENU_INDEX = {10}

The index of the Menu button.

static constexpr std::size_t BTN_OPTIONS_INDEX = {9}

The index of the Options button.

static constexpr std::size_t BTN_CAPTURE_INDEX = {14}

The index of the Capture button.

template<uint8_t REPORT_ID = 49>
class PlaystationDualsenseBLEComplexInputReport : public hid::report::base<hid::report::type::INPUT, 49>

HID Playstation DualSense Bluetooth Gamepad Input Report

This class implements a HID Playstation DualSense Bluetooth Gamepad Report. It supports 15 buttons, a d-pad, 4 joystick axes, and 2 trigger axes. It also includes a timestamp, packet counter, and vendor defined data. The vendor defined data includes IMU data, battery level, touchpad data, and CRC32.

This matches the information found here: https://github.com/nondebug/dualsense which provides a bluetooth VID/PID of 054C:0CE6

HID-RP Playstation Gamepad Example

  static constexpr uint8_t input_report_id = 1;
  static constexpr uint8_t battery_report_id = 4;
  static constexpr size_t num_buttons = 15;
  static constexpr int joystick_min = 0;
  static constexpr int joystick_max = 65535;
  static constexpr int trigger_min = 0;
  static constexpr int trigger_max = 1023;

  using GamepadInput =
      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
                               joystick_max, trigger_min, trigger_max, input_report_id>;
  GamepadInput gamepad_input_report;

  using XboxInput = espp::XboxGamepadInputReport<input_report_id>;
  XboxInput xbox_input_report;

  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
  BatteryReport battery_input_report;

  static constexpr uint8_t led_output_report_id = 2;
  static constexpr size_t num_leds = 4;
  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, led_output_report_id>;
  GamepadLeds gamepad_leds_report;

  static constexpr uint8_t rumble_output_report_id = 3;
  using RumbleReport = espp::XboxRumbleOutputReport<rumble_output_report_id>;
  RumbleReport rumble_output_report;

  using namespace hid::page;
  using namespace hid::rdf;
  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
                                   collection::application(gamepad_input_report.get_descriptor(),
                                                           rumble_output_report.get_descriptor(),
                                                           battery_input_report.get_descriptor(),
                                                           gamepad_leds_report.get_descriptor()));

  // Generate the report descriptor for the gamepad
  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());

  logger.info("Report Descriptor:");
  logger.info("  Size: {}", descriptor.size());
  logger.info("  Data: {::#04X}", descriptor);

  using SwitchProInput = espp::SwitchProGamepadInputReport<>;
  SwitchProInput switch_pro_input_report;
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
  logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());

  auto sp_raw_descriptor = espp::switch_pro_descriptor();
  auto sp_descriptor = std::vector<uint8_t>(sp_raw_descriptor.begin(), sp_raw_descriptor.end());

  logger.info("Switch Report Descriptor:");
  logger.info("  Size: {}", sp_descriptor.size());
  std::string str = "";
  for (auto &byte : sp_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
  PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
  using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
  PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
  logger.info("Playstation Dualsense BLE Report Descriptor:");
  auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
  auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
  logger.info("  Size: {}", ps_descriptor.size());
  str = "";
  for (auto &byte : ps_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PS4DualShock4Input = espp::PS4DualShock4GamepadInputReport<>;
  PS4DualShock4Input ps4_input_report;
  logger.info("{}", ps4_input_report);
  logger.info("PS4 DualShock 4 Input Report Size: {}", ps4_input_report.get_report().size());
  logger.info("PS4 DualShock 4 Input Report Data: {::#04X}", ps4_input_report.get_report());

  auto ps4_raw_descriptor = espp::ps4_dualshock4_descriptor();
  auto ps4_descriptor = std::vector<uint8_t>(ps4_raw_descriptor.begin(), ps4_raw_descriptor.end());

  logger.info("PS4 DualShock 4 Report Descriptor:");
  logger.info("  Size: {}", ps4_descriptor.size());
  str = "";
  for (auto &byte : ps4_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
  int button_index = 5;
  float angle = 2.0f * M_PI * button_index / num_buttons;

  // reset all reports
  gamepad_input_report.reset();
  xbox_input_report.reset();
  switch_pro_input_report.reset();
  dualsense_simple_input_report.reset();
  dualsense_complex_input_report.reset();
  ps4_input_report.reset();

  // print out the reports in their default states
  logger.info("{}", gamepad_input_report);
  logger.info("{}", xbox_input_report);
  logger.info("{}", switch_pro_input_report);
  logger.info("{}", dualsense_simple_input_report);
  logger.info("{}", dualsense_complex_input_report);
  logger.info("{}", ps4_input_report);

  // update the gamepad input report
  logger.info("{}", gamepad_input_report);
  gamepad_input_report.set_hat(hat);
  gamepad_input_report.set_button(button_index, true);
  // joystick inputs are in the range [-1, 1] float
  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
  // trigger inputs are in the range [0, 1] float
  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
  gamepad_input_report.set_brake(std::abs(cos(angle)));

  switch_pro_input_report.set_button(button_index, true);
  switch_pro_input_report.set_dpad(false, true, false, true); // down-right
  switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
  switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
  switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
  switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));

  dualsense_simple_input_report.set_button(button_index, true);
  dualsense_simple_input_report.set_hat(hat);
  dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));

  dualsense_complex_input_report.set_button(button_index, true);
  dualsense_complex_input_report.set_hat(hat);
  dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));

  ps4_input_report.set_hat(hat);
  ps4_input_report.set_button_cross(button_index == 1);
  ps4_input_report.set_button_circle(button_index == 2);
  ps4_input_report.set_button_square(button_index == 3);
  ps4_input_report.set_button_triangle(button_index == 4);
  ps4_input_report.set_left_joystick(128 + 127 * sin(angle), 128 + 127 * cos(angle));
  ps4_input_report.set_right_joystick(128 + 127 * cos(angle), 128 + 127 * sin(angle));
  ps4_input_report.set_l2_trigger(std::abs(cos(angle)) * 255);
  ps4_input_report.set_r2_trigger(std::abs(sin(angle)) * 255);
  ps4_input_report.set_battery_level(8);

  button_index = (button_index % num_buttons) + 1;

  // send an input report
  auto report = gamepad_input_report.get_report();
  logger.info("{}", gamepad_input_report);
  logger.info("Gamepad Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = switch_pro_input_report.get_report();
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_simple_input_report.get_report();
  logger.info("{}", dualsense_simple_input_report);
  logger.info("Playstation Dualsense BLE Simple Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_complex_input_report.get_report();
  logger.info("{}", dualsense_complex_input_report);
  logger.info("Playstation Dualsense BLE Complex Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  // update the battery input report
  battery_input_report.reset();
  battery_input_report.set_rechargeable(true);
  battery_input_report.set_charging(false);
  battery_input_report.set_rechargeable(true);
  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
  battery_input_report.set_battery_level(50);

  // send a battery report
  report = battery_input_report.get_report();
  logger.info("Battery report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

Note

I have tested the playstation dualsense report descriptor and input reports over BLE with iOS, MacOS, Windows, and Android and found that:

  • iOS, MacOS, and Windows only parse the complex report (0x31) and ignore the simple report (0x01). This means that the simple report is effectively unused fields in the report descriptor.

  • Android seems to require Audio support, which it cannot find over BLE, so it does not work at all.

Public Types

using Hat = PlaystationHat

The type used for the hat switch.

using JOYSTICK_TYPE = std::uint8_t

The type used for the joystick axes.

using TRIGGER_TYPE = std::uint8_t

The type used for the trigger axes.

Public Functions

constexpr PlaystationDualsenseBLEComplexInputReport() = default

Construct a new PlaystationPDualSenseBLE Gamepad Input Report object.

inline constexpr void reset()

Reset the gamepad inputs.

inline constexpr void set_counter(uint8_t value)

Set the counter

Parameters:

value – The value to set the counter to.

inline constexpr void increment_counter(uint8_t inc = 1)

Increment the counter.

inline constexpr uint8_t get_counter() const

Get the counter value

Returns:

The counter value

inline constexpr void set_battery_level(uint8_t level, bool charging)

Set the battery level as a percentage (0-100) and if it is charging

Parameters:
  • level – The battery level as a percentage (0-100)

  • charging – True if the battery is charging, false otherwise

inline constexpr void set_battery_level(uint8_t level)

Set the battery level as a percentage (0-100)

Parameters:

level – The battery level as a percentage (0-100)

inline constexpr uint8_t get_battery_level() const

Get the battery level as a percentage (0-100)

Returns:

The battery level as a percentage (0-100)

inline constexpr bool is_battery_charging() const

Check if the battery is charging

Returns:

True if the battery is charging, false otherwise

inline constexpr void set_battery_charging(bool charging)

Set if the battery is charging

Parameters:

charging – True if the battery is charging, false otherwise

template<PlaystationDualsenseButtonStruct T>
inline constexpr void set_buttons(const T &buttons)

Set the buttons

Parameters:

buttons – The struct containing the button values

template<PlaystationDualsenseButtonStruct T>
inline constexpr void get_buttons(T &t) const

Get the button values

Parameters:

t – The struct to fill with the button values

inline constexpr void get_left_joystick(float &lx, float &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value, in the range [-1, 1]

  • ly[out] left joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_joystick(JOYSTICK_TYPE &lx, JOYSTICK_TYPE &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value

  • ly[out] left joystick y axis value

inline constexpr void get_right_joystick(float &rx, float &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value, in the range [-1, 1]

  • ry[out] right joystick y axis value, in the range [-1, 1]

inline constexpr void get_right_joystick(JOYSTICK_TYPE &rx, JOYSTICK_TYPE &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value

  • ry[out] right joystick y axis value

inline constexpr void set_left_joystick(float lx, float ly)

Set the left joystick X and Y axis values

Parameters:
  • lx – left joystick x axis value, in the range [-1, 1]

  • ly – left joystick y axis value, in the range [-1, 1]

inline constexpr void set_right_joystick(float rx, float ry)

Set the right joystick X and Y axis values

Parameters:
  • rx – right joystick x axis value, in the range [-1, 1]

  • ry – right joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_trigger(float &value) const

Get the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void set_left_trigger(float value)

Set the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void get_right_trigger(float &value) const

Get the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_right_trigger(float value)

Set the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_joystick_axis(size_t index, JOYSTICK_TYPE value)

Set the joystick axis value

Note

The value should be in the range [joystick_min, joystick_max].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void set_joystick_axis(size_t index, float value)

Set the joystick axis value

Note

The value should be in the range [-1, 1].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void get_joystick_axis(size_t index, float &value) const

Get the joystick axis value

Parameters:
  • index – The index of the joystick axis to get. Should be between 0 and 3, inclusive.

  • value – The variable to store the joystick axis value in.

inline constexpr void get_joystick_axis(size_t index, JOYSTICK_TYPE &value) const

Get the joystick axis value

Parameters:
  • index – The index of the joystick axis to get. Should be between 0 and 3, inclusive.

  • value – The variable to store the joystick axis value in.

inline constexpr void set_trigger_axis(size_t index, TRIGGER_TYPE value)

Set the trigger axis value

Note

The value should be in the range [trigger_min, trigger_max].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr void set_trigger_axis(size_t index, float value)

Set the trigger axis value

Note

The value should be in the range [0, 1].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr void get_trigger_axis(size_t index, float &value) const

Get the trigger axis value

Parameters:
  • index – The index of the trigger axis to get. Should be between 0 and 1, inclusive.

  • value – The variable to store the trigger axis value in.

inline constexpr void get_trigger_axis(size_t index, TRIGGER_TYPE &value) const

Get the trigger axis value

Parameters:
  • index – The index of the trigger axis to get. Should be between 0 and 1, inclusive.

  • value – The variable to store the trigger axis value in.

inline constexpr bool get_button(int button_index) const

Get the button value

Parameters:

button_index – The button for which you want to get the value.

Returns:

The true/false value of the button.

inline constexpr void set_button(int button_index, bool value)

Set the button value

Parameters:
  • button_index – The button for which you want to set the value. Should be between 1 and 14, inclusive.

  • value – The true/false value you want to se the button to.

inline constexpr void set_hat_switch(espp::gamepad::Hat hat)

Set the hat switch value from espp::gamepad::Hat

Parameters:

hat – The espp::gamepad::Hat value to set.

inline constexpr void set_hat_switch(Hat hat)

Set the hat switch value

Parameters:

hat – The hat switch value to set.

inline constexpr void set_hat_switch(std::uint8_t value)

Set the hat switch value

Note

The value should match the values within the Hat enum.

Parameters:

value – The hat switch value to set.

inline constexpr void set_hat(espp::gamepad::Hat hat)

Set the hat switch (d-pad) value

Parameters:

hat – Hat enum / direction to set

inline constexpr void set_hat(Hat hat)

Set the hat switch (d-pad) value

Parameters:

hat – Hat enum / direction to set

inline constexpr void set_hat(bool up, bool down, bool left, bool right)

Set the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr Hat get_hat() const

Get the hat switch (d-pad) value

Returns:

Hat enum / direction

inline constexpr void get_hat(bool &up, bool &down, bool &left, bool &right) const

Get the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr auto get_report() const

Get the input report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The input report as a vector of bytes.

inline constexpr void set_data(const std::vector<uint8_t> &data)

Set the output report data from a vector of bytes

Parameters:

data – The data to set the output report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
using namespace hid::rdf;
auto gamepad_descriptor = gamepad_input_report.get_descriptor();
auto rdf_descriptor = descriptor(
    usage_page<generic_desktop>(),
    usage(generic_desktop::GAMEPAD),
    collection::application(
        gamepad_descriptor
    )
);
auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());

Returns:

The report descriptor as a hid::rdf::descriptor.

Public Static Attributes

static constexpr size_t button_count = 15

Number of buttons supported.

static constexpr JOYSTICK_TYPE joystick_min = 0

Minimum value for the joystick axes.

static constexpr JOYSTICK_TYPE joystick_max = 255

Maximum value for the joystick axes.

static constexpr JOYSTICK_TYPE joystick_center = (joystick_min + joystick_max) / 2

Center value for the joystick axes.

static constexpr size_t joystick_value_range = joystick_max - joystick_min

Range of values for the joystick axes.

static constexpr JOYSTICK_TYPE joystick_range = joystick_value_range / 2

Half the range of values for the joystick axes.

static constexpr size_t num_joystick_bits = num_bits(joystick_value_range)

Number of bits needed to represent the joystick axes.

static constexpr TRIGGER_TYPE trigger_min = 0

Minimum value for the trigger axes.

static constexpr TRIGGER_TYPE trigger_max = 255

Maximum value for the trigger axes.

static constexpr TRIGGER_TYPE trigger_center = trigger_min

Center value for the trigger axes.

static constexpr size_t trigger_range = trigger_max - trigger_min

Range of values for the trigger axes.

static constexpr size_t num_trigger_bits = num_bits(trigger_range)

Number of bits needed to represent the trigger axes.

static constexpr std::size_t BTN_SQUARE_INDEX = {1}

The index of the SQUARE button.

static constexpr std::size_t BTN_CROSS_INDEX = {2}

The index of the CROSS button.

static constexpr std::size_t BTN_CIRCLE_INDEX = {3}

The index of the CIRCLE button.

static constexpr std::size_t BTN_TRIANGLE_INDEX = {4}

The index of the TRIANGLE button.

static constexpr std::size_t BTN_L1_INDEX = {5}

The index of the L1 button.

static constexpr std::size_t BTN_R1_INDEX = {6}

The index of the R1 button.

static constexpr std::size_t BTN_L2_INDEX = {7}

The index of the L2 button.

static constexpr std::size_t BTN_R2_INDEX = {8}

The index of the R2 button.

static constexpr std::size_t BTN_L3_INDEX = {11}

The index of the L3 button.

static constexpr std::size_t BTN_R3_INDEX = {12}

The index of the R3 button.

static constexpr std::size_t BTN_HOME_INDEX = {13}

The index of the Home button.

static constexpr std::size_t BTN_MENU_INDEX = {10}

The index of the Menu button.

static constexpr std::size_t BTN_OPTIONS_INDEX = {9}

The index of the Options button.

static constexpr std::size_t BTN_CAPTURE_INDEX = {14}

The index of the Capture button.

static constexpr std::size_t BTN_MIC_INDEX = {15}

The index of the Mic Mute button.

Header File

Unions

union PS4DualShock4GamepadButtons
#include <hid-rp-ps4.hpp>

PS4 DualShock 4 Gamepad Buttons Used in input report 0x01 over BLE

Public Members

std::array<std::uint8_t, 3> raw
struct espp::PS4DualShock4GamepadButtons
espp::PS4DualShock4FeatureReport02.__unnamed51__

Public Members

struct espp::PS4DualShock4FeatureReport02
std::array<std::uint8_t, 38> raw
espp::PS4DualShock4FeatureReport04.__unnamed55__

Public Members

struct espp::PS4DualShock4FeatureReport04
std::array<std::uint8_t, 42> raw
espp::PS4DualShock4FeatureReportF1.__unnamed59__

Public Members

struct espp::PS4DualShock4FeatureReportF1
std::array<std::uint8_t, 64> raw
espp::PS4DualShock4FeatureReportF2.__unnamed63__

Public Members

struct espp::PS4DualShock4FeatureReportF2
std::array<std::uint8_t, 64> raw
espp::PS4DualShock4OutputReport.__unnamed67__

Public Members

struct espp::PS4DualShock4OutputReport
std::array<std::uint8_t, 32> raw

Classes

template<uint8_t REPORT_ID = 0x01>
class PS4DualShock4GamepadInputReport : public hid::report::base<hid::report::type::INPUT, 0x01>

HID PS4 DualShock 4 Gamepad Input Report

This class implements a HID PS4 DualShock 4 Gamepad Input Report for BLE. It supports 14 buttons, a d-pad (hat switch), 2 joystick axes, 2 analog triggers, touchpad data, IMU (accelerometer and gyroscope), and battery status.

The PS4 DualShock 4 uses report ID 0x01 for input reports over BLE (77 bytes). The report structure follows the official Sony PS4 DualShock 4 HID descriptor.

Button mapping:

  • Buttons 1-4: Square, Cross, Circle, Triangle

  • Buttons 5-8: L1, R1, L2, R2

  • Buttons 9-12: Share, Options, L3, R3

  • Buttons 13-14: PS Home, Touchpad Click

References

HID-RP PS4 Example

  static constexpr uint8_t input_report_id = 1;
  static constexpr uint8_t battery_report_id = 4;
  static constexpr size_t num_buttons = 15;
  static constexpr int joystick_min = 0;
  static constexpr int joystick_max = 65535;
  static constexpr int trigger_min = 0;
  static constexpr int trigger_max = 1023;

  using GamepadInput =
      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
                               joystick_max, trigger_min, trigger_max, input_report_id>;
  GamepadInput gamepad_input_report;

  using XboxInput = espp::XboxGamepadInputReport<input_report_id>;
  XboxInput xbox_input_report;

  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
  BatteryReport battery_input_report;

  static constexpr uint8_t led_output_report_id = 2;
  static constexpr size_t num_leds = 4;
  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, led_output_report_id>;
  GamepadLeds gamepad_leds_report;

  static constexpr uint8_t rumble_output_report_id = 3;
  using RumbleReport = espp::XboxRumbleOutputReport<rumble_output_report_id>;
  RumbleReport rumble_output_report;

  using namespace hid::page;
  using namespace hid::rdf;
  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
                                   collection::application(gamepad_input_report.get_descriptor(),
                                                           rumble_output_report.get_descriptor(),
                                                           battery_input_report.get_descriptor(),
                                                           gamepad_leds_report.get_descriptor()));

  // Generate the report descriptor for the gamepad
  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());

  logger.info("Report Descriptor:");
  logger.info("  Size: {}", descriptor.size());
  logger.info("  Data: {::#04X}", descriptor);

  using SwitchProInput = espp::SwitchProGamepadInputReport<>;
  SwitchProInput switch_pro_input_report;
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
  logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());

  auto sp_raw_descriptor = espp::switch_pro_descriptor();
  auto sp_descriptor = std::vector<uint8_t>(sp_raw_descriptor.begin(), sp_raw_descriptor.end());

  logger.info("Switch Report Descriptor:");
  logger.info("  Size: {}", sp_descriptor.size());
  std::string str = "";
  for (auto &byte : sp_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
  PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
  using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
  PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
  logger.info("Playstation Dualsense BLE Report Descriptor:");
  auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
  auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
  logger.info("  Size: {}", ps_descriptor.size());
  str = "";
  for (auto &byte : ps_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PS4DualShock4Input = espp::PS4DualShock4GamepadInputReport<>;
  PS4DualShock4Input ps4_input_report;
  logger.info("{}", ps4_input_report);
  logger.info("PS4 DualShock 4 Input Report Size: {}", ps4_input_report.get_report().size());
  logger.info("PS4 DualShock 4 Input Report Data: {::#04X}", ps4_input_report.get_report());

  auto ps4_raw_descriptor = espp::ps4_dualshock4_descriptor();
  auto ps4_descriptor = std::vector<uint8_t>(ps4_raw_descriptor.begin(), ps4_raw_descriptor.end());

  logger.info("PS4 DualShock 4 Report Descriptor:");
  logger.info("  Size: {}", ps4_descriptor.size());
  str = "";
  for (auto &byte : ps4_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
  int button_index = 5;
  float angle = 2.0f * M_PI * button_index / num_buttons;

  // reset all reports
  gamepad_input_report.reset();
  xbox_input_report.reset();
  switch_pro_input_report.reset();
  dualsense_simple_input_report.reset();
  dualsense_complex_input_report.reset();
  ps4_input_report.reset();

  // print out the reports in their default states
  logger.info("{}", gamepad_input_report);
  logger.info("{}", xbox_input_report);
  logger.info("{}", switch_pro_input_report);
  logger.info("{}", dualsense_simple_input_report);
  logger.info("{}", dualsense_complex_input_report);
  logger.info("{}", ps4_input_report);

  // update the gamepad input report
  logger.info("{}", gamepad_input_report);
  gamepad_input_report.set_hat(hat);
  gamepad_input_report.set_button(button_index, true);
  // joystick inputs are in the range [-1, 1] float
  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
  // trigger inputs are in the range [0, 1] float
  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
  gamepad_input_report.set_brake(std::abs(cos(angle)));

  switch_pro_input_report.set_button(button_index, true);
  switch_pro_input_report.set_dpad(false, true, false, true); // down-right
  switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
  switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
  switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
  switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));

  dualsense_simple_input_report.set_button(button_index, true);
  dualsense_simple_input_report.set_hat(hat);
  dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));

  dualsense_complex_input_report.set_button(button_index, true);
  dualsense_complex_input_report.set_hat(hat);
  dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));

  ps4_input_report.set_hat(hat);
  ps4_input_report.set_button_cross(button_index == 1);
  ps4_input_report.set_button_circle(button_index == 2);
  ps4_input_report.set_button_square(button_index == 3);
  ps4_input_report.set_button_triangle(button_index == 4);
  ps4_input_report.set_left_joystick(128 + 127 * sin(angle), 128 + 127 * cos(angle));
  ps4_input_report.set_right_joystick(128 + 127 * cos(angle), 128 + 127 * sin(angle));
  ps4_input_report.set_l2_trigger(std::abs(cos(angle)) * 255);
  ps4_input_report.set_r2_trigger(std::abs(sin(angle)) * 255);
  ps4_input_report.set_battery_level(8);

  button_index = (button_index % num_buttons) + 1;

  // send an input report
  auto report = gamepad_input_report.get_report();
  logger.info("{}", gamepad_input_report);
  logger.info("Gamepad Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = switch_pro_input_report.get_report();
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_simple_input_report.get_report();
  logger.info("{}", dualsense_simple_input_report);
  logger.info("Playstation Dualsense BLE Simple Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_complex_input_report.get_report();
  logger.info("{}", dualsense_complex_input_report);
  logger.info("Playstation Dualsense BLE Complex Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  // update the battery input report
  battery_input_report.reset();
  battery_input_report.set_rechargeable(true);
  battery_input_report.set_charging(false);
  battery_input_report.set_rechargeable(true);
  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
  battery_input_report.set_battery_level(50);

  // send a battery report
  report = battery_input_report.get_report();
  logger.info("Battery report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);
template<uint8_t REPORT_ID = 0x02>
class PS4DualShock4FeatureReport02 : public hid::report::base<hid::report::type::FEATURE, 0x02>

HID PS4 DualShock 4 Feature Report (0x02)

This class implements a HID PS4 DualShock 4 Feature Report for BLE. Report ID 0x02 - 37 bytes

template<uint8_t REPORT_ID = 0x04>
class PS4DualShock4FeatureReport04 : public hid::report::base<hid::report::type::FEATURE, 0x04>

HID PS4 DualShock 4 Feature Report (0x04)

This class implements a HID PS4 DualShock 4 Feature Report for BLE. Report ID 0x04 - 41 bytes

template<uint8_t REPORT_ID = 0xF1>
class PS4DualShock4FeatureReportF1 : public hid::report::base<hid::report::type::FEATURE, 0xF1>

HID PS4 DualShock 4 Feature Report (0xF1)

This class implements a HID PS4 DualShock 4 Feature Report for BLE. Report ID 0xF1 - 63 bytes (device info)

template<uint8_t REPORT_ID = 0xF2>
class PS4DualShock4FeatureReportF2 : public hid::report::base<hid::report::type::FEATURE, 0xF2>

HID PS4 DualShock 4 Feature Report (0xF2)

This class implements a HID PS4 DualShock 4 Feature Report for BLE. Report ID 0xF2 - 63 bytes (firmware info)

template<uint8_t REPORT_ID = 0x05>
class PS4DualShock4OutputReport : public hid::report::base<hid::report::type::OUTPUT, 0x05>

HID PS4 DualShock 4 Output Report

This class implements a HID PS4 DualShock 4 Output Report for BLE. It supports rumble (left/right motors), LED color, and flash settings.

Note

See https://www.psdevwiki.com/ps4/DS4-BT for BLE output report format

Note

See https://www.psdevwiki.com/ps4/DS4-USB for USB output report format

Note

For BLE, the report uses report ID 0x11 (17 decimal)

Note

The official descriptor uses report ID 0x05 for OUTPUT reports (31 bytes)

Header File

Classes

template<uint8_t REPORT_ID = 0x30>
class SwitchProGamepadInputReport : public hid::report::base<hid::report::type::INPUT, 0x30>

HID Switch Pro Gamepad Input Report

This class implements a HID Switch Pro Gamepad Input Report. It supports 15 buttons, a d-pad, 4 joystick axes and two trigger buttons. It supports setting the buttons, d-pad, joysticks, and triggers, as well as serializing the input report and getting the report descriptor.

HID-RP Switch Pro Example

  static constexpr uint8_t input_report_id = 1;
  static constexpr uint8_t battery_report_id = 4;
  static constexpr size_t num_buttons = 15;
  static constexpr int joystick_min = 0;
  static constexpr int joystick_max = 65535;
  static constexpr int trigger_min = 0;
  static constexpr int trigger_max = 1023;

  using GamepadInput =
      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
                               joystick_max, trigger_min, trigger_max, input_report_id>;
  GamepadInput gamepad_input_report;

  using XboxInput = espp::XboxGamepadInputReport<input_report_id>;
  XboxInput xbox_input_report;

  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
  BatteryReport battery_input_report;

  static constexpr uint8_t led_output_report_id = 2;
  static constexpr size_t num_leds = 4;
  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, led_output_report_id>;
  GamepadLeds gamepad_leds_report;

  static constexpr uint8_t rumble_output_report_id = 3;
  using RumbleReport = espp::XboxRumbleOutputReport<rumble_output_report_id>;
  RumbleReport rumble_output_report;

  using namespace hid::page;
  using namespace hid::rdf;
  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
                                   collection::application(gamepad_input_report.get_descriptor(),
                                                           rumble_output_report.get_descriptor(),
                                                           battery_input_report.get_descriptor(),
                                                           gamepad_leds_report.get_descriptor()));

  // Generate the report descriptor for the gamepad
  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());

  logger.info("Report Descriptor:");
  logger.info("  Size: {}", descriptor.size());
  logger.info("  Data: {::#04X}", descriptor);

  using SwitchProInput = espp::SwitchProGamepadInputReport<>;
  SwitchProInput switch_pro_input_report;
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
  logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());

  auto sp_raw_descriptor = espp::switch_pro_descriptor();
  auto sp_descriptor = std::vector<uint8_t>(sp_raw_descriptor.begin(), sp_raw_descriptor.end());

  logger.info("Switch Report Descriptor:");
  logger.info("  Size: {}", sp_descriptor.size());
  std::string str = "";
  for (auto &byte : sp_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
  PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
  using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
  PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
  logger.info("Playstation Dualsense BLE Report Descriptor:");
  auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
  auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
  logger.info("  Size: {}", ps_descriptor.size());
  str = "";
  for (auto &byte : ps_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PS4DualShock4Input = espp::PS4DualShock4GamepadInputReport<>;
  PS4DualShock4Input ps4_input_report;
  logger.info("{}", ps4_input_report);
  logger.info("PS4 DualShock 4 Input Report Size: {}", ps4_input_report.get_report().size());
  logger.info("PS4 DualShock 4 Input Report Data: {::#04X}", ps4_input_report.get_report());

  auto ps4_raw_descriptor = espp::ps4_dualshock4_descriptor();
  auto ps4_descriptor = std::vector<uint8_t>(ps4_raw_descriptor.begin(), ps4_raw_descriptor.end());

  logger.info("PS4 DualShock 4 Report Descriptor:");
  logger.info("  Size: {}", ps4_descriptor.size());
  str = "";
  for (auto &byte : ps4_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
  int button_index = 5;
  float angle = 2.0f * M_PI * button_index / num_buttons;

  // reset all reports
  gamepad_input_report.reset();
  xbox_input_report.reset();
  switch_pro_input_report.reset();
  dualsense_simple_input_report.reset();
  dualsense_complex_input_report.reset();
  ps4_input_report.reset();

  // print out the reports in their default states
  logger.info("{}", gamepad_input_report);
  logger.info("{}", xbox_input_report);
  logger.info("{}", switch_pro_input_report);
  logger.info("{}", dualsense_simple_input_report);
  logger.info("{}", dualsense_complex_input_report);
  logger.info("{}", ps4_input_report);

  // update the gamepad input report
  logger.info("{}", gamepad_input_report);
  gamepad_input_report.set_hat(hat);
  gamepad_input_report.set_button(button_index, true);
  // joystick inputs are in the range [-1, 1] float
  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
  // trigger inputs are in the range [0, 1] float
  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
  gamepad_input_report.set_brake(std::abs(cos(angle)));

  switch_pro_input_report.set_button(button_index, true);
  switch_pro_input_report.set_dpad(false, true, false, true); // down-right
  switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
  switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
  switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
  switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));

  dualsense_simple_input_report.set_button(button_index, true);
  dualsense_simple_input_report.set_hat(hat);
  dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));

  dualsense_complex_input_report.set_button(button_index, true);
  dualsense_complex_input_report.set_hat(hat);
  dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));

  ps4_input_report.set_hat(hat);
  ps4_input_report.set_button_cross(button_index == 1);
  ps4_input_report.set_button_circle(button_index == 2);
  ps4_input_report.set_button_square(button_index == 3);
  ps4_input_report.set_button_triangle(button_index == 4);
  ps4_input_report.set_left_joystick(128 + 127 * sin(angle), 128 + 127 * cos(angle));
  ps4_input_report.set_right_joystick(128 + 127 * cos(angle), 128 + 127 * sin(angle));
  ps4_input_report.set_l2_trigger(std::abs(cos(angle)) * 255);
  ps4_input_report.set_r2_trigger(std::abs(sin(angle)) * 255);
  ps4_input_report.set_battery_level(8);

  button_index = (button_index % num_buttons) + 1;

  // send an input report
  auto report = gamepad_input_report.get_report();
  logger.info("{}", gamepad_input_report);
  logger.info("Gamepad Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = switch_pro_input_report.get_report();
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_simple_input_report.get_report();
  logger.info("{}", dualsense_simple_input_report);
  logger.info("Playstation Dualsense BLE Simple Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_complex_input_report.get_report();
  logger.info("{}", dualsense_complex_input_report);
  logger.info("Playstation Dualsense BLE Complex Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  // update the battery input report
  battery_input_report.reset();
  battery_input_report.set_rechargeable(true);
  battery_input_report.set_charging(false);
  battery_input_report.set_rechargeable(true);
  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
  battery_input_report.set_battery_level(50);

  // send a battery report
  report = battery_input_report.get_report();
  logger.info("Battery report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

Public Functions

constexpr SwitchProGamepadInputReport() = default

Construct a new Gamepad Input Report object.

inline constexpr void reset()

Reset the gamepad inputs.

inline constexpr void set_counter(uint8_t value)

Set the counter

Parameters:

value – The value to set the counter to.

inline constexpr void increment_counter()

Increment the counter.

inline constexpr uint8_t get_counter() const

Get the counter value

Returns:

The counter value

inline constexpr void set_subcmd_ack(uint8_t ack)

Set the subcommand ACK

Parameters:

ack – The subcommand ACK to set

inline constexpr uint8_t get_subcmd_ack() const

Get the subcommand ACK

Returns:

The subcommand ACK

inline constexpr void set_subcmd_id(uint8_t id)

Set the subcommand ID

Parameters:

id – The subcommand ID to set

inline constexpr uint8_t get_subcmd_id() const

Get the subcommand ID

Returns:

The subcommand ID

inline constexpr void set_subcmd_reply(const std::vector<uint8_t> &reply)

Set the subcommand reply

Parameters:

reply – The subcommand reply to set

inline constexpr auto get_subcmd_reply() const

Get the subcommand reply

Returns:

The subcommand reply

inline constexpr void set_left_joystick(float lx, float ly)

Set the left joystick X and Y axis values

Parameters:
  • lx – left joystick x axis value, in the range [-1, 1]

  • ly – left joystick y axis value, in the range [-1, 1]

inline constexpr void set_right_joystick(float rx, float ry)

Set the right joystick X and Y axis values

Parameters:
  • rx – right joystick x axis value, in the range [-1, 1]

  • ry – right joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_joystick(float &lx, float &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx – left joystick x axis value, in the range [-1, 1]

  • ly – left joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_joystick(JOYSTICK_TYPE &lx, JOYSTICK_TYPE &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx – left joystick x axis value

  • ly – left joystick y axis value

inline constexpr void get_right_joystick(float &rx, float &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx – right joystick x axis value, in the range [-1, 1]

  • ry – right joystick y axis value, in the range [-1, 1]

inline constexpr void get_right_joystick(JOYSTICK_TYPE &rx, JOYSTICK_TYPE &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx – right joystick x axis value

  • ry – right joystick y axis value

inline constexpr void set_left_trigger(float value)

Set the left trigger value

Parameters:

value – The value to set the left trigger to. Should be in the range [0, 1].

inline constexpr void set_left_trigger(bool pressed)

Set the right trigger value

Parameters:

pressed – Whether the right trigger is pressed or not

inline constexpr void set_right_trigger(float value)

Set the right trigger value

Parameters:

value – The value to set the right trigger to. Should be in the range [0, 1].

inline constexpr void set_right_trigger(bool pressed)

Set the right trigger value

Parameters:

pressed – Whether the right trigger is pressed or not

inline constexpr void set_brake(bool pressed)

Set the brake trigger value

Parameters:

pressed – Whether the brake trigger is pressed or not

inline constexpr void set_brake(float value)

Set the brake trigger value

Parameters:

value – The value to set the brake trigger to. Should be in the range [0, 1].

inline constexpr void set_accelerator(bool pressed)

Set the accelerator trigger value

Parameters:

pressed – Whether the accelerator trigger is pressed or not

inline constexpr void set_accelerator(float value)

Set the accelerator trigger value

Parameters:

value – The value to set the accelerator trigger to. Should be in the range [0, 1].

inline constexpr void get_brake(float &value) const

Get the brake trigger value

Parameters:

value – The value of the brake trigger

inline constexpr void get_accelerator(float &value) const

Get the accelerator trigger value

Parameters:

value – The value of the accelerator trigger

inline constexpr void set_battery_level(float level)

Set the battery level

Parameters:

level – battery level, in the range [0, 100]

inline constexpr void set_battery_charging(bool charging)

Set the battery charging status

Parameters:

charging – whether the battery is charging or not

inline constexpr void set_connection_info(uint8_t info)

Set the connection info

Parameters:

info – connection info

inline constexpr void set_dpad(bool up, bool down, bool left, bool right)

Set the dpad value

Parameters:
  • up – up dpad value

  • down – down dpad value

  • left – left dpad value

  • right – right dpad value

inline constexpr void set_hat_switch(espp::gamepad::Hat hat)

Set the d-pad as a hat switch value from espp::gamepad::Hat

Parameters:

hat – The espp::gamepad::Hat value to set.

inline constexpr void set_hat(espp::gamepad::Hat hat)

Set the hat switch (d-pad) value

Parameters:

hat – Hat enum / direction to set

template<SwitchProButtonStruct T>
inline constexpr void set_buttons(const T &buttons)

Set the buttons

Parameters:

buttons – The struct containing the button values

template<SwitchProButtonStruct T>
inline constexpr void get_buttons(T &t) const

Get the button values

Parameters:

t – The struct to fill with the button values

inline constexpr void get_dpad(bool &up, bool &down, bool &left, bool &right) const

Get the dpad value

Parameters:
  • up – up dpad value

  • down – down dpad value

  • left – left dpad value

  • right – right dpad value

inline constexpr void set_button(int button_index, bool value)

Set the button value

Parameters:
  • button_index – The button for which you want to set the value. Should be between 1 and 24, inclusive.

  • value – The true/false value you want to se the button to.

inline constexpr bool get_button(int button_index) const

Get the button value

Parameters:

button_index – The button for which you want to get the value. Should be between 1 and 24, inclusive.

Returns:

The true/false value of the button.

inline constexpr void set_trigger_axis(size_t index, float value)

Set the trigger axis value

Note

The value should be in the range [0, 1].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr void set_trigger_axis(size_t index, bool pressed)

Set the trigger pressed value

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • pressed – Whether the trigger is pressed or not

inline constexpr auto get_report() const

Get the input report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The input report as a vector of bytes.

inline constexpr void set_data(const std::vector<uint8_t> &data)

Set the output report data from a vector of bytes

Parameters:

data – The data to set the output report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

Returns:

The report descriptor as a hid::rdf::descriptor.

Header File

Classes

template<uint8_t REPORT_ID = 1>
class XboxGamepadInputReport : public espp::GamepadInputReport<15, std::uint16_t, std::uint16_t, 0, 65535, 0, 1023, 1>

HID Xbox Gamepad Input Report

This class implements a HID Xbox Gamepad Report. It supports 15 buttons, a d-pad, 4 joystick axes, 2 trigger axes as well as consumer record button.

HID-RP Xbox Gamepad Example

  static constexpr uint8_t input_report_id = 1;
  static constexpr uint8_t battery_report_id = 4;
  static constexpr size_t num_buttons = 15;
  static constexpr int joystick_min = 0;
  static constexpr int joystick_max = 65535;
  static constexpr int trigger_min = 0;
  static constexpr int trigger_max = 1023;

  using GamepadInput =
      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
                               joystick_max, trigger_min, trigger_max, input_report_id>;
  GamepadInput gamepad_input_report;

  using XboxInput = espp::XboxGamepadInputReport<input_report_id>;
  XboxInput xbox_input_report;

  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
  BatteryReport battery_input_report;

  static constexpr uint8_t led_output_report_id = 2;
  static constexpr size_t num_leds = 4;
  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, led_output_report_id>;
  GamepadLeds gamepad_leds_report;

  static constexpr uint8_t rumble_output_report_id = 3;
  using RumbleReport = espp::XboxRumbleOutputReport<rumble_output_report_id>;
  RumbleReport rumble_output_report;

  using namespace hid::page;
  using namespace hid::rdf;
  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
                                   collection::application(gamepad_input_report.get_descriptor(),
                                                           rumble_output_report.get_descriptor(),
                                                           battery_input_report.get_descriptor(),
                                                           gamepad_leds_report.get_descriptor()));

  // Generate the report descriptor for the gamepad
  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());

  logger.info("Report Descriptor:");
  logger.info("  Size: {}", descriptor.size());
  logger.info("  Data: {::#04X}", descriptor);

  using SwitchProInput = espp::SwitchProGamepadInputReport<>;
  SwitchProInput switch_pro_input_report;
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
  logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());

  auto sp_raw_descriptor = espp::switch_pro_descriptor();
  auto sp_descriptor = std::vector<uint8_t>(sp_raw_descriptor.begin(), sp_raw_descriptor.end());

  logger.info("Switch Report Descriptor:");
  logger.info("  Size: {}", sp_descriptor.size());
  std::string str = "";
  for (auto &byte : sp_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
  PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
  using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
  PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
  logger.info("Playstation Dualsense BLE Report Descriptor:");
  auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
  auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
  logger.info("  Size: {}", ps_descriptor.size());
  str = "";
  for (auto &byte : ps_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PS4DualShock4Input = espp::PS4DualShock4GamepadInputReport<>;
  PS4DualShock4Input ps4_input_report;
  logger.info("{}", ps4_input_report);
  logger.info("PS4 DualShock 4 Input Report Size: {}", ps4_input_report.get_report().size());
  logger.info("PS4 DualShock 4 Input Report Data: {::#04X}", ps4_input_report.get_report());

  auto ps4_raw_descriptor = espp::ps4_dualshock4_descriptor();
  auto ps4_descriptor = std::vector<uint8_t>(ps4_raw_descriptor.begin(), ps4_raw_descriptor.end());

  logger.info("PS4 DualShock 4 Report Descriptor:");
  logger.info("  Size: {}", ps4_descriptor.size());
  str = "";
  for (auto &byte : ps4_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
  int button_index = 5;
  float angle = 2.0f * M_PI * button_index / num_buttons;

  // reset all reports
  gamepad_input_report.reset();
  xbox_input_report.reset();
  switch_pro_input_report.reset();
  dualsense_simple_input_report.reset();
  dualsense_complex_input_report.reset();
  ps4_input_report.reset();

  // print out the reports in their default states
  logger.info("{}", gamepad_input_report);
  logger.info("{}", xbox_input_report);
  logger.info("{}", switch_pro_input_report);
  logger.info("{}", dualsense_simple_input_report);
  logger.info("{}", dualsense_complex_input_report);
  logger.info("{}", ps4_input_report);

  // update the gamepad input report
  logger.info("{}", gamepad_input_report);
  gamepad_input_report.set_hat(hat);
  gamepad_input_report.set_button(button_index, true);
  // joystick inputs are in the range [-1, 1] float
  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
  // trigger inputs are in the range [0, 1] float
  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
  gamepad_input_report.set_brake(std::abs(cos(angle)));

  switch_pro_input_report.set_button(button_index, true);
  switch_pro_input_report.set_dpad(false, true, false, true); // down-right
  switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
  switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
  switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
  switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));

  dualsense_simple_input_report.set_button(button_index, true);
  dualsense_simple_input_report.set_hat(hat);
  dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));

  dualsense_complex_input_report.set_button(button_index, true);
  dualsense_complex_input_report.set_hat(hat);
  dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));

  ps4_input_report.set_hat(hat);
  ps4_input_report.set_button_cross(button_index == 1);
  ps4_input_report.set_button_circle(button_index == 2);
  ps4_input_report.set_button_square(button_index == 3);
  ps4_input_report.set_button_triangle(button_index == 4);
  ps4_input_report.set_left_joystick(128 + 127 * sin(angle), 128 + 127 * cos(angle));
  ps4_input_report.set_right_joystick(128 + 127 * cos(angle), 128 + 127 * sin(angle));
  ps4_input_report.set_l2_trigger(std::abs(cos(angle)) * 255);
  ps4_input_report.set_r2_trigger(std::abs(sin(angle)) * 255);
  ps4_input_report.set_battery_level(8);

  button_index = (button_index % num_buttons) + 1;

  // send an input report
  auto report = gamepad_input_report.get_report();
  logger.info("{}", gamepad_input_report);
  logger.info("Gamepad Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = switch_pro_input_report.get_report();
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_simple_input_report.get_report();
  logger.info("{}", dualsense_simple_input_report);
  logger.info("Playstation Dualsense BLE Simple Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_complex_input_report.get_report();
  logger.info("{}", dualsense_complex_input_report);
  logger.info("Playstation Dualsense BLE Complex Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  // update the battery input report
  battery_input_report.reset();
  battery_input_report.set_rechargeable(true);
  battery_input_report.set_charging(false);
  battery_input_report.set_rechargeable(true);
  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
  battery_input_report.set_battery_level(50);

  // send a battery report
  report = battery_input_report.get_report();
  logger.info("Battery report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

Public Functions

template<XboxButtonStruct T>
inline constexpr void set_buttons(const T &buttons)

Set the buttons

Parameters:

buttons – The struct containing the button values

template<XboxButtonStruct T>
inline constexpr void get_buttons(T &t) const

Get the button values

Parameters:

t – The struct to fill with the button values

inline constexpr void reset()

Reset the gamepad inputs.

inline constexpr void get_left_joystick(float &lx, float &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value, in the range [-1, 1]

  • ly[out] left joystick y axis value, in the range [-1, 1]

inline constexpr void get_left_joystick(JOYSTICK_TYPE &lx, JOYSTICK_TYPE &ly) const

Get the left joystick X and Y axis values

Parameters:
  • lx[out] left joystick x axis value

  • ly[out] left joystick y axis value

inline constexpr void get_right_joystick(float &rx, float &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value, in the range [-1, 1]

  • ry[out] right joystick y axis value, in the range [-1, 1]

inline constexpr void get_right_joystick(JOYSTICK_TYPE &rx, JOYSTICK_TYPE &ry) const

Get the right joystick X and Y axis values

Parameters:
  • rx[out] right joystick x axis value

  • ry[out] right joystick y axis value

inline constexpr void set_left_joystick(float lx, float ly)

Set the left joystick X and Y axis values

Parameters:
  • lx – left joystick x axis value, in the range [-1, 1]

  • ly – left joystick y axis value, in the range [-1, 1]

inline constexpr void set_right_joystick(float rx, float ry)

Set the right joystick X and Y axis values

Parameters:
  • rx – right joystick x axis value, in the range [-1, 1]

  • ry – right joystick y axis value, in the range [-1, 1]

inline constexpr void get_brake(float &value) const

Get the brake trigger value

Parameters:

value – brake trigger value, in the range [0, 1]

inline constexpr void get_brake(TRIGGER_TYPE &value) const

Get the brake trigger value

Parameters:

value – brake trigger value

inline constexpr void get_left_trigger(float &value) const

Get the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void set_brake(float value)

Set the brake trigger value

Parameters:

value – brake trigger value, in the range [0, 1]

inline constexpr void set_left_trigger(float value)

Set the left trigger value

Parameters:

value – left trigger value, in the range [0, 1]

inline constexpr void get_accelerator(float &value) const

Get the accelerator trigger value

Parameters:

value – accelerator trigger value, in the range [0, 1]

inline constexpr void get_accelerator(TRIGGER_TYPE &value) const

Get the accelerator trigger value

Parameters:

value – accelerator trigger value

inline constexpr void get_right_trigger(float &value) const

Get the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_accelerator(float value)

Set the accelerator trigger value

Parameters:

value – accelerator trigger value, in the range [0, 1]

inline constexpr void set_right_trigger(float value)

Set the right trigger value

Parameters:

value – right trigger value, in the range [0, 1]

inline constexpr void set_hat(Hat hat)

Set the hat switch (d-pad) value

Parameters:

hat – Hat enum / direction to set

inline constexpr void set_hat(bool up, bool down, bool left, bool right)

Set the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr Hat get_hat() const

Get the hat switch (d-pad) value

Returns:

Hat enum / direction

inline constexpr void get_hat(bool &up, bool &down, bool &left, bool &right) const

Get the hat switch (d-pad) value

Parameters:
  • up – up direction

  • down – down direction

  • left – left direction

  • right – right direction

inline constexpr void set_button(int button_index, bool value)

Set the button value

Parameters:
  • button_index – The button for which you want to set the value. Should be between 1 and BUTTON_COUNT, inclusive.

  • value – The true/false value you want to se the button to.

inline constexpr void set_joystick_axis(size_t index, JOYSTICK_TYPE value)

Set the joystick axis value

Note

The value should be in the range [joystick_min, joystick_max].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void set_joystick_axis(size_t index, float value)

Set the joystick axis value

Note

The value should be in the range [-1, 1].

Parameters:
  • index – The index of the joystick axis to set. Should be between 0 and 3, inclusive.

  • value – The value to set the joystick axis to.

inline constexpr void set_trigger_axis(size_t index, TRIGGER_TYPE value)

Set the trigger axis value

Note

The value should be in the range [trigger_min, trigger_max].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr void set_trigger_axis(size_t index, float value)

Set the trigger axis value

Note

The value should be in the range [0, 1].

Parameters:
  • index – The index of the trigger axis to set. Should be between 0 and 1, inclusive.

  • value – The value to set the trigger axis to.

inline constexpr bool get_button(int button_index) const

Get the button value

Parameters:

button_index – The button for which you want to get the value.

Returns:

The true/false value of the button.

inline constexpr void set_hat_switch(Hat hat)

Set the hat switch value

Parameters:

hat – The hat switch value to set.

inline constexpr void set_hat_switch(std::uint8_t value)

Set the hat switch value

Note

The value should match the values within the Hat enum.

Parameters:

value – The hat switch value to set.

inline constexpr bool get_consumer_record() const

Get the consumer record button value

Returns:

The consumer record button value.

inline constexpr void set_consumer_record(bool value)

Set the consumer record button value

Parameters:

value – The true/false value you want to se the consumer record button to.

inline constexpr auto get_report() const

Get the input report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The input report as a vector of bytes.

inline constexpr void set_data(const std::vector<uint8_t> &data)

Set the output report data from a vector of bytes

Parameters:

data – The data to set the output report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

using namespace hid::page;
using namespace hid::rdf;
auto gamepad_descriptor = gamepad_input_report.get_descriptor();
auto rdf_descriptor = descriptor(
    usage_page<generic_desktop>(),
    usage(generic_desktop::GAMEPAD),
    collection::application(
        gamepad_descriptor
    )
);
auto descriptor = std::vector<uint8_t>(rdf_descriptor.begin(), rdf_descriptor.end());

Returns:

The report descriptor as a hid::rdf::descriptor.

Public Static Attributes

static constexpr std::size_t BTN_A_INDEX = {1}

The index of the A button.

static constexpr std::size_t BTN_B_INDEX = {2}

The index of the B button.

static constexpr std::size_t BTN_X_INDEX = {4}

The index of the X button.

static constexpr std::size_t BTN_Y_INDEX = {5}

The index of the Y button.

static constexpr std::size_t BTN_L1_INDEX = {7}

The index of the L1 button.

static constexpr std::size_t BTN_R1_INDEX = {8}

The index of the R1 button.

static constexpr std::size_t BTN_L2_INDEX = {9}

The index of the L2 button.

static constexpr std::size_t BTN_R2_INDEX = {10}

The index of the R2 button.

static constexpr std::size_t BTN_L3_INDEX = {14}

The index of the L3 button.

static constexpr std::size_t BTN_R3_INDEX = {15}

The index of the R3 button.

static constexpr std::size_t BTN_HOME_INDEX = {13}

The index of the Home button.

static constexpr std::size_t BTN_MENU_INDEX = {12}

The index of the Menu button.

static constexpr std::size_t BTN_OPTIONS_INDEX = {11}

The index of the Options button.

template<uint8_t REPORT_ID = 3>
class XboxRumbleOutputReport : public hid::report::base<hid::report::type::OUTPUT, 3>

HID Xbox Rumble Output Report

This class implements a HID Rumble Output Report providing rumble effect on the left and right motors, as well as serializing the output report and getting the report descriptor.

Public Functions

constexpr XboxRumbleOutputReport() = default

Construct a new Xbox Rumble Output Report object.

inline constexpr void reset()

Reset the rumble effect.

inline constexpr auto get_enabled()

Get the enabled mask for the rumble motors

Returns:

The enabled mask for the rumble motors

inline constexpr void set_enabled(std::uint8_t new_enabled)

Set the enabled mask for the rumble motors

Parameters:

new_enabled – The enabled mask for the rumble motors

inline constexpr auto get_magnitude(std::size_t motor)

Get the magnitude of the rumble effect for the specified motor

Parameters:

motor – The motor for which you want to get the magnitude.

Returns:

The magnitude of the rumble effect for the specified motor.

inline constexpr void set_magnitude(std::size_t motor, std::uint8_t value)

Set the magnitude of the rumble effect for the specified motor

Note

The value should be in the range [0, 100].

Parameters:
  • motor – The motor for which you want to set the magnitude.

  • value – The magnitude of the rumble effect for the specified motor.

inline constexpr void set_magnitude(std::size_t motor, float value)

Set the magnitude of the rumble effect for the specified motor

Note

The value should be in the range [0, 1].

Parameters:
  • motor – The motor for which you want to set the magnitude.

  • value – The magnitude of the rumble effect for the specified motor.

inline constexpr auto get_duration()

Get the duration of the rumble effect

Returns:

The duration of the rumble effect

inline constexpr void set_duration(std::uint8_t value)

Set the duration of the rumble effect

Note

The value should be in the range [0, 255].

Parameters:

value – The duration of the rumble effect.

inline constexpr auto get_start_delay()

Get the start delay of the rumble effect

Returns:

The start delay of the rumble effect

inline constexpr void set_start_delay(std::uint8_t value)

Set the start delay of the rumble effect

Note

The value should be in the range [0, 255].

Parameters:

value – The start delay of the rumble effect.

inline constexpr auto get_loop_count()

Get the loop count of the rumble effect

Returns:

The loop count of the rumble effect

inline constexpr void set_loop_count(std::uint8_t value)

Set the loop count of the rumble effect

Note

The value should be in the range [0, 255].

Parameters:

value – The loop count of the rumble effect.

inline constexpr auto get_report() const

Get the output report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The output report as a vector of bytes.

inline constexpr void set_data(const std::vector<uint8_t> &data)

Set the output report data from a vector of bytes

Parameters:

data – The data to set the output report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

Returns:

The report descriptor as a hid::rdf::descriptor.

template<uint8_t REPORT_ID = 4>
class XboxBatteryInputReport : public hid::report::base<hid::report::type::INPUT, 4>

HID Xbox Battery Input Report This class implements a copy of the Xbox Battery input report. It is a single byte input which contains information about the type of the battery, its battery level, as well as a few other things.

HID-RP Xbox Battery Input Example

  static constexpr uint8_t input_report_id = 1;
  static constexpr uint8_t battery_report_id = 4;
  static constexpr size_t num_buttons = 15;
  static constexpr int joystick_min = 0;
  static constexpr int joystick_max = 65535;
  static constexpr int trigger_min = 0;
  static constexpr int trigger_max = 1023;

  using GamepadInput =
      espp::GamepadInputReport<num_buttons, std::uint16_t, std::uint16_t, joystick_min,
                               joystick_max, trigger_min, trigger_max, input_report_id>;
  GamepadInput gamepad_input_report;

  using XboxInput = espp::XboxGamepadInputReport<input_report_id>;
  XboxInput xbox_input_report;

  using BatteryReport = espp::XboxBatteryInputReport<battery_report_id>;
  BatteryReport battery_input_report;

  static constexpr uint8_t led_output_report_id = 2;
  static constexpr size_t num_leds = 4;
  using GamepadLeds = espp::GamepadLedOutputReport<num_leds, led_output_report_id>;
  GamepadLeds gamepad_leds_report;

  static constexpr uint8_t rumble_output_report_id = 3;
  using RumbleReport = espp::XboxRumbleOutputReport<rumble_output_report_id>;
  RumbleReport rumble_output_report;

  using namespace hid::page;
  using namespace hid::rdf;
  auto raw_descriptor = descriptor(usage_page<generic_desktop>(), usage(generic_desktop::GAMEPAD),
                                   collection::application(gamepad_input_report.get_descriptor(),
                                                           rumble_output_report.get_descriptor(),
                                                           battery_input_report.get_descriptor(),
                                                           gamepad_leds_report.get_descriptor()));

  // Generate the report descriptor for the gamepad
  auto descriptor = std::vector<uint8_t>(raw_descriptor.begin(), raw_descriptor.end());

  logger.info("Report Descriptor:");
  logger.info("  Size: {}", descriptor.size());
  logger.info("  Data: {::#04X}", descriptor);

  using SwitchProInput = espp::SwitchProGamepadInputReport<>;
  SwitchProInput switch_pro_input_report;
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
  logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());

  auto sp_raw_descriptor = espp::switch_pro_descriptor();
  auto sp_descriptor = std::vector<uint8_t>(sp_raw_descriptor.begin(), sp_raw_descriptor.end());

  logger.info("Switch Report Descriptor:");
  logger.info("  Size: {}", sp_descriptor.size());
  std::string str = "";
  for (auto &byte : sp_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
  PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
  using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
  PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
  logger.info("Playstation Dualsense BLE Report Descriptor:");
  auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
  auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
  logger.info("  Size: {}", ps_descriptor.size());
  str = "";
  for (auto &byte : ps_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  using PS4DualShock4Input = espp::PS4DualShock4GamepadInputReport<>;
  PS4DualShock4Input ps4_input_report;
  logger.info("{}", ps4_input_report);
  logger.info("PS4 DualShock 4 Input Report Size: {}", ps4_input_report.get_report().size());
  logger.info("PS4 DualShock 4 Input Report Data: {::#04X}", ps4_input_report.get_report());

  auto ps4_raw_descriptor = espp::ps4_dualshock4_descriptor();
  auto ps4_descriptor = std::vector<uint8_t>(ps4_raw_descriptor.begin(), ps4_raw_descriptor.end());

  logger.info("PS4 DualShock 4 Report Descriptor:");
  logger.info("  Size: {}", ps4_descriptor.size());
  str = "";
  for (auto &byte : ps4_descriptor) {
    str += fmt::format("0x{:02X}, ", byte);
  }
  logger.info("  Data: [{}]", str);

  GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
  int button_index = 5;
  float angle = 2.0f * M_PI * button_index / num_buttons;

  // reset all reports
  gamepad_input_report.reset();
  xbox_input_report.reset();
  switch_pro_input_report.reset();
  dualsense_simple_input_report.reset();
  dualsense_complex_input_report.reset();
  ps4_input_report.reset();

  // print out the reports in their default states
  logger.info("{}", gamepad_input_report);
  logger.info("{}", xbox_input_report);
  logger.info("{}", switch_pro_input_report);
  logger.info("{}", dualsense_simple_input_report);
  logger.info("{}", dualsense_complex_input_report);
  logger.info("{}", ps4_input_report);

  // update the gamepad input report
  logger.info("{}", gamepad_input_report);
  gamepad_input_report.set_hat(hat);
  gamepad_input_report.set_button(button_index, true);
  // joystick inputs are in the range [-1, 1] float
  gamepad_input_report.set_right_joystick(cos(angle), sin(angle));
  gamepad_input_report.set_left_joystick(sin(angle), cos(angle));
  // trigger inputs are in the range [0, 1] float
  gamepad_input_report.set_accelerator(std::abs(sin(angle)));
  gamepad_input_report.set_brake(std::abs(cos(angle)));

  switch_pro_input_report.set_button(button_index, true);
  switch_pro_input_report.set_dpad(false, true, false, true); // down-right
  switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
  switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
  switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
  switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));

  dualsense_simple_input_report.set_button(button_index, true);
  dualsense_simple_input_report.set_hat(hat);
  dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));

  dualsense_complex_input_report.set_button(button_index, true);
  dualsense_complex_input_report.set_hat(hat);
  dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
  dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
  dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
  dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));

  ps4_input_report.set_hat(hat);
  ps4_input_report.set_button_cross(button_index == 1);
  ps4_input_report.set_button_circle(button_index == 2);
  ps4_input_report.set_button_square(button_index == 3);
  ps4_input_report.set_button_triangle(button_index == 4);
  ps4_input_report.set_left_joystick(128 + 127 * sin(angle), 128 + 127 * cos(angle));
  ps4_input_report.set_right_joystick(128 + 127 * cos(angle), 128 + 127 * sin(angle));
  ps4_input_report.set_l2_trigger(std::abs(cos(angle)) * 255);
  ps4_input_report.set_r2_trigger(std::abs(sin(angle)) * 255);
  ps4_input_report.set_battery_level(8);

  button_index = (button_index % num_buttons) + 1;

  // send an input report
  auto report = gamepad_input_report.get_report();
  logger.info("{}", gamepad_input_report);
  logger.info("Gamepad Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = switch_pro_input_report.get_report();
  logger.info("{}", switch_pro_input_report);
  logger.info("Switch Pro Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_simple_input_report.get_report();
  logger.info("{}", dualsense_simple_input_report);
  logger.info("Playstation Dualsense BLE Simple Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  report = dualsense_complex_input_report.get_report();
  logger.info("{}", dualsense_complex_input_report);
  logger.info("Playstation Dualsense BLE Complex Input report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

  // update the battery input report
  battery_input_report.reset();
  battery_input_report.set_rechargeable(true);
  battery_input_report.set_charging(false);
  battery_input_report.set_rechargeable(true);
  // note: it can only show 5, 40, 70, 100 so this will be rounded to 40
  battery_input_report.set_battery_level(50);

  // send a battery report
  report = battery_input_report.get_report();
  logger.info("Battery report:");
  logger.info("  Size: {}", report.size());
  logger.info("  Data: {::#02X}", report);

Public Types

enum class Error

The possible errors for the battery.

Values:

enumerator NONE

No error.

enumerator BATTERY_LOW

The battery is low.

enumerator BATTERY_CRITICAL

The battery is critically low.

Public Functions

inline constexpr void reset()

Reset the battery status.

inline constexpr void set_rechargeable(bool rechargeable)

Set whether the battery is rechargeable

Parameters:

rechargeable – True if the battery is rechargeable, false otherwise.

inline constexpr void set_battery_level(int level)

Set the battery level

Parameters:

level – The battery level as a percentage, from 0 to 100.

inline constexpr void set_cable_connected(bool connected)

Set whether the battery is connected to a cable

Parameters:

connected – True if the battery is connected to a cable, false otherwise.

inline constexpr void set_charging(bool charging)

Set whether the battery is charging

Parameters:

charging – True if the battery is charging, false otherwise.

inline constexpr void set_error(Error error)

Set the error state of the battery

Parameters:

error – The error state of the battery.

inline constexpr auto get_report() const

Get the input report as a vector of bytes

Note

The report id is not included in the returned vector.

Returns:

The input report as a vector of bytes.

inline constexpr auto set_data(const std::vector<uint8_t> &data)

Set the input report data from a vector of bytes

Parameters:

data – The data to set the input report to.

Public Static Functions

static inline constexpr auto get_descriptor()

Get the report descriptor as a hid::rdf::descriptor

Note

This is an incomplete descriptor, you will need to add it to a collection::application descriptor to create a complete report descriptor.

Returns:

The report descriptor as a hid::rdf::descriptor.