1
0
mirror of https://github.com/raphnet/gc_n64_usb-v3 synced 2024-12-21 14:58:51 -05:00

Merge branch 'performance'

This commit is contained in:
Raphael Assenat 2017-01-08 16:21:51 -05:00
commit eeb2ecbae4
12 changed files with 213 additions and 38 deletions

View File

@ -7,7 +7,7 @@ include Makefile.inc
PROGNAME=gcn64usb
OBJDIR=objs-$(PROGNAME)
CPU=atmega32u2
CFLAGS=-Wall -mmcu=$(CPU) -DF_CPU=16000000L -Os -DUART1_STDOUT -DVERSIONSTR=$(VERSIONSTR) -DVERSIONSTR_SHORT=$(VERSIONSTR_SHORT)
CFLAGS=-Wall -mmcu=$(CPU) -DF_CPU=16000000L -Os -DUART1_STDOUT -DVERSIONSTR=$(VERSIONSTR) -DVERSIONSTR_SHORT=$(VERSIONSTR_SHORT) -std=gnu99
LDFLAGS=-mmcu=$(CPU) -Wl,-Map=$(PROGNAME).map
HEXFILE=$(PROGNAME).hex
@ -58,3 +58,7 @@ chip_erase:
reset:
dfu-programmer atmega32u2 reset
restart:
- ./scripts/enter_bootloader.sh
./scripts/start.sh $(CPU)

View File

@ -1,3 +1,3 @@
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 intervaltimer.o version.o gcn64txrx0.o gcn64txrx1.o gcn64txrx2.o gcn64txrx3.o gamepads.o
VERSIONSTR=\"3.3.2\"
VERSIONSTR_SHORT=\"3.3\"
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 intervaltimer.o version.o gcn64txrx0.o gcn64txrx1.o gcn64txrx2.o gcn64txrx3.o gamepads.o stkchk.o
VERSIONSTR=\"3.4.0\"
VERSIONSTR_SHORT=\"3.4\"

View File

@ -7,7 +7,7 @@ include Makefile.inc
PROGNAME=gcn64usb-stk500
OBJDIR=objs-$(PROGNAME)
CPU=at90usb1287
CFLAGS=-Wall -mmcu=$(CPU) -DF_CPU=16000000L -Os -DUART1_STDOUT -DSTK525 -DVERSIONSTR=$(VERSIONSTR) -DVERSIONSTR_SHORT=$(VERSIONSTR_SHORT)
CFLAGS=-Wall -mmcu=$(CPU) -DF_CPU=16000000L -Os -DUART1_STDOUT -DSTK525 -DVERSIONSTR=$(VERSIONSTR) -DVERSIONSTR_SHORT=$(VERSIONSTR_SHORT) -std=gnu99
LDFLAGS=-mmcu=$(CPU) -Wl,-Map=$(PROGNAME).map
HEXFILE=$(PROGNAME).hex

View File

@ -24,7 +24,7 @@ const uint8_t dataHidReport[] PROGMEM = {
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 40, // REPORT_COUNT (40)
0x95, 63, // REPORT_COUNT (63)
0x09, 0x01, // USAGE (Vendor defined)
0xB1, 0x00, // FEATURE (Data,Ary,Abs)
0xc0 // END_COLLECTION

View File

@ -25,8 +25,8 @@
#include "version.h"
#include "main.h"
// dataHidReport is 40 bytes.
#define CMDBUF_SIZE 41
// dataHidReport is 63 bytes. Endpoint is 64 bytes.
#define CMDBUF_SIZE 64
#define STATE_IDLE 0
#define STATE_NEW_COMMAND 1 // New command in buffer
@ -74,6 +74,51 @@ uint8_t hiddata_set_report(void *ctx, const struct usb_request *rq, const uint8_
return 0;
}
static uint8_t processBlockIO(void)
{
uint8_t requestCopy[CMDBUF_SIZE];
int i, rx_offset = 0, rx;
uint8_t chn, n_tx, n_rx;
memcpy(requestCopy, cmdbuf, CMDBUF_SIZE);
memset(cmdbuf + 1, 0xff, CMDBUF_SIZE-1);
for (rx_offset = 1, i=1; i<CMDBUF_SIZE; ) {
if (i + 3 >= CMDBUF_SIZE)
break;
chn = requestCopy[i];
if (chn == 0xff)
break;
i++;
n_tx = requestCopy[i];
i++;
n_rx = requestCopy[i];
i++;
if (n_tx == 0)
continue;
if (rx_offset + 1 + n_rx >= CMDBUF_SIZE) {
break;
}
rx = gcn64_transaction(chn, requestCopy + i, n_tx, cmdbuf + rx_offset + 1, n_rx);
cmdbuf[rx_offset] = n_rx;
if (rx <= 0) {
// timeout
cmdbuf[rx_offset] |= 0x80;
} else if (rx < n_rx) {
// less than expected
cmdbuf[rx_offset] |= 0x40;
}
rx_offset += n_rx + 1;
i += n_tx;
}
return 63;
}
static void hiddata_processCommandBuffer(struct hiddata_ops *ops)
{
unsigned char channel;
@ -147,6 +192,9 @@ static void hiddata_processCommandBuffer(struct hiddata_ops *ops)
}
cmdbuf_len = 3;
break;
case RQ_GCN64_BLOCK_IO:
cmdbuf_len = processBlockIO();
break;
}
#ifdef DEBUG

