mirror of
https://github.com/raphnet/gc_n64_usb-v3
synced 2024-12-21 23:08:53 -05:00
Channels for raw SI commands
Configurable poll interval
This commit is contained in:
parent
fd83e0ae7d
commit
0627841025
41
config.c
41
config.c
@ -10,10 +10,15 @@ struct eeprom_data_struct g_eeprom_data;
|
|||||||
* values. */
|
* values. */
|
||||||
void eeprom_app_write_defaults(void)
|
void eeprom_app_write_defaults(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
const char default_serial[SERIAL_NUM_LEN] = { '0','0','0','0','0','1' };
|
const char default_serial[SERIAL_NUM_LEN] = { '0','0','0','0','0','1' };
|
||||||
|
|
||||||
memcpy(g_eeprom_data.cfg.serial, default_serial, SERIAL_NUM_LEN);
|
memcpy(g_eeprom_data.cfg.serial, default_serial, SERIAL_NUM_LEN);
|
||||||
g_eeprom_data.cfg.mode = CFG_MODE_STANDARD;
|
g_eeprom_data.cfg.mode = CFG_MODE_STANDARD;
|
||||||
|
|
||||||
|
for (i=0; i<NUM_CHANNELS; i++) {
|
||||||
|
g_eeprom_data.cfg.poll_interval[i] = 5; // 5ms default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void config_set_serial(char serial[SERIAL_NUM_LEN])
|
static void config_set_serial(char serial[SERIAL_NUM_LEN])
|
||||||
@ -32,6 +37,24 @@ unsigned char config_getParam(unsigned char param, unsigned char *value, unsigne
|
|||||||
case CFG_PARAM_SERIAL:
|
case CFG_PARAM_SERIAL:
|
||||||
memcpy(value, g_eeprom_data.cfg.serial, SERIAL_NUM_LEN);
|
memcpy(value, g_eeprom_data.cfg.serial, SERIAL_NUM_LEN);
|
||||||
return SERIAL_NUM_LEN;
|
return SERIAL_NUM_LEN;
|
||||||
|
case CFG_PARAM_POLL_INTERVAL0:
|
||||||
|
*value = g_eeprom_data.cfg.poll_interval[0];
|
||||||
|
return 1;
|
||||||
|
#if NUM_CHANNELS > 1
|
||||||
|
case CFG_PARAM_POLL_INTERVAL1:
|
||||||
|
*value = g_eeprom_data.cfg.poll_interval[1];
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
#if NUM_CHANNELS > 2
|
||||||
|
case CFG_PARAM_POLL_INTERVAL2:
|
||||||
|
*value = g_eeprom_data.cfg.poll_interval[2];
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
#if NUM_CHANNELS > 3
|
||||||
|
case CFG_PARAM_POLL_INTERVAL3:
|
||||||
|
*value = g_eeprom_data.cfg.poll_interval[3];
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -50,6 +73,24 @@ unsigned char config_setParam(unsigned char param, const unsigned char *value)
|
|||||||
case CFG_PARAM_SERIAL:
|
case CFG_PARAM_SERIAL:
|
||||||
config_set_serial((char*)value);
|
config_set_serial((char*)value);
|
||||||
return 1;
|
return 1;
|
||||||
|
case CFG_PARAM_POLL_INTERVAL0:
|
||||||
|
g_eeprom_data.cfg.poll_interval[0] = value[0];
|
||||||
|
return 1;
|
||||||
|
#if NUM_CHANNELS > 1
|
||||||
|
case CFG_PARAM_POLL_INTERVAL1:
|
||||||
|
g_eeprom_data.cfg.poll_interval[1] = value[0];
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
#if NUM_CHANNELS > 2
|
||||||
|
case CFG_PARAM_POLL_INTERVAL2:
|
||||||
|
g_eeprom_data.cfg.poll_interval[2] = value[0];
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
#if NUM_CHANNELS > 3
|
||||||
|
case CFG_PARAM_POLL_INTERVAL3:
|
||||||
|
g_eeprom_data.cfg.poll_interval[3] = value[0];
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
2
config.h
2
config.h
@ -1,10 +1,12 @@
|
|||||||
#ifndef _config_h__
|
#ifndef _config_h__
|
||||||
#define _config_h__
|
#define _config_h__
|
||||||
|
|
||||||
|
#define NUM_CHANNELS 4
|
||||||
#define SERIAL_NUM_LEN 6
|
#define SERIAL_NUM_LEN 6
|
||||||
struct eeprom_cfg {
|
struct eeprom_cfg {
|
||||||
uint8_t serial[SERIAL_NUM_LEN];
|
uint8_t serial[SERIAL_NUM_LEN];
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
uint8_t poll_interval[NUM_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
void eeprom_app_write_defaults(void);
|
void eeprom_app_write_defaults(void);
|
||||||
|
18
hiddata.c
18
hiddata.c
@ -38,9 +38,8 @@ 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(const struct usb_request *rq, const uint8_t *dat, uint16_t len)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
int i;
|
||||||
printf("Set data %d\n", len);
|
printf("Set data %d\n", len);
|
||||||
for (i=0; i<len; i++) {
|
for (i=0; i<len; i++) {
|
||||||
printf("0x%02x ", dat[i]);
|
printf("0x%02x ", dat[i]);
|
||||||
@ -57,8 +56,8 @@ uint8_t hiddata_set_report(const struct usb_request *rq, const uint8_t *dat, uin
|
|||||||
|
|
||||||
static void hiddata_processCommandBuffer(void)
|
static void hiddata_processCommandBuffer(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int bits;
|
int bits;
|
||||||
|
unsigned char channel;
|
||||||
|
|
||||||
if (cmdbuf_len < 1) {
|
if (cmdbuf_len < 1) {
|
||||||
state = STATE_IDLE;
|
state = STATE_IDLE;
|
||||||
@ -73,11 +72,13 @@ static void hiddata_processCommandBuffer(void)
|
|||||||
break;
|
break;
|
||||||
case RQ_GCN64_RAW_SI_COMMAND:
|
case RQ_GCN64_RAW_SI_COMMAND:
|
||||||
// TODO : Range checking
|
// TODO : Range checking
|
||||||
// cmd : RQ, LEN, data[]
|
// cmdbuf[] : RQ, CHN, LEN, data[]
|
||||||
bits = gcn64_transaction(cmdbuf+2, cmdbuf[1]);
|
channel = cmdbuf[1];
|
||||||
|
bits = gcn64_transaction(cmdbuf+3, cmdbuf[2]);
|
||||||
cmdbuf_len = bits / 8; // The above return a number of bits
|
cmdbuf_len = bits / 8; // The above return a number of bits
|
||||||
gcn64_protocol_getBytes(0, cmdbuf_len, cmdbuf + 2);
|
gcn64_protocol_getBytes(0, cmdbuf_len, cmdbuf + 3);
|
||||||
cmdbuf_len += 2; // Answer: RQ, LEN, data[]
|
cmdbuf[2] = cmdbuf_len;
|
||||||
|
cmdbuf_len += 3; // Answer: RQ, CHN, LEN, data[]
|
||||||
break;
|
break;
|
||||||
case RQ_GCN64_GET_CONFIG_PARAM:
|
case RQ_GCN64_GET_CONFIG_PARAM:
|
||||||
// Cmd : RQ, PARAM
|
// Cmd : RQ, PARAM
|
||||||
@ -92,7 +93,8 @@ static void hiddata_processCommandBuffer(void)
|
|||||||
cmdbuf_len = 2;
|
cmdbuf_len = 2;
|
||||||
break;
|
break;
|
||||||
case RQ_GCN64_SUSPEND_POLLING:
|
case RQ_GCN64_SUSPEND_POLLING:
|
||||||
g_polling_suspended = 1;
|
// CMD: RQ, PARAM
|
||||||
|
g_polling_suspended = cmdbuf[1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
main.c
13
main.c
@ -480,6 +480,14 @@ void eeprom_app_ready(void)
|
|||||||
|
|
||||||
char g_polling_suspended = 0;
|
char g_polling_suspended = 0;
|
||||||
|
|
||||||
|
void pollDelay(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0; i<g_eeprom_data.cfg.poll_interval[0]; i++) {
|
||||||
|
_delay_ms(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
Gamepad *pad = NULL;
|
Gamepad *pad = NULL;
|
||||||
@ -512,7 +520,10 @@ int main(void)
|
|||||||
// for polling the controller...
|
// for polling the controller...
|
||||||
hiddata_doTask();
|
hiddata_doTask();
|
||||||
|
|
||||||
_delay_ms(5);
|
if (!g_polling_suspended) {
|
||||||
|
pollDelay();
|
||||||
|
}
|
||||||
|
|
||||||
decideVibration();
|
decideVibration();
|
||||||
|
|
||||||
if (last_v != gamepad_vibrate) {
|
if (last_v != gamepad_vibrate) {
|
||||||
|
@ -14,5 +14,10 @@
|
|||||||
|
|
||||||
#define CFG_PARAM_SERIAL 0x01
|
#define CFG_PARAM_SERIAL 0x01
|
||||||
|
|
||||||
|
#define CFG_PARAM_POLL_INTERVAL0 0x10
|
||||||
|
#define CFG_PARAM_POLL_INTERVAL1 0x11
|
||||||
|
#define CFG_PARAM_POLL_INTERVAL2 0x12
|
||||||
|
#define CFG_PARAM_POLL_INTERVAL3 0x13
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@ PREFIX=/usr/local
|
|||||||
|
|
||||||
PROG=gcn64ctl
|
PROG=gcn64ctl
|
||||||
|
|
||||||
OBJS=main.o gcn64.o mempak.o
|
OBJS=main.o gcn64.o mempak.o gcn64lib.o
|
||||||
|
|
||||||
.PHONY : clean install
|
.PHONY : clean install
|
||||||
|
|
||||||
|
@ -35,6 +35,5 @@ int gcn64_poll_result(gcn64_hdl_t hdl, unsigned char *cmd, int cmdlen);
|
|||||||
|
|
||||||
int gcn64_exchange(gcn64_hdl_t hdl, unsigned char *outcmd, int outlen, unsigned char *result, int result_max);
|
int gcn64_exchange(gcn64_hdl_t hdl, unsigned char *outcmd, int outlen, unsigned char *result, int result_max);
|
||||||
|
|
||||||
|
|
||||||
#endif // _gcn64_h__
|
#endif // _gcn64_h__
|
||||||
|
|
||||||
|
BIN
tool/gcn64ctl
Executable file
BIN
tool/gcn64ctl
Executable file
Binary file not shown.
77
tool/gcn64lib.c
Normal file
77
tool/gcn64lib.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "gcn64lib.h"
|
||||||
|
#include "../requests.h"
|
||||||
|
|
||||||
|
int gcn64lib_getConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *rx, unsigned char rx_max)
|
||||||
|
{
|
||||||
|
unsigned char cmd[2];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
cmd[0] = RQ_GCN64_GET_CONFIG_PARAM;
|
||||||
|
cmd[1] = param;
|
||||||
|
|
||||||
|
n = gcn64_exchange(hdl, cmd, 2, rx, rx_max);
|
||||||
|
if (n<2)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
n -= 2;
|
||||||
|
|
||||||
|
// Drop the leading CMD and PARAM
|
||||||
|
if (n) {
|
||||||
|
memmove(rx, rx+2, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
int gcn64lib_setConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *data, unsigned char len)
|
||||||
|
{
|
||||||
|
unsigned char cmd[2 + len];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
cmd[0] = RQ_GCN64_SET_CONFIG_PARAM;
|
||||||
|
cmd[1] = param;
|
||||||
|
memcpy(cmd + 2, data, len);
|
||||||
|
|
||||||
|
n = gcn64_exchange(hdl, cmd, 2 + len, cmd, sizeof(cmd));
|
||||||
|
if (n<0)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gcn64lib_suspendPolling(gcn64_hdl_t hdl, unsigned char suspend)
|
||||||
|
{
|
||||||
|
unsigned char cmd[2];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
cmd[0] = RQ_GCN64_SUSPEND_POLLING;
|
||||||
|
cmd[1] = suspend;
|
||||||
|
|
||||||
|
n = gcn64_exchange(hdl, cmd, 2, cmd, sizeof(cmd));
|
||||||
|
if (n<0)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gcn64lib_rawSiCommand(gcn64_hdl_t hdl, unsigned char channel, unsigned char *tx, unsigned char tx_len, unsigned char *rx, unsigned char max_rx)
|
||||||
|
{
|
||||||
|
unsigned char cmd[3 + tx_len];
|
||||||
|
int cmdlen, rx_len, n;
|
||||||
|
|
||||||
|
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
||||||
|
cmd[1] = channel;
|
||||||
|
cmd[2] = tx_len;
|
||||||
|
memcpy(cmd+3, tx, tx_len);
|
||||||
|
cmdlen = 3 + tx_len;
|
||||||
|
|
||||||
|
n = gcn64_exchange(hdl, cmd, cmdlen, rx, max_rx);
|
||||||
|
if (n<0)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
rx_len = rx[2];
|
||||||
|
|
||||||
|
memmove(rx, rx + 3, rx_len);
|
||||||
|
|
||||||
|
return rx_len;
|
||||||
|
}
|
11
tool/gcn64lib.h
Normal file
11
tool/gcn64lib.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _gcn64_lib_h__
|
||||||
|
#define _gcn64_lib_h__
|
||||||
|
|
||||||
|
#include "gcn64.h"
|
||||||
|
|
||||||
|
int gcn64lib_suspendPolling(gcn64_hdl_t hdl, unsigned char suspend);
|
||||||
|
int gcn64lib_setConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *data, unsigned char len);
|
||||||
|
int gcn64lib_getConfig(gcn64_hdl_t hdl, unsigned char param, unsigned char *rx, unsigned char rx_max);
|
||||||
|
int gcn64lib_rawSiCommand(gcn64_hdl_t hdl, unsigned char channel, unsigned char *tx, unsigned char tx_len, unsigned char *rx, unsigned char max_rx);
|
||||||
|
|
||||||
|
#endif // _gcn64_lib_h__
|
5
tool/gcn64utils.h
Normal file
5
tool/gcn64utils.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#ifndef _gcn64_utils_h__
|
||||||
|
#define _gcn64_utils_h__
|
||||||
|
|
||||||
|
#endif // _gcn64_utils_h__
|
||||||
|
|
106
tool/main.c
106
tool/main.c
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "gcn64.h"
|
#include "gcn64.h"
|
||||||
|
#include "gcn64lib.h"
|
||||||
#include "mempak.h"
|
#include "mempak.h"
|
||||||
#include "../requests.h"
|
#include "../requests.h"
|
||||||
#include "../gcn64_protocol.h"
|
#include "../gcn64_protocol.h"
|
||||||
@ -40,15 +41,18 @@ static void printUsage(void)
|
|||||||
printf(" -l, --list List devices\n");
|
printf(" -l, --list List devices\n");
|
||||||
printf(" -s serial Operate on specified device (required unless -f is specified)\n");
|
printf(" -s serial Operate on specified device (required unless -f is specified)\n");
|
||||||
printf(" -f, --force If no serial is specified, use first device detected.\n");
|
printf(" -f, --force If no serial is specified, use first device detected.\n");
|
||||||
printf(" -o, --outfile Output file for read operations (eg: --n64-mempak-dump)\n");
|
printf(" -o, --outfile file Output file for read operations (eg: --n64-mempak-dump)\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Configuration commands:\n");
|
printf("Configuration commands:\n");
|
||||||
printf(" --set_serial serial Assign a new device serial number\n");
|
printf(" --set_serial serial Assign a new device serial number\n");
|
||||||
printf(" --get_serial Read serial from eeprom\n");
|
printf(" --get_serial Read serial from eeprom\n");
|
||||||
|
printf(" --set_poll_rate ms Set time between controller polls in milliseconds\n");
|
||||||
|
printf(" --get_poll_rate Read configured poll rate\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Advanced commands:\n");
|
printf("Advanced commands:\n");
|
||||||
printf(" --bootloader Re-enumerate in bootloader mode\n");
|
printf(" --bootloader Re-enumerate in bootloader mode\n");
|
||||||
printf(" --suspend_polling Stop polling controller\n");
|
printf(" --suspend_polling Stop polling the controller\n");
|
||||||
|
printf(" --resume_polling Re-start polling the controller\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Raw controller commands:\n");
|
printf("Raw controller commands:\n");
|
||||||
printf(" --n64_getstatus Read N64 controller status now\n");
|
printf(" --n64_getstatus Read N64 controller status now\n");
|
||||||
@ -58,6 +62,17 @@ static void printUsage(void)
|
|||||||
printf(" --n64_mempak_dump Dump N64 mempak contents (Use with --outfile to write to file)\n");
|
printf(" --n64_mempak_dump Dump N64 mempak contents (Use with --outfile to write to file)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void printHexBuf(unsigned char *buf, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
printf("%02x ", buf[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define OPT_OUTFILE 'o'
|
#define OPT_OUTFILE 'o'
|
||||||
#define OPT_SET_SERIAL 257
|
#define OPT_SET_SERIAL 257
|
||||||
#define OPT_GET_SERIAL 258
|
#define OPT_GET_SERIAL 258
|
||||||
@ -68,6 +83,9 @@ static void printUsage(void)
|
|||||||
#define OPT_N64_MEMPAK_DUMP 304
|
#define OPT_N64_MEMPAK_DUMP 304
|
||||||
#define OPT_N64_GETCAPS 305
|
#define OPT_N64_GETCAPS 305
|
||||||
#define OPT_SUSPEND_POLLING 306
|
#define OPT_SUSPEND_POLLING 306
|
||||||
|
#define OPT_RESUME_POLLING 307
|
||||||
|
#define OPT_SET_POLL_INTERVAL 308
|
||||||
|
#define OPT_GET_POLL_INTERVAL 309
|
||||||
|
|
||||||
struct option longopts[] = {
|
struct option longopts[] = {
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
@ -82,7 +100,10 @@ struct option longopts[] = {
|
|||||||
{ "n64_getcaps", 0, NULL, OPT_N64_GETCAPS },
|
{ "n64_getcaps", 0, NULL, OPT_N64_GETCAPS },
|
||||||
{ "n64_mempak_dump", 0, NULL, OPT_N64_MEMPAK_DUMP },
|
{ "n64_mempak_dump", 0, NULL, OPT_N64_MEMPAK_DUMP },
|
||||||
{ "suspend_polling", 0, NULL, OPT_SUSPEND_POLLING },
|
{ "suspend_polling", 0, NULL, OPT_SUSPEND_POLLING },
|
||||||
|
{ "resume_polling", 0, NULL, OPT_RESUME_POLLING },
|
||||||
{ "outfile", 1, NULL, OPT_OUTFILE },
|
{ "outfile", 1, NULL, OPT_OUTFILE },
|
||||||
|
{ "set_poll_rate", 1, NULL, OPT_SET_POLL_INTERVAL },
|
||||||
|
{ "get_poll_rate", 0, NULL, OPT_GET_POLL_INTERVAL },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -209,68 +230,83 @@ int main(int argc, char **argv)
|
|||||||
unsigned char cmd[64] = { };
|
unsigned char cmd[64] = { };
|
||||||
int n;
|
int n;
|
||||||
int cmdlen = 0;
|
int cmdlen = 0;
|
||||||
|
int do_exchange = 0;
|
||||||
|
|
||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
|
case OPT_SET_POLL_INTERVAL:
|
||||||
|
cmd[0] = atoi(optarg);
|
||||||
|
printf("Setting poll interval to %d ms\n", cmd[0]);
|
||||||
|
gcn64lib_setConfig(hdl, CFG_PARAM_POLL_INTERVAL0, cmd, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_GET_POLL_INTERVAL:
|
||||||
|
n = gcn64lib_getConfig(hdl, CFG_PARAM_POLL_INTERVAL0, cmd, sizeof(cmd));
|
||||||
|
if (n == 1) {
|
||||||
|
printf("Poll interval: %d ms\n", cmd[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPT_SET_SERIAL:
|
case OPT_SET_SERIAL:
|
||||||
printf("Setting serial...");
|
printf("Setting serial...");
|
||||||
if (strlen(optarg) != 6) {
|
if (strlen(optarg) != 6) {
|
||||||
fprintf(stderr, "Serial number must be 6 characters\n");
|
fprintf(stderr, "Serial number must be 6 characters\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cmd[0] = RQ_GCN64_SET_CONFIG_PARAM;
|
gcn64lib_setConfig(hdl, CFG_PARAM_SERIAL, (void*)optarg, 6);
|
||||||
cmd[1] = CFG_PARAM_SERIAL;
|
|
||||||
memcpy(cmd + 2, optarg, 6);
|
|
||||||
cmdlen = 8;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_GET_SERIAL:
|
case OPT_GET_SERIAL:
|
||||||
cmd[0] = RQ_GCN64_GET_CONFIG_PARAM;
|
n = gcn64lib_getConfig(hdl, CFG_PARAM_SERIAL, cmd, sizeof(cmd));
|
||||||
cmd[1] = CFG_PARAM_SERIAL;
|
if (n==6) {
|
||||||
cmdlen = 2;
|
cmd[6] = 0;
|
||||||
|
printf("Serial: %s\n", cmd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_BOOTLOADER:
|
case OPT_BOOTLOADER:
|
||||||
printf("Sending 'jump to bootloader' command...");
|
printf("Sending 'jump to bootloader' command...");
|
||||||
cmd[0] = RQ_GCN64_JUMP_TO_BOOTLOADER;
|
cmd[0] = RQ_GCN64_JUMP_TO_BOOTLOADER;
|
||||||
cmdlen = 1;
|
cmdlen = 1;
|
||||||
|
do_exchange = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SUSPEND_POLLING:
|
case OPT_SUSPEND_POLLING:
|
||||||
cmd[0] = RQ_GCN64_SUSPEND_POLLING;
|
gcn64lib_suspendPolling(hdl, 1);
|
||||||
cmdlen = 1;
|
break;
|
||||||
|
|
||||||
|
case OPT_RESUME_POLLING:
|
||||||
|
gcn64lib_suspendPolling(hdl, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_N64_GETSTATUS:
|
case OPT_N64_GETSTATUS:
|
||||||
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
cmd[0] = N64_GET_STATUS;
|
||||||
cmd[1] = 0x01; // Length of SI command
|
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 1, cmd, sizeof(cmd));
|
||||||
cmd[2] = N64_GET_STATUS; // N64 GET status
|
if (n >= 0) {
|
||||||
cmdlen = 3;
|
printf("N64 Get status[%d]: ", n);
|
||||||
break;
|
printHexBuf(cmd, n);
|
||||||
|
}
|
||||||
case OPT_GC_GETSTATUS:
|
|
||||||
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
|
||||||
cmd[1] = 0x03; // Length of SI command
|
|
||||||
cmd[2] = GC_GETSTATUS1;
|
|
||||||
cmd[3] = GC_GETSTATUS2;
|
|
||||||
cmd[4] = GC_GETSTATUS3(0);
|
|
||||||
cmdlen = 5;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_GC_GETSTATUS_RUMBLE:
|
case OPT_GC_GETSTATUS_RUMBLE:
|
||||||
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
case OPT_GC_GETSTATUS:
|
||||||
cmd[1] = 0x03; // Length of SI command
|
cmd[0] = GC_GETSTATUS1;
|
||||||
cmd[2] = GC_GETSTATUS1;
|
cmd[1] = GC_GETSTATUS2;
|
||||||
cmd[3] = GC_GETSTATUS2;
|
cmd[2] = GC_GETSTATUS3(opt == OPT_GC_GETSTATUS_RUMBLE);
|
||||||
cmd[4] = GC_GETSTATUS3(0);
|
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 3, cmd, sizeof(cmd));
|
||||||
cmdlen = 5;
|
if (n >= 0) {
|
||||||
|
printf("GC Get status[%d]: ", n);
|
||||||
|
printHexBuf(cmd, n);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_N64_GETCAPS:
|
case OPT_N64_GETCAPS:
|
||||||
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
cmd[0] = N64_GET_CAPABILITIES;
|
||||||
cmd[1] = 0x01; // Length of SI command
|
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 1, cmd, sizeof(cmd));
|
||||||
cmd[2] = N64_GET_CAPABILITIES; // N64 GET status
|
if (n >= 0) {
|
||||||
cmdlen = 3;
|
printf("N64 Get caps[%d]: ", n);
|
||||||
|
printHexBuf(cmd, n);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_N64_MEMPAK_DUMP:
|
case OPT_N64_MEMPAK_DUMP:
|
||||||
@ -282,7 +318,7 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd[0]) {
|
if (do_exchange) {
|
||||||
int i;
|
int i;
|
||||||
n = gcn64_exchange(hdl, cmd, cmdlen, cmd, sizeof(cmd));
|
n = gcn64_exchange(hdl, cmd, cmdlen, cmd, sizeof(cmd));
|
||||||
if (n<0)
|
if (n<0)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "gcn64.h"
|
#include "gcn64.h"
|
||||||
|
#include "gcn64lib.h"
|
||||||
#include "mempak.h"
|
#include "mempak.h"
|
||||||
#include "../gcn64_protocol.h"
|
#include "../gcn64_protocol.h"
|
||||||
#include "../requests.h"
|
#include "../requests.h"
|
||||||
@ -122,30 +123,42 @@ int mempak_writeBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char data[3
|
|||||||
int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32])
|
int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32])
|
||||||
{
|
{
|
||||||
unsigned char cmd[64];
|
unsigned char cmd[64];
|
||||||
int cmdlen;
|
//int cmdlen;
|
||||||
int n;
|
int n;
|
||||||
uint16_t addr_crc;
|
uint16_t addr_crc;
|
||||||
unsigned char crc;
|
unsigned char crc;
|
||||||
|
|
||||||
addr_crc = __calc_address_crc(addr);
|
addr_crc = __calc_address_crc(addr);
|
||||||
|
|
||||||
|
cmd[0] = N64_EXPANSION_READ;
|
||||||
|
cmd[1] = addr_crc>>8; // Address high byte
|
||||||
|
cmd[2] = addr_crc&0xff; // Address low byte
|
||||||
|
|
||||||
|
/*
|
||||||
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
||||||
cmd[1] = 3;
|
cmd[1] = 3;
|
||||||
cmd[2] = N64_EXPANSION_READ;
|
cmd[2] = N64_EXPANSION_READ;
|
||||||
cmd[3] = addr_crc>>8; // Address high byte
|
cmd[3] = addr_crc>>8; // Address high byte
|
||||||
cmd[4] = addr_crc&0xff; // Address low byte
|
cmd[4] = addr_crc&0xff; // Address low byte
|
||||||
cmdlen = 5;
|
cmdlen = 5;
|
||||||
|
*/
|
||||||
//printf("Addr 0x%04x with crc -> 0x%04x\n", addr, addr_crc);
|
//printf("Addr 0x%04x with crc -> 0x%04x\n", addr, addr_crc);
|
||||||
|
|
||||||
n = gcn64_exchange(hdl, cmd, cmdlen, cmd, sizeof(cmd));
|
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 3, cmd, sizeof(cmd));
|
||||||
if (n != 35)
|
if (n != 33) {
|
||||||
|
printf("Hey! %d\n", n);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(dst, cmd + 2, 0x20);
|
// n = gcn64_exchange(hdl, cmd, cmdlen, cmd, sizeof(cmd));
|
||||||
|
// if (n != 35)
|
||||||
|
// return -1;
|
||||||
|
|
||||||
|
//memcpy(dst, cmd + 2, 0x20);
|
||||||
|
memcpy(dst, cmd, 0x20);
|
||||||
|
|
||||||
crc = __calc_data_crc(dst);
|
crc = __calc_data_crc(dst);
|
||||||
if (crc != cmd[34]) {
|
if (crc != cmd[32]) {
|
||||||
fprintf(stderr, "Bad CRC reading address 0x%04x\n", addr);
|
fprintf(stderr, "Bad CRC reading address 0x%04x\n", addr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -184,7 +197,7 @@ int mempak_readAll(gcn64_hdl_t hdl, unsigned char dstbuf[0x8000])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mempak_dump(gcn64_hdl_t hdl)
|
int mempak_dump(gcn64_hdl_t hdl)
|
||||||
{
|
{
|
||||||
unsigned char cardbuf[0x8000];
|
unsigned char cardbuf[0x8000];
|
||||||
int i,j;
|
int i,j;
|
||||||
@ -193,7 +206,10 @@ void mempak_dump(gcn64_hdl_t hdl)
|
|||||||
mempak_init(hdl);
|
mempak_init(hdl);
|
||||||
|
|
||||||
printf("Reading card...\n");
|
printf("Reading card...\n");
|
||||||
mempak_readAll(hdl, cardbuf);
|
i = mempak_readAll(hdl, cardbuf);
|
||||||
|
if (i<0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
for (i=0; i<DUMP_SIZE; i+=0x20) {
|
for (i=0; i<DUMP_SIZE; i+=0x20) {
|
||||||
printf("%04x: ", i);
|
printf("%04x: ", i);
|
||||||
@ -207,6 +223,8 @@ void mempak_dump(gcn64_hdl_t hdl)
|
|||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NUM_COPIES 4
|
#define NUM_COPIES 4
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
void mempak_dump(gcn64_hdl_t hdl);
|
int mempak_dump(gcn64_hdl_t hdl);
|
||||||
int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32]);
|
int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32]);
|
||||||
int mempak_dumpToFile(gcn64_hdl_t hdl, const char *out_filename);
|
int mempak_dumpToFile(gcn64_hdl_t hdl, const char *out_filename);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user