1
0
mirror of https://github.com/raphnet/gc_n64_usb-v3 synced 2024-12-21 23:08:53 -05:00

Multi-player support complete

Works, but very light testing so far
This commit is contained in:
Raphael Assenat 2016-10-10 14:19:58 -04:00
parent 90aae55470
commit 4ecc3f571e
12 changed files with 384 additions and 244 deletions

View File

@ -23,20 +23,23 @@
#include "gcn64_protocol.h" #include "gcn64_protocol.h"
/*********** prototypes *************/ /*********** prototypes *************/
static void gamecubeInit(void); static void gamecubeInit(unsigned char chn);
static char gamecubeUpdate(void); static char gamecubeUpdate(unsigned char chn);
static char gamecubeChanged(void); static char gamecubeChanged(unsigned char chn);
static char gc_rumbling = 0; static char gc_rumbling[GAMEPAD_MAX_CHANNELS] = { };
static char origins_set = 0; static char origins_set[GAMEPAD_MAX_CHANNELS] = { };
static unsigned char orig_x, orig_y, orig_cx, orig_cy; static unsigned char orig_x[GAMEPAD_MAX_CHANNELS];
static unsigned char orig_y[GAMEPAD_MAX_CHANNELS];
static unsigned char orig_cx[GAMEPAD_MAX_CHANNELS];
static unsigned char orig_cy[GAMEPAD_MAX_CHANNELS];
static void gamecubeInit(void) static void gamecubeInit(unsigned char chn)
{ {
gamecubeUpdate(); gamecubeUpdate(chn);
} }
void gc_decodeAnswer(unsigned char data[8]) void gc_decodeAnswer(unsigned char chn, unsigned char data[8])
{ {
unsigned char x,y,cx,cy; unsigned char x,y,cx,cy;
@ -91,74 +94,74 @@ void gc_decodeAnswer(unsigned char data[8])
last_built_report.gc.rt = data[7]; last_built_report.gc.rt = data[7];
memcpy(last_built_report.gc.raw_data, data, 8); memcpy(last_built_report.gc.raw_data, data, 8);
if (origins_set) { if (origins_set[chn]) {
last_built_report.gc.x = ((int)x-(int)orig_x); last_built_report.gc.x = ((int)x-(int)orig_x[chn]);
last_built_report.gc.y = ((int)y-(int)orig_y); last_built_report.gc.y = ((int)y-(int)orig_y[chn]);
last_built_report.gc.cx = ((int)cx-(int)orig_cx); last_built_report.gc.cx = ((int)cx-(int)orig_cx[chn]);
last_built_report.gc.cy = ((int)cy-(int)orig_cy); last_built_report.gc.cy = ((int)cy-(int)orig_cy[chn]);
} else { } else {
orig_x = x; orig_x[chn] = x;
orig_y = y; orig_y[chn] = y;
orig_cx = cx; orig_cx[chn] = cx;
orig_cy = cy; orig_cy[chn] = cy;
last_built_report.gc.x = 0; last_built_report.gc.x = 0;
last_built_report.gc.y = 0; last_built_report.gc.y = 0;
last_built_report.gc.cx = 0; last_built_report.gc.cx = 0;
last_built_report.gc.cy = 0; last_built_report.gc.cy = 0;
origins_set = 1; origins_set[chn] = 1;
} }
} }
static char gamecubeUpdate() static char gamecubeUpdate(unsigned char chn)
{ {
unsigned char tmpdata[GC_GETSTATUS_REPLY_LENGTH]; unsigned char tmpdata[GC_GETSTATUS_REPLY_LENGTH];
unsigned char count; unsigned char count;
tmpdata[0] = GC_GETSTATUS1; tmpdata[0] = GC_GETSTATUS1;
tmpdata[1] = GC_GETSTATUS2; tmpdata[1] = GC_GETSTATUS2;
tmpdata[2] = GC_GETSTATUS3(gc_rumbling); tmpdata[2] = GC_GETSTATUS3(gc_rumbling[chn]);
count = gcn64_transaction(GCN64_CHANNEL_0, tmpdata, 3, tmpdata, GC_GETSTATUS_REPLY_LENGTH); count = gcn64_transaction(GCN64_CHANNEL_0, tmpdata, 3, tmpdata, GC_GETSTATUS_REPLY_LENGTH);
if (count != GC_GETSTATUS_REPLY_LENGTH) { if (count != GC_GETSTATUS_REPLY_LENGTH) {
return 1; return 1;
} }
gc_decodeAnswer(tmpdata); gc_decodeAnswer(chn, tmpdata);
return 0; return 0;
} }
static void gamecubeHotplug(void) static void gamecubeHotplug(unsigned char chn)
{ {
// Make sure next read becomes the refence center values // Make sure next read becomes the refence center values
origins_set = 0; origins_set[chn] = 0;
} }
static char gamecubeProbe(void) static char gamecubeProbe(unsigned char chn)
{ {
origins_set = 0; origins_set[chn] = 0;
if (gamecubeUpdate()) { if (gamecubeUpdate(chn)) {
return 0; return 0;
} }
return 1; return 1;
} }
static char gamecubeChanged(void) static char gamecubeChanged(unsigned char chn)
{ {
return memcmp(&last_built_report, &last_sent_report, sizeof(gamepad_data)); return memcmp(&last_built_report, &last_sent_report, sizeof(gamepad_data));
} }
static void gamecubeGetReport(gamepad_data *dst) static void gamecubeGetReport(unsigned char chn, gamepad_data *dst)
{ {
if (dst) if (dst)
memcpy(dst, &last_built_report, sizeof(gamepad_data)); memcpy(dst, &last_built_report, sizeof(gamepad_data));
} }
static void gamecubeVibration(char enable) static void gamecubeVibration(unsigned char chn, char enable)
{ {
gc_rumbling = enable; gc_rumbling[chn] = enable;
} }
Gamepad GamecubeGamepad = { Gamepad GamecubeGamepad = {

View File

@ -1,7 +1,4 @@
#include "gamepads.h" #include "gamepads.h"
#define GAMECUBE_UPDATE_NORMAL 0
#define GAMECUBE_UPDATE_ORIGIN 1
Gamepad *gamecubeGetGamepad(void); Gamepad *gamecubeGetGamepad(void);

View File

@ -1,5 +1,5 @@
/* gc_n64_usb : Gamecube or N64 controller to USB adapter firmware /* gc_n64_usb : Gamecube or N64 controller to USB adapter firmware
Copyright (C) 2007-2015 Raphael Assenat <raph@raphnet.net> Copyright (C) 2007-2016 Raphael Assenat <raph@raphnet.net>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,7 +16,8 @@
*/ */
#include "gamepads.h" #include "gamepads.h"
/* Shared between N64 and GC (only one is used at a time). Saves memory. */
/* Shared between N64 and GC (only one is used at a time). Saves memory. */
gamepad_data last_sent_report; gamepad_data last_sent_report;
gamepad_data last_built_report; gamepad_data last_built_report;

View File

@ -71,14 +71,15 @@ typedef struct _gamepad_data {
}; };
} gamepad_data; } gamepad_data;
#define GAMEPAD_MAX_CHANNELS 2
typedef struct { typedef struct {
void (*init)(void); void (*init)(unsigned char chn);
char (*update)(void); char (*update)(unsigned char chn);
char (*changed)(void); char (*changed)(unsigned char chn);
void (*hotplug)(void); void (*hotplug)(unsigned char chn);
void (*getReport)(gamepad_data *dst); void (*getReport)(unsigned char chn, gamepad_data *dst);
void (*setVibration)(char enable); void (*setVibration)(unsigned char chn, char enable);
char (*probe)(void); /* return true if found */ char (*probe)(unsigned char chn); /* return true if found */
} Gamepad; } Gamepad;
/* What was most recently read from the controller */ /* What was most recently read from the controller */

