From 54196a0d76d258e00c30ab168705692a5f9b8de3 Mon Sep 17 00:00:00 2001 From: Raphael Assenat Date: Sat, 17 Oct 2015 17:21:22 -0400 Subject: [PATCH] Move more logic from main to usbpad, implement serial from eeprom --- Makefile.inc | 2 +- main.c | 282 +++++---------------------------------------------- usbpad.c | 253 ++++++++++++++++++++++++++++++++++++++++++++- usbpad.h | 10 +- usbstrings.c | 9 ++ usbstrings.h | 11 ++ 6 files changed, 301 insertions(+), 266 deletions(-) create mode 100644 usbstrings.c create mode 100644 usbstrings.h diff --git a/Makefile.inc b/Makefile.inc index 7a558d3..92abf2a 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -1 +1 @@ -OBJS=main.o usb.o usbpad.o mappings.o gcn64_protocol.o n64.o gamecube.o usart1.o bootloader.o eeprom.o config.o hiddata.o +OBJS=main.o usb.o usbpad.o mappings.o gcn64_protocol.o n64.o gamecube.o usart1.o bootloader.o eeprom.o config.o hiddata.o usbstrings.o diff --git a/main.c b/main.c index 6340dd9..b70303b 100644 --- a/main.c +++ b/main.c @@ -17,21 +17,13 @@ #include "usbpad.h" #include "eeprom.h" #include "hiddata.h" +#include "usbstrings.h" -uint16_t hid_get_report_main(struct usb_request *rq, const uint8_t **dat); -uint8_t hid_set_report_main(const struct usb_request *rq, const uint8_t *dat, uint16_t len); - -uint16_t hid_get_report_data(struct usb_request *rq, const uint8_t **dat); -uint8_t hid_set_report_data(const struct usb_request *rq, const uint8_t *dat, uint16_t len); - +/* Those .c files are included rather than linked for we + * want the sizeof() operator to work on the arrays */ #include "reportdesc.c" #include "dataHidReport.c" -const wchar_t *const g_usb_strings[] = { - [0] = L"raphnet technologies", // 1 : Vendor - [1] = L"GC/N64 to USB v3.0", // 2: Product - [2] = L"123456", // 3 : Serial -}; struct cfg0 { struct usb_configuration_descriptor configdesc; @@ -141,7 +133,7 @@ static struct usb_parameters usb_params = { .devdesc = (PGM_VOID_P)&device_descriptor, .configdesc = (PGM_VOID_P)&cfg0, .configdesc_ttllen = sizeof(cfg0), - .num_strings = ARRAY_SIZE(g_usb_strings), + .num_strings = NUM_USB_STRINGS, .strings = g_usb_strings, .n_hid_interfaces = 2, @@ -149,8 +141,8 @@ static struct usb_parameters usb_params = { [0] = { .reportdesc = gcn64_usbHidReportDescriptor, .reportdesc_len = sizeof(gcn64_usbHidReportDescriptor), - .getReport = hid_get_report_main, - .setReport = hid_set_report_main, + .getReport = usbpad_hid_get_report, + .setReport = usbpad_hid_set_report, }, [1] = { .reportdesc = dataHidReport, @@ -213,240 +205,6 @@ void hwinit(void) PRR1 = 0; } -static unsigned char hid_report_data[32]; -static unsigned char gamepad_report0[32]; - -// Output Report IDs for various functions -#define REPORT_SET_EFFECT 0x01 -#define REPORT_SET_STATUS 0x02 -#define REPORT_SET_PERIODIC 0x04 -#define REPORT_SET_CONSTANT_FORCE 0x05 -#define REPORT_EFFECT_OPERATION 0x0A -#define REPORT_EFFECT_BLOCK_IDX 0x0B -#define REPORT_DISABLE_ACTUATORS 0x0C -#define REPORT_PID_POOL 0x0D - -// Feature reports -#define REPORT_CREATE_EFFECT 0x09 - -// For the 'Usage Effect Operation' report -#define EFFECT_OP_START 1 -#define EFFECT_OP_START_SOLO 2 -#define EFFECT_OP_STOP 3 - -// Feature report -#define PID_SIMULTANEOUS_MAX 3 -#define PID_BLOCK_LOAD_REPORT 2 - -static volatile unsigned char gamepad_vibrate = 0; // output - -static unsigned char vibration_on = 0; -static unsigned char constant_force = 0; -static unsigned char magnitude = 0; - -static unsigned char _FFB_effect_index; -#define LOOP_MAX 0xFFFF -static unsigned int _loop_count; - -static void decideVibration(void) -{ - if (!vibration_on) { - gamepad_vibrate = 0; - } else { - if (constant_force > 0x7f) { - gamepad_vibrate = 1; - } - if (magnitude > 0x7f) { - gamepad_vibrate = 1; - } - } -} - -uint16_t hid_get_report_main(struct usb_request *rq, const uint8_t **dat) -{ - uint8_t report_id = (rq->wValue & 0xff); - - // USB HID 1.11 section 7.2.1 Get_Report - // wValue high byte : report type - // wValue low byte : report id - // wIndex Interface - switch (rq->wValue >> 8) - { - case HID_REPORT_TYPE_INPUT: - { - if (report_id == 1) { // Joystick - // report_id = rq->wValue & 0xff - // interface = rq->wIndex - *dat = gamepad_report0; - printf_P(PSTR("Get joy report\r\n")); - return 9; - } else if (report_id == 2) { // 2 : ES playing - hid_report_data[0] = report_id; - hid_report_data[1] = 0; - hid_report_data[2] = _FFB_effect_index; - printf_P(PSTR("ES playing\r\n")); - *dat = hid_report_data; - return 3; - } else { - printf_P(PSTR("Get input report %d ??\r\n"), rq->wValue & 0xff); - } - } - break; - - case HID_REPORT_TYPE_FEATURE: - if (report_id == PID_BLOCK_LOAD_REPORT) { - hid_report_data[0] = report_id; - hid_report_data[1] = 0x1; // Effect block index - hid_report_data[2] = 0x1; // (1: success, 2: oom, 3: load error) - hid_report_data[3] = 10; - hid_report_data[4] = 10; - printf_P(PSTR("block load\r\n")); - *dat = hid_report_data; - return 5; - } - else if (report_id == PID_SIMULTANEOUS_MAX) { - hid_report_data[0] = report_id; - // ROM Effect Block count - hid_report_data[1] = 0x1; - hid_report_data[2] = 0x1; - // PID pool move report? - hid_report_data[3] = 0xff; - hid_report_data[4] = 1; - printf_P(PSTR("simultaneous max\r\n")); - *dat = hid_report_data; - return 5; - } - else if (report_id == REPORT_CREATE_EFFECT) { - hid_report_data[0] = report_id; - hid_report_data[1] = 1; - printf_P(PSTR("create effect\r\n")); - *dat = hid_report_data; - return 2; - } else { - printf_P(PSTR("Unknown feature %d\r\n"), rq->wValue & 0xff); - } - break; - } - - printf_P(PSTR("Unhandled hid get report type=0x%02x, rq=0x%02x, wVal=0x%04x, wLen=0x%04x\r\n"), rq->bmRequestType, rq->bRequest, rq->wValue, rq->wLength); - return 0; -} - -uint8_t hid_set_report_main(const struct usb_request *rq, const uint8_t *data, uint16_t len) -{ - if (len < 1) { - printf_P(PSTR("shrt\n")); - return -1; - } - - if ((rq->wValue >> 8) == HID_REPORT_TYPE_OUTPUT) { - - switch(data[0]) - { - case REPORT_SET_STATUS: - printf_P(PSTR("eff. set stat 0x%02x 0x%02x\r\n"),data[1],data[2]); - break; - case REPORT_EFFECT_BLOCK_IDX: - printf_P(PSTR("eff. blk. idx %d\r\n"), data[1]); - break; - case REPORT_DISABLE_ACTUATORS: - printf_P(PSTR("disable actuators\r\n")); - break; - case REPORT_PID_POOL: - printf_P(PSTR("pid pool\r\n")); - break; - case REPORT_SET_EFFECT: - _FFB_effect_index = data[1]; - printf_P(PSTR("set effect %d\n"), data[1]); - break; - case REPORT_SET_PERIODIC: - magnitude = data[2]; - // decideVibration(); - printf_P(PSTR("periodic mag: %d"), data[2]); - break; - case REPORT_SET_CONSTANT_FORCE: - if (data[1] == 1) { - constant_force = data[2]; - decideVibration(); - printf_P(PSTR("Constant force")); - } - break; - case REPORT_EFFECT_OPERATION: - if (len != 4) - return -1; - /* Byte 0 : report ID - * Byte 1 : bit 7=rom flag, bits 6-0=effect block index - * Byte 2 : Effect operation - * Byte 3 : Loop count */ - _loop_count = data[3]<<3; - - printf_P(PSTR("EFFECT OP: rom=%s, idx=0x%02x"), data[1] & 0x80 ? "Yes":"No", data[1] & 0x7F); - - switch(data[1] & 0x7F) // Effect block index - { - case 1: // constant force - case 3: // square - case 4: // sine - switch (data[2]) // effect operation - { - case EFFECT_OP_START: - printf_P(PSTR("Start\r\n")); - vibration_on = 1; - decideVibration(); - break; - - case EFFECT_OP_START_SOLO: - printf_P(PSTR("Start solo\r\n")); - vibration_on = 1; - decideVibration(); - break; - - case EFFECT_OP_STOP: - printf_P(PSTR("Stop\r\n")); - vibration_on = 0; - decideVibration(); - break; - } - break; - - // TODO : should probably drop these from the descriptor since they are - - case 2: // ramp - case 5: // triangle - case 6: // sawtooth up - case 7: // sawtooth down - case 8: // spring - case 9: // damper - case 10: // inertia - case 11: // friction - case 12: // custom force data - printf_P(PSTR("Ununsed effect %d\n"), data[1] & 0x7F); - break; - } - break; - default: - printf_P(PSTR("Set output report 0x%02x\r\n"), data[0]); - } - } - else if ((rq->wValue >> 8) == HID_REPORT_TYPE_FEATURE) { - switch(data[0]) - { - case REPORT_CREATE_EFFECT: - _FFB_effect_index = data[1]; - printf_P(PSTR("create effect %d\n"), data[1]); - break; - - default: - printf_P(PSTR("What?\n")); - } - } - else { - printf_P(PSTR("impossible\n")); - } - return 0; -} - - #define NUM_PAD_TYPES 2 @@ -475,7 +233,14 @@ Gamepad *detectPad(void) void eeprom_app_ready(void) { - // TODO : Set serial number from configured value + static wchar_t serial_from_eeprom[SERIAL_NUM_LEN+1]; + int i; + + for (i=0; isetVibration) { pad->setVibration(gamepad_vibrate); @@ -537,17 +302,16 @@ int main(void) pad->update(); if (pad->changed()) { - int report_size; pad->getReport(&pad_data); - usbpad_buildReport(&pad_data, gamepad_report0); - report_size = usbpad_getReportSize(); - usb_interruptSend(gamepad_report0, report_size); + usbpad_update(&pad_data); + + usb_interruptSend(usbpad_getReportBuffer(), usbpad_getReportSize()); } } else { - /* Just make sure gamepad_report0 holds valid and - * inactive data for the HID GET_REPORT request */ - usbpad_buildReport(NULL, gamepad_report0); + /* Just make sure the gamepad state holds valid data + * to appear inactive (no buttons and axes in neutral) */ + usbpad_update(NULL); } } diff --git a/usbpad.c b/usbpad.c index c007a13..364af76 100644 --- a/usbpad.c +++ b/usbpad.c @@ -1,4 +1,6 @@ #include +#include +#include "usb.h" #include "gamepads.h" #include "usbpad.h" #include "mappings.h" @@ -6,10 +8,44 @@ #define REPORT_ID 1 #define REPORT_SIZE 15 +// Output Report IDs for various functions +#define REPORT_SET_EFFECT 0x01 +#define REPORT_SET_STATUS 0x02 +#define REPORT_SET_PERIODIC 0x04 +#define REPORT_SET_CONSTANT_FORCE 0x05 +#define REPORT_EFFECT_OPERATION 0x0A +#define REPORT_EFFECT_BLOCK_IDX 0x0B +#define REPORT_DISABLE_ACTUATORS 0x0C +#define REPORT_PID_POOL 0x0D + +// Feature reports +#define REPORT_CREATE_EFFECT 0x09 + +// For the 'Usage Effect Operation' report +#define EFFECT_OP_START 1 +#define EFFECT_OP_START_SOLO 2 +#define EFFECT_OP_STOP 3 + +// Feature report +#define PID_SIMULTANEOUS_MAX 3 +#define PID_BLOCK_LOAD_REPORT 2 -void usbpad_init(void) + +static volatile unsigned char gamepad_vibrate = 0; // output +static unsigned char vibration_on = 0; +static unsigned char constant_force = 0; +static unsigned char magnitude = 0; + +static unsigned char _FFB_effect_index; +#define LOOP_MAX 0xFFFF +static unsigned int _loop_count; + +static unsigned char gamepad_report0[32]; +static unsigned char hid_report_data[32]; + +void usbpad_init() { } @@ -132,22 +168,22 @@ static void buildReportFromN64(const n64_pad_data *n64_data, unsigned char dstbu btnsToReport(buttons, dstbuf+13); } -void usbpad_buildReport(const gamepad_data *pad_data, unsigned char dstbuf[REPORT_SIZE]) +void usbpad_update(const gamepad_data *pad_data) { /* Always start with an idle report. Specific report builders can just * simply ignore unused parts */ - buildIdleReport(dstbuf); + buildIdleReport(gamepad_report0); if (pad_data) { switch (pad_data->pad_type) { case PAD_TYPE_N64: - buildReportFromN64(&pad_data->n64, dstbuf); + buildReportFromN64(&pad_data->n64, gamepad_report0); break; case PAD_TYPE_GAMECUBE: - buildReportFromGC(&pad_data->gc, dstbuf); + buildReportFromGC(&pad_data->gc, gamepad_report0); break; default: @@ -156,3 +192,210 @@ void usbpad_buildReport(const gamepad_data *pad_data, unsigned char dstbuf[REPOR } } +char usbpad_mustVibrate(void) +{ + if (!vibration_on) { + gamepad_vibrate = 0; + } else { + if (constant_force > 0x7f) { + gamepad_vibrate = 1; + } + if (magnitude > 0x7f) { + gamepad_vibrate = 1; + } + } + + return gamepad_vibrate; +} + +unsigned char *usbpad_getReportBuffer(void) +{ + return gamepad_report0; +} + +uint16_t usbpad_hid_get_report(struct usb_request *rq, const uint8_t **dat) +{ + uint8_t report_id = (rq->wValue & 0xff); + + // USB HID 1.11 section 7.2.1 Get_Report + // wValue high byte : report type + // wValue low byte : report id + // wIndex Interface + switch (rq->wValue >> 8) + { + case HID_REPORT_TYPE_INPUT: + { + if (report_id == 1) { // Joystick + // report_id = rq->wValue & 0xff + // interface = rq->wIndex + *dat = gamepad_report0; + printf_P(PSTR("Get joy report\r\n")); + return 9; + } else if (report_id == 2) { // 2 : ES playing + hid_report_data[0] = report_id; + hid_report_data[1] = 0; + hid_report_data[2] = _FFB_effect_index; + printf_P(PSTR("ES playing\r\n")); + *dat = hid_report_data; + return 3; + } else { + printf_P(PSTR("Get input report %d ??\r\n"), rq->wValue & 0xff); + } + } + break; + + case HID_REPORT_TYPE_FEATURE: + if (report_id == PID_BLOCK_LOAD_REPORT) { + hid_report_data[0] = report_id; + hid_report_data[1] = 0x1; // Effect block index + hid_report_data[2] = 0x1; // (1: success, 2: oom, 3: load error) + hid_report_data[3] = 10; + hid_report_data[4] = 10; + printf_P(PSTR("block load\r\n")); + *dat = hid_report_data; + return 5; + } + else if (report_id == PID_SIMULTANEOUS_MAX) { + hid_report_data[0] = report_id; + // ROM Effect Block count + hid_report_data[1] = 0x1; + hid_report_data[2] = 0x1; + // PID pool move report? + hid_report_data[3] = 0xff; + hid_report_data[4] = 1; + printf_P(PSTR("simultaneous max\r\n")); + *dat = hid_report_data; + return 5; + } + else if (report_id == REPORT_CREATE_EFFECT) { + hid_report_data[0] = report_id; + hid_report_data[1] = 1; + printf_P(PSTR("create effect\r\n")); + *dat = hid_report_data; + return 2; + } else { + printf_P(PSTR("Unknown feature %d\r\n"), rq->wValue & 0xff); + } + break; + } + + printf_P(PSTR("Unhandled hid get report type=0x%02x, rq=0x%02x, wVal=0x%04x, wLen=0x%04x\r\n"), rq->bmRequestType, rq->bRequest, rq->wValue, rq->wLength); + return 0; +} + +uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data, uint16_t len) +{ + if (len < 1) { + printf_P(PSTR("shrt\n")); + return -1; + } + + if ((rq->wValue >> 8) == HID_REPORT_TYPE_OUTPUT) { + + switch(data[0]) + { + case REPORT_SET_STATUS: + printf_P(PSTR("eff. set stat 0x%02x 0x%02x\r\n"),data[1],data[2]); + break; + case REPORT_EFFECT_BLOCK_IDX: + printf_P(PSTR("eff. blk. idx %d\r\n"), data[1]); + break; + case REPORT_DISABLE_ACTUATORS: + printf_P(PSTR("disable actuators\r\n")); + break; + case REPORT_PID_POOL: + printf_P(PSTR("pid pool\r\n")); + break; + case REPORT_SET_EFFECT: + _FFB_effect_index = data[1]; + printf_P(PSTR("set effect %d\n"), data[1]); + break; + case REPORT_SET_PERIODIC: + magnitude = data[2]; + printf_P(PSTR("periodic mag: %d"), data[2]); + break; + case REPORT_SET_CONSTANT_FORCE: + if (data[1] == 1) { + constant_force = data[2]; + //decideVibration(); + printf_P(PSTR("Constant force")); + } + break; + case REPORT_EFFECT_OPERATION: + if (len != 4) + return -1; + /* Byte 0 : report ID + * Byte 1 : bit 7=rom flag, bits 6-0=effect block index + * Byte 2 : Effect operation + * Byte 3 : Loop count */ + _loop_count = data[3]<<3; + + printf_P(PSTR("EFFECT OP: rom=%s, idx=0x%02x"), data[1] & 0x80 ? "Yes":"No", data[1] & 0x7F); + + switch(data[1] & 0x7F) // Effect block index + { + case 1: // constant force + case 3: // square + case 4: // sine + switch (data[2]) // effect operation + { + case EFFECT_OP_START: + printf_P(PSTR("Start\r\n")); + vibration_on = 1; + // decideVibration(); + break; + + case EFFECT_OP_START_SOLO: + printf_P(PSTR("Start solo\r\n")); + vibration_on = 1; + // decideVibration(); + break; + + case EFFECT_OP_STOP: + printf_P(PSTR("Stop\r\n")); + vibration_on = 0; + // decideVibration(); + break; + } + break; + + // TODO : should probably drop these from the descriptor since they are + + case 2: // ramp + case 5: // triangle + case 6: // sawtooth up + case 7: // sawtooth down + case 8: // spring + case 9: // damper + case 10: // inertia + case 11: // friction + case 12: // custom force data + printf_P(PSTR("Ununsed effect %d\n"), data[1] & 0x7F); + break; + } + break; + default: + printf_P(PSTR("Set output report 0x%02x\r\n"), data[0]); + } + } + else if ((rq->wValue >> 8) == HID_REPORT_TYPE_FEATURE) { + switch(data[0]) + { + case REPORT_CREATE_EFFECT: + _FFB_effect_index = data[1]; + printf_P(PSTR("create effect %d\n"), data[1]); + break; + + default: + printf_P(PSTR("What?\n")); + } + } + else { + printf_P(PSTR("impossible\n")); + } + return 0; +} + + + + diff --git a/usbpad.h b/usbpad.h index ceaafd2..d6d6bf5 100644 --- a/usbpad.h +++ b/usbpad.h @@ -1,9 +1,17 @@ #ifndef USBPAD_H__ #define USBPAD_H__ +#include "usb.h" + void usbpad_init(void); int usbpad_getReportSize(void); -void usbpad_buildReport(const gamepad_data *pad_data, unsigned char *dstbuf); +unsigned char *usbpad_getReportBuffer(void); + +void usbpad_update(const gamepad_data *pad_data); +char usbpad_mustVibrate(void); + +uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data, uint16_t len); +uint16_t usbpad_hid_get_report(struct usb_request *rq, const uint8_t **dat); // For mappings. ID starts at 0. #define USB_BTN(id) (0x0001 << (id)) diff --git a/usbstrings.c b/usbstrings.c new file mode 100644 index 0000000..4caaf39 --- /dev/null +++ b/usbstrings.c @@ -0,0 +1,9 @@ +#include // for wchar_t +#include "usbstrings.h" + +const wchar_t *g_usb_strings[] = { + [0] = L"raphnet technologies", // 1 : Vendor + [1] = L"GC/N64 to USB v3.0", // 2: Product + [2] = L"123456", // 3 : Serial +}; + diff --git a/usbstrings.h b/usbstrings.h new file mode 100644 index 0000000..7d767ba --- /dev/null +++ b/usbstrings.h @@ -0,0 +1,11 @@ +#ifndef _usbstrings_h__ +#define _usbstrings_h__ + +extern const wchar_t *g_usb_strings[]; + +#define NUM_USB_STRINGS 3 + +/* Array indexes (i.e. zero-based0 */ +#define USB_STRING_SERIAL_IDX 2 + +#endif