Merge pull request #93 from awalol/refactor/state_mgr
Refactor: unified Controller SetStateData
This commit is contained in:
@@ -87,6 +87,7 @@ add_executable(ds5-bridge
|
|||||||
src/bt.cpp
|
src/bt.cpp
|
||||||
src/config.cpp
|
src/config.cpp
|
||||||
src/cmd.cpp
|
src/cmd.cpp
|
||||||
|
src/state_mgr.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ENABLE_BATT_LED)
|
if (ENABLE_BATT_LED)
|
||||||
|
|||||||
+15
-7
@@ -14,6 +14,7 @@
|
|||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
#include "pico/util/queue.h"
|
#include "pico/util/queue.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "state_mgr.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
#define INPUT_CHANNELS 4
|
#define INPUT_CHANNELS 4
|
||||||
@@ -116,20 +117,27 @@ void audio_loop() {
|
|||||||
pkt[8] = buf_len; // 这 4 个字节的作用未知,调整没有效果
|
pkt[8] = buf_len; // 这 4 个字节的作用未知,调整没有效果
|
||||||
pkt[9] = buf_len; // audio buffer length 只有调整这个字节生效。
|
pkt[9] = buf_len; // audio buffer length 只有调整这个字节生效。
|
||||||
pkt[10] = packetCounter++;
|
pkt[10] = packetCounter++;
|
||||||
pkt[11] = 0x12 | 0 << 6 | 1 << 7;
|
// SetStateData
|
||||||
pkt[12] = SAMPLE_SIZE;
|
pkt[11] = 0x10 | 0 << 6 | 1 << 7;
|
||||||
memcpy(pkt + 13, haptic_buf, SAMPLE_SIZE);
|
pkt[12] = 63;
|
||||||
|
state_set(pkt + 13,63);
|
||||||
|
// Haptics Audio Data
|
||||||
|
pkt[76] = 0x12 | 0 << 6 | 1 << 7;
|
||||||
|
pkt[77] = SAMPLE_SIZE;
|
||||||
|
memcpy(pkt + 78, haptic_buf, SAMPLE_SIZE);
|
||||||
#if !DISABLE_SPEAKER_PROC
|
#if !DISABLE_SPEAKER_PROC
|
||||||
pkt[77] = (plug_headset ? 0x16 : 0x13) | 0 << 6 | 1 << 7; // Speaker: 0x13
|
// Speaker Audio Data
|
||||||
|
pkt[142] = (plug_headset ? 0x16 : 0x13) | 0 << 6 | 1 << 7; // Speaker: 0x13
|
||||||
// L Headset Mono: 0x14
|
// L Headset Mono: 0x14
|
||||||
// L Headset R Speaker: 0x15
|
// L Headset R Speaker: 0x15
|
||||||
// Headset: 0x16
|
// Headset: 0x16
|
||||||
pkt[78] = 200;
|
pkt[143] = 200;
|
||||||
critical_section_enter_blocking(&opus_cs);
|
critical_section_enter_blocking(&opus_cs);
|
||||||
memcpy(pkt + 79, opus_buf, 200);
|
memcpy(pkt + 144, opus_buf, 200);
|
||||||
critical_section_exit(&opus_cs);
|
critical_section_exit(&opus_cs);
|
||||||
#endif
|
#endif
|
||||||
bt_write(pkt, sizeof(pkt), true);
|
|
||||||
|
bt_write(pkt, sizeof(pkt));
|
||||||
haptic_buf_pos = 0;
|
haptic_buf_pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-39
@@ -16,6 +16,7 @@
|
|||||||
#include "bsp/board_api.h"
|
#include "bsp/board_api.h"
|
||||||
#include "classic/sdp_server.h"
|
#include "classic/sdp_server.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "state_mgr.h"
|
||||||
#include "pico/util/queue.h"
|
#include "pico/util/queue.h"
|
||||||
|
|
||||||
#define MTU_CONTROL 672
|
#define MTU_CONTROL 672
|
||||||
@@ -41,7 +42,6 @@ static bool check_dse = false;
|
|||||||
static int8_t bt_rssi = 0;
|
static int8_t bt_rssi = 0;
|
||||||
unordered_map<uint8_t, vector<uint8_t> > feature_data;
|
unordered_map<uint8_t, vector<uint8_t> > feature_data;
|
||||||
queue_t send_fifo;
|
queue_t send_fifo;
|
||||||
queue_t priority_send_fifo;
|
|
||||||
|
|
||||||
struct send_element {
|
struct send_element {
|
||||||
uint8_t data[512];
|
uint8_t data[512];
|
||||||
@@ -101,7 +101,6 @@ void bt_l2cap_init() {
|
|||||||
|
|
||||||
int bt_init() {
|
int bt_init() {
|
||||||
queue_init(&send_fifo, sizeof(send_element), 10);
|
queue_init(&send_fifo, sizeof(send_element), 10);
|
||||||
queue_init(&priority_send_fifo, sizeof(send_element), 10);
|
|
||||||
|
|
||||||
bt_l2cap_init();
|
bt_l2cap_init();
|
||||||
|
|
||||||
@@ -448,30 +447,19 @@ static void l2cap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
|||||||
|
|
||||||
init_feature();
|
init_feature();
|
||||||
// 初始化手柄状态
|
// 初始化手柄状态
|
||||||
uint8_t report32[142];
|
uint8_t report32[142]{};
|
||||||
report32[0] = 0x32;
|
report32[0] = 0x32;
|
||||||
report32[1] = 0x10; // reportSeqCounter
|
report32[1] = 0x10; // reportSeqCounter
|
||||||
uint8_t packet_0x10[] =
|
report32[2] = 0x10 | 0 << 6 | 1 << 7;
|
||||||
{
|
report32[3] = 0x3f; // 63 bytes
|
||||||
0x90, // Packet: 0x10
|
state_set(report32 + 4,sizeof(SetStateData));
|
||||||
0x3f, // 63
|
|
||||||
// SetStateData
|
|
||||||
0xfd, 0xf7, 0x0, 0x0,
|
|
||||||
0x7f, 0x7f, // Headphones, Speaker
|
|
||||||
0xff, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
||||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
||||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
||||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa,
|
|
||||||
0x7, 0x0, 0x0, 0x2, 0x1,
|
|
||||||
0x00,
|
|
||||||
0xff, 0xd7, 0x00 // RGB LED: R, G, B (Nijika Color!)✨
|
|
||||||
};
|
|
||||||
memcpy(report32 + 2, packet_0x10, sizeof(packet_0x10));
|
|
||||||
bt_write(report32, sizeof(report32));
|
bt_write(report32, sizeof(report32));
|
||||||
|
|
||||||
const auto mtu = l2cap_get_remote_mtu_for_local_cid(hid_interrupt_cid);
|
const auto mtu = l2cap_get_remote_mtu_for_local_cid(hid_interrupt_cid);
|
||||||
printf("[L2CAP] Remote Interrupt MTU: %d\n",mtu);
|
printf("[L2CAP] Remote Interrupt MTU: %d\n",mtu);
|
||||||
|
|
||||||
|
gap_connectable_control(false);
|
||||||
|
gap_discoverable_control(false);
|
||||||
// tud_connect();
|
// tud_connect();
|
||||||
} else {
|
} else {
|
||||||
printf("[L2CAP] Unknown Channel psm: 0x%02X", psm);
|
printf("[L2CAP] Unknown Channel psm: 0x%02X", psm);
|
||||||
@@ -521,19 +509,13 @@ static void l2cap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
|||||||
// printf("[L2CAP] L2CAP_EVENT_CAN_SEND_NOW\n");
|
// printf("[L2CAP] L2CAP_EVENT_CAN_SEND_NOW\n");
|
||||||
|
|
||||||
send_element send_packet{};
|
send_element send_packet{};
|
||||||
bool get_data = false;
|
if (queue_try_remove(&send_fifo, &send_packet)) {
|
||||||
if (!queue_is_empty(&priority_send_fifo)) {
|
|
||||||
get_data = queue_try_remove(&priority_send_fifo, &send_packet);
|
|
||||||
}else {
|
|
||||||
get_data = queue_try_remove(&send_fifo, &send_packet);
|
|
||||||
}
|
|
||||||
if (get_data) {
|
|
||||||
const uint8_t status = l2cap_send(hid_interrupt_cid, send_packet.data, send_packet.len);
|
const uint8_t status = l2cap_send(hid_interrupt_cid, send_packet.data, send_packet.len);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
printf("[L2CAP] L2CAP Send Error, Status: 0x%02X\n", status);
|
printf("[L2CAP] L2CAP Send Error, Status: 0x%02X\n", status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!queue_is_empty(&priority_send_fifo) || !queue_is_empty(&send_fifo)) {
|
if (!queue_is_empty(&send_fifo)) {
|
||||||
l2cap_request_can_send_now_event(hid_interrupt_cid);
|
l2cap_request_can_send_now_event(hid_interrupt_cid);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -541,7 +523,7 @@ static void l2cap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_write(const uint8_t *data, const uint16_t len, const bool priority) {
|
void bt_write(const uint8_t *data, const uint16_t len) {
|
||||||
if (hid_interrupt_cid == 0) return;
|
if (hid_interrupt_cid == 0) return;
|
||||||
static send_element packet{};
|
static send_element packet{};
|
||||||
memset(packet.data, 0, 512);
|
memset(packet.data, 0, 512);
|
||||||
@@ -550,18 +532,11 @@ void bt_write(const uint8_t *data, const uint16_t len, const bool priority) {
|
|||||||
memcpy(packet.data + 1, data, len);
|
memcpy(packet.data + 1, data, len);
|
||||||
fill_output_report_checksum(packet.data + 1, len);
|
fill_output_report_checksum(packet.data + 1, len);
|
||||||
|
|
||||||
if (priority) {
|
if (!queue_try_add(&send_fifo, &packet)) {
|
||||||
if (!queue_try_add(&priority_send_fifo, &packet)) {
|
printf("[L2CAP bt_write] Error: Failed to add packet to send FIFO\n");
|
||||||
printf("[L2CAP bt_write] Error: Failed to add packet to priority send FIFO\n");
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
if (!queue_try_add(&send_fifo, &packet)) {
|
|
||||||
printf("[L2CAP bt_write] Error: Failed to add packet to send FIFO\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (queue_get_level(&send_fifo) + queue_get_level(&priority_send_fifo) == 1) {
|
if (queue_get_level(&send_fifo) == 1) {
|
||||||
l2cap_request_can_send_now_event(hid_interrupt_cid);
|
l2cap_request_can_send_now_event(hid_interrupt_cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ int bt_init();
|
|||||||
void bt_register_data_callback(bt_data_callback_t callback);
|
void bt_register_data_callback(bt_data_callback_t callback);
|
||||||
void bt_send_packet(uint8_t *data, uint16_t len);
|
void bt_send_packet(uint8_t *data, uint16_t len);
|
||||||
void bt_send_control(uint8_t *data, uint16_t len);
|
void bt_send_control(uint8_t *data, uint16_t len);
|
||||||
void bt_write(const uint8_t *data, uint16_t len, bool priority = false);
|
void bt_write(const uint8_t *data, uint16_t len);
|
||||||
void bt_get_signal_strength(int8_t *rssi);
|
void bt_get_signal_strength(int8_t *rssi);
|
||||||
std::vector<uint8_t> get_feature_data(uint8_t reportId,uint16_t len);
|
std::vector<uint8_t> get_feature_data(uint8_t reportId,uint16_t len);
|
||||||
void init_feature();
|
void init_feature();
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ struct __attribute__((packed)) Config_body {
|
|||||||
uint8_t config_version; // Config Version
|
uint8_t config_version; // Config Version
|
||||||
float haptics_gain; // [1.0,2.0]
|
float haptics_gain; // [1.0,2.0]
|
||||||
float speaker_volume; // [-100,0]
|
float speaker_volume; // [-100,0]
|
||||||
uint8_t inactive_time; // [10,60] min
|
uint8_t inactive_time; // [5,60] min
|
||||||
uint8_t disable_inactive_disconnect; // bool: 0 disable,1 enable
|
uint8_t disable_inactive_disconnect; // bool: 0 disable,1 enable
|
||||||
uint8_t disable_pico_led; // bool
|
uint8_t disable_pico_led; // bool
|
||||||
uint8_t polling_rate_mode; // 0: 250Hz, 1: 500Hz, 2: real-time
|
uint8_t polling_rate_mode; // 0: 250Hz, 1: 500Hz, 2: real-time
|
||||||
|
|||||||
+11
-2
@@ -12,6 +12,7 @@
|
|||||||
#include "hardware/vreg.h"
|
#include "hardware/vreg.h"
|
||||||
#include "hardware/watchdog.h"
|
#include "hardware/watchdog.h"
|
||||||
#include "pico/cyw43_arch.h"
|
#include "pico/cyw43_arch.h"
|
||||||
|
#include "state_mgr.h"
|
||||||
#if ENABLE_SERIAL
|
#if ENABLE_SERIAL
|
||||||
#include "pico/stdio_usb.h"
|
#include "pico/stdio_usb.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
|
|
||||||
int reportSeqCounter = 0;
|
int reportSeqCounter = 0;
|
||||||
uint8_t packetCounter = 0;
|
uint8_t packetCounter = 0;
|
||||||
|
bool spk_active = false;
|
||||||
|
|
||||||
uint8_t interrupt_in_data[63] = {
|
uint8_t interrupt_in_data[63] = {
|
||||||
0x7f, 0x7d, 0x7f, 0x7e, 0x00, 0x00, 0xa7,
|
0x7f, 0x7d, 0x7f, 0x7e, 0x00, 0x00, 0xa7,
|
||||||
@@ -140,6 +142,7 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_reques
|
|||||||
|
|
||||||
if (itf == 1) {
|
if (itf == 1) {
|
||||||
printf("[AUDIO] Set interface Speaker to alternate setting %d\n", alt);
|
printf("[AUDIO] Set interface Speaker to alternate setting %d\n", alt);
|
||||||
|
spk_active = alt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -165,14 +168,19 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
|
|||||||
if (report_id == 0) {
|
if (report_id == 0) {
|
||||||
switch (buffer[0]) {
|
switch (buffer[0]) {
|
||||||
case 0x02: {
|
case 0x02: {
|
||||||
uint8_t outputData[78];
|
state_update(buffer + 1, bufsize - 1);
|
||||||
|
if (spk_active) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint8_t outputData[78]{};
|
||||||
outputData[0] = 0x31;
|
outputData[0] = 0x31;
|
||||||
outputData[1] = reportSeqCounter << 4;
|
outputData[1] = reportSeqCounter << 4;
|
||||||
if (++reportSeqCounter == 256) {
|
if (++reportSeqCounter == 256) {
|
||||||
reportSeqCounter = 0;
|
reportSeqCounter = 0;
|
||||||
}
|
}
|
||||||
outputData[2] = 0x10;
|
outputData[2] = 0x10;
|
||||||
memcpy(outputData + 3, buffer + 1, bufsize - 1);
|
// memcpy(outputData + 3, buffer + 1, bufsize - 1);
|
||||||
|
state_set(outputData + 3,sizeof(SetStateData));
|
||||||
bt_write(outputData, sizeof(outputData));
|
bt_write(outputData, sizeof(outputData));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -243,6 +251,7 @@ int main() {
|
|||||||
bt_register_data_callback(on_bt_data);
|
bt_register_data_callback(on_bt_data);
|
||||||
|
|
||||||
audio_init();
|
audio_init();
|
||||||
|
state_init();
|
||||||
|
|
||||||
#if !ENABLE_SERIAL
|
#if !ENABLE_SERIAL
|
||||||
watchdog_enable(1000, true);
|
watchdog_enable(1000, true);
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
//
|
||||||
|
// Created by awalol on 2026/5/15.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr size_t kAudioControlOffset = offsetof(SetStateData, MuteLightMode) - sizeof(uint8_t);
|
||||||
|
constexpr size_t kMuteControlOffset = offsetof(SetStateData, RightTriggerFFB) - sizeof(uint8_t);
|
||||||
|
constexpr size_t kMotorPowerLevelOffset = offsetof(SetStateData, HostTimestamp) + sizeof(uint32_t);
|
||||||
|
constexpr size_t kAudioControl2Offset = kMotorPowerLevelOffset + sizeof(uint8_t);
|
||||||
|
constexpr size_t kHapticLowPassFilterOffset = offsetof(SetStateData, LightFadeAnimation) - 2 * sizeof(uint8_t);
|
||||||
|
constexpr size_t kPlayerIndicatorsOffset = offsetof(SetStateData, LedRed) - sizeof(uint8_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint8_t state_init_data[63] = {
|
||||||
|
0xfd, 0xf7, 0x0, 0x0,
|
||||||
|
0x7f, 0x64, // Headphones, Speaker
|
||||||
|
0xff, 0x9, 0x0, 0x0F, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa,
|
||||||
|
0x7, 0x0, 0x0, 0x2, 0x1,
|
||||||
|
0x00,
|
||||||
|
0xff, 0xd7, 0x00 // RGB LED: R, G, B (Nijika Color!)✨
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t state[63]{};
|
||||||
|
|
||||||
|
void state_init() {
|
||||||
|
memcpy(state, state_init_data, sizeof(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
void state_set(uint8_t *data, const uint8_t size) {
|
||||||
|
if (size > 63) {
|
||||||
|
printf("[StateMgr] Warning: State Set over 63 bytes\n");
|
||||||
|
}
|
||||||
|
memcpy(data, state, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void state_update(const uint8_t *data, const uint8_t size) {
|
||||||
|
if (size < sizeof(SetStateData)) {
|
||||||
|
printf(
|
||||||
|
"[StateMgr] Error: SetStateData at least %u bytes\n",
|
||||||
|
static_cast<unsigned>(sizeof(SetStateData))
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetStateData update{};
|
||||||
|
memcpy(&update, data, sizeof(update));
|
||||||
|
|
||||||
|
const auto copy_if_allowed = [&](const bool allowed, const size_t offset, const size_t length) {
|
||||||
|
if (allowed) {
|
||||||
|
memcpy(state + offset, data + offset, length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto set_bit = [](uint8_t &byte, const int bit, const bool value) {
|
||||||
|
byte = (byte & ~(1 << bit)) | (value << bit);
|
||||||
|
};
|
||||||
|
|
||||||
|
set_bit(state[0], 1, update.UseRumbleNotHaptics);
|
||||||
|
set_bit(state[38], 2, update.EnableImprovedRumbleEmulation);
|
||||||
|
copy_if_allowed(
|
||||||
|
update.EnableRumbleEmulation,
|
||||||
|
offsetof(SetStateData, RumbleEmulationRight),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowHeadphoneVolume,
|
||||||
|
offsetof(SetStateData, VolumeHeadphones),
|
||||||
|
sizeof(update.VolumeHeadphones)
|
||||||
|
);*/
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowSpeakerVolume,
|
||||||
|
offsetof(SetStateData, VolumeSpeaker),
|
||||||
|
sizeof(update.VolumeSpeaker)
|
||||||
|
);*/
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowMicVolume,
|
||||||
|
offsetof(SetStateData, VolumeMic),
|
||||||
|
sizeof(update.VolumeMic)
|
||||||
|
);*/
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowAudioControl,
|
||||||
|
kAudioControlOffset,
|
||||||
|
sizeof(uint8_t)
|
||||||
|
);*/
|
||||||
|
|
||||||
|
copy_if_allowed(
|
||||||
|
update.AllowMuteLight,
|
||||||
|
offsetof(SetStateData, MuteLightMode),
|
||||||
|
sizeof(update.MuteLightMode)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowAudioMute,
|
||||||
|
kMuteControlOffset,
|
||||||
|
sizeof(uint8_t)
|
||||||
|
);*/
|
||||||
|
|
||||||
|
copy_if_allowed(
|
||||||
|
update.AllowRightTriggerFFB,
|
||||||
|
offsetof(SetStateData, RightTriggerFFB),
|
||||||
|
sizeof(update.RightTriggerFFB)
|
||||||
|
);
|
||||||
|
copy_if_allowed(
|
||||||
|
update.AllowLeftTriggerFFB,
|
||||||
|
offsetof(SetStateData, LeftTriggerFFB),
|
||||||
|
sizeof(update.LeftTriggerFFB)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowMotorPowerLevel,
|
||||||
|
kMotorPowerLevelOffset,
|
||||||
|
sizeof(uint8_t)
|
||||||
|
);*/
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowAudioControl2,
|
||||||
|
kAudioControl2Offset,
|
||||||
|
sizeof(uint8_t)
|
||||||
|
);*/
|
||||||
|
/*copy_if_allowed(
|
||||||
|
update.AllowHapticLowPassFilter,
|
||||||
|
kHapticLowPassFilterOffset,
|
||||||
|
sizeof(uint8_t)
|
||||||
|
);*/
|
||||||
|
|
||||||
|
copy_if_allowed(
|
||||||
|
update.AllowColorLightFadeAnimation,
|
||||||
|
offsetof(SetStateData, LightFadeAnimation),
|
||||||
|
sizeof(update.LightFadeAnimation)
|
||||||
|
);
|
||||||
|
copy_if_allowed(
|
||||||
|
update.AllowLightBrightnessChange,
|
||||||
|
offsetof(SetStateData, LightBrightness),
|
||||||
|
sizeof(update.LightBrightness)
|
||||||
|
);
|
||||||
|
copy_if_allowed(
|
||||||
|
update.AllowPlayerIndicators,
|
||||||
|
kPlayerIndicatorsOffset,
|
||||||
|
sizeof(uint8_t)
|
||||||
|
);
|
||||||
|
copy_if_allowed(
|
||||||
|
update.AllowLedColor,
|
||||||
|
offsetof(SetStateData, LedRed),
|
||||||
|
sizeof(update.LedRed) * 3
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by awalol on 2026/5/15.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DS5_BRIDGE_STATE_MGR_H
|
||||||
|
#define DS5_BRIDGE_STATE_MGR_H
|
||||||
|
|
||||||
|
void state_init();
|
||||||
|
void state_set(uint8_t *data, const uint8_t size);
|
||||||
|
void state_update(const uint8_t *data, const uint8_t size);
|
||||||
|
|
||||||
|
#endif //DS5_BRIDGE_STATE_MGR_H
|
||||||
+226
-68
@@ -145,7 +145,7 @@ inline void fill_feature_report_checksum(uint8_t *data, const size_t len) {
|
|||||||
data[len - 1] = (crc >> 24) & 0xFF;
|
data[len - 1] = (crc >> 24) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PowerState : uint8_t {
|
/*enum PowerState : uint8_t {
|
||||||
Discharging = 0x00, // Use PowerPercent
|
Discharging = 0x00, // Use PowerPercent
|
||||||
Charging = 0x01, // Use PowerPercent
|
Charging = 0x01, // Use PowerPercent
|
||||||
Complete = 0x02, // PowerPercent not valid? assume 100%?
|
Complete = 0x02, // PowerPercent not valid? assume 100%?
|
||||||
@@ -167,88 +167,246 @@ enum Direction : uint8_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((packed)) TouchFingerData { // 4
|
struct __attribute__((packed)) TouchFingerData { // 4
|
||||||
/*0.0*/ uint32_t Index : 7;
|
/*0.0#1# uint32_t Index : 7;
|
||||||
/*0.7*/ uint32_t NotTouching : 1;
|
/*0.7#1# uint32_t NotTouching : 1;
|
||||||
/*1.0*/ uint32_t FingerX : 12;
|
/*1.0#1# uint32_t FingerX : 12;
|
||||||
/*2.4*/ uint32_t FingerY : 12;
|
/*2.4#1# uint32_t FingerY : 12;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((packed)) TouchData { // 9
|
struct __attribute__((packed)) TouchData { // 9
|
||||||
/*0*/ TouchFingerData Finger[2];
|
/*0#1# TouchFingerData Finger[2];
|
||||||
/*8*/ uint8_t Timestamp;
|
/*8#1# uint8_t Timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__((packed)) USBGetStateData { // 63
|
struct __attribute__((packed)) USBGetStateData { // 63
|
||||||
/* 0 */ uint8_t LeftStickX;
|
/* 0 #1# uint8_t LeftStickX;
|
||||||
/* 1 */ uint8_t LeftStickY;
|
/* 1 #1# uint8_t LeftStickY;
|
||||||
/* 2 */ uint8_t RightStickX;
|
/* 2 #1# uint8_t RightStickX;
|
||||||
/* 3 */ uint8_t RightStickY;
|
/* 3 #1# uint8_t RightStickY;
|
||||||
/* 4 */ uint8_t TriggerLeft;
|
/* 4 #1# uint8_t TriggerLeft;
|
||||||
/* 5 */ uint8_t TriggerRight;
|
/* 5 #1# uint8_t TriggerRight;
|
||||||
/* 6 */ uint8_t SeqNo; // always 0x01 on BT
|
/* 6 #1# uint8_t SeqNo; // always 0x01 on BT
|
||||||
/* 7.0*/ Direction DPad : 4;
|
/* 7.0#1# Direction DPad : 4;
|
||||||
/* 7.4*/ uint8_t ButtonSquare : 1;
|
/* 7.4#1# uint8_t ButtonSquare : 1;
|
||||||
/* 7.5*/ uint8_t ButtonCross : 1;
|
/* 7.5#1# uint8_t ButtonCross : 1;
|
||||||
/* 7.6*/ uint8_t ButtonCircle : 1;
|
/* 7.6#1# uint8_t ButtonCircle : 1;
|
||||||
/* 7.7*/ uint8_t ButtonTriangle : 1;
|
/* 7.7#1# uint8_t ButtonTriangle : 1;
|
||||||
/* 8.0*/ uint8_t ButtonL1 : 1;
|
/* 8.0#1# uint8_t ButtonL1 : 1;
|
||||||
/* 8.1*/ uint8_t ButtonR1 : 1;
|
/* 8.1#1# uint8_t ButtonR1 : 1;
|
||||||
/* 8.2*/ uint8_t ButtonL2 : 1;
|
/* 8.2#1# uint8_t ButtonL2 : 1;
|
||||||
/* 8.3*/ uint8_t ButtonR2 : 1;
|
/* 8.3#1# uint8_t ButtonR2 : 1;
|
||||||
/* 8.4*/ uint8_t ButtonCreate : 1;
|
/* 8.4#1# uint8_t ButtonCreate : 1;
|
||||||
/* 8.5*/ uint8_t ButtonOptions : 1;
|
/* 8.5#1# uint8_t ButtonOptions : 1;
|
||||||
/* 8.6*/ uint8_t ButtonL3 : 1;
|
/* 8.6#1# uint8_t ButtonL3 : 1;
|
||||||
/* 8.7*/ uint8_t ButtonR3 : 1;
|
/* 8.7#1# uint8_t ButtonR3 : 1;
|
||||||
/* 9.0*/ uint8_t ButtonHome : 1;
|
/* 9.0#1# uint8_t ButtonHome : 1;
|
||||||
/* 9.1*/ uint8_t ButtonPad : 1;
|
/* 9.1#1# uint8_t ButtonPad : 1;
|
||||||
/* 9.2*/ uint8_t ButtonMute : 1;
|
/* 9.2#1# uint8_t ButtonMute : 1;
|
||||||
/* 9.3*/ uint8_t UNK1 : 1; // appears unused
|
/* 9.3#1# uint8_t UNK1 : 1; // appears unused
|
||||||
/* 9.4*/ uint8_t ButtonLeftFunction : 1; // DualSense Edge
|
/* 9.4#1# uint8_t ButtonLeftFunction : 1; // DualSense Edge
|
||||||
/* 9.5*/ uint8_t ButtonRightFunction : 1; // DualSense Edge
|
/* 9.5#1# uint8_t ButtonRightFunction : 1; // DualSense Edge
|
||||||
/* 9.6*/ uint8_t ButtonLeftPaddle : 1; // DualSense Edge
|
/* 9.6#1# uint8_t ButtonLeftPaddle : 1; // DualSense Edge
|
||||||
/* 9.7*/ uint8_t ButtonRightPaddle : 1; // DualSense Edge
|
/* 9.7#1# uint8_t ButtonRightPaddle : 1; // DualSense Edge
|
||||||
/*10 */ uint8_t UNK2; // appears unused
|
/*10 #1# uint8_t UNK2; // appears unused
|
||||||
/*11 */ uint32_t UNK_COUNTER; // Linux driver calls this reserved, tools leak calls the 2 high bytes "random"
|
/*11 #1# uint32_t UNK_COUNTER; // Linux driver calls this reserved, tools leak calls the 2 high bytes "random"
|
||||||
/*15 */ int16_t AngularVelocityX;
|
/*15 #1# int16_t AngularVelocityX;
|
||||||
/*17 */ int16_t AngularVelocityZ;
|
/*17 #1# int16_t AngularVelocityZ;
|
||||||
/*19 */ int16_t AngularVelocityY;
|
/*19 #1# int16_t AngularVelocityY;
|
||||||
/*21 */ int16_t AccelerometerX;
|
/*21 #1# int16_t AccelerometerX;
|
||||||
/*23 */ int16_t AccelerometerY;
|
/*23 #1# int16_t AccelerometerY;
|
||||||
/*25 */ int16_t AccelerometerZ;
|
/*25 #1# int16_t AccelerometerZ;
|
||||||
/*27 */ uint32_t SensorTimestamp;
|
/*27 #1# uint32_t SensorTimestamp;
|
||||||
/*31 */ int8_t Temperature; // reserved2 in Linux driver
|
/*31 #1# int8_t Temperature; // reserved2 in Linux driver
|
||||||
/*32 */ TouchData Touch;
|
/*32 #1# TouchData Touch;
|
||||||
/*41.0*/ uint8_t TriggerRightStopLocation: 4; // trigger stop can be a range from 0 to 9 (F/9.0 for Apple interface)
|
/*41.0#1# uint8_t TriggerRightStopLocation: 4; // trigger stop can be a range from 0 to 9 (F/9.0 for Apple interface)
|
||||||
/*41.4*/ uint8_t TriggerRightStatus: 4;
|
/*41.4#1# uint8_t TriggerRightStatus: 4;
|
||||||
/*42.0*/ uint8_t TriggerLeftStopLocation: 4;
|
/*42.0#1# uint8_t TriggerLeftStopLocation: 4;
|
||||||
/*42.4*/ uint8_t TriggerLeftStatus: 4; // 0 feedbackNoLoad
|
/*42.4#1# uint8_t TriggerLeftStatus: 4; // 0 feedbackNoLoad
|
||||||
// 1 feedbackLoadApplied
|
// 1 feedbackLoadApplied
|
||||||
// 0 weaponReady
|
// 0 weaponReady
|
||||||
// 1 weaponFiring
|
// 1 weaponFiring
|
||||||
// 2 weaponFired
|
// 2 weaponFired
|
||||||
// 0 vibrationNotVibrating
|
// 0 vibrationNotVibrating
|
||||||
// 1 vibrationIsVibrating
|
// 1 vibrationIsVibrating
|
||||||
/*43 */ uint32_t HostTimestamp; // mirrors data from report write
|
/*43 #1# uint32_t HostTimestamp; // mirrors data from report write
|
||||||
/*47.0*/ uint8_t TriggerRightEffect: 4; // Active trigger effect, previously we thought this was status max
|
/*47.0#1# uint8_t TriggerRightEffect: 4; // Active trigger effect, previously we thought this was status max
|
||||||
/*47.4*/ uint8_t TriggerLeftEffect: 4; // 0 for reset and all other effects
|
/*47.4#1# uint8_t TriggerLeftEffect: 4; // 0 for reset and all other effects
|
||||||
// 1 for feedback effect
|
// 1 for feedback effect
|
||||||
// 2 for weapon effect
|
// 2 for weapon effect
|
||||||
// 3 for vibration
|
// 3 for vibration
|
||||||
/*48 */ uint32_t DeviceTimeStamp;
|
/*48 #1# uint32_t DeviceTimeStamp;
|
||||||
/*52.0*/ uint8_t PowerPercent : 4; // 0x00-0x0A
|
/*52.0#1# uint8_t PowerPercent : 4; // 0x00-0x0A
|
||||||
/*52.4*/ PowerState Power : 4;
|
/*52.4#1# PowerState Power : 4;
|
||||||
/*53.0*/ uint8_t PluggedHeadphones : 1;
|
/*53.0#1# uint8_t PluggedHeadphones : 1;
|
||||||
/*53.1*/ uint8_t PluggedMic : 1;
|
/*53.1#1# uint8_t PluggedMic : 1;
|
||||||
/*53.2*/ uint8_t MicMuted: 1; // Mic muted by powersave/mute command
|
/*53.2#1# uint8_t MicMuted: 1; // Mic muted by powersave/mute command
|
||||||
/*53.3*/ uint8_t PluggedUsbData : 1;
|
/*53.3#1# uint8_t PluggedUsbData : 1;
|
||||||
/*53.4*/ uint8_t PluggedUsbPower : 1; // appears that this cannot be 1 if PluggedUsbData is 1
|
/*53.4#1# uint8_t PluggedUsbPower : 1; // appears that this cannot be 1 if PluggedUsbData is 1
|
||||||
/*53.5*/ uint8_t UsbPowerOnBT : 1; // appears this is only 1 if BT connected and USB powered
|
/*53.5#1# uint8_t UsbPowerOnBT : 1; // appears this is only 1 if BT connected and USB powered
|
||||||
/*53.5*/ uint8_t DockDetect : 1;
|
/*53.5#1# uint8_t DockDetect : 1;
|
||||||
/*53.5*/ uint8_t PluggedUnk : 1;
|
/*53.5#1# uint8_t PluggedUnk : 1;
|
||||||
/*54.0*/ uint8_t PluggedExternalMic : 1; // Is external mic active (automatic in mic auto mode)
|
/*54.0#1# uint8_t PluggedExternalMic : 1; // Is external mic active (automatic in mic auto mode)
|
||||||
/*54.1*/ uint8_t HapticLowPassFilter : 1; // Is the Haptic Low-Pass-Filter active?
|
/*54.1#1# uint8_t HapticLowPassFilter : 1; // Is the Haptic Low-Pass-Filter active?
|
||||||
/*54.2*/ uint8_t PluggedUnk3 : 6;
|
/*54.2#1# uint8_t PluggedUnk3 : 6;
|
||||||
/*55 */ uint8_t AesCmac[8];
|
/*55 #1# uint8_t AesCmac[8];
|
||||||
|
};*/
|
||||||
|
|
||||||
|
namespace MuteLight{
|
||||||
|
enum MuteLight : uint8_t {
|
||||||
|
Off = 0,
|
||||||
|
On,
|
||||||
|
Breathing,
|
||||||
|
DoNothing, // literally nothing, this input is ignored,
|
||||||
|
// though it might be a faster blink in other versions
|
||||||
|
NoAction4,
|
||||||
|
NoAction5,
|
||||||
|
NoAction6,
|
||||||
|
NoAction7= 7
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace LightBrightness{
|
||||||
|
enum LightBrightness : uint8_t {
|
||||||
|
Bright = 0,
|
||||||
|
Mid,
|
||||||
|
Dim,
|
||||||
|
NoAction3,
|
||||||
|
NoAction4,
|
||||||
|
NoAction5,
|
||||||
|
NoAction6,
|
||||||
|
NoAction7= 7
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace LightFadeAnimation {
|
||||||
|
enum LightFadeAnimation : uint8_t {
|
||||||
|
Nothing = 0,
|
||||||
|
FadeIn, // from black to blue
|
||||||
|
FadeOut // from blue to black
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct __attribute__((packed)) SetStateData { // 47
|
||||||
|
/* */ // Report Set Flags
|
||||||
|
/* */ // These flags are used to indicate what contents from this report should be processed
|
||||||
|
/* 0.0*/ uint8_t EnableRumbleEmulation: 1; // Suggest halving rumble strength
|
||||||
|
/* 0.1*/ uint8_t UseRumbleNotHaptics: 1; //
|
||||||
|
/* */
|
||||||
|
/* 0.2*/ uint8_t AllowRightTriggerFFB: 1; // Enable setting RightTriggerFFB
|
||||||
|
/* 0.3*/ uint8_t AllowLeftTriggerFFB: 1; // Enable setting LeftTriggerFFB
|
||||||
|
/* */
|
||||||
|
/* 0.4*/ uint8_t AllowHeadphoneVolume: 1; // Enable setting VolumeHeadphones
|
||||||
|
/* 0.5*/ uint8_t AllowSpeakerVolume: 1; // Enable setting VolumeSpeaker
|
||||||
|
/* 0.6*/ uint8_t AllowMicVolume: 1; // Enable setting VolumeMic
|
||||||
|
/* */
|
||||||
|
/* 0.7*/ uint8_t AllowAudioControl: 1; // Enable setting AudioControl section
|
||||||
|
/* 1.0*/ uint8_t AllowMuteLight: 1; // Enable setting MuteLightMode
|
||||||
|
/* 1.1*/ uint8_t AllowAudioMute: 1; // Enable setting MuteControl section
|
||||||
|
/* */
|
||||||
|
/* 1.2*/ uint8_t AllowLedColor: 1; // Enable RGB LED section
|
||||||
|
/* */
|
||||||
|
/* 1.3*/ uint8_t ResetLights: 1; // Release the LEDs from Wireless firmware control
|
||||||
|
/* */ // When in wireless mode this must be signaled to control LEDs
|
||||||
|
/* */ // This cannot be applied during the BT pair animation.
|
||||||
|
/* */ // SDL2 waits until the SensorTimestamp value is >= 10200000
|
||||||
|
/* */ // before pulsing this bit once.
|
||||||
|
/* */
|
||||||
|
/* 1.4*/ uint8_t AllowPlayerIndicators: 1; // Enable setting PlayerIndicators section
|
||||||
|
/* 1.5*/ uint8_t AllowHapticLowPassFilter: 1; // Enable HapticLowPassFilter
|
||||||
|
/* 1.6*/ uint8_t AllowMotorPowerLevel: 1; // MotorPowerLevel reductions for trigger/haptic
|
||||||
|
/* 1.7*/ uint8_t AllowAudioControl2: 1; // Enable setting AudioControl2 section
|
||||||
|
/* */
|
||||||
|
/* 2 */ uint8_t RumbleEmulationRight; // emulates the light weight
|
||||||
|
/* 3 */ uint8_t RumbleEmulationLeft; // emulated the heavy weight
|
||||||
|
/* */
|
||||||
|
/* 4 */ uint8_t VolumeHeadphones; // max 0x7f
|
||||||
|
/* 5 */ uint8_t VolumeSpeaker; // PS5 appears to only use the range 0x3d-0x64
|
||||||
|
/* 6 */ uint8_t VolumeMic; // not linear, seems to max at 64, 0 is fully muted only in chat mode
|
||||||
|
/* */
|
||||||
|
/* */ // AudioControl
|
||||||
|
/* 7.0*/ uint8_t MicSelect: 2; // 0 Auto
|
||||||
|
/* */ // 1 Internal Only
|
||||||
|
/* */ // 2 External Only
|
||||||
|
/* */ // 3 Unclear, sets external mic flag but might use internal mic, do test
|
||||||
|
/* 7.2*/ uint8_t EchoCancelEnable: 1;
|
||||||
|
/* 7.3*/ uint8_t NoiseCancelEnable: 1;
|
||||||
|
/* 7.4*/ uint8_t OutputPathSelect: 2; // 0 L_R_X
|
||||||
|
/* */ // 1 L_L_X
|
||||||
|
/* */ // 2 L_L_R
|
||||||
|
/* */ // 3 X_X_R
|
||||||
|
/* 7.6*/ uint8_t InputPathSelect: 2; // 0 CHAT_ASR
|
||||||
|
/* */ // 1 CHAT_CHAT
|
||||||
|
/* */ // 2 ASR_ASR
|
||||||
|
/* */ // 3 Does Nothing, invalid
|
||||||
|
/* */
|
||||||
|
/* 8 */ MuteLight::MuteLight MuteLightMode;
|
||||||
|
/* */
|
||||||
|
/* */ // MuteControl
|
||||||
|
/* 9.0*/ uint8_t TouchPowerSave: 1;
|
||||||
|
/* 9.1*/ uint8_t MotionPowerSave: 1;
|
||||||
|
/* 9.2*/ uint8_t HapticPowerSave: 1; // AKA BulletPowerSave
|
||||||
|
/* 9.3*/ uint8_t AudioPowerSave: 1;
|
||||||
|
/* 9.4*/ uint8_t MicMute: 1;
|
||||||
|
/* 9.5*/ uint8_t SpeakerMute: 1;
|
||||||
|
/* 9.6*/ uint8_t HeadphoneMute: 1;
|
||||||
|
/* 9.7*/ uint8_t HapticMute: 1; // AKA BulletMute
|
||||||
|
/* */
|
||||||
|
/*10 */ uint8_t RightTriggerFFB[11];
|
||||||
|
/*21 */ uint8_t LeftTriggerFFB[11];
|
||||||
|
/*32 */ uint32_t HostTimestamp; // mirrored into report read
|
||||||
|
/* */
|
||||||
|
/* */ // MotorPowerLevel
|
||||||
|
/*36.0*/ uint8_t TriggerMotorPowerReduction : 4; // 0x0-0x7 (no 0x8?) Applied in 12.5% reductions
|
||||||
|
/*36.4*/ uint8_t RumbleMotorPowerReduction : 4; // 0x0-0x7 (no 0x8?) Applied in 12.5% reductions
|
||||||
|
/* */
|
||||||
|
/* */ // AudioControl2
|
||||||
|
/*37.0*/ uint8_t SpeakerCompPreGain: 3; // additional speaker volume boost
|
||||||
|
/*37.3*/ uint8_t BeamformingEnable: 1; // Probably for MIC given there's 2, might be more bits, can't find what it does
|
||||||
|
/*37.4*/ uint8_t UnkAudioControl2: 4; // some of these bits might apply to the above
|
||||||
|
/* */
|
||||||
|
/*38.0*/ uint8_t AllowLightBrightnessChange: 1; // LED_BRIHTNESS_CONTROL
|
||||||
|
/*38.1*/ uint8_t AllowColorLightFadeAnimation: 1; // LIGHTBAR_SETUP_CONTROL
|
||||||
|
/*38.2*/ uint8_t EnableImprovedRumbleEmulation: 1; // Use instead of EnableRumbleEmulation
|
||||||
|
// requires FW >= 0x0224
|
||||||
|
// No need to halve rumble strength
|
||||||
|
/*38.3*/ uint8_t UNKBITC: 5; // unused
|
||||||
|
/* */
|
||||||
|
/*39.0*/ uint8_t HapticLowPassFilter: 1;
|
||||||
|
/*39.1*/ uint8_t UNKBIT: 7;
|
||||||
|
/* */
|
||||||
|
/*40 */ uint8_t UNKBYTE; // previous notes suggested this was HLPF, was probably off by 1
|
||||||
|
/* */
|
||||||
|
/*41 */ LightFadeAnimation::LightFadeAnimation LightFadeAnimation;
|
||||||
|
/*42 */ LightBrightness::LightBrightness LightBrightness;
|
||||||
|
/* */
|
||||||
|
/* */ // PlayerIndicators
|
||||||
|
/* */ // These bits control the white LEDs under the touch pad.
|
||||||
|
/* */ // Note the reduction in functionality for later revisions.
|
||||||
|
/* */ // Generation 0x03 - Full Functionality
|
||||||
|
/* */ // Generation 0x04 - Mirrored Only
|
||||||
|
/* */ // Suggested detection: (HardwareInfo & 0x00FFFF00) == 0X00000400
|
||||||
|
/* */ //
|
||||||
|
/* */ // Layout used by PS5:
|
||||||
|
/* */ // 0x04 - -x- - Player 1
|
||||||
|
/* */ // 0x06 - x-x - Player 2
|
||||||
|
/* */ // 0x15 x -x- x Player 3
|
||||||
|
/* */ // 0x1B x x-x x Player 4
|
||||||
|
/* */ // 0x1F x xxx x Player 5* (Unconfirmed)
|
||||||
|
/* */ //
|
||||||
|
/* */ // // HW 0x03 // HW 0x04
|
||||||
|
/*43.0*/ uint8_t PlayerLight1 : 1; // x --- - // x --- x
|
||||||
|
/*43.1*/ uint8_t PlayerLight2 : 1; // - x-- - // - x-x -
|
||||||
|
/*43.2*/ uint8_t PlayerLight3 : 1; // - -x- - // - -x- -
|
||||||
|
/*43.3*/ uint8_t PlayerLight4 : 1; // - --x - // - x-x -
|
||||||
|
/*43.4*/ uint8_t PlayerLight5 : 1; // - --- x // x --- x
|
||||||
|
/*43.5*/ uint8_t PlayerLightFade: 1; // if low player lights fade in, if high player lights instantly change
|
||||||
|
/*43.6*/ uint8_t PlayerLightUNK : 2;
|
||||||
|
/* */
|
||||||
|
/* */ // RGB LED
|
||||||
|
/*44 */ uint8_t LedRed;
|
||||||
|
/*45 */ uint8_t LedGreen;
|
||||||
|
/*46 */ uint8_t LedBlue;
|
||||||
|
// Structure ends here though on BT there is padding and a CRC, see ReportOut31
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void print_hex(const uint8_t* data,size_t size) {
|
inline void print_hex(const uint8_t* data,size_t size) {
|
||||||
|
|||||||
Reference in New Issue
Block a user