50
main.c
View File

@ -37,16 +37,17 @@
#include "usbstrings.h"
#include "intervaltimer.h"
#include "requests.h"
#include "stkchk.h"
#define MAX_PLAYERS 2
#define GCN64_USB_PID 0x001D
#define N64_USB_PID 0x0020
#define GC_USB_PID 0x0021
#define GCN64_USB_PID 0x0032
#define N64_USB_PID 0x0033
#define GC_USB_PID 0x0034
#define DUAL_GCN64_USB_PID 0x0022
#define DUAL_N64_USB_PID 0x0030
#define DUAL_GC_USB_PID 0x0031
#define DUAL_GCN64_USB_PID 0x0035
#define DUAL_N64_USB_PID 0x0036
#define DUAL_GC_USB_PID 0x0037
/* Those .c files are included rather than linked for we
* want the sizeof() operator to work on the arrays */
@ -54,6 +55,7 @@
#include "dataHidReport.c"
#define MAX_READ_ERRORS 30
static uint8_t error_count[MAX_PLAYERS] = { };
struct cfg0 {
struct usb_configuration_descriptor configdesc;
@ -402,15 +404,6 @@ void eeprom_app_ready(void)
g_usb_strings[USB_STRING_SERIAL_IDX] = serial_from_eeprom;
}
void pollDelay(void)
{
int i;
for (i=0; i<g_eeprom_data.cfg.poll_interval[0]; i++) {
_delay_ms(1);
}
}
static struct usbpad usbpads[MAX_PLAYERS];
static char g_polling_suspended = 0;
@ -442,36 +435,37 @@ int main(void)
{
Gamepad *pads[MAX_PLAYERS] = { };
gamepad_data pad_data;
unsigned char gamepad_vibrate = 0;
unsigned char state = STATE_WAIT_POLLTIME;
int error_count[MAX_PLAYERS] = { };
int i;
int channel;
int num_players = 1;
uint8_t gamepad_vibrate = 0;
uint8_t state = STATE_WAIT_POLLTIME;
uint8_t channel;
uint8_t num_players = 1;
uint8_t i;
hwinit();
usart1_init();
eeprom_init();
intervaltimer_init();
stkchk_init();
switch (g_eeprom_data.cfg.mode)
{
default:
case CFG_MODE_STANDARD:
usbstrings_changeProductString_P(PSTR("GC/N64 to USB v"VERSIONSTR_SHORT));
break;
case CFG_MODE_N64_ONLY:
usbstrings_changeProductString(L"N64 to USB v"VERSIONSTR_SHORT);
usbstrings_changeProductString_P(PSTR("N64 to USB v"VERSIONSTR_SHORT));
device_descriptor.idProduct = N64_USB_PID;
break;
case CFG_MODE_GC_ONLY:
usbstrings_changeProductString(L"Gamecube to USB v"VERSIONSTR_SHORT);
usbstrings_changeProductString_P(PSTR("Gamecube to USB v"VERSIONSTR_SHORT));
device_descriptor.idProduct = GC_USB_PID;
break;
case CFG_MODE_2P_STANDARD:
usbstrings_changeProductString(L"Dual GC/N64 to USB v"VERSIONSTR_SHORT);
usbstrings_changeProductString_P(PSTR("Dual GC/N64 to USB v"VERSIONSTR_SHORT));
device_descriptor.idProduct = DUAL_GCN64_USB_PID;
usb_params.configdesc = (PGM_VOID_P)&cfg0_2p;
usb_params.configdesc_ttllen = sizeof(cfg0_2p);
@ -480,7 +474,7 @@ int main(void)
break;
case CFG_MODE_2P_N64_ONLY:
usbstrings_changeProductString(L"Dual N64 to USB v"VERSIONSTR_SHORT);
usbstrings_changeProductString_P(PSTR("Dual N64 to USB v"VERSIONSTR_SHORT));
device_descriptor.idProduct = DUAL_N64_USB_PID;
usb_params.configdesc = (PGM_VOID_P)&cfg0_2p;
usb_params.configdesc_ttllen = sizeof(cfg0_2p);
@ -489,7 +483,7 @@ int main(void)
break;
case CFG_MODE_2P_GC_ONLY:
usbstrings_changeProductString(L"Dual Gamecube to USB v"VERSIONSTR_SHORT);
usbstrings_changeProductString_P(PSTR("Dual Gamecube to USB v"VERSIONSTR_SHORT));
device_descriptor.idProduct = DUAL_GC_USB_PID;
usb_params.configdesc = (PGM_VOID_P)&cfg0_2p;
usb_params.configdesc_ttllen = sizeof(cfg0_2p);
@ -520,6 +514,10 @@ int main(void)
{
static char last_v[MAX_PLAYERS] = { };
if (stkchk_verify()) {
enterBootLoader();
}
usb_doTasks();
hiddata_doTask(&hiddata_ops);

View File

@ -10,6 +10,7 @@
#define RQ_GCN64_GET_CONTROLLER_TYPE 0x06
#define RQ_GCN64_SET_VIBRATION 0x07
#define RQ_GCN64_RAW_SI_COMMAND 0x80
#define RQ_GCN64_BLOCK_IO 0x81
#define RQ_GCN64_JUMP_TO_BOOTLOADER 0xFF
/* Configuration parameters and constants */

21
scripts/start.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Syntax: ./start.sh CPU"
exit 1;
fi
CPU=$1
echo "Polling for chip..."
while true; do
dfu-programmer $1 start
if [ $? -eq 0 ]; then
echo "Chip found. Started."
break;
fi
sleep 1
done

60
stkchk.c Normal file
View File

@ -0,0 +1,60 @@
#include <stdio.h>
#include <stdint.h>
#include <avr/io.h>
#include <util/atomic.h>
#include "stkchk.h"
extern uint16_t __stack;
extern uint16_t _end;
/** Write a canary at the end of the stack. */
void stkchk_init(void)
{
*((&_end)-1) = 0xDEAD;
}
/** Check if the canary is still alive.
*
* Call this perdiocally to check if the
* stack grew too large.
**/
char stkchk_verify(void)
{
if (*((&_end)-1) != 0xDEAD) {
return -1;
}
return 0;
}
/* In order to get an approximate idea of how
* much stack you are using, this can be called
* at strategic places where you know the
* call stack is deep or where large automatic
* buffers are used.
*/
#ifdef STKCHK_WITH_STATUS_CHECK
void stkchk(const char *fname)
{
static int max_usage = 0;
uint16_t end = ((uint16_t)&_end);
uint16_t s_top = ((uint16_t)&__stack);
uint16_t s_cur = SPL | SPH<<8;
uint16_t used, s_size;
uint8_t grew = 0;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
used = s_top - s_cur;
s_size = s_top - end;
if (used > max_usage) {
max_usage = used;
grew = 1;
}
}
if (grew) {
printf("[stkchk] %s: %d/%d\r\n", fname, used, s_size);
}
}
#endif

16
stkchk.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _stkchk_h__
#define _stkchk_h__
#undef STKCHK_WITH_STATUS_CHECK
#ifdef STKCHK_WITH_STATUS_CHECK
#define stkcheck() stkchk(__FUNCTION__);
void stkchk(const char *label);
#else
#define stkcheck()
#endif
void stkchk_init(void);
char stkchk_verify(void);
#endif // _stkchk_h__

View File

@ -17,13 +17,32 @@
#include <stdlib.h> // for wchar_t
#include "usbstrings.h"
static wchar_t product_string[PRODUCT_STRING_MAXCHARS]; // = L"GC/N64 to USB v"VERSIONSTR_SHORT;
const wchar_t *g_usb_strings[] = {
[0] = L"raphnet technologies", // 1 : Vendor
[1] = L"GC/N64 to USB v"VERSIONSTR_SHORT, // 2: Product
[1] = product_string, // 2: Product
[2] = L"123456", // 3 : Serial
};
void usbstrings_changeProductString(const wchar_t *str)
void usbstrings_changeProductString_P(const char *str)
{
g_usb_strings[1] = str;
const char *s = str;
wchar_t *d = product_string;
uint8_t c;
int n = 0;
do {
/* Make sure target is always NUL terminated. */
n++;
if (n == PRODUCT_STRING_MAXCHARS) {
*d = 0;
break;
}
c = pgm_read_byte(s);
*d = c;
s++; d++;
} while (c);
}

View File

@ -1,13 +1,21 @@
#ifndef _usbstrings_h__
#define _usbstrings_h__
#include <avr/pgmspace.h>
extern const wchar_t *g_usb_strings[];
/* Sample: "Dual Gamecube to USB v3.4" (25) */
#define PRODUCT_STRING_MAXCHARS 32
#define NUM_USB_STRINGS 3
/* Array indexes (i.e. zero-based0 */
#define USB_STRING_SERIAL_IDX 2
void usbstrings_changeProductString(const wchar_t *str);
/**
* \param str Must be in PROGMEM
*/
void usbstrings_changeProductString_P(const char *str);
#endif