View File

@ -41,7 +41,7 @@ static unsigned char cmdbuf[CMDBUF_SIZE];
static volatile unsigned char cmdbuf_len = 0; static volatile unsigned char cmdbuf_len = 0;
/*** Get/Set report called from interrupt context! */ /*** Get/Set report called from interrupt context! */
uint16_t hiddata_get_report(struct usb_request *rq, const uint8_t **dat) uint16_t hiddata_get_report(void *ctx, struct usb_request *rq, const uint8_t **dat)
{ {
// printf("Get data\n"); // printf("Get data\n");
if (state == STATE_COMMAND_DONE) { if (state == STATE_COMMAND_DONE) {
@ -56,7 +56,7 @@ uint16_t hiddata_get_report(struct usb_request *rq, const uint8_t **dat)
} }
/*** Get/Set report called from interrupt context! */ /*** Get/Set report called from interrupt context! */
uint8_t hiddata_set_report(const struct usb_request *rq, const uint8_t *dat, uint16_t len) uint8_t hiddata_set_report(void *ctx, const struct usb_request *rq, const uint8_t *dat, uint16_t len)
{ {
#ifdef DEBUG #ifdef DEBUG
int i; int i;
@ -74,7 +74,7 @@ uint8_t hiddata_set_report(const struct usb_request *rq, const uint8_t *dat, uin
return 0; return 0;
} }
static void hiddata_processCommandBuffer(void) static void hiddata_processCommandBuffer(struct hiddata_ops *ops)
{ {
unsigned char channel; unsigned char channel;
#ifdef DEBUG #ifdef DEBUG
@ -114,7 +114,9 @@ static void hiddata_processCommandBuffer(void)
break; break;
case RQ_GCN64_SUSPEND_POLLING: case RQ_GCN64_SUSPEND_POLLING:
// CMD: RQ, PARAM // CMD: RQ, PARAM
g_polling_suspended = cmdbuf[1]; if (ops && ops->suspendPolling) {
ops->suspendPolling(cmdbuf[1]);
}
break; break;
case RQ_GCN64_GET_VERSION: case RQ_GCN64_GET_VERSION:
// CMD: RQ // CMD: RQ
@ -135,7 +137,9 @@ static void hiddata_processCommandBuffer(void)
case RQ_GCN64_SET_VIBRATION: case RQ_GCN64_SET_VIBRATION:
// CMD : RQ, CHN, Vibrate // CMD : RQ, CHN, Vibrate
// Answer: RQ, CHN, Vibrate // Answer: RQ, CHN, Vibrate
usbpad_forceVibrate(cmdbuf[2]); if (ops && ops->forceVibration) {
ops->forceVibration(cmdbuf[1], cmdbuf[2]);
}
cmdbuf_len = 3; cmdbuf_len = 3;
break; break;
} }
@ -151,7 +155,7 @@ static void hiddata_processCommandBuffer(void)
state = STATE_COMMAND_DONE; state = STATE_COMMAND_DONE;
} }
void hiddata_doTask(void) void hiddata_doTask(struct hiddata_ops *ops)
{ {
switch (state) switch (state)
{ {
@ -161,7 +165,7 @@ void hiddata_doTask(void)
break; break;
case STATE_NEW_COMMAND: case STATE_NEW_COMMAND:
hiddata_processCommandBuffer(); hiddata_processCommandBuffer(ops);
break; break;
case STATE_COMMAND_DONE: case STATE_COMMAND_DONE:

View File

@ -4,9 +4,14 @@
#include <stdint.h> #include <stdint.h>
#include "usb.h" #include "usb.h"
uint16_t hiddata_get_report(struct usb_request *rq, const uint8_t **dat); struct hiddata_ops {
uint8_t hiddata_set_report(const struct usb_request *rq, const uint8_t *dat, uint16_t len); void (*suspendPolling)(uint8_t suspend);
void (*forceVibration)(uint8_t channel, uint8_t force);
};
void hiddata_doTask(void); uint16_t hiddata_get_report(void *ctx, struct usb_request *rq, const uint8_t **dat);
uint8_t hiddata_set_report(void *ctx, const struct usb_request *rq, const uint8_t *dat, uint16_t len);
void hiddata_doTask(struct hiddata_ops *ops);
#endif #endif

223
main.c
View File

@ -38,6 +38,8 @@
#include "intervaltimer.h" #include "intervaltimer.h"
#include "requests.h" #include "requests.h"
#define NUM_PLAYERS 2
#define GCN64_USB_PID 0x001D #define GCN64_USB_PID 0x001D
#define N64_USB_PID 0x0020 #define N64_USB_PID 0x0020
#define GC_USB_PID 0x0021 #define GC_USB_PID 0x0021
@ -58,6 +60,22 @@ struct cfg0 {
struct usb_interface_descriptor interface_admin; struct usb_interface_descriptor interface_admin;
struct usb_hid_descriptor hid_data; struct usb_hid_descriptor hid_data;
struct usb_endpoint_descriptor ep2_in; struct usb_endpoint_descriptor ep2_in;
#if NUM_PLAYERS >= 2
struct usb_interface_descriptor interface_p2;
struct usb_hid_descriptor hid_p2;
struct usb_endpoint_descriptor ep3_in;
#endif
#if NUM_PLAYERS >= 3
struct usb_interface_descriptor interface_p3;
struct usb_hid_descriptor hid_p3;
struct usb_endpoint_descriptor ep4_in;
#endif
#if NUM_PLAYERS >= 4
struct usb_interface_descriptor interface_p4;
struct usb_hid_descriptor hid_p4;
struct usb_endpoint_descriptor ep5_in;
#endif
}; };
static const struct cfg0 cfg0 PROGMEM = { static const struct cfg0 cfg0 PROGMEM = {
@ -65,13 +83,13 @@ static const struct cfg0 cfg0 PROGMEM = {
.bLength = sizeof(struct usb_configuration_descriptor), .bLength = sizeof(struct usb_configuration_descriptor),
.bDescriptorType = CONFIGURATION_DESCRIPTOR, .bDescriptorType = CONFIGURATION_DESCRIPTOR,
.wTotalLength = sizeof(cfg0), // includes all descriptors returned together .wTotalLength = sizeof(cfg0), // includes all descriptors returned together
.bNumInterfaces = 2, .bNumInterfaces = NUM_PLAYERS + 1, // one interface per player + one management interface
.bConfigurationValue = 1, .bConfigurationValue = 1,
.bmAttributes = CFG_DESC_ATTR_RESERVED, // set Self-powred and remote-wakeup here if needed. .bmAttributes = CFG_DESC_ATTR_RESERVED, // set Self-powred and remote-wakeup here if needed.
.bMaxPower = 25, // for 50mA .bMaxPower = 25, // for 50mA
}, },
// Main interface, HID // Main interface, HID (player 1)
.interface = { .interface = {
.bLength = sizeof(struct usb_interface_descriptor), .bLength = sizeof(struct usb_interface_descriptor),
.bDescriptorType = INTERFACE_DESCRIPTOR, .bDescriptorType = INTERFACE_DESCRIPTOR,
@ -96,7 +114,7 @@ static const struct cfg0 cfg0 PROGMEM = {
.bDescriptorType = ENDPOINT_DESCRIPTOR, .bDescriptorType = ENDPOINT_DESCRIPTOR,
.bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 1, // 0x81 .bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 1, // 0x81
.bmAttributes = TRANSFER_TYPE_INT, .bmAttributes = TRANSFER_TYPE_INT,
.wMaxPacketsize = 32, .wMaxPacketsize = 16,
.bInterval = LS_FS_INTERVAL_MS(1), .bInterval = LS_FS_INTERVAL_MS(1),
}, },
@ -129,6 +147,37 @@ static const struct cfg0 cfg0 PROGMEM = {
.bInterval = LS_FS_INTERVAL_MS(1), .bInterval = LS_FS_INTERVAL_MS(1),
}, },
#if NUM_PLAYERS >= 2
// Main interface, HID (player 2)
.interface_p2 = {
.bLength = sizeof(struct usb_interface_descriptor),
.bDescriptorType = INTERFACE_DESCRIPTOR,
.bInterfaceNumber = 2,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_DEVICE_CLASS_HID,
.bInterfaceSubClass = HID_SUBCLASS_NONE,
.bInterfaceProtocol = HID_PROTOCOL_NONE,
},
.hid_p2 = {
.bLength = sizeof(struct usb_hid_descriptor),
.bDescriptorType = HID_DESCRIPTOR,
.bcdHid = 0x0101,
.bCountryCode = HID_COUNTRY_NOT_SUPPORTED,
.bNumDescriptors = 1, // Only a report descriptor
.bClassDescriptorType = REPORT_DESCRIPTOR,
.wClassDescriptorLength = sizeof(gcn64_usbHidReportDescriptor),
},
.ep3_in = {
.bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = ENDPOINT_DESCRIPTOR,
.bEndpointAddress = USB_RQT_DEVICE_TO_HOST | 3, // 0x83
.bmAttributes = TRANSFER_TYPE_INT,
.wMaxPacketsize = 16,
.bInterval = LS_FS_INTERVAL_MS(1),
},
#endif
}; };
struct usb_device_descriptor device_descriptor = { struct usb_device_descriptor device_descriptor = {
@ -150,6 +199,16 @@ struct usb_device_descriptor device_descriptor = {
/** **/ /** **/
static uint16_t _usbpad_hid_get_report(void *ctx, struct usb_request *rq, const uint8_t **dat)
{
return usbpad_hid_get_report((struct usbpad*)ctx, rq, dat);
}
static uint8_t _usbpad_hid_set_report(void *ctx, const struct usb_request *rq, const uint8_t *dat, uint16_t len)
{
return usbpad_hid_set_report((struct usbpad*)ctx, rq, dat, len);
}
static struct usb_parameters usb_params = { static struct usb_parameters usb_params = {
.flags = USB_PARAM_FLAG_CONFDESC_PROGMEM | .flags = USB_PARAM_FLAG_CONFDESC_PROGMEM |
USB_PARAM_FLAG_REPORTDESC_PROGMEM, USB_PARAM_FLAG_REPORTDESC_PROGMEM,
@ -159,13 +218,13 @@ static struct usb_parameters usb_params = {
.num_strings = NUM_USB_STRINGS, .num_strings = NUM_USB_STRINGS,
.strings = g_usb_strings, .strings = g_usb_strings,
.n_hid_interfaces = 2, .n_hid_interfaces = 1 + NUM_PLAYERS,
.hid_params = { .hid_params = {
[0] = { [0] = {
.reportdesc = gcn64_usbHidReportDescriptor, .reportdesc = gcn64_usbHidReportDescriptor,
.reportdesc_len = sizeof(gcn64_usbHidReportDescriptor), .reportdesc_len = sizeof(gcn64_usbHidReportDescriptor),
.getReport = usbpad_hid_get_report, .getReport = _usbpad_hid_get_report,
.setReport = usbpad_hid_set_report, .setReport = _usbpad_hid_set_report,
}, },
[1] = { [1] = {
.reportdesc = dataHidReport, .reportdesc = dataHidReport,
@ -173,6 +232,14 @@ static struct usb_parameters usb_params = {
.getReport = hiddata_get_report, .getReport = hiddata_get_report,
.setReport = hiddata_set_report, .setReport = hiddata_set_report,
}, },
#if NUM_PLAYERS >= 2
[2] = {
.reportdesc = gcn64_usbHidReportDescriptor,
.reportdesc_len = sizeof(gcn64_usbHidReportDescriptor),
.getReport = _usbpad_hid_get_report,
.setReport = _usbpad_hid_set_report,
},
#endif
}, },
}; };
@ -229,13 +296,11 @@ void hwinit(void)
} }
#define NUM_PAD_TYPES 2
unsigned char current_pad_type = CONTROLLER_IS_ABSENT; unsigned char current_pad_type = CONTROLLER_IS_ABSENT;
Gamepad *detectPad(void) Gamepad *detectPad(unsigned char chn)
{ {
current_pad_type = gcn64_detectController(GCN64_CHANNEL_0); current_pad_type = gcn64_detectController(chn);
switch (current_pad_type) switch (current_pad_type)
{ {
@ -269,7 +334,6 @@ void eeprom_app_ready(void)
g_usb_strings[USB_STRING_SERIAL_IDX] = serial_from_eeprom; g_usb_strings[USB_STRING_SERIAL_IDX] = serial_from_eeprom;
} }
char g_polling_suspended = 0;
void pollDelay(void) void pollDelay(void)
{ {
@ -279,25 +343,51 @@ void pollDelay(void)
} }
} }
static struct usbpad usbpads[NUM_PLAYERS];
static char g_polling_suspended = 0;
static void setSuspendPolling(uint8_t suspend)
{
g_polling_suspended = suspend;
}
static void forceVibration(uint8_t channel, uint8_t force)
{
if (channel < NUM_PLAYERS) {
usbpad_forceVibrate(&usbpads[channel], force);
}
}
static struct hiddata_ops hiddata_ops = {
.suspendPolling = setSuspendPolling,
.forceVibration = forceVibration,
};
#define STATE_WAIT_POLLTIME 0 #define STATE_WAIT_POLLTIME 0
#define STATE_POLL_PAD 1 #define STATE_POLL_PAD 1
#define STATE_WAIT_INTERRUPT_READY 2 #define STATE_WAIT_INTERRUPT_READY 2
#define STATE_TRANSMIT 3 #define STATE_TRANSMIT 3
#define STATE_WAIT_INTERRUPT_READY_P2 4
#define STATE_TRANSMIT_P2 5
int main(void) int main(void)
{ {
Gamepad *pad = NULL; Gamepad *pads[NUM_PLAYERS] = { };
gamepad_data pad_data; gamepad_data pad_data;
unsigned char gamepad_vibrate = 0; unsigned char gamepad_vibrate = 0;
unsigned char state = STATE_WAIT_POLLTIME; unsigned char state = STATE_WAIT_POLLTIME;
int error_count=0; int error_count[NUM_PLAYERS] = { };
int i;
int channel;
hwinit(); hwinit();
usart1_init(); usart1_init();
eeprom_init(); eeprom_init();
intervaltimer_init(); intervaltimer_init();
usbpad_init(); for (i=0; i<NUM_PLAYERS; i++) {
usbpad_init(&usbpads[i]);
}
switch (g_eeprom_data.cfg.mode) switch (g_eeprom_data.cfg.mode)
{ {
@ -321,10 +411,10 @@ int main(void)
while (1) while (1)
{ {
static char last_v = 0; static char last_v[NUM_PLAYERS] = { };
usb_doTasks(); usb_doTasks();
hiddata_doTask(); hiddata_doTask(&hiddata_ops);
switch(state) switch(state)
{ {
@ -338,62 +428,89 @@ int main(void)
break; break;
case STATE_POLL_PAD: case STATE_POLL_PAD:
/* Try to auto-detect controller if none*/ for (channel=0; channel<NUM_PLAYERS; channel++)
if (!pad) { {
pad = detectPad(); /* Try to auto-detect controller if none*/
if (pad && (pad->hotplug)) { if (!pads[channel]) {
// For gamecube, this make sure the next pads[channel] = detectPad(channel);
// analog values we read become the center if (pads[channel] && (pads[channel]->hotplug)) {
// reference. // For gamecube, this make sure the next
pad->hotplug(); // analog values we read become the center
// reference.
pads[channel]->hotplug(channel);
}
} }
}
if (pad) { /* Read from the pad by calling update */
if (pad->update()) { if (pads[channel]) {
error_count++; if (pads[channel]->update(channel)) {
if (error_count > MAX_READ_ERRORS) { error_count[channel]++;
pad = NULL; if (error_count[channel] > MAX_READ_ERRORS) {
state = STATE_WAIT_POLLTIME; pads[channel] = NULL;
error_count = 0; error_count[channel] = 0;
continue;
}
} else {
error_count[channel]=0;
}
if (pads[channel]->changed(channel))
{
pads[channel]->getReport(channel, &pad_data);
usbpad_update(&usbpads[channel], &pad_data);
state = STATE_WAIT_INTERRUPT_READY;
break; break;
} }
} else { } else {
error_count=0; /* Just make sure the gamepad state holds valid data
* to appear inactive (no buttons and axes in neutral) */
usbpad_update(&usbpads[channel], NULL);
} }
if (pad->changed()) {
pad->getReport(&pad_data);
usbpad_update(&pad_data);
state = STATE_WAIT_INTERRUPT_READY;
break;
}
} else {
/* Just make sure the gamepad state holds valid data
* to appear inactive (no buttons and axes in neutral) */
usbpad_update(NULL);
} }
state = STATE_WAIT_POLLTIME; /* If there were change on any of the gamepads, state will
* be set to STATE_WAIT_INTERRUPT_READY. Otherwise, go back
* to WAIT_POLLTIME. */
if (state == STATE_POLL_PAD) {
state = STATE_WAIT_POLLTIME;
}
break; break;
case STATE_WAIT_INTERRUPT_READY: case STATE_WAIT_INTERRUPT_READY:
if (usb_interruptReady()) { if (usb_interruptReady_ep1()) {
state = STATE_TRANSMIT; state = STATE_TRANSMIT;
} }
break; break;
case STATE_TRANSMIT: case STATE_TRANSMIT:
usb_interruptSend(usbpad_getReportBuffer(), usbpad_getReportSize()); usb_interruptSend_ep1(usbpad_getReportBuffer(&usbpads[0]), usbpad_getReportSize());
if (NUM_PLAYERS > 1) {
state = STATE_WAIT_INTERRUPT_READY_P2;
} else {
state = STATE_WAIT_POLLTIME;
}
break;
case STATE_WAIT_INTERRUPT_READY_P2:
if (usb_interruptReady_ep3()) {
state = STATE_TRANSMIT_P2;
}
break;
case STATE_TRANSMIT_P2:
usb_interruptSend_ep3(usbpad_getReportBuffer(&usbpads[1]), usbpad_getReportSize());
state = STATE_WAIT_POLLTIME; state = STATE_WAIT_POLLTIME;
break; break;
} }
gamepad_vibrate = usbpad_mustVibrate(); for (channel=0; channel < NUM_PLAYERS; channel++) {
if (last_v != gamepad_vibrate) { gamepad_vibrate = usbpad_mustVibrate(&usbpads[channel]);
if (pad && pad->setVibration) { if (last_v[channel] != gamepad_vibrate) {
pad->setVibration(gamepad_vibrate); if (pads[channel] && pads[channel]->setVibration) {
pads[channel]->setVibration(channel, gamepad_vibrate);
}
last_v[channel] = gamepad_vibrate;
} }
last_v = gamepad_vibrate;
} }
} }

111
n64.c
View File

@ -25,32 +25,33 @@
#undef BUTTON_A_RUMBLE_TEST #undef BUTTON_A_RUMBLE_TEST
/*********** prototypes *************/ /*********** prototypes *************/
static void n64Init(void); static void n64Init(unsigned char chn);
static char n64Update(void); static char n64Update(unsigned char chn);
static char n64Changed(void); static char n64Changed(unsigned char chn);
static void n64GetReport(gamepad_data *dst); static void n64GetReport(unsigned char chn, gamepad_data *dst);
static void n64SetVibration(char enable); static void n64SetVibration(unsigned char chn, char enable);
static char must_rumble = 0; static char must_rumble[GAMEPAD_MAX_CHANNELS] = { };
#ifdef BUTTON_A_RUMBLE_TEST #ifdef BUTTON_A_RUMBLE_TEST
static char force_rumble = 0; static char force_rumble[GAMEPAD_MAX_CHANNELS] = { };
#endif #endif
static unsigned char n64_rumble_state[GAMEPAD_MAX_CHANNELS] = { };
static void n64Init(void) unsigned char tmpdata[40]; // Shared between channels
{
n64Update();
}
#define RSTATE_INIT 0 #define RSTATE_UNAVAILABLE 0
#define RSTATE_OFF 1 #define RSTATE_OFF 1
#define RSTATE_TURNON 2 #define RSTATE_TURNON 2
#define RSTATE_ON 3 #define RSTATE_ON 3
#define RSTATE_TURNOFF 4 #define RSTATE_TURNOFF 4
#define RSTATE_UNAVAILABLE 5 #define RSTATE_INIT 5
static unsigned char n64_rumble_state = RSTATE_UNAVAILABLE;
unsigned char tmpdata[40];
static char initRumble(void) static void n64Init(unsigned char chn)
{
n64Update(chn);
}
static char initRumble(unsigned char chn)
{ {
int count; int count;
unsigned char data[4]; unsigned char data[4];
@ -60,14 +61,14 @@ static char initRumble(void)
tmpdata[2] = 0x01; tmpdata[2] = 0x01;
memset(tmpdata+3, 0x80, 32); memset(tmpdata+3, 0x80, 32);
count = gcn64_transaction(GCN64_CHANNEL_0, tmpdata, 35, data, sizeof(data)); count = gcn64_transaction(chn, tmpdata, 35, data, sizeof(data));
if (count == 1) if (count == 1)
return 0; return 0;
return -1; return -1;
} }
static char controlRumble(char enable) static char controlRumble(unsigned char chn, char enable)
{ {
int count; int count;
unsigned char data[4]; unsigned char data[4];
@ -76,14 +77,14 @@ static char controlRumble(char enable)
tmpdata[1] = 0xc0; tmpdata[1] = 0xc0;
tmpdata[2] = 0x1b; tmpdata[2] = 0x1b;
memset(tmpdata+3, enable ? 0x01 : 0x00, 32); memset(tmpdata+3, enable ? 0x01 : 0x00, 32);
count = gcn64_transaction(GCN64_CHANNEL_0, tmpdata, 35, data, sizeof(data)); count = gcn64_transaction(chn, tmpdata, 35, data, sizeof(data));
if (count == 1) if (count == 1)
return 0; return 0;
return -1; return -1;
} }
static char n64Update(void) static char n64Update(unsigned char chn)
{ {
unsigned char count; unsigned char count;
unsigned char x,y; unsigned char x,y;
@ -101,78 +102,78 @@ static char n64Update(void)
* Bit 1 tells is if there was something connected that has been removed. * Bit 1 tells is if there was something connected that has been removed.
*/ */
tmpdata[0] = N64_GET_CAPABILITIES; tmpdata[0] = N64_GET_CAPABILITIES;
count = gcn64_transaction(GCN64_CHANNEL_0, tmpdata, 1, caps, sizeof(caps)); count = gcn64_transaction(chn, tmpdata, 1, caps, sizeof(caps));
if (count != N64_CAPS_REPLY_LENGTH) { if (count != N64_CAPS_REPLY_LENGTH) {
// a failed read could mean the pack or controller was gone. Init // a failed read could mean the pack or controller was gone. Init
// will be necessary next time we detect a pack is present. // will be necessary next time we detect a pack is present.
n64_rumble_state = RSTATE_INIT; n64_rumble_state[chn] = RSTATE_INIT;
return -1; return -1;
} }
/* Detect when a pack becomes present and schedule initialisation when it happens. */ /* Detect when a pack becomes present and schedule initialisation when it happens. */
if ((caps[2] & 0x01) && (n64_rumble_state == RSTATE_UNAVAILABLE)) { if ((caps[2] & 0x01) && (n64_rumble_state[chn] == RSTATE_UNAVAILABLE)) {
n64_rumble_state = RSTATE_INIT; n64_rumble_state[chn] = RSTATE_INIT;
} }
/* Detect when a pack is removed. */ /* Detect when a pack is removed. */
if (!(caps[2] & 0x01) || (caps[2] & 0x02) ) { if (!(caps[2] & 0x01) || (caps[2] & 0x02) ) {
n64_rumble_state = RSTATE_UNAVAILABLE; n64_rumble_state[chn] = RSTATE_UNAVAILABLE;
} }
#ifdef BUTTON_A_RUMBLE_TEST #ifdef BUTTON_A_RUMBLE_TEST
must_rumble = force_rumble; must_rumble[chn] = force_rumble[chn];
//printf("Caps: %02x %02x %02x\r\n", caps[0], caps[1], caps[2]); //printf("Caps: %02x %02x %02x\r\n", caps[0], caps[1], caps[2]);
#endif #endif
switch (n64_rumble_state) switch (n64_rumble_state[chn])
{ {
case RSTATE_INIT: case RSTATE_INIT:
/* Retry until the controller answers with a full byte. */ /* Retry until the controller answers with a full byte. */
if (initRumble() != 0) { if (initRumble(chn) != 0) {
if (initRumble() != 0) { if (initRumble(chn) != 0) {
n64_rumble_state = RSTATE_UNAVAILABLE; n64_rumble_state[chn] = RSTATE_UNAVAILABLE;
} }
break; break;
} }
if (must_rumble) { if (must_rumble[chn]) {
controlRumble(1); controlRumble(chn, 1);
n64_rumble_state = RSTATE_ON; n64_rumble_state[chn] = RSTATE_ON;
} else { } else {
controlRumble(0); controlRumble(chn, 0);
n64_rumble_state = RSTATE_OFF; n64_rumble_state[chn] = RSTATE_OFF;
} }
break; break;
case RSTATE_TURNON: case RSTATE_TURNON:
if (0 == controlRumble(1)) { if (0 == controlRumble(chn, 1)) {
n64_rumble_state = RSTATE_ON; n64_rumble_state[chn] = RSTATE_ON;
} }
break; break;
case RSTATE_TURNOFF: case RSTATE_TURNOFF:
if (0 == controlRumble(0)) { if (0 == controlRumble(chn, 0)) {
n64_rumble_state = RSTATE_OFF; n64_rumble_state[chn] = RSTATE_OFF;
} }
break; break;
case RSTATE_ON: case RSTATE_ON:
if (!must_rumble) { if (!must_rumble[chn]) {
controlRumble(0); controlRumble(chn, 0);
n64_rumble_state = RSTATE_OFF; n64_rumble_state[chn] = RSTATE_OFF;
} }
break; break;
case RSTATE_OFF: case RSTATE_OFF:
if (must_rumble) { if (must_rumble[chn]) {
controlRumble(1); controlRumble(chn, 1);
n64_rumble_state = RSTATE_ON; n64_rumble_state[chn] = RSTATE_ON;
} }
break; break;
} }
tmpdata[0] = N64_GET_STATUS; tmpdata[0] = N64_GET_STATUS;
count = gcn64_transaction(GCN64_CHANNEL_0, tmpdata, 1, status, sizeof(status)); count = gcn64_transaction(chn, tmpdata, 1, status, sizeof(status));
if (count != N64_GET_STATUS_REPLY_LENGTH) { if (count != N64_GET_STATUS_REPLY_LENGTH) {
return -1; return -1;
} }
@ -206,9 +207,9 @@ static char n64Update(void)
#ifdef BUTTON_A_RUMBLE_TEST #ifdef BUTTON_A_RUMBLE_TEST
if (btns1 & 0x80) { if (btns1 & 0x80) {
force_rumble = 1; force_rumble[chn] = 1;
} else { } else {
force_rumble = 0; force_rumble[chn] = 0;
} }
#endif #endif
@ -250,7 +251,7 @@ static char n64Update(void)
return 0; return 0;
} }
static char n64Probe(void) static char n64Probe(unsigned char chn)
{ {
int count; int count;
char i; char i;
@ -267,14 +268,14 @@ static char n64Probe(void)
* Bit 1 tells is if there was something connected that has been removed. * Bit 1 tells is if there was something connected that has been removed.
*/ */
n64_rumble_state = RSTATE_UNAVAILABLE; n64_rumble_state[chn] = RSTATE_UNAVAILABLE;
for (i=0; i<15; i++) for (i=0; i<15; i++)
{ {
_delay_ms(30); _delay_ms(30);
tmp = N64_GET_CAPABILITIES; tmp = N64_GET_CAPABILITIES;
count = gcn64_transaction(GCN64_CHANNEL_0, &tmp, 1, data, sizeof(data)); count = gcn64_transaction(chn, &tmp, 1, data, sizeof(data));
if (count == N64_CAPS_REPLY_LENGTH) { if (count == N64_CAPS_REPLY_LENGTH) {
return 1; return 1;
@ -283,12 +284,12 @@ static char n64Probe(void)
return 0; return 0;
} }
static char n64Changed(void) static char n64Changed(unsigned char chn)
{ {
return memcmp(&last_built_report, &last_sent_report, sizeof(gamepad_data)); return memcmp(&last_built_report, &last_sent_report, sizeof(gamepad_data));
} }
static void n64GetReport(gamepad_data *dst) static void n64GetReport(unsigned char chn, gamepad_data *dst)
{ {
if (dst) if (dst)
memcpy(dst, &last_built_report, sizeof(gamepad_data)); memcpy(dst, &last_built_report, sizeof(gamepad_data));
@ -296,9 +297,9 @@ static void n64GetReport(gamepad_data *dst)
memcpy(&last_sent_report, &last_built_report, sizeof(gamepad_data)); memcpy(&last_sent_report, &last_built_report, sizeof(gamepad_data));
} }
static void n64SetVibration(char enable) static void n64SetVibration(unsigned char chn, char enable)
{ {
must_rumble = enable; must_rumble[chn] = enable;
} }
static Gamepad N64Gamepad = { static Gamepad N64Gamepad = {

8
usb.c
View File

@ -434,7 +434,9 @@ static void handleSetupPacket(struct usb_request *rq)
if (g_params->hid_params[rq->wIndex].getReport) { if (g_params->hid_params[rq->wIndex].getReport) {
const unsigned char *data; const unsigned char *data;
uint16_t len; uint16_t len;
len = g_params->hid_params[rq->wIndex].getReport(rq, &data); len = g_params->hid_params[rq->wIndex].getReport(
g_params->hid_params[rq->wIndex].ctx,
rq, &data);
if (len) { if (len) {
buf2EP(0, data, len, rq->wLength, 0); buf2EP(0, data, len, rq->wLength, 0);
} }
@ -513,7 +515,9 @@ static void handleDataPacket(const struct usb_request *rq, uint8_t *dat, uint16_
return; return;
if (g_params->hid_params[rq->wIndex].setReport) { if (g_params->hid_params[rq->wIndex].setReport) {
if (g_params->hid_params[rq->wIndex].setReport(rq, dat, len)) { if (g_params->hid_params[rq->wIndex].setReport(
g_params->hid_params[rq->wIndex].ctx,
rq, dat, len)) {
UECONX |= (1<<STALLRQ); UECONX |= (1<<STALLRQ);
} else { } else {
// xmit status // xmit status

5
usb.h
View File

@ -176,8 +176,9 @@ struct usb_hid_parameters {
const unsigned char *reportdesc; const unsigned char *reportdesc;
// Warning: Called from interrupt handler. Implement accordingly. // Warning: Called from interrupt handler. Implement accordingly.
uint16_t (*getReport)(struct usb_request *rq, const uint8_t **dat); void *ctx;
uint8_t (*setReport)(const struct usb_request *rq, const uint8_t *dat, uint16_t len); uint16_t (*getReport)(void *ctx, struct usb_request *rq, const uint8_t **dat);
uint8_t (*setReport)(void *ctx, const struct usb_request *rq, const uint8_t *dat, uint16_t len);
}; };
struct usb_parameters { struct usb_parameters {

134
usbpad.c
View File

@ -16,6 +16,7 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "usb.h" #include "usb.h"
#include "gamepads.h" #include "gamepads.h"
#include "usbpad.h" #include "usbpad.h"
@ -24,7 +25,6 @@
#include "config.h" #include "config.h"
#define REPORT_ID 1 #define REPORT_ID 1
#define REPORT_SIZE 15
// Output Report IDs for various functions // Output Report IDs for various functions
#define REPORT_SET_EFFECT 0x01 #define REPORT_SET_EFFECT 0x01
@ -48,28 +48,17 @@
#define PID_SIMULTANEOUS_MAX 3 #define PID_SIMULTANEOUS_MAX 3
#define PID_BLOCK_LOAD_REPORT 2 #define PID_BLOCK_LOAD_REPORT 2
static void buildIdleReport(unsigned char dstbuf[REPORT_SIZE]); static void buildIdleReport(unsigned char dstbuf[USBPAD_REPORT_SIZE]);
static volatile unsigned char gamepad_vibrate = 0; // output void usbpad_init(struct usbpad *pad)
static unsigned char vibration_on = 0, force_vibrate = 0;
static unsigned char constant_force = 0;
static unsigned char periodic_magnitude = 0;
static unsigned char _FFB_effect_index;
#define LOOP_MAX 0xFFFF
static unsigned int _loop_count;
static unsigned char gamepad_report0[REPORT_SIZE];
static unsigned char hid_report_data[8]; // Used for force feedback
void usbpad_init()
{ {
buildIdleReport(gamepad_report0); memset(pad, 0, sizeof(struct usbpad));
buildIdleReport(pad->gamepad_report0);
} }
int usbpad_getReportSize(void) int usbpad_getReportSize(void)
{ {
return REPORT_SIZE; return USBPAD_REPORT_SIZE;
} }
static int16_t minmax(int16_t input, int16_t min, int16_t max) static int16_t minmax(int16_t input, int16_t min, int16_t max)
@ -88,7 +77,7 @@ static void btnsToReport(unsigned short buttons, unsigned char dstbuf[2])
dstbuf[1] = buttons >> 8; dstbuf[1] = buttons >> 8;
} }
static void buildIdleReport(unsigned char dstbuf[REPORT_SIZE]) static void buildIdleReport(unsigned char dstbuf[USBPAD_REPORT_SIZE])
{ {
int i; int i;
@ -105,7 +94,7 @@ static void buildIdleReport(unsigned char dstbuf[REPORT_SIZE])
dstbuf[14] = 0; dstbuf[14] = 0;
} }
static void buildReportFromGC(const gc_pad_data *gc_data, unsigned char dstbuf[REPORT_SIZE]) static void buildReportFromGC(const gc_pad_data *gc_data, unsigned char dstbuf[USBPAD_REPORT_SIZE])
{ {
int16_t xval,yval,cxval,cyval,ltrig,rtrig; int16_t xval,yval,cxval,cyval,ltrig,rtrig;
uint16_t buttons; uint16_t buttons;
@ -174,7 +163,7 @@ static void buildReportFromGC(const gc_pad_data *gc_data, unsigned char dstbuf[R
btnsToReport(buttons, dstbuf+13); btnsToReport(buttons, dstbuf+13);
} }
static void buildReportFromN64(const n64_pad_data *n64_data, unsigned char dstbuf[REPORT_SIZE]) static void buildReportFromN64(const n64_pad_data *n64_data, unsigned char dstbuf[USBPAD_REPORT_SIZE])
{ {
int16_t xval, yval; int16_t xval, yval;
uint16_t buttons; uint16_t buttons;
@ -201,22 +190,22 @@ static void buildReportFromN64(const n64_pad_data *n64_data, unsigned char dstbu
btnsToReport(buttons, dstbuf+13); btnsToReport(buttons, dstbuf+13);
} }
void usbpad_update(const gamepad_data *pad_data) void usbpad_update(struct usbpad *pad, const gamepad_data *pad_data)
{ {
/* Always start with an idle report. Specific report builders can just /* Always start with an idle report. Specific report builders can just
* simply ignore unused parts */ * simply ignore unused parts */
buildIdleReport(gamepad_report0); buildIdleReport(pad->gamepad_report0);
if (pad_data) if (pad_data)
{ {
switch (pad_data->pad_type) switch (pad_data->pad_type)
{ {
case PAD_TYPE_N64: case PAD_TYPE_N64:
buildReportFromN64(&pad_data->n64, gamepad_report0); buildReportFromN64(&pad_data->n64, pad->gamepad_report0);
break; break;
case PAD_TYPE_GAMECUBE: case PAD_TYPE_GAMECUBE:
buildReportFromGC(&pad_data->gc, gamepad_report0); buildReportFromGC(&pad_data->gc, pad->gamepad_report0);
break; break;
default: default:
@ -225,38 +214,38 @@ void usbpad_update(const gamepad_data *pad_data)
} }
} }
void usbpad_forceVibrate(char force) void usbpad_forceVibrate(struct usbpad *pad, char force)
{ {
force_vibrate = force; pad->force_vibrate = force;
} }
char usbpad_mustVibrate(void) char usbpad_mustVibrate(struct usbpad *pad)
{ {
if (force_vibrate) { if (pad->force_vibrate) {
return 1; return 1;
} }
if (!vibration_on) { if (!pad->vibration_on) {
gamepad_vibrate = 0; pad->gamepad_vibrate = 0;
} else { } else {
if (constant_force > 0x7f) { if (pad->constant_force > 0x7f) {
gamepad_vibrate = 1; pad->gamepad_vibrate = 1;
} else if (periodic_magnitude > 0x7f) { } else if (pad->periodic_magnitude > 0x7f) {
gamepad_vibrate = 1; pad->gamepad_vibrate = 1;
} else { } else {
gamepad_vibrate = 0; pad->gamepad_vibrate = 0;
} }
} }
return gamepad_vibrate; return pad->gamepad_vibrate;
} }
unsigned char *usbpad_getReportBuffer(void) unsigned char *usbpad_getReportBuffer(struct usbpad *pad)
{ {
return gamepad_report0; return pad->gamepad_report0;
} }
uint16_t usbpad_hid_get_report(struct usb_request *rq, const uint8_t **dat) uint16_t usbpad_hid_get_report(struct usbpad *pad, struct usb_request *rq, const uint8_t **dat)
{ {
uint8_t report_id = (rq->wValue & 0xff); uint8_t report_id = (rq->wValue & 0xff);
@ -271,15 +260,16 @@ uint16_t usbpad_hid_get_report(struct usb_request *rq, const uint8_t **dat)
if (report_id == 1) { // Joystick if (report_id == 1) { // Joystick
// report_id = rq->wValue & 0xff // report_id = rq->wValue & 0xff
// interface = rq->wIndex // interface = rq->wIndex
*dat = gamepad_report0; *dat = pad->gamepad_report0;
printf_P(PSTR("Get joy report\r\n")); printf_P(PSTR("Get joy report\r\n"));
return REPORT_SIZE; return USBPAD_REPORT_SIZE
;
} else if (report_id == 2) { // 2 : ES playing } else if (report_id == 2) { // 2 : ES playing
hid_report_data[0] = report_id; pad->hid_report_data[0] = report_id;
hid_report_data[1] = 0; pad->hid_report_data[1] = 0;
hid_report_data[2] = _FFB_effect_index; pad->hid_report_data[2] = pad->_FFB_effect_index;
printf_P(PSTR("ES playing\r\n")); printf_P(PSTR("ES playing\r\n"));
*dat = hid_report_data; *dat = pad->hid_report_data;
return 3; return 3;
} else { } else {
printf_P(PSTR("Get input report %d ??\r\n"), rq->wValue & 0xff); printf_P(PSTR("Get input report %d ??\r\n"), rq->wValue & 0xff);
@ -289,32 +279,32 @@ uint16_t usbpad_hid_get_report(struct usb_request *rq, const uint8_t **dat)
case HID_REPORT_TYPE_FEATURE: case HID_REPORT_TYPE_FEATURE:
if (report_id == PID_BLOCK_LOAD_REPORT) { if (report_id == PID_BLOCK_LOAD_REPORT) {
hid_report_data[0] = report_id; pad->hid_report_data[0] = report_id;
hid_report_data[1] = 0x1; // Effect block index pad->hid_report_data[1] = 0x1; // Effect block index
hid_report_data[2] = 0x1; // (1: success, 2: oom, 3: load error) pad->hid_report_data[2] = 0x1; // (1: success, 2: oom, 3: load error)
hid_report_data[3] = 10; pad->hid_report_data[3] = 10;
hid_report_data[4] = 10; pad->hid_report_data[4] = 10;
printf_P(PSTR("block load\r\n")); printf_P(PSTR("block load\r\n"));
*dat = hid_report_data; *dat = pad->hid_report_data;
return 5; return 5;
} }
else if (report_id == PID_SIMULTANEOUS_MAX) { else if (report_id == PID_SIMULTANEOUS_MAX) {
hid_report_data[0] = report_id; pad->hid_report_data[0] = report_id;
// ROM Effect Block count // ROM Effect Block count
hid_report_data[1] = 0x1; pad->hid_report_data[1] = 0x1;
hid_report_data[2] = 0x1; pad->hid_report_data[2] = 0x1;
// PID pool move report? // PID pool move report?
hid_report_data[3] = 0xff; pad->hid_report_data[3] = 0xff;
hid_report_data[4] = 1; pad->hid_report_data[4] = 1;
printf_P(PSTR("simultaneous max\r\n")); printf_P(PSTR("simultaneous max\r\n"));
*dat = hid_report_data; *dat = pad->hid_report_data;
return 5; return 5;
} }
else if (report_id == REPORT_CREATE_EFFECT) { else if (report_id == REPORT_CREATE_EFFECT) {
hid_report_data[0] = report_id; pad->hid_report_data[0] = report_id;
hid_report_data[1] = 1; pad->hid_report_data[1] = 1;
printf_P(PSTR("create effect\r\n")); printf_P(PSTR("create effect\r\n"));
*dat = hid_report_data; *dat = pad->hid_report_data;
return 2; return 2;
} else { } else {
printf_P(PSTR("Unknown feature %d\r\n"), rq->wValue & 0xff); printf_P(PSTR("Unknown feature %d\r\n"), rq->wValue & 0xff);
@ -326,7 +316,7 @@ uint16_t usbpad_hid_get_report(struct usb_request *rq, const uint8_t **dat)
return 0; return 0;
} }
uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data, uint16_t len) uint8_t usbpad_hid_set_report(struct usbpad *pad, const struct usb_request *rq, const uint8_t *data, uint16_t len)
{ {
if (len < 1) { if (len < 1) {
printf_P(PSTR("shrt\n")); printf_P(PSTR("shrt\n"));
@ -345,24 +335,24 @@ uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data,
break; break;
case REPORT_DISABLE_ACTUATORS: case REPORT_DISABLE_ACTUATORS:
printf_P(PSTR("disable actuators\r\n")); printf_P(PSTR("disable actuators\r\n"));
periodic_magnitude = 0; pad->periodic_magnitude = 0;
constant_force = 0; pad->constant_force = 0;
vibration_on = 0; pad->vibration_on = 0;
break; break;
case REPORT_PID_POOL: case REPORT_PID_POOL:
printf_P(PSTR("pid pool\r\n")); printf_P(PSTR("pid pool\r\n"));
break; break;
case REPORT_SET_EFFECT: case REPORT_SET_EFFECT:
_FFB_effect_index = data[1]; pad->_FFB_effect_index = data[1];
printf_P(PSTR("set effect %d\r\n"), data[1]); printf_P(PSTR("set effect %d\r\n"), data[1]);
break; break;
case REPORT_SET_PERIODIC: case REPORT_SET_PERIODIC:
periodic_magnitude = data[2]; pad->periodic_magnitude = data[2];
printf_P(PSTR("periodic mag: %d"), data[2]); printf_P(PSTR("periodic mag: %d"), data[2]);
break; break;
case REPORT_SET_CONSTANT_FORCE: case REPORT_SET_CONSTANT_FORCE:
if (data[1] == 1) { if (data[1] == 1) {
constant_force = data[2]; pad->constant_force = data[2];
printf_P(PSTR("Constant force %d\r\n"), data[2]); printf_P(PSTR("Constant force %d\r\n"), data[2]);
} }
break; break;
@ -373,7 +363,7 @@ uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data,
* Byte 1 : bit 7=rom flag, bits 6-0=effect block index * Byte 1 : bit 7=rom flag, bits 6-0=effect block index
* Byte 2 : Effect operation * Byte 2 : Effect operation
* Byte 3 : Loop count */ * Byte 3 : Loop count */
_loop_count = data[3]<<3; pad->_loop_count = data[3]<<3;
printf_P(PSTR("EFFECT OP: rom=%s, idx=0x%02x"), data[1] & 0x80 ? "Yes":"No", data[1] & 0x7F); printf_P(PSTR("EFFECT OP: rom=%s, idx=0x%02x"), data[1] & 0x80 ? "Yes":"No", data[1] & 0x7F);
@ -386,17 +376,17 @@ uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data,
{ {
case EFFECT_OP_START: case EFFECT_OP_START:
printf_P(PSTR("Start\r\n")); printf_P(PSTR("Start\r\n"));
vibration_on = 1; pad->vibration_on = 1;
break; break;
case EFFECT_OP_START_SOLO: case EFFECT_OP_START_SOLO:
printf_P(PSTR("Start solo\r\n")); printf_P(PSTR("Start solo\r\n"));
vibration_on = 1; pad->vibration_on = 1;
break; break;
case EFFECT_OP_STOP: case EFFECT_OP_STOP:
printf_P(PSTR("Stop\r\n")); printf_P(PSTR("Stop\r\n"));
vibration_on = 0; pad->vibration_on = 0;
break; break;
} }
break; break;
@ -424,7 +414,7 @@ uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data,
switch(data[0]) switch(data[0])
{ {
case REPORT_CREATE_EFFECT: case REPORT_CREATE_EFFECT:
_FFB_effect_index = data[1]; pad->_FFB_effect_index = data[1];
printf_P(PSTR("create effect %d\n"), data[1]); printf_P(PSTR("create effect %d\n"), data[1]);
break; break;

View File

@ -4,16 +4,32 @@
#include "gamepads.h" #include "gamepads.h"
#include "usb.h" #include "usb.h"
void usbpad_init(void); #define USBPAD_REPORT_SIZE 15
struct usbpad {
volatile unsigned char gamepad_vibrate; // output
unsigned char vibration_on, force_vibrate;
unsigned char constant_force;
unsigned char periodic_magnitude;
unsigned char _FFB_effect_index;
#define LOOP_MAX 0xFFFF
unsigned int _loop_count;
unsigned char gamepad_report0[USBPAD_REPORT_SIZE];
unsigned char hid_report_data[8]; // Used for force feedback
};
void usbpad_init(struct usbpad *pad);
int usbpad_getReportSize(void); int usbpad_getReportSize(void);
unsigned char *usbpad_getReportBuffer(void); unsigned char *usbpad_getReportBuffer(struct usbpad *pad);
void usbpad_update(const gamepad_data *pad_data); void usbpad_update(struct usbpad *pad, const gamepad_data *pad_data);
char usbpad_mustVibrate(void); char usbpad_mustVibrate(struct usbpad *pad);
void usbpad_forceVibrate(char force); void usbpad_forceVibrate(struct usbpad *pad, char force);
uint8_t usbpad_hid_set_report(const struct usb_request *rq, const uint8_t *data, uint16_t len); uint8_t usbpad_hid_set_report(struct usbpad *pad, 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); uint16_t usbpad_hid_get_report(struct usbpad *pad, struct usb_request *rq, const uint8_t **dat);
// For mappings. ID starts at 0. // For mappings. ID starts at 0.
#define USB_BTN(id) (0x0001 << (id)) #define USB_BTN(id) (0x0001 << (id))