diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 0c792a91..d8254695 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -19,6 +19,7 @@ idf_component_register(SRCS "main.c" "adapter/wired/jvs.c" "adapter/wired/n64.c" "adapter/wired/dc.c" + "adapter/wired/joystick_serial_out.c" "adapter/wired/gc.c" "adapter/wired/ps.c" "adapter/wired/sea.c" diff --git a/main/adapter/adapter.c b/main/adapter/adapter.c index 895ee7c9..4bddcfb1 100644 --- a/main/adapter/adapter.c +++ b/main/adapter/adapter.c @@ -437,6 +437,10 @@ void adapter_bridge(struct bt_data *bt_data) { adapter_out_mask[bt_data->base.pids->out_idx] = out_mask = adapter_mapping(&config.in_cfg[bt_data->base.pids->out_idx]); + if (wired_adapter.system_id == JOYSTICK_SERIAL_OUT) { + adapter_debug_joystick_serial_out(bt_data->base.pids->out_idx, bt_data->base.pids->type, &ctrl_output[bt_data->base.pids->out_idx]); + } + #ifdef CONFIG_BLUERETRO_ADAPTER_INPUT_MAP_DBG #ifdef CONFIG_BLUERETRO_JSON_DBG printf("{\"log_type\": \"mapped_input\""); diff --git a/main/adapter/adapter.h b/main/adapter/adapter.h index 228ffd34..7cb12104 100644 --- a/main/adapter/adapter.h +++ b/main/adapter/adapter.h @@ -89,6 +89,7 @@ enum { PARALLEL_1P_OD, PARALLEL_2P_OD, SEA_BOARD, + JOYSTICK_SERIAL_OUT, WIRED_MAX, }; @@ -140,6 +141,24 @@ enum { PAD_RJ, }; +enum { + JOYSTICK_SERIAL_OUT_BTN_LD_LEFT, + JOYSTICK_SERIAL_OUT_BTN_LD_RIGHT, + JOYSTICK_SERIAL_OUT_BTN_LD_DOWN, + JOYSTICK_SERIAL_OUT_BTN_LD_UP, + JOYSTICK_SERIAL_OUT_BTN_RB_LEFT, + JOYSTICK_SERIAL_OUT_BTN_RB_RIGHT, + JOYSTICK_SERIAL_OUT_BTN_RB_DOWN, + JOYSTICK_SERIAL_OUT_BTN_RB_UP, + JOYSTICK_SERIAL_OUT_BTN_MM, + JOYSTICK_SERIAL_OUT_BTN_MS, + JOYSTICK_SERIAL_OUT_BTN_MT, + JOYSTICK_SERIAL_OUT_BTN_LS, + JOYSTICK_SERIAL_OUT_BTN_LJ, + JOYSTICK_SERIAL_OUT_BTN_RS, + JOYSTICK_SERIAL_OUT_BTN_RJ, +}; + /* Stage the Mouse & KB mapping to be a good default when used as a joystick */ enum { KBM_NONE = -1, diff --git a/main/adapter/adapter_debug.c b/main/adapter/adapter_debug.c index 0c3cdd68..78ed836a 100644 --- a/main/adapter/adapter_debug.c +++ b/main/adapter/adapter_debug.c @@ -14,6 +14,7 @@ #include "bluetooth/host.h" #include "bluetooth/hci.h" #include "bluetooth/hidp/hidp.h" +#include #ifdef CONFIG_BLUERETRO_PKT_INJECTION enum { @@ -39,6 +40,8 @@ struct adapter_debug_pkt { static uint8_t uart_buffer[2048]; #endif +static uint64_t lastSerialOut[6]; + #ifdef CONFIG_BLUERETRO_ADAPTER_BTNS_DBG static void adapter_debug_btns(int32_t value) { uint32_t b = value; @@ -191,6 +194,44 @@ void adapter_debug_wireless_print(struct wireless_ctrl *ctrl_input) { #endif } +void adapter_debug_joystick_serial_out(int32_t out_idx, int32_t type, struct wired_ctrl *ctrl_input) { + uint64_t currentTime = esp_timer_get_time(); + uint64_t durationSinceLastUpdate = currentTime - lastSerialOut[out_idx]; + + uint32_t b = ctrl_input->btns[0].value; + uint32_t buttonValues = 0; + + if (b & BIT(PAD_LD_LEFT)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_LD_LEFT); + if (b & BIT(PAD_LD_RIGHT)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_LD_RIGHT); + if (b & BIT(PAD_LD_DOWN)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_LD_DOWN); + if (b & BIT(PAD_LD_UP)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_LD_UP); + + if (b & BIT(PAD_RB_LEFT)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_RB_LEFT); + if (b & BIT(PAD_RB_RIGHT)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_RB_RIGHT); + if (b & BIT(PAD_RB_DOWN)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_RB_DOWN); + if (b & BIT(PAD_RB_UP)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_RB_UP); + + if (b & BIT(PAD_MS)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_MS); + if (b & BIT(PAD_MM)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_MM); + if (b & BIT(PAD_MT)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_MT); + + if (b & BIT(PAD_LS)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_LS); + if (b & BIT(PAD_LJ)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_LJ); + if (b & BIT(PAD_RS)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_RS); + if (b & BIT(PAD_RJ)) buttonValues |= BIT(JOYSTICK_SERIAL_OUT_BTN_RJ); + + // type 3 controllers like 8bitdo pro/pro+ and Xbox One only send updates when there are changes so we should always process these messages + // other controller types send messages continuously so we want to limit based on duration to avoid sending too much serial data + if (type == 3 || durationSinceLastUpdate > 3000) + { + lastSerialOut[out_idx] = currentTime; + + printf("[%ld%5lu%4ld%4ld%4ld%4ld%3ld%3ld]\n", out_idx, buttonValues, + ctrl_input->axes[0].value, ctrl_input->axes[1].value, ctrl_input->axes[2].value, + ctrl_input->axes[3].value, ctrl_input->axes[4].value, ctrl_input->axes[5].value); + } +} + void adapter_debug_wired_print(struct wired_ctrl *ctrl_input) { #ifdef CONFIG_BLUERETRO_JSON_DBG printf(", \"axes\": [%ld, %ld, %ld, %ld, %lu, %lu], \"btns\": [%lu, %lu, %lu, %lu]}\n", diff --git a/main/adapter/adapter_debug.h b/main/adapter/adapter_debug.h index a3e60b99..c904fd74 100644 --- a/main/adapter/adapter_debug.h +++ b/main/adapter/adapter_debug.h @@ -7,6 +7,7 @@ #define _ADAPTER_DEBUG_H_ void adapter_debug_wireless_print(struct wireless_ctrl *ctrl_input); +void adapter_debug_joystick_serial_out(int32_t out_idx, int32_t type, struct wired_ctrl *ctrl_input); void adapter_debug_wired_print(struct wired_ctrl *ctrl_input); void adapter_debug_injector_init(void); diff --git a/main/adapter/wired/joystick_serial_out.c b/main/adapter/wired/joystick_serial_out.c new file mode 100644 index 00000000..6bd290ef --- /dev/null +++ b/main/adapter/wired/joystick_serial_out.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2019-2023, Jacques Gagnon + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "zephyr/types.h" +#include "tools/util.h" +#include "adapter/config.h" +#include "adapter/kb_monitor.h" +#include "adapter/wired/wired.h" +#include "joystick_serial_out.h" + +enum { + JOYSTICK_SERIAL_OUT_SELECT = 0, + JOYSTICK_SERIAL_OUT_L3, + JOYSTICK_SERIAL_OUT_R3, + JOYSTICK_SERIAL_OUT_START, + JOYSTICK_SERIAL_OUT_D_UP, + JOYSTICK_SERIAL_OUT_D_RIGHT, + JOYSTICK_SERIAL_OUT_D_DOWN, + JOYSTICK_SERIAL_OUT_D_LEFT, + JOYSTICK_SERIAL_OUT_L2, + JOYSTICK_SERIAL_OUT_R2, + JOYSTICK_SERIAL_OUT_L1, + JOYSTICK_SERIAL_OUT_R1, + JOYSTICK_SERIAL_OUT_Y, + JOYSTICK_SERIAL_OUT_B, + JOYSTICK_SERIAL_OUT_A, + JOYSTICK_SERIAL_OUT_X, +}; + +static DRAM_ATTR const uint8_t joystick_serial_out_axes_idx[ADAPTER_MAX_AXES] = +{ +/* AXIS_LX, AXIS_LY, AXIS_RX, AXIS_RY, TRIG_L, TRIG_R */ + 0, 1, 2, 3, 4, 5 +}; + +static DRAM_ATTR const struct ctrl_meta joystick_serial_out_axes_meta[ADAPTER_MAX_AXES] = +{ + {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x7F, .abs_min = 0x80}, + {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x7F, .abs_min = 0x80, .polarity = 1}, + {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x7F, .abs_min = 0x80}, + {.size_min = -128, .size_max = 127, .neutral = 0x80, .abs_max = 0x7F, .abs_min = 0x80, .polarity = 1}, + {.size_min = 0, .size_max = 255, .neutral = 0x00, .abs_max = 0xFF, .abs_min = 0x00}, + {.size_min = 0, .size_max = 255, .neutral = 0x00, .abs_max = 0xFF, .abs_min = 0x00}, +}; + +struct joystick_serial_out_map { + uint16_t buttons; + uint8_t axes[6]; +} __packed; + +static const uint32_t joystick_serial_out_mask[4] = {0xBB7F0FFF, 0x00000000, 0x00000000, BR_COMBO_MASK}; +static const uint32_t joystick_serial_out_desc[4] = {0x110000FF, 0x00000000, 0x00000000, 0x00000000}; +static DRAM_ATTR const uint32_t joystick_serial_out_btns_mask[32] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + BIT(JOYSTICK_SERIAL_OUT_D_LEFT), BIT(JOYSTICK_SERIAL_OUT_D_RIGHT), BIT(JOYSTICK_SERIAL_OUT_D_DOWN), BIT(JOYSTICK_SERIAL_OUT_D_UP), + 0, 0, 0, 0, + BIT(JOYSTICK_SERIAL_OUT_X), BIT(JOYSTICK_SERIAL_OUT_B), BIT(JOYSTICK_SERIAL_OUT_A), BIT(JOYSTICK_SERIAL_OUT_Y), + BIT(JOYSTICK_SERIAL_OUT_START), BIT(JOYSTICK_SERIAL_OUT_SELECT), 0, 0, + 0, BIT(JOYSTICK_SERIAL_OUT_L1), 0, BIT(JOYSTICK_SERIAL_OUT_L3), + 0, BIT(JOYSTICK_SERIAL_OUT_R1), 0, BIT(JOYSTICK_SERIAL_OUT_R3), +}; + +void IRAM_ATTR joystick_serial_out_init_buffer(int32_t dev_mode, struct wired_data *wired_data) { + struct joystick_serial_out_map *map = (struct joystick_serial_out_map *)wired_data->output; + struct joystick_serial_out_map *map_mask = (struct joystick_serial_out_map *)wired_data->output_mask; + memset((void *)map, 0, sizeof(*map)); + + map->buttons = 0xFFFF; + map_mask->buttons = 0x0000; + for (uint32_t i = 0; i < ADAPTER_MAX_AXES; i++) { + map->axes[joystick_serial_out_axes_idx[i]] = joystick_serial_out_axes_meta[i].neutral; + } + memset(map_mask->axes, 0x00, sizeof(map_mask->axes)); +} + +void joystick_serial_out_meta_init(struct wired_ctrl *ctrl_data) { + memset((void *)ctrl_data, 0, sizeof(*ctrl_data)*WIRED_MAX_DEV); + + for (uint32_t i = 0; i < WIRED_MAX_DEV; i++) { + for (uint32_t j = 0; j < ADAPTER_MAX_AXES; j++) { + ctrl_data[i].mask = joystick_serial_out_mask; + ctrl_data[i].desc = joystick_serial_out_desc; + ctrl_data[i].axes[j].meta = &joystick_serial_out_axes_meta[j]; + } + } +} + +static void joystick_serial_out_ctrl_from_generic(struct wired_ctrl *ctrl_data, struct wired_data *wired_data) { + struct joystick_serial_out_map map_tmp; + uint32_t map_mask = 0xFFFF; + + memcpy((void *)&map_tmp, wired_data->output, sizeof(map_tmp)); + + for (uint32_t i = 0; i < ARRAY_SIZE(generic_btns_mask); i++) { + if (ctrl_data->map_mask[0] & generic_btns_mask[i]) { + if (ctrl_data->btns[0].value & generic_btns_mask[i]) { + map_tmp.buttons |= joystick_serial_out_btns_mask[i]; + map_mask &= ~joystick_serial_out_btns_mask[i]; + wired_data->cnt_mask[i] = ctrl_data->btns[0].cnt_mask[i]; + } + else if (map_mask & joystick_serial_out_btns_mask[i]) { + map_tmp.buttons &= ~joystick_serial_out_btns_mask[i]; + wired_data->cnt_mask[i] = 0; + } + } + } + + for (uint32_t i = 0; i < ADAPTER_MAX_AXES; i++) { + if (ctrl_data->map_mask[0] & (axis_to_btn_mask(i) & joystick_serial_out_desc[0])) { + if (ctrl_data->axes[i].value > ctrl_data->axes[i].meta->size_max) { + map_tmp.axes[joystick_serial_out_axes_idx[i]] = 255; + } + else if (ctrl_data->axes[i].value < ctrl_data->axes[i].meta->size_min) { + map_tmp.axes[joystick_serial_out_axes_idx[i]] = 0; + } + else { + map_tmp.axes[joystick_serial_out_axes_idx[i]] = (uint8_t)(ctrl_data->axes[i].value + ctrl_data->axes[i].meta->neutral); + } + } + wired_data->cnt_mask[axis_to_btn_id(i)] = ctrl_data->axes[i].cnt_mask; + } + + memcpy(wired_data->output, (void *)&map_tmp, sizeof(map_tmp)); +#ifdef CONFIG_BLUERETRO_RAW_OUTPUT + printf("{\"log_type\": \"wired_output\", \"axes\": [%d, %d, %d, %d, %d, %d], \"btns\": [%d]}\n", + map_tmp.axes[joystick_serial_out_axes_idx[0]], map_tmp.axes[joystick_serial_out_axes_idx[1]], + map_tmp.axes[joystick_serial_out_axes_idx[2]], map_tmp.axes[joystick_serial_out_axes_idx[3]], + map_tmp.axes[joystick_serial_out_axes_idx[4]], map_tmp.axes[joystick_serial_out_axes_idx[5]], + map_tmp.buttons); +#endif +} + +void joystick_serial_out_from_generic(int32_t dev_mode, struct wired_ctrl *ctrl_data, struct wired_data *wired_data) { + joystick_serial_out_ctrl_from_generic(ctrl_data, wired_data); +} + +void IRAM_ATTR joystick_serial_out_gen_turbo_mask(struct wired_data *wired_data) { + struct joystick_serial_out_map *map_mask = (struct joystick_serial_out_map *)wired_data->output_mask; + + map_mask->buttons = 0xFFFF; + memset(map_mask->axes, 0x00, sizeof(map_mask->axes)); + + wired_gen_turbo_mask_btns16_pos(wired_data, &map_mask->buttons, joystick_serial_out_btns_mask); + wired_gen_turbo_mask_axes8(wired_data, map_mask->axes, ADAPTER_MAX_AXES, joystick_serial_out_axes_idx, joystick_serial_out_axes_meta); +} \ No newline at end of file diff --git a/main/adapter/wired/joystick_serial_out.h b/main/adapter/wired/joystick_serial_out.h new file mode 100644 index 00000000..7573e4c4 --- /dev/null +++ b/main/adapter/wired/joystick_serial_out.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2019-2022, Jacques Gagnon + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _JOYSTICK_SERIAL_OUT_H_ +#define _JOYSTICK_SERIAL_OUT_H_ +#include "adapter/adapter.h" + +void joystick_serial_out_meta_init(struct wired_ctrl *ctrl_data); +void joystick_serial_out_init_buffer(int32_t dev_mode, struct wired_data *wired_data); +void joystick_serial_out_from_generic(int32_t dev_mode, struct wired_ctrl *ctrl_data, struct wired_data *wired_data); +void joystick_serial_out_gen_turbo_mask(struct wired_data *wired_data); + +#endif /* _JOYSTICK_SERIAL_OUT_H_ */ diff --git a/main/adapter/wired/wired.c b/main/adapter/wired/wired.c index 9098c1d0..985160db 100644 --- a/main/adapter/wired/wired.c +++ b/main/adapter/wired/wired.c @@ -19,6 +19,7 @@ #include "jvs.h" #include "n64.h" #include "dc.h" +#include "joystick_serial_out.h" #include "gc.h" #include "parallel_1p.h" #include "parallel_2p.h" @@ -51,6 +52,7 @@ static from_generic_t from_generic_func[WIRED_MAX] = { para_1p_from_generic, /* PARALLEL_1P_OD */ para_2p_from_generic, /* PARALLEL_2P_OD */ sea_from_generic, /* SEA_BOARD */ + joystick_serial_out_from_generic, /* JOYSTICK_SERIAL_OUT */ }; static fb_to_generic_t fb_to_generic_func[WIRED_MAX] = { @@ -78,6 +80,7 @@ static fb_to_generic_t fb_to_generic_func[WIRED_MAX] = { NULL, /* PARALLEL_1P_OD */ NULL, /* PARALLEL_2P_OD */ NULL, /* SEA_BOARD */ + NULL, /* JOYSTICK_SERIAL_OUT */ }; static meta_init_t meta_init_func[WIRED_MAX] = { @@ -105,6 +108,7 @@ static meta_init_t meta_init_func[WIRED_MAX] = { para_1p_meta_init, /* PARALLEL_1P_OD */ para_2p_meta_init, /* PARALLEL_2P_OD */ sea_meta_init, /* SEA_BOARD */ + joystick_serial_out_meta_init, /* JOYSTICK_SERIAL_OUT */ }; static DRAM_ATTR buffer_init_t buffer_init_func[WIRED_MAX] = { @@ -132,6 +136,7 @@ static DRAM_ATTR buffer_init_t buffer_init_func[WIRED_MAX] = { para_1p_init_buffer, /* PARALLEL_1P_OD */ para_2p_init_buffer, /* PARALLEL_2P_OD */ sea_init_buffer, /* SEA_BOARD */ + joystick_serial_out_init_buffer, /* JOYSTICK_SERIAL_OUT */ }; int32_t wired_meta_init(struct wired_ctrl *ctrl_data) { diff --git a/main/wired/wired_bare.c b/main/wired/wired_bare.c index 2176998e..caf21f15 100644 --- a/main/wired/wired_bare.c +++ b/main/wired/wired_bare.c @@ -51,6 +51,7 @@ static const char *sys_name[WIRED_MAX] = { "PARALLEL_1P_OD", "PARALLEL_2P_OD", "SEA Board", + "JOYSTICK_SERIAL_OUT" }; static const wired_init_t wired_init[WIRED_MAX] = { @@ -78,6 +79,7 @@ static const wired_init_t wired_init[WIRED_MAX] = { NULL, /* PARALLEL_1P_OD */ NULL, /* PARALLEL_2P_OD */ NULL, /* SEA_BOARD */ + NULL, /* JOYSTICK_SERIAL_OUT */ }; static const wired_port_cfg_t wired_port_cfg[WIRED_MAX] = { @@ -105,6 +107,7 @@ static const wired_port_cfg_t wired_port_cfg[WIRED_MAX] = { NULL, /* PARALLEL_1P_OD */ NULL, /* PARALLEL_2P_OD */ NULL, /* SEA_BOARD */ + NULL, /* JOYSTICK_SERIAL_OUT */ }; void wired_bare_init(uint32_t package) { diff --git a/main/wired/wired_bare.h b/main/wired/wired_bare.h index f650e394..2006e990 100644 --- a/main/wired/wired_bare.h +++ b/main/wired/wired_bare.h @@ -32,6 +32,8 @@ #define HARDCODED_SYS PS2 #elif defined(CONFIG_BLUERETRO_SYSTEM_SATURN) #define HARDCODED_SYS SATURN +#elif defined(CONFIG_BLUERETRO_SYSTEM_JOYSTICK_SERIAL_OUT) +#define HARDCODED_SYS JOYSTICK_SERIAL_OUT #elif defined(CONFIG_BLUERETRO_SYSTEM_PCFX) #define HARDCODED_SYS PCFX #elif defined(CONFIG_BLUERETRO_SYSTEM_JVS) diff --git a/main/wired/wired_rtos.c b/main/wired/wired_rtos.c index e5b22e63..2a5dfb23 100644 --- a/main/wired/wired_rtos.c +++ b/main/wired/wired_rtos.c @@ -36,6 +36,7 @@ static const wired_init_t wired_init[WIRED_MAX] = { parallel_io_init, /* PARALLEL_1P_OD */ parallel_io_init, /* PARALLEL_2P_OD */ sea_init, /* SEA_BOARD */ + NULL, /* JOYSTICK_SERIAL_OUT */ }; void wired_rtos_init(void) { diff --git a/sdkconfig.defaults b/sdkconfig.defaults index e6b6df05..fe326706 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -21,7 +21,7 @@ CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y # Can't use SRAM1 for IRAM as it conflict with un-updatable bootloaders in the wild :@ . # CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM=y CONFIG_ESP_CONSOLE_UART_CUSTOM=y -CONFIG_ESP_CONSOLE_UART_BAUDRATE=921600 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=1000000 CONFIG_ESP_COREDUMP_ENABLE_TO_UART=y CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n CONFIG_ESP_WIFI_IRAM_OPT=n diff --git a/tests/device_data/br.py b/tests/device_data/br.py index 40b0577c..d21dda10 100644 --- a/tests/device_data/br.py +++ b/tests/device_data/br.py @@ -70,6 +70,7 @@ class system(IntEnum): PARALLEL_1P_OD = auto() PARALLEL_2P_OD = auto() SEA_BOARD = auto() + JOYSTICK_SERIAL_OUT = auto() class report_type(IntEnum):