|
| 1 | +#include <stdbool.h> |
| 2 | +#include <stdio.h> |
| 3 | +#include <string.h> |
| 4 | + |
| 5 | +#include "pico/stdlib.h" |
| 6 | + |
| 7 | +#include "boot_mode.h" |
| 8 | +#include "dinput.h" |
| 9 | +#include "gamepad_state.h" |
| 10 | +#include "tusb.h" |
| 11 | +#include "usb_diag.h" |
| 12 | + |
| 13 | +static int failures = 0; |
| 14 | +static run_persona_t current_persona = RUN_PERSONA_PS3; |
| 15 | + |
| 16 | +#define CHECK(cond) \ |
| 17 | + do { \ |
| 18 | + if (!(cond)) { \ |
| 19 | + printf("FAIL %s:%d %s\n", __FILE__, __LINE__, #cond); \ |
| 20 | + failures++; \ |
| 21 | + } \ |
| 22 | + } while (0) |
| 23 | + |
| 24 | +volatile gamepad_state_t g_gamepad_state; |
| 25 | +volatile uint32_t g_last_packet_ms; |
| 26 | +volatile uint8_t g_parsec_connected; |
| 27 | + |
| 28 | +absolute_time_t get_absolute_time(void) { |
| 29 | + return 0; |
| 30 | +} |
| 31 | + |
| 32 | +uint32_t to_ms_since_boot(absolute_time_t t) { |
| 33 | + return t; |
| 34 | +} |
| 35 | + |
| 36 | +run_persona_t boot_mode_run_persona(void) { |
| 37 | + return current_persona; |
| 38 | +} |
| 39 | + |
| 40 | +bool tud_mounted(void) { |
| 41 | + return false; |
| 42 | +} |
| 43 | + |
| 44 | +bool tud_suspended(void) { |
| 45 | + return false; |
| 46 | +} |
| 47 | + |
| 48 | +bool tud_hid_ready(void) { |
| 49 | + return false; |
| 50 | +} |
| 51 | + |
| 52 | +bool tud_hid_report(uint8_t report_id, void const *report, uint8_t len) { |
| 53 | + (void)report_id; |
| 54 | + (void)report; |
| 55 | + (void)len; |
| 56 | + return false; |
| 57 | +} |
| 58 | + |
| 59 | +void usb_diag_note_xinput_in_queued(uint32_t bytes) { |
| 60 | + (void)bytes; |
| 61 | +} |
| 62 | + |
| 63 | +void usb_diag_note_xinput_in_sent(uint32_t bytes) { |
| 64 | + (void)bytes; |
| 65 | +} |
| 66 | + |
| 67 | +void usb_diag_note_xinput_in_blocked(uint8_t reason, uint16_t want, uint16_t got) { |
| 68 | + (void)reason; |
| 69 | + (void)want; |
| 70 | + (void)got; |
| 71 | +} |
| 72 | + |
| 73 | +void usb_diag_note_xinput_in_idle_suppressed(void) {} |
| 74 | + |
| 75 | +static uint16_t get_feature_report_wire(uint8_t report_id, uint16_t host_len, uint8_t *wire, |
| 76 | + uint16_t wire_len) { |
| 77 | + memset(wire, 0xA5, wire_len); |
| 78 | + if (host_len == 0 || wire_len < host_len) |
| 79 | + return 0; |
| 80 | + |
| 81 | + uint8_t *payload = wire; |
| 82 | + uint16_t payload_len = host_len; |
| 83 | + uint16_t xfer_len = 0; |
| 84 | + |
| 85 | + if (report_id != HID_REPORT_TYPE_INVALID && payload_len > 1) { |
| 86 | + *payload++ = report_id; |
| 87 | + payload_len--; |
| 88 | + xfer_len++; |
| 89 | + } |
| 90 | + |
| 91 | + xfer_len += dinput_get_report_payload(report_id, HID_REPORT_TYPE_FEATURE, payload, payload_len); |
| 92 | + return xfer_len; |
| 93 | +} |
| 94 | + |
| 95 | +static void test_ps3_operational_report_f2_matches_linux_request_size(void) { |
| 96 | + uint8_t wire[32]; |
| 97 | + current_persona = RUN_PERSONA_PS3; |
| 98 | + dinput_init(); |
| 99 | + |
| 100 | + uint16_t len = get_feature_report_wire(0xF2, 17, wire, sizeof(wire)); |
| 101 | + |
| 102 | + CHECK(len == 17); |
| 103 | + CHECK(wire[0] == 0xF2); |
| 104 | + CHECK(wire[1] == 0xFF); |
| 105 | + CHECK(wire[2] == 0xFF); |
| 106 | + CHECK(wire[3] == 0x00); |
| 107 | + CHECK(wire[4] == 0x20); |
| 108 | + CHECK(wire[5] == 0x40); |
| 109 | + CHECK(wire[6] == 0xCE); |
| 110 | + CHECK(wire[7] == 0x21); |
| 111 | + CHECK(wire[8] == 0x43); |
| 112 | + CHECK(wire[9] == 0x65); |
| 113 | +} |
| 114 | + |
| 115 | +static void test_ps3_operational_report_f2_accepts_longer_request(void) { |
| 116 | + uint8_t wire[32]; |
| 117 | + current_persona = RUN_PERSONA_PS3; |
| 118 | + dinput_init(); |
| 119 | + |
| 120 | + uint16_t len = get_feature_report_wire(0xF2, 18, wire, sizeof(wire)); |
| 121 | + |
| 122 | + CHECK(len == 18); |
| 123 | + CHECK(wire[0] == 0xF2); |
| 124 | + CHECK(wire[17] == 0x00); |
| 125 | +} |
| 126 | + |
| 127 | +static void test_ps4_feature_reports_still_copy_at_full_size(void) { |
| 128 | + uint8_t payload[64]; |
| 129 | + current_persona = RUN_PERSONA_PS4; |
| 130 | + dinput_init(); |
| 131 | + |
| 132 | + uint16_t len = dinput_get_report_payload(0xF2, HID_REPORT_TYPE_FEATURE, payload, 15); |
| 133 | + |
| 134 | + CHECK(len == 15); |
| 135 | + CHECK(payload[0] == 0x01); |
| 136 | + CHECK(payload[1] == 0x10); |
| 137 | + CHECK(payload[14] == 0x2A); |
| 138 | +} |
| 139 | + |
| 140 | +int main(void) { |
| 141 | + test_ps3_operational_report_f2_matches_linux_request_size(); |
| 142 | + test_ps3_operational_report_f2_accepts_longer_request(); |
| 143 | + test_ps4_feature_reports_still_copy_at_full_size(); |
| 144 | + if (failures != 0) |
| 145 | + return 1; |
| 146 | + puts("dinput_feature tests passed"); |
| 147 | + return 0; |
| 148 | +} |
0 commit comments