Merge branch 'master' into feasibility/adapter-parity
This commit is contained in:
commit
604450375d
5 changed files with 214 additions and 7 deletions
|
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
// Local confirmation pulse sent only to the controller that toggled.
|
// Local confirmation pulse sent only to the controller that toggled.
|
||||||
#define SWITCH_ABXY_FEEDBACK_DURATION_MS 120
|
#define SWITCH_ABXY_FEEDBACK_DURATION_MS 120
|
||||||
#define SWITCH_ABXY_FEEDBACK_WEAK_MAGNITUDE 0x80
|
#define SWITCH_ABXY_FEEDBACK_WEAK_MAGNITUDE 0xFF
|
||||||
#define SWITCH_ABXY_FEEDBACK_STRONG_MAGNITUDE 0x80
|
#define SWITCH_ABXY_FEEDBACK_STRONG_MAGNITUDE 0xFF
|
||||||
|
|
||||||
// A longer pulse confirms disabled; a shorter pulse confirms enabled.
|
// A longer pulse confirms disabled; a shorter pulse confirms enabled.
|
||||||
#define SWITCH_MOTION_DISABLED_FEEDBACK_DURATION_MS 180
|
#define SWITCH_MOTION_DISABLED_FEEDBACK_DURATION_MS 180
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -259,10 +259,10 @@ index 0265f93..5c0f2bb 100644
|
||||||
return (psmove_instance_t*)&d->parser_data[0];
|
return (psmove_instance_t*)&d->parser_data[0];
|
||||||
}
|
}
|
||||||
diff --git a/src/components/bluepad32/parser/uni_hid_parser_switch.c b/src/components/bluepad32/parser/uni_hid_parser_switch.c
|
diff --git a/src/components/bluepad32/parser/uni_hid_parser_switch.c b/src/components/bluepad32/parser/uni_hid_parser_switch.c
|
||||||
index 599fc35..c72f056 100644
|
index 599fc35..9f073b4 100644
|
||||||
--- a/src/components/bluepad32/parser/uni_hid_parser_switch.c
|
--- a/src/components/bluepad32/parser/uni_hid_parser_switch.c
|
||||||
+++ b/src/components/bluepad32/parser/uni_hid_parser_switch.c
|
+++ b/src/components/bluepad32/parser/uni_hid_parser_switch.c
|
||||||
@@ -51,7 +51,8 @@ static const int16_t DEFAULT_ACCEL_OFFSET = 0;
|
@@ -51,13 +51,15 @@ static const int16_t DEFAULT_ACCEL_OFFSET = 0;
|
||||||
static const int16_t DEFAULT_ACCEL_SCALE = 16384;
|
static const int16_t DEFAULT_ACCEL_SCALE = 16384;
|
||||||
static const int16_t DEFAULT_GYRO_OFFSET = 0;
|
static const int16_t DEFAULT_GYRO_OFFSET = 0;
|
||||||
static const int16_t DEFAULT_GYRO_SCALE = 13371;
|
static const int16_t DEFAULT_GYRO_SCALE = 13371;
|
||||||
|
|
@ -272,7 +272,97 @@ index 599fc35..c72f056 100644
|
||||||
|
|
||||||
#define SWITCH_FACTORY_IMU_CAL_DATA_SIZE 24
|
#define SWITCH_FACTORY_IMU_CAL_DATA_SIZE 24
|
||||||
static const uint16_t SWITCH_FACTORY_IMU_CAL_DATA_ADDR = 0x6020;
|
static const uint16_t SWITCH_FACTORY_IMU_CAL_DATA_ADDR = 0x6020;
|
||||||
@@ -823,19 +824,26 @@ static void parse_imu(uni_hid_device_t* d, const struct switch_imu_data_s* r) {
|
|
||||||
|
#define SWITCH_DUMP_ROM_DATA_SIZE 24 // Max size is 24
|
||||||
|
#define SWITCH_SETUP_TIMEOUT_MS 800
|
||||||
|
+#define SWITCH_RUMBLE_REFRESH_MS 40
|
||||||
|
#if ENABLE_SPI_FLASH_DUMP
|
||||||
|
static const uint32_t SWITCH_DUMP_ROM_DATA_ADDR_START = 0x20000;
|
||||||
|
static const uint32_t SWITCH_DUMP_ROM_DATA_ADDR_END = 0x30000;
|
||||||
|
@@ -72,6 +74,7 @@ enum switch_state {
|
||||||
|
STATE_READ_FACTORY_IMU_CALIBRATION, // Factory IMU calibration info
|
||||||
|
STATE_SET_FULL_REPORT, // Request report 0x30
|
||||||
|
STATE_ENABLE_IMU, // Enable/Disable gyro/accel
|
||||||
|
+ STATE_ENABLE_RUMBLE, // Enable controller vibration
|
||||||
|
STATE_DUMP_FLASH, // Dump SPI Flash memory
|
||||||
|
STATE_UPDATE_LED, // Update LEDs
|
||||||
|
STATE_READY, // Gamepad setup ready!
|
||||||
|
@@ -111,6 +114,7 @@ enum switch_subcmd {
|
||||||
|
SUBCMD_SPI_FLASH_READ = 0x10,
|
||||||
|
SUBCMD_SET_PLAYER_LEDS = 0x30,
|
||||||
|
SUBCMD_ENABLE_IMU = 0x40,
|
||||||
|
+ SUBCMD_ENABLE_RUMBLE = 0x48,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
@@ -137,6 +141,7 @@ typedef struct switch_instance_s {
|
||||||
|
// Although technically, we can use one timer for delay and duration, easier to debug/maintain if we have two.
|
||||||
|
btstack_timer_source_t rumble_timer_duration;
|
||||||
|
btstack_timer_source_t rumble_timer_delayed_start;
|
||||||
|
+ btstack_timer_source_t rumble_timer_refresh;
|
||||||
|
switch_state_rumble_t rumble_state;
|
||||||
|
|
||||||
|
btstack_timer_source_t setup_timer;
|
||||||
|
@@ -322,6 +327,7 @@ static void fsm_read_user_stick_calibration(struct uni_hid_device_s* d);
|
||||||
|
static void fsm_read_factory_imu_calibration(struct uni_hid_device_s* d);
|
||||||
|
static void fsm_set_full_report(struct uni_hid_device_s* d);
|
||||||
|
static void fsm_enable_imu(struct uni_hid_device_s* d);
|
||||||
|
+static void fsm_enable_rumble(struct uni_hid_device_s* d);
|
||||||
|
static void fsm_update_led(struct uni_hid_device_s* d);
|
||||||
|
static void fsm_ready(struct uni_hid_device_s* d);
|
||||||
|
static void process_reply_read_spi_dump(struct uni_hid_device_s* d, const uint8_t* data, int len);
|
||||||
|
@@ -333,11 +339,16 @@ static void process_reply_set_report_mode(struct uni_hid_device_s* d, const stru
|
||||||
|
static void process_reply_spi_flash_read(struct uni_hid_device_s* d, const struct switch_report_21_s* r, int len);
|
||||||
|
static void process_reply_set_player_leds(struct uni_hid_device_s* d, const struct switch_report_21_s* r, int len);
|
||||||
|
static void process_reply_enable_imu(struct uni_hid_device_s* d, const struct switch_report_21_s* r, int len);
|
||||||
|
+static void process_reply_enable_rumble(struct uni_hid_device_s* d, const struct switch_report_21_s* r, int len);
|
||||||
|
static int32_t calibrate_axis(int32_t v, switch_cal_stick_t cal);
|
||||||
|
static void set_led(uni_hid_device_t* d, uint8_t leds);
|
||||||
|
static void on_switch_set_rumble_on(btstack_timer_source_t* ts);
|
||||||
|
static void on_switch_set_rumble_off(btstack_timer_source_t* ts);
|
||||||
|
+static void on_switch_refresh_rumble(btstack_timer_source_t* ts);
|
||||||
|
static void switch_stop_rumble_now(uni_hid_device_t* d);
|
||||||
|
+static void switch_send_dual_rumble_now(uni_hid_device_t* d,
|
||||||
|
+ uint8_t weak_magnitude,
|
||||||
|
+ uint8_t strong_magnitude);
|
||||||
|
static void switch_play_dual_rumble_now(uni_hid_device_t* d,
|
||||||
|
uint16_t duration_ms,
|
||||||
|
uint8_t weak_magnitude,
|
||||||
|
@@ -451,6 +462,10 @@ static void process_fsm(struct uni_hid_device_s* d) {
|
||||||
|
break;
|
||||||
|
case STATE_ENABLE_IMU:
|
||||||
|
logd("STATE_ENABLE_IMU\n");
|
||||||
|
+ fsm_enable_rumble(d);
|
||||||
|
+ break;
|
||||||
|
+ case STATE_ENABLE_RUMBLE:
|
||||||
|
+ logd("STATE_ENABLE_RUMBLE\n");
|
||||||
|
fsm_dump_rom(d);
|
||||||
|
break;
|
||||||
|
case STATE_DUMP_FLASH:
|
||||||
|
@@ -725,6 +740,12 @@ static void process_reply_enable_imu(struct uni_hid_device_s* d, const struct sw
|
||||||
|
ARG_UNUSED(r);
|
||||||
|
ARG_UNUSED(len);
|
||||||
|
}
|
||||||
|
+static void process_reply_enable_rumble(struct uni_hid_device_s* d, const struct switch_report_21_s* r, int len) {
|
||||||
|
+ ARG_UNUSED(d);
|
||||||
|
+ ARG_UNUSED(r);
|
||||||
|
+ ARG_UNUSED(len);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
|
||||||
|
// Process 0x21 input report: SWITCH_INPUT_SUBCMD_REPLY
|
||||||
|
static void process_input_subcmd_reply(struct uni_hid_device_s* d, const uint8_t* report, int len) {
|
||||||
|
@@ -752,6 +773,9 @@ static void process_input_subcmd_reply(struct uni_hid_device_s* d, const uint8_t
|
||||||
|
case SUBCMD_ENABLE_IMU:
|
||||||
|
process_reply_enable_imu(d, r, len);
|
||||||
|
break;
|
||||||
|
+ case SUBCMD_ENABLE_RUMBLE:
|
||||||
|
+ process_reply_enable_rumble(d, r, len);
|
||||||
|
+ break;
|
||||||
|
default:
|
||||||
|
loge("Switch: Error, unexpected subcmd_id=0x%02x in report 0x21\n", r->subcmd_id);
|
||||||
|
break;
|
||||||
|
@@ -823,19 +847,26 @@ static void parse_imu(uni_hid_device_t* d, const struct switch_imu_data_s* r) {
|
||||||
switch_instance_t* ins = get_switch_instance(d);
|
switch_instance_t* ins = get_switch_instance(d);
|
||||||
uni_controller_t* ctl = &d->controller;
|
uni_controller_t* ctl = &d->controller;
|
||||||
|
|
||||||
|
|
@ -308,7 +398,7 @@ index 599fc35..c72f056 100644
|
||||||
if (ins->controller_type == SWITCH_CONTROLLER_TYPE_JCR) {
|
if (ins->controller_type == SWITCH_CONTROLLER_TYPE_JCR) {
|
||||||
accel[1] = -accel[1];
|
accel[1] = -accel[1];
|
||||||
accel[2] = -accel[2];
|
accel[2] = -accel[2];
|
||||||
@@ -843,10 +851,13 @@ static void parse_imu(uni_hid_device_t* d, const struct switch_imu_data_s* r) {
|
@@ -843,10 +874,13 @@ static void parse_imu(uni_hid_device_t* d, const struct switch_imu_data_s* r) {
|
||||||
gyro[2] = -gyro[2];
|
gyro[2] = -gyro[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,6 +416,121 @@ index 599fc35..c72f056 100644
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process 0x30 input report: SWITCH_INPUT_IMU_DATA
|
// Process 0x30 input report: SWITCH_INPUT_IMU_DATA
|
||||||
|
@@ -1172,6 +1206,18 @@ static void fsm_enable_imu(struct uni_hid_device_s* d) {
|
||||||
|
req->data[0] = (ins->mode == SWITCH_MODE_IMU);
|
||||||
|
send_subcmd(d, req, sizeof(out));
|
||||||
|
}
|
||||||
|
+static void fsm_enable_rumble(struct uni_hid_device_s* d) {
|
||||||
|
+ switch_instance_t* ins = get_switch_instance(d);
|
||||||
|
+ ins->state = STATE_ENABLE_RUMBLE;
|
||||||
|
+
|
||||||
|
+ uint8_t out[sizeof(struct switch_subcmd_request) + 1] = {0};
|
||||||
|
+ struct switch_subcmd_request* req = (struct switch_subcmd_request*)&out[0];
|
||||||
|
+ req->report_id = OUTPUT_RUMBLE_AND_SUBCMD;
|
||||||
|
+ req->subcmd_id = SUBCMD_ENABLE_RUMBLE;
|
||||||
|
+ req->data[0] = 0x01;
|
||||||
|
+ send_subcmd(d, req, sizeof(out));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
|
||||||
|
static void fsm_update_led(struct uni_hid_device_s* d) {
|
||||||
|
switch_instance_t* ins = get_switch_instance(d);
|
||||||
|
@@ -1203,6 +1249,10 @@ static struct switch_rumble_freq_data find_rumble_freq(uint16_t freq) {
|
||||||
|
return rumble_freqs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
+static uint16_t switch_magnitude_to_amp(uint8_t magnitude) {
|
||||||
|
+ return (uint16_t)(((uint32_t)magnitude * 1003 + 127) / 255);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static struct switch_rumble_amp_data find_rumble_amp(uint16_t amp) {
|
||||||
|
unsigned int i = 0;
|
||||||
|
if (amp > rumble_amps[0].amp) {
|
||||||
|
@@ -1259,6 +1309,7 @@ void uni_hid_parser_switch_play_dual_rumble(struct uni_hid_device_s* d,
|
||||||
|
break;
|
||||||
|
case SWITCH_STATE_RUMBLE_IN_PROGRESS:
|
||||||
|
btstack_run_loop_remove_timer(&ins->rumble_timer_duration);
|
||||||
|
+ btstack_run_loop_remove_timer(&ins->rumble_timer_refresh);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
|
@@ -1366,6 +1417,7 @@ static void switch_stop_rumble_now(uni_hid_device_t* d) {
|
||||||
|
|
||||||
|
// No need to protect it with a mutex since it runs in the same main thread
|
||||||
|
assert(ins->rumble_state == SWITCH_STATE_RUMBLE_IN_PROGRESS);
|
||||||
|
+ btstack_run_loop_remove_timer(&ins->rumble_timer_refresh);
|
||||||
|
ins->rumble_state = SWITCH_STATE_RUMBLE_DISABLED;
|
||||||
|
|
||||||
|
struct switch_subcmd_request req = {0};
|
||||||
|
@@ -1379,6 +1431,22 @@ static void switch_stop_rumble_now(uni_hid_device_t* d) {
|
||||||
|
send_subcmd(d, (struct switch_subcmd_request*)&req, sizeof(req) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void switch_send_dual_rumble_now(uni_hid_device_t* d,
|
||||||
|
+ uint8_t weak_magnitude,
|
||||||
|
+ uint8_t strong_magnitude) {
|
||||||
|
+ struct switch_subcmd_request req = {
|
||||||
|
+ .report_id = OUTPUT_RUMBLE_ONLY,
|
||||||
|
+ };
|
||||||
|
+ // Fixed frequencies match the standard Switch LRA envelope and the
|
||||||
|
+ // 8BitDo Switch-mode implementation. Magnitudes control amplitude only.
|
||||||
|
+ switch_encode_rumble(req.rumble_left, 453, 135,
|
||||||
|
+ switch_magnitude_to_amp(weak_magnitude));
|
||||||
|
+ switch_encode_rumble(req.rumble_right, 453, 99,
|
||||||
|
+ switch_magnitude_to_amp(strong_magnitude));
|
||||||
|
+ // Rumble request don't include the last byte of "switch_subcmd_request": subcmd_id
|
||||||
|
+ send_subcmd(d, &req, sizeof(req) - 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void switch_play_dual_rumble_now(uni_hid_device_t* d,
|
||||||
|
uint16_t duration_ms,
|
||||||
|
uint8_t weak_magnitude,
|
||||||
|
@@ -1391,14 +1459,17 @@ static void switch_play_dual_rumble_now(uni_hid_device_t* d,
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- struct switch_subcmd_request req = {
|
||||||
|
- .report_id = OUTPUT_RUMBLE_ONLY,
|
||||||
|
- };
|
||||||
|
- switch_encode_rumble(req.rumble_left, weak_magnitude << 2, weak_magnitude, 500);
|
||||||
|
- switch_encode_rumble(req.rumble_right, strong_magnitude << 2, strong_magnitude, 500);
|
||||||
|
+ ins->rumble_weak_magnitude = weak_magnitude;
|
||||||
|
+ ins->rumble_strong_magnitude = strong_magnitude;
|
||||||
|
+ switch_send_dual_rumble_now(d, weak_magnitude, strong_magnitude);
|
||||||
|
|
||||||
|
- // Rumble request don't include the last byte of "switch_subcmd_request": subcmd_id
|
||||||
|
- send_subcmd(d, &req, sizeof(req) - 1);
|
||||||
|
+ // Refresh active rumble for Switch-compatible controllers that do not
|
||||||
|
+ // retain a single output packet, including 8BitDo Switch mode.
|
||||||
|
+ ins->rumble_timer_refresh.process = &on_switch_refresh_rumble;
|
||||||
|
+ ins->rumble_timer_refresh.context = d;
|
||||||
|
+ btstack_run_loop_set_timer(&ins->rumble_timer_refresh,
|
||||||
|
+ SWITCH_RUMBLE_REFRESH_MS);
|
||||||
|
+ btstack_run_loop_add_timer(&ins->rumble_timer_refresh);
|
||||||
|
|
||||||
|
// Set timer to turn off rumble
|
||||||
|
ins->rumble_timer_duration.process = &on_switch_set_rumble_off;
|
||||||
|
@@ -1414,6 +1485,20 @@ static void on_switch_set_rumble_on(btstack_timer_source_t* ts) {
|
||||||
|
|
||||||
|
switch_play_dual_rumble_now(d, ins->rumble_duration_ms, ins->rumble_weak_magnitude, ins->rumble_strong_magnitude);
|
||||||
|
}
|
||||||
|
+static void on_switch_refresh_rumble(btstack_timer_source_t* ts) {
|
||||||
|
+ uni_hid_device_t* d = btstack_run_loop_get_timer_context(ts);
|
||||||
|
+ switch_instance_t* ins = get_switch_instance(d);
|
||||||
|
+ if (ins->rumble_state != SWITCH_STATE_RUMBLE_IN_PROGRESS) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ switch_send_dual_rumble_now(
|
||||||
|
+ d, (uint8_t)ins->rumble_weak_magnitude,
|
||||||
|
+ (uint8_t)ins->rumble_strong_magnitude);
|
||||||
|
+ btstack_run_loop_set_timer(&ins->rumble_timer_refresh,
|
||||||
|
+ SWITCH_RUMBLE_REFRESH_MS);
|
||||||
|
+ btstack_run_loop_add_timer(&ins->rumble_timer_refresh);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
|
||||||
|
static void on_switch_set_rumble_off(btstack_timer_source_t* ts) {
|
||||||
|
uni_hid_device_t* d = btstack_run_loop_get_timer_context(ts);
|
||||||
diff --git a/src/components/bluepad32/parser/uni_hid_parser_wii.c b/src/components/bluepad32/parser/uni_hid_parser_wii.c
|
diff --git a/src/components/bluepad32/parser/uni_hid_parser_wii.c b/src/components/bluepad32/parser/uni_hid_parser_wii.c
|
||||||
index be2103e..4819639 100644
|
index be2103e..4819639 100644
|
||||||
--- a/src/components/bluepad32/parser/uni_hid_parser_wii.c
|
--- a/src/components/bluepad32/parser/uni_hid_parser_wii.c
|
||||||
|
|
|
||||||
|
|
@ -889,8 +889,10 @@ void test_abxy_hotkey() {
|
||||||
require(slot_zero.rumble_calls == 1 &&
|
require(slot_zero.rumble_calls == 1 &&
|
||||||
slot_zero.last_high == kAbxyFeedbackWeakMagnitude &&
|
slot_zero.last_high == kAbxyFeedbackWeakMagnitude &&
|
||||||
slot_zero.last_low == kAbxyFeedbackStrongMagnitude &&
|
slot_zero.last_low == kAbxyFeedbackStrongMagnitude &&
|
||||||
|
slot_zero.last_high == UINT8_MAX &&
|
||||||
|
slot_zero.last_low == UINT8_MAX &&
|
||||||
g_slots[0].rumble_pending,
|
g_slots[0].rumble_pending,
|
||||||
"ABXY confirmation did not take priority over host rumble");
|
"ABXY confirmation was not full-strength or did not take priority");
|
||||||
|
|
||||||
platform_on_controller_data(&slot_zero, &input);
|
platform_on_controller_data(&slot_zero, &input);
|
||||||
process_rumble_timer(&g_rumble_timer);
|
process_rumble_timer(&g_rumble_timer);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue