Joystick support on all firmwares

This commit is contained in:
Ian Scott committed 2023-11-11 21:14:46 -07:00
1 parent d1792468cc
commit 0f6f21630b
15 files changed
+321 -166

No files matched your search

+5 -13
View File
@@ -50,7 +50,7 @@ jobs:
working-directory: ${{github.workspace}}/build
run: |
mkdir -p $OUTPUT_DIR
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="GUS" -DUSE_LTO=
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="GUS" -DUSE_LTO=1 -DUSB_JOYSTICK=1
cmake --build . --config $BUILD_TYPE --parallel $(nproc)
cp picogus.uf2 $OUTPUT_DIR/pg-gus.uf2
@@ -58,7 +58,7 @@ jobs:
working-directory: ${{github.workspace}}/build
shell: bash
run: |
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="OPL" -DUSE_LTO=
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="OPL" -DUSE_LTO=1 -DUSB_JOYSTICK=1
cmake --build . --config $BUILD_TYPE --parallel $(nproc)
cp picogus.uf2 $OUTPUT_DIR/pg-adlib.uf2
@@ -66,7 +66,7 @@ jobs:
working-directory: ${{github.workspace}}/build
shell: bash
run: |
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="MPU" -DUSE_LTO=
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="MPU" -DUSE_LTO=1 -DUSB_JOYSTICK=1
cmake --build . --config $BUILD_TYPE --parallel $(nproc)
cp picogus.uf2 $OUTPUT_DIR/pg-mpu.uf2
@@ -74,7 +74,7 @@ jobs:
working-directory: ${{github.workspace}}/build
shell: bash
run: |
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="TANDY" -DUSE_LTO=
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="TANDY" -DUSE_LTO=1 -DUSB_JOYSTICK=1
cmake --build . --config $BUILD_TYPE --parallel $(nproc)
cp picogus.uf2 $OUTPUT_DIR/pg-tandy.uf2
@@ -82,18 +82,10 @@ jobs:
working-directory: ${{github.workspace}}/build
shell: bash
run: |
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="CMS" -DUSE_LTO=
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="CMS" -DUSE_LTO=1 -DUSB_JOYSTICK=1
cmake --build . --config $BUILD_TYPE --parallel $(nproc)
cp picogus.uf2 $OUTPUT_DIR/pg-cms.uf2
- name: Build Joy Firmware
working-directory: ${{github.workspace}}/build
shell: bash
run: |
cmake $GITHUB_WORKSPACE/sw -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPROJECT_TYPE="JOY" -DUSE_LTO=
cmake --build . --config $BUILD_TYPE --parallel $(nproc)
cp picogus.uf2 $OUTPUT_DIR/pg-joy.uf2
# will generate PicoGUS Firmwares.zip as downloadable artifact with all .uf2 files
- name: Upload All Firmwares
uses: actions/upload-artifact@v3
+6
View File
@@ -1,3 +1,9 @@
[submodule "sw/rp2040-psram"]
path = sw/rp2040-psram
url = https://github.com/polpo/rp2040-psram.git
[submodule "sw/tinyusb"]
path = sw/tinyusb
url = https://github.com/hathach/tinyusb
[submodule "sw/tusb_xinput"]
path = sw/tusb_xinput
url = https://github.com/RobertDaleSmith/tusb_xinput
+14 -4
View File
@@ -30,7 +30,7 @@ typedef enum {
} card_mode_t;
void banner(void) {
printf("PicoGUSinit v1.3.0 (c) 2023 Ian Scott - licensed under the GNU GPL v2\n\n");
printf("PicoGUSinit v1.3.0-beta0 (c) 2023 Ian Scott - licensed under the GNU GPL v2\n\n");
}
const char* usage_by_card[] = {
@@ -47,11 +47,12 @@ void usage(char *argv0, card_mode_t mode) {
fprintf(stderr, "Usage:\n");
fprintf(stderr, " %s [/?] | [/f fw.uf2]", argv0);
if (mode <= CMS_MODE) {
fprintf(stderr, " | %s", usage_by_card[mode]);
fprintf(stderr, " | [/j] %s", usage_by_card[mode]);
}
fprintf(stderr, "\n\n");
fprintf(stderr, " /? - show this message\n");
fprintf(stderr, " /f fw.uf2 - Program the PicoGUS with the firmware file fw.uf2.\n");
fprintf(stderr, " /? - show this message\n");
fprintf(stderr, " /f fw.uf2 - program the PicoGUS with the firmware file fw.uf2\n");
fprintf(stderr, " /j - enable USB joystick support\n");
if (mode != GUS_MODE) {
fprintf(stderr, "AdLib, MPU-401, Tandy, CMS modes only:\n");
fprintf(stderr, " /p x - set the (hex) base port address of the emulated card. Defaults:\n");
@@ -209,6 +210,8 @@ int write_firmware(const char* fw_filename, uint8_t protocol) {
// Put card into programming mode
outp(CONTROL_PORT, 0xCC); // Knock on the door...
outp(CONTROL_PORT, 0xFF); // Select firmware programming mode
// Wait a bit for 2nd core on Pico to restart
delay(100);
if (inp(DATA_PORT_HIGH) != PICO_FIRMWARE_IDLE) {
fprintf(stderr, "ERROR: Card is not in programming mode?\n");
return 13;
@@ -275,6 +278,7 @@ int main(int argc, char* argv[]) {
card_mode_t mode;
uint8_t mpu_delaysysex = 0;
uint8_t mpu_fakeallnotesoff = 0;
uint8_t enable_joystick = 0;
banner();
// Get magic value from port on PicoGUS that is not on real GUS
@@ -295,6 +299,8 @@ int main(int argc, char* argv[]) {
if (stricmp(argv[i], "/?") == 0) {
usage(argv[0], mode);
return 0;
} else if (stricmp(argv[i], "/j") == 0) {
enable_joystick = 1;
} else if (stricmp(argv[i], "/a") == 0) {
if (i + 1 >= argc) {
usage(argv[0], mode);
@@ -390,6 +396,10 @@ int main(int argc, char* argv[]) {
port = inpw(DATA_PORT_LOW); // Get port
}
outp(CONTROL_PORT, 0x0f); // Select joystick enable register
outp(DATA_PORT_HIGH, enable_joystick);
printf("USB joystick support %s\n", enable_joystick ? "enabled" : "disabled");
switch(mode) {
case GUS_MODE:
init_gus(argv[0]);
+29 -15
View File
@@ -25,6 +25,10 @@ set(CMAKE_BUILD_TYPE "Release")
set(PICO_COPY_TO_RAM 1)
#set(SKIP_PICO_MALLOC 1)
# Tell the Pico SDK to use our local tinyusb instead of the one included in the SDK
# This is needed to support tusb_xinput
set(PICO_TINYUSB_PATH ${CMAKE_CURRENT_LIST_DIR}/tinyusb)
if(NOT PROJECT_TYPE)
set(PROJECT_TYPE "GUS")
message("PROJECT_TYPE not set, defaulting to ${PROJECT_TYPE}")
@@ -33,7 +37,7 @@ endif()
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
if(DEFINED USE_LTO)
if(USE_LTO)
# Pico SDK must be patched to allow for LTO so it is not enabled by default.
# To patch to Pico SDK, run:
# sed -i 's/WRAPPER_FUNC(x) __wrap_/WRAPPER_FUNC(x) __attribute__((used)) __wrap_/' "$PICO_SDK_PATH"/src/rp2_common/pico_platform/include/pico/platform.h
@@ -103,11 +107,18 @@ if(PROJECT_TYPE STREQUAL "GUS")
endif()
pico_enable_stdio_usb(picogus 0)
pico_enable_stdio_semihosting(picogus 0)
# Joystick stuff
target_sources(picogus PRIVATE joy_hid/joy_hid.c)
target_link_libraries(picogus tinyusb_host tinyusb_board hardware_pwm)
target_include_directories(picogus PUBLIC ${CMAKE_CURRENT_LIST_DIR}/joy_hid)
target_compile_definitions(picogus PRIVATE USB_JOYSTICK=1)
endif()
if(PROJECT_TYPE STREQUAL "OPL")
pico_set_program_name(picogus "picogus-adlib")
target_sources(picogus PRIVATE adlibplay.cpp)
target_link_libraries(
picogus
opl
@@ -167,7 +178,7 @@ if(PROJECT_TYPE STREQUAL "CMS")
pico_pic.c
square/square.cpp
)
target_sources(picogus PRIVATE cmsplay.cpp)
pico_enable_stdio_uart(picogus 1)
pico_enable_stdio_usb(picogus 0)
pico_enable_stdio_semihosting(picogus 0)
@@ -175,25 +186,28 @@ endif()
if(PROJECT_TYPE STREQUAL "JOY")
pico_set_program_name(picogus "picogus-joy")
set(USB_JOYSTICK=1)
target_compile_definitions(picogus PRIVATE
USB_JOYSTICK=1
USB_JOYSTICK_ONLY=1
)
target_sources(picogus PRIVATE
joy_hid/joy_hid.c
usbplay.cpp
)
pico_enable_stdio_uart(picogus 1)
pico_enable_stdio_usb(picogus 0)
pico_enable_stdio_semihosting(picogus 0)
pico_enable_stdio_uart(picogus 1)
pico_enable_stdio_usb(picogus 0)
pico_enable_stdio_semihosting(picogus 0)
endif()
# Make sure TinyUSB can find tusb_config.h
target_include_directories(picogus PUBLIC
${CMAKE_CURRENT_LIST_DIR}/joy_hid)
# In addition to pico_stdlib required for common PicoSDK functionality, add dependency on tinyusb_host
# for TinyUSB device support and tinyusb_board for the additional board support library used by the example
target_link_libraries(picogus tinyusb_host tinyusb_board hardware_pwm)
if(USB_JOYSTICK)
# Joystick stuff
target_sources(picogus PRIVATE joy_hid/joy_hid.c)
target_link_libraries(picogus hardware_pwm)
target_include_directories(picogus PUBLIC ${CMAKE_CURRENT_LIST_DIR}/joy_hid)
target_link_libraries(picogus tinyusb_host)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/tusb_xinput)
target_link_libraries(picogus xinput_host_app_driver)
target_compile_definitions(picogus PRIVATE USB_JOYSTICK=1)
endif()
target_sources(picogus PRIVATE M62429/M62429.cpp)
+7
View File
@@ -20,6 +20,8 @@
#include "opl.h"
#include "tusb.h"
#if PICO_ON_DEVICE
#include "pico/binary_info.h"
bi_decl(bi_3pins_with_names(PICO_AUDIO_I2S_DATA_PIN, "I2S DIN", PICO_AUDIO_I2S_CLOCK_PIN_BASE, "I2S BCK", PICO_AUDIO_I2S_CLOCK_PIN_BASE+1, "I2S LRCK"));
@@ -69,11 +71,16 @@ void play_adlib() {
puts("starting core 1");
uint32_t start, end;
// Init TinyUSB for joystick support
tuh_init(BOARD_TUH_RHPORT);
struct audio_buffer_pool *ap = init_audio();
for (;;) {
struct audio_buffer *buffer = take_audio_buffer(ap, true);
OPL_Pico_Mix_callback(buffer);
// putchar((unsigned char)buffer->buffer->bytes[1]);
give_audio_buffer(ap, buffer);
// Service TinyUSB events
tuh_task();
}
}
+7
View File
@@ -19,6 +19,8 @@
#include "pico/audio_i2s.h"
#include "tusb.h"
#ifdef MAME_CMS
#include "saa1099/saa1099.h"
saa1099_device *saa0, *saa1;
@@ -72,6 +74,9 @@ struct audio_buffer_pool *init_audio() {
void play_cms() {
puts("starting core 1 CMS");
// Init TinyUSB for joystick support
tuh_init(BOARD_TUH_RHPORT);
#ifdef MAME_CMS
puts("Creating SAA1099 1");
saa0 = new saa1099_device(7159090);
@@ -155,5 +160,7 @@ void play_cms() {
buffer->sample_count = buffer->max_sample_count;
give_audio_buffer(ap, buffer);
// Service TinyUSB events
tuh_task();
}
}
+6
View File
@@ -20,6 +20,8 @@
#include "pico_pic.h"
#endif
#include "tusb.h"
#ifdef PSRAM
#include "psram_spi.h"
extern psram_spi_inst_t psram_spi;
@@ -112,6 +114,8 @@ void play_gus() {
#endif
#endif
GUS_Setup();
// Init TinyUSB for joystick support
tuh_init(BOARD_TUH_RHPORT);
struct audio_buffer_pool *ap = init_audio();
for (;;) {
@@ -143,5 +147,7 @@ void play_gus() {
*/
// gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN);
give_audio_buffer(ap, buffer);
// Service TinyUSB events
tuh_task();
}
}
+199 -124
View File
@@ -25,6 +25,7 @@
/* #include "bsp/board_api.h" */
#include "tusb.h"
#include "xinput_host.h"
#include "joy.h"
joystate_struct_t joystate_struct;
@@ -107,44 +108,29 @@ typedef struct TU_ATTR_PACKED
} sony_ds4_report_t;
typedef struct TU_ATTR_PACKED {
// First 16 bits set what data is pertinent in this structure (1 = set; 0 = not set)
uint8_t set_rumble : 1;
uint8_t set_led : 1;
uint8_t set_led_blink : 1;
uint8_t set_ext_write : 1;
uint8_t set_left_volume : 1;
uint8_t set_right_volume : 1;
uint8_t set_mic_volume : 1;
uint8_t set_speaker_volume : 1;
uint8_t set_flags2;
typedef struct TU_ATTR_PACKED
{
uint8_t x_axis, y_axis, z_axis, rz_axis; // joystick
uint8_t reserved;
struct {
uint8_t dpad : 4; // (hat format, 0x08 is released, 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW)
uint8_t a : 1; // west
uint8_t b : 1; // south
uint8_t x : 1; // east
uint8_t y : 1; // north
};
uint8_t motor_right;
uint8_t motor_left;
uint8_t lightbar_red;
uint8_t lightbar_green;
uint8_t lightbar_blue;
uint8_t lightbar_blink_on;
uint8_t lightbar_blink_off;
uint8_t ext_data[8];
uint8_t volume_left;
uint8_t volume_right;
uint8_t volume_mic;
uint8_t volume_speaker;
uint8_t other[9];
} sony_ds4_output_report_t;
static bool ds4_mounted = false;
static uint8_t ds4_dev_addr = 0;
static uint8_t ds4_instance = 0;
static uint8_t motor_left = 0;
static uint8_t motor_right = 0;
struct {
uint8_t l1 : 1;
uint8_t r1 : 1;
uint8_t l2 : 1;
uint8_t r2 : 1;
uint8_t start : 1;
uint8_t back : 1;
uint8_t l3 : 1;
uint8_t r3 : 1;
};
} generic_report_t;
// check if device is Sony DualShock 4
static inline bool is_sony_ds4(uint8_t dev_addr)
@@ -159,31 +145,34 @@ static inline bool is_sony_ds4(uint8_t dev_addr)
);
}
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
void hid_app_task(void)
static inline bool is_generic(uint8_t dev_addr)
{
/*
if (ds4_mounted)
{
const uint32_t interval_ms = 200;
static uint32_t start_ms = 0;
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
uint32_t current_time_ms = board_millis();
if ( current_time_ms - start_ms >= interval_ms)
{
start_ms = current_time_ms;
return ( (vid == 0x2e24 && pid == 0x16fa ) // Hyperkin thing
);
}
sony_ds4_output_report_t output_report = {0};
output_report.set_rumble = 1;
output_report.motor_left = motor_left;
output_report.motor_right = motor_right;
tuh_hid_send_report(ds4_dev_addr, ds4_instance, 5, &output_report, sizeof(output_report));
}
}
*/
static inline bool is_xbox(uint8_t dev_addr)
{
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
return ( (vid == 0x2563 && pid == 0x0575 ) // Clone Xbox 360 controller
|| (vid == 0x045E && (pid == 0x028E || pid == 0x028f || pid == 0x0291)) // Official Xbox 360 wired controller
|| (vid == 0x046d && (pid == 0xc21d || pid == 0xc21e || pid == 0xc21f || pid == 0xc216)) // Official Xbox 360 wired controller
);
}
static inline bool is_ps_classic(uint8_t dev_addr)
{
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
return ( (vid == 0x054c && pid == 0x0cda) // PS Classic USB controller
);
}
//--------------------------------------------------------------------+
@@ -206,18 +195,11 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
printf("VID = %04x, PID = %04x\r\n", vid, pid);
// Sony DualShock 4 [CUH-ZCT2x]
if ( is_sony_ds4(dev_addr) )
if ( is_sony_ds4(dev_addr) | is_xbox(dev_addr) | is_generic(dev_addr) )
{
if (!ds4_mounted)
{
ds4_dev_addr = dev_addr;
ds4_instance = instance;
motor_left = 0;
motor_right = 0;
ds4_mounted = true;
}
// request to receive report
// tuh_hid_report_received_cb() will be invoked when report is available
printf("requesting report from it\n");
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
printf("Error: cannot request to receive report\r\n");
@@ -229,10 +211,6 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
if (ds4_mounted && ds4_dev_addr == dev_addr && ds4_instance == instance)
{
ds4_mounted = false;
}
}
// check if different than 2
@@ -256,25 +234,9 @@ bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2)
return result;
}
void process_sony_ds4(uint8_t const* report, uint16_t len)
{
const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" };
// previous report used to compare for changes
static sony_ds4_report_t prev_report = { 0 };
uint8_t const report_id = report[0];
report++;
len--;
// all buttons state is stored in ID 1
if (report_id == 1)
{
sony_ds4_report_t ds4_report;
memcpy(&ds4_report, report, sizeof(ds4_report));
joystate_struct.button_mask = (!ds4_report.cross << 4) | (!ds4_report.circle << 5) | (!ds4_report.square << 6) | (!ds4_report.triangle << 7);
switch (ds4_report.dpad) {
void update_joystate(uint8_t dpad, uint8_t x, uint8_t y, uint8_t z, uint8_t rz, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
joystate_struct.button_mask = (!b1 << 4) | (!b2 << 5) | (!b3 << 6) | (!b4 << 7);
switch (dpad) {
case 0: // N
joystate_struct.joy1_x = 127;
joystate_struct.joy1_y = 0;
@@ -308,61 +270,109 @@ void process_sony_ds4(uint8_t const* report, uint16_t len)
joystate_struct.joy1_y = 0;
break;
case 8: // None - use analog stick instead
joystate_struct.joy1_x = ds4_report.x;
joystate_struct.joy1_y = ds4_report.y;
joystate_struct.joy1_x = x;
joystate_struct.joy1_y = y;
break;
}
joystate_struct.joy2_x = ds4_report.z;
joystate_struct.joy2_y = ds4_report.rz;
joystate_struct.joy2_x = z;
joystate_struct.joy2_y = rz;
}
inline void process_generic(uint8_t const* report, uint16_t len)
{
uint8_t const report_id = report[0];
report++;
len--;
// all buttons state is stored in ID 1
if (report_id == 1)
{
generic_report_t generic_report;
memcpy(&generic_report, report, sizeof(generic_report));
update_joystate(generic_report.dpad, generic_report.x_axis, generic_report.y_axis, generic_report.z_axis, generic_report.rz_axis,
generic_report.a, generic_report.b, generic_report.x, generic_report.y);
return;
// counter is +1, assign to make it easier to compare 2 report
prev_report.counter = ds4_report.counter;
// only print if changes since it is polled ~ 5ms
// Since count+1 after each report and x, y, z, rz fluctuate within 1 or 2
// We need more than memcmp to check if report is different enough
if ( diff_report(&prev_report, &ds4_report) )
{
printf("(x, y, z, rz) = (%u, %u, %u, %u)\r\n", ds4_report.x, ds4_report.y, ds4_report.z, ds4_report.rz);
printf("DPad = %s ", dpad_str[ds4_report.dpad]);
const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" };
if (ds4_report.square ) printf("Square ");
if (ds4_report.cross ) printf("Cross ");
if (ds4_report.circle ) printf("Circle ");
if (ds4_report.triangle ) printf("Triangle ");
printf("(x, y, z, rz) = (%u, %u, %u, %u)\r\n", generic_report.x_axis, generic_report.y_axis, generic_report.z_axis, generic_report.rz_axis);
printf("DPad = %s ", dpad_str[generic_report.dpad]);
if (ds4_report.l1 ) printf("L1 ");
if (ds4_report.r1 ) printf("R1 ");
if (ds4_report.l2 ) printf("L2 ");
if (ds4_report.r2 ) printf("R2 ");
if (generic_report.a ) printf("A ");
if (generic_report.b ) printf("B ");
if (generic_report.x ) printf("X ");
if (generic_report.y ) printf("Y ");
if (ds4_report.share ) printf("Share ");
if (ds4_report.option ) printf("Option ");
if (ds4_report.l3 ) printf("L3 ");
if (ds4_report.r3 ) printf("R3 ");
if (generic_report.l1 ) printf("L1 ");
if (generic_report.r1 ) printf("R1 ");
if (generic_report.l2 ) printf("L2 ");
if (generic_report.r2 ) printf("R2 ");
if (ds4_report.ps ) printf("PS ");
if (ds4_report.tpad ) printf("TPad ");
if (generic_report.start ) printf("Share ");
if (generic_report.back ) printf("Option ");
if (generic_report.l3 ) printf("L3 ");
if (generic_report.r3 ) printf("R3 ");
printf("\r\n");
}
printf("\r\n");
}
}
// The left and right triggers control the intensity of the left and right rumble motors
motor_left = ds4_report.l2_trigger;
motor_right = ds4_report.r2_trigger;
inline void process_sony_ds4(uint8_t const* report, uint16_t len)
{
uint8_t const report_id = report[0];
report++;
len--;
prev_report = ds4_report;
// all buttons state is stored in ID 1
if (report_id == 1)
{
sony_ds4_report_t ds4_report;
memcpy(&ds4_report, report, sizeof(ds4_report));
update_joystate(ds4_report.dpad, ds4_report.x, ds4_report.y, ds4_report.z, ds4_report.rz,
ds4_report.cross, ds4_report.circle, ds4_report.square, ds4_report.triangle);
return;
const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" };
printf("(x, y, z, rz) = (%u, %u, %u, %u)\r\n", ds4_report.x, ds4_report.y, ds4_report.z, ds4_report.rz);
printf("DPad = %s ", dpad_str[ds4_report.dpad]);
if (ds4_report.square ) printf("Square ");
if (ds4_report.cross ) printf("Cross ");
if (ds4_report.circle ) printf("Circle ");
if (ds4_report.triangle ) printf("Triangle ");
if (ds4_report.l1 ) printf("L1 ");
if (ds4_report.r1 ) printf("R1 ");
if (ds4_report.l2 ) printf("L2 ");
if (ds4_report.r2 ) printf("R2 ");
if (ds4_report.share ) printf("Share ");
if (ds4_report.option ) printf("Option ");
if (ds4_report.l3 ) printf("L3 ");
if (ds4_report.r3 ) printf("R3 ");
if (ds4_report.ps ) printf("PS ");
if (ds4_report.tpad ) printf("TPad ");
printf("\r\n");
}
}
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
/* putchar('.'); */
if ( is_sony_ds4(dev_addr) )
{
process_sony_ds4(report, len);
/* process_generic(report, len); */
} else if ( is_generic(dev_addr) )
{
process_generic(report, len);
/* process_generic(report, len); */
}
// continue to request to receive report
@@ -371,3 +381,68 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
printf("Error: cannot request to receive report\r\n");
}
}
inline void update_joystate_xinput(uint16_t wButtons, int16_t sThumbLX, int16_t sThumbLY, int16_t sThumbRX, int16_t sThumbRY, uint8_t bLeftTrigger, uint8_t bRightTrigger) {
uint8_t dpad = wButtons & 0xf;
if (!dpad) {
joystate_struct.joy1_x = ((int32_t)sThumbLX + 32768) >> 8;
joystate_struct.joy1_y = ((-(int32_t)sThumbLY) + 32767) >> 8;
} else {
joystate_struct.joy1_x = (dpad & XINPUT_GAMEPAD_DPAD_RIGHT) ? 255 : ((dpad & XINPUT_GAMEPAD_DPAD_LEFT) ? 0 : 127);
joystate_struct.joy1_y = (dpad & XINPUT_GAMEPAD_DPAD_DOWN) ? 255 : ((dpad & XINPUT_GAMEPAD_DPAD_UP) ? 0 : 127);
}
if (bLeftTrigger) {
joystate_struct.joy1_y = 127u + (bLeftTrigger >> 1);
} else if (bRightTrigger) {
joystate_struct.joy1_y = 127u - (bRightTrigger >> 1);
}
joystate_struct.joy2_x = ((int32_t)sThumbRX + 32768) >> 8;
joystate_struct.joy2_y = ((-(int32_t)sThumbRY) + 32767) >> 8;
joystate_struct.button_mask = (~(wButtons >> 12)) << 4;
/* printf("%04x %04x\n", wButtons, joystate_struct.button_mask); */
}
void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len)
{
xinputh_interface_t *xid_itf = (xinputh_interface_t *)report;
xinput_gamepad_t *p = &xid_itf->pad;
/* const char* type_str; */
/* switch (xid_itf->type) */
/* { */
/* case 1: type_str = "Xbox One"; break; */
/* case 2: type_str = "Xbox 360 Wireless"; break; */
/* case 3: type_str = "Xbox 360 Wired"; break; */
/* case 4: type_str = "Xbox OG"; break; */
/* default: type_str = "Unknown"; */
/* } */
if (xid_itf->connected && xid_itf->new_pad_data)
{
/* printf("[%02x, %02x], Type: %s, Buttons %04x, LT: %02x RT: %02x, LX: %d, LY: %d, RX: %d, RY: %d\n", */
/* dev_addr, instance, type_str, p->wButtons, p->bLeftTrigger, p->bRightTrigger, p->sThumbLX, p->sThumbLY, p->sThumbRX, p->sThumbRY); */
update_joystate_xinput(p->wButtons, p->sThumbLX, p->sThumbLY, p->sThumbRX, p->sThumbRY, p->bLeftTrigger, p->bRightTrigger);
}
tuh_xinput_receive_report(dev_addr, instance);
}
void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const xinputh_interface_t *xinput_itf)
{
printf("XINPUT MOUNTED %02x %d\n", dev_addr, instance);
// If this is a Xbox 360 Wireless controller we need to wait for a connection packet
// on the in pipe before setting LEDs etc. So just start getting data until a controller is connected.
if (xinput_itf->type == XBOX360_WIRELESS && xinput_itf->connected == false)
{
tuh_xinput_receive_report(dev_addr, instance);
return;
}
tuh_xinput_set_led(dev_addr, instance, 0, true);
tuh_xinput_set_led(dev_addr, instance, 1, true);
tuh_xinput_set_rumble(dev_addr, instance, 0, 0, true);
tuh_xinput_receive_report(dev_addr, instance);
}
void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance)
{
printf("XINPUT UNMOUNTED %02x %d\n", dev_addr, instance);
}
+3
View File
@@ -33,6 +33,9 @@
//--------------------------------------------------------------------+
// Board Specific Configuration
//--------------------------------------------------------------------+
#define CFG_TUSB_MCU OPT_MCU_RP2040
#define CFG_TUH_XINPUT 1
#if CFG_TUSB_MCU == OPT_MCU_RP2040
// change to 1 if using pico-pio-usb as host controller for raspberry rp2040
+9 -2
View File
@@ -4,18 +4,25 @@
#include "pico_pic.h"
#endif
#include "tusb.h"
#include "mpu401/export.h"
void play_mpu() {
puts("starting core 1");
puts("starting core 1 MPU");
// Init TinyUSB for joystick support
tuh_init(BOARD_TUH_RHPORT);
#ifdef USE_ALARM
// Init PIC on this core so it handles timers
PIC_Init();
puts("pic inited on core 1");
#endif
puts("pic inited");
for (;;) {
send_midi_byte(); // see if we need to send a byte
// Service TinyUSB events
tuh_task();
}
}
+27 -7
View File
@@ -85,8 +85,10 @@ cms_buffer_t cms_buffer = { {0}, 0, 0 };
#endif
#ifdef USB_JOYSTICK
static uint16_t basePort = 0x201u;
static uint16_t joyPort = 0xffffu;
#ifdef USB_JOYSTICK_ONLY
void play_usb(void);
#endif
#include "joy_hid/joy.h"
extern "C" joystate_struct_t joystate_struct;
uint8_t joystate_bin;
@@ -127,6 +129,8 @@ __force_inline void select_picogus(uint8_t value) {
case 0x04: // Base port
basePort_tmp = 0;
break;
case 0x0f: // enable joystick
break;
#ifdef SOUND_GUS
case 0x10: // Audio buffer size
case 0x11: // DMA interval
@@ -158,12 +162,16 @@ __force_inline void write_picogus_low(uint8_t value) {
__force_inline void write_picogus_high(uint8_t value) {
switch (sel_reg) {
case 0x04: // Base port
#if defined(SOUND_GUS) || defined(SOUND_OPL) || defined(SOUND_MPU) || defined(SOUND_TANDY) || defined(SOUND_CMS)
basePort = (value << 8) | basePort_tmp;
#endif
#ifdef SOUND_GUS
gus_port_test = basePort >> 4 | 0x10;
// GUS_SetPort(basePort);
#endif
break;
case 0x0f: // enable joystick
joyPort = value ? 0x201u : 0xffff;
#ifdef SOUND_GUS
case 0x10: // Audio buffer size
// Value is sent by pgusinit as the size - 1, so we need to add 1 back to it
@@ -241,6 +249,8 @@ __force_inline uint8_t read_picogus_high(void) {
return 0xff;
#endif
break;
case 0x0f: // enable joystick
return joyPort == 0x201u;
#ifdef SOUND_MPU
case 0x20: // Wavetable mixer volume
if (BOARD_TYPE == PICOGUS_2) {
@@ -372,14 +382,22 @@ __force_inline void handle_iow(void) {
}
#endif // SOUND_CMS
#ifdef USB_JOYSTICK
if (port == basePort) {
if (port == joyPort) {
pio_sm_put(pio0, iow_sm, IO_END);
// Set times in # of cycles (affected by clkdiv) for each PWM slice to count up and wrap back to 0
// TODO better calibrate this
pwm_set_wrap(0, 2000 + (joystate_struct.joy1_x << 6));
pwm_set_wrap(1, 2000 + (joystate_struct.joy1_y << 6));
pwm_set_wrap(2, 2000 + (joystate_struct.joy2_x << 6));
pwm_set_wrap(3, 2000 + (joystate_struct.joy2_y << 6));
// GUS w/ gravis gamestick -
// sbdiag: 322/267 16/18 572/520
// gravutil 34/29 2/2 61/56
// checkit 556/451 23/25 984/902
// Noname w/ gravis gamestick
// sbdiag: 256/214 7/6 495/435
// gravutil 28/23 1/1 53/47
// checkit 355/284 6/5 675/585
pwm_set_wrap(0, 2000 + ((uint16_t)joystate_struct.joy1_x << 6));
pwm_set_wrap(1, 2000 + ((uint16_t)joystate_struct.joy1_y << 6));
pwm_set_wrap(2, 2000 + ((uint16_t)joystate_struct.joy2_x << 6));
pwm_set_wrap(3, 2000 + ((uint16_t)joystate_struct.joy2_y << 6));
// Convince PWM to run as one-shot by immediately setting wrap to 0. This will take effect once the wrap
// times set above hit, so after wrapping the counter value will stay at 0 instead of counting again
pwm_set_wrap(0, 0);
@@ -470,7 +488,7 @@ __force_inline void handle_ior(void) {
}
#endif // SOUND_CMS
#ifdef USB_JOYSTICK
if (port == basePort) {
if (port == joyPort) {
pio_sm_put(pio0, ior_sm, IO_WAIT);
uint8_t value =
// Proportional bits: 1 if counter is still counting, 0 otherwise
@@ -694,7 +712,9 @@ int main()
pwm_init(1, &pwm_c, true);
pwm_init(2, &pwm_c, true);
pwm_init(3, &pwm_c, true);
#ifdef USB_JOYSTICK_ONLY
multicore_launch_core1(&play_usb);
#endif // USB_JOYSTICK_ONLY
#endif // USB_JOYSTICK
for(int i=AD0_PIN; i<(AD0_PIN + 10); ++i) {
+7
View File
@@ -23,6 +23,8 @@
#include "cmd_buffers.h"
extern tandy_buffer_t tandy_buffer;
#include "tusb.h"
#include <string.h>
#if PICO_ON_DEVICE
@@ -69,6 +71,9 @@ struct audio_buffer_pool *init_audio() {
void play_tandy() {
puts("starting core 1 tandy");
// Init TinyUSB for joystick support
tuh_init(BOARD_TUH_RHPORT);
tandysound_t tandysound;
struct audio_buffer_pool *ap = init_audio();
#ifdef SQUARE_FLOAT_OUTPUT
@@ -102,5 +107,7 @@ void play_tandy() {
buffer->sample_count = SAMPLES_PER_BUFFER;
give_audio_buffer(ap, buffer);
// Service TinyUSB events
tuh_task();
}
}
Submodule
+1
Submodule sw/tinyusb added at f84eafcaa2.
+1
Submodule sw/tusb_xinput added at 4a2882bffa.
-1
View File
@@ -1,6 +1,5 @@
#include <stdio.h>
#include "bsp/board.h"
#include "tusb.h"
// #include <string.h>