mirror of
https://github.com/raphnet/gc_n64_usb-v3
synced 2025-01-03 17:58:04 -05:00
Work in progress
This commit is contained in:
parent
255315d93a
commit
d1f3dbc9d8
@ -19,5 +19,11 @@
|
|||||||
#define CFG_PARAM_POLL_INTERVAL2 0x12
|
#define CFG_PARAM_POLL_INTERVAL2 0x12
|
||||||
#define CFG_PARAM_POLL_INTERVAL3 0x13
|
#define CFG_PARAM_POLL_INTERVAL3 0x13
|
||||||
|
|
||||||
|
#define CFG_PARAM_N64_SQUARE 0x20
|
||||||
|
#define CFG_PARAM_GC_MAIN_SQUARE 0x21
|
||||||
|
#define CFG_PARAM_GC_CSTICK_SQUARE 0x22
|
||||||
|
#define CFG_PARAM_FULL_SLIDERS 0x23
|
||||||
|
#define CFG_PARAM_INVERT_TRIG 0x24
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@ PREFIX=/usr/local
|
|||||||
|
|
||||||
PROG=gcn64ctl
|
PROG=gcn64ctl
|
||||||
|
|
||||||
OBJS=main.o gcn64.o mempak.o gcn64lib.o
|
OBJS=main.o gcn64.o mempak.o gcn64lib.o hexdump.o
|
||||||
|
|
||||||
.PHONY : clean install
|
.PHONY : clean install
|
||||||
|
|
||||||
|
BIN
tool/gcn64ctl
BIN
tool/gcn64ctl
Binary file not shown.
@ -358,7 +358,7 @@
|
|||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="checkbutton1">
|
<object class="GtkCheckButton" id="chkbtn_n64_square">
|
||||||
<property name="label" translatable="yes">N64 Square joystick</property>
|
<property name="label" translatable="yes">N64 Square joystick</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
@ -374,7 +374,7 @@
|
|||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="checkbutton2">
|
<object class="GtkCheckButton" id="chkbtn_gc_main_square">
|
||||||
<property name="label" translatable="yes">GC Square main stick</property>
|
<property name="label" translatable="yes">GC Square main stick</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
@ -390,7 +390,7 @@
|
|||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="checkbutton3">
|
<object class="GtkCheckButton" id="chkbtn_gc_cstick_square">
|
||||||
<property name="label" translatable="yes">GC Square C-stick</property>
|
<property name="label" translatable="yes">GC Square C-stick</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
@ -406,7 +406,7 @@
|
|||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="checkbutton4">
|
<object class="GtkCheckButton" id="chkbtn_gc_full_sliders">
|
||||||
<property name="label" translatable="yes">GC Full range sliders
|
<property name="label" translatable="yes">GC Full range sliders
|
||||||
(non-centered)</property>
|
(non-centered)</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -423,7 +423,7 @@
|
|||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="checkbutton5">
|
<object class="GtkCheckButton" id="chkbtn_invert_trig">
|
||||||
<property name="label" translatable="yes">GC Inverted triggers</property>
|
<property name="label" translatable="yes">GC Inverted triggers</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
|
Binary file not shown.
@ -42,6 +42,30 @@ G_MODULE_EXPORT void pollIntervalChanged(GtkWidget *win, gpointer data)
|
|||||||
n = gcn64lib_setConfig(app->current_adapter_handle, CFG_PARAM_POLL_INTERVAL0, &buf, 1);
|
n = gcn64lib_setConfig(app->current_adapter_handle, CFG_PARAM_POLL_INTERVAL0, &buf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
G_MODULE_EXPORT void config_checkbox_changed(GtkWidget *win, gpointer data)
|
||||||
|
{
|
||||||
|
struct application *app = data;
|
||||||
|
struct {
|
||||||
|
unsigned char cfg_param;
|
||||||
|
GtkCheckButton *chkbtn;
|
||||||
|
} configurable_bits[] = {
|
||||||
|
{ CFG_PARAM_N64_SQUARE, GET_UI_ELEMENT(GtkCheckButton, chkbtn_n64_square) },
|
||||||
|
{ CFG_PARAM_GC_MAIN_SQUARE, GET_UI_ELEMENT(GtkCheckButton, chkbtn_gc_main_square) },
|
||||||
|
{ CFG_PARAM_GC_CSTICK_SQUARE, GET_UI_ELEMENT(GtkCheckButton, chkbtn_gc_cstick_square) },
|
||||||
|
{ CFG_PARAM_FULL_SLIDERS, GET_UI_ELEMENT(GtkCheckButton, chkbtn_gc_full_sliders) },
|
||||||
|
{ CFG_PARAM_INVERT_TRIG, GET_UI_ELEMENT(GtkCheckButton, chkbtn_gc_invert_trig) },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
unsigned char buf;
|
||||||
|
|
||||||
|
for (i=0; configurable_bits[i].chkbtn; i++) {
|
||||||
|
buf = gtk_toggle_button_get_active(configurable_bits[i].chkbtn);
|
||||||
|
gcn64lib_setConfig(app->current_adapter_handle, configurable_bits[i], &buf, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
G_MODULE_EXPORT void onMainWindowShow(GtkWidget *win, gpointer data)
|
G_MODULE_EXPORT void onMainWindowShow(GtkWidget *win, gpointer data)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@ -133,6 +157,8 @@ G_MODULE_EXPORT void resume_polling(GtkButton *button, gpointer data)
|
|||||||
gcn64lib_suspendPolling(app->current_adapter_handle, 0);
|
gcn64lib_suspendPolling(app->current_adapter_handle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main( int argc,
|
main( int argc,
|
||||||
char **argv )
|
char **argv )
|
||||||
|
13
tool/hexdump.c
Normal file
13
tool/hexdump.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void printHexBuf(unsigned char *buf, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<n; i++) {
|
||||||
|
printf("%02x ", buf[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
3
tool/hexdump.h
Normal file
3
tool/hexdump.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
void printHexBuf(unsigned char *buf, int n);
|
||||||
|
|
19
tool/main.c
19
tool/main.c
@ -24,6 +24,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include "hexdump.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "gcn64.h"
|
#include "gcn64.h"
|
||||||
#include "gcn64lib.h"
|
#include "gcn64lib.h"
|
||||||
@ -60,16 +61,7 @@ static void printUsage(void)
|
|||||||
printf(" --gc_getstatus_rumble Read GC controller status now (turns rumble ON)\n");
|
printf(" --gc_getstatus_rumble Read GC controller status now (turns rumble ON)\n");
|
||||||
printf(" --n64_getcaps Get N64 controller capabilities (or status such as pak present)\n");
|
printf(" --n64_getcaps Get N64 controller capabilities (or status such as pak present)\n");
|
||||||
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");
|
||||||
}
|
printf(" --n64_mempak_write file Write file to N64 mempak\n");
|
||||||
|
|
||||||
static void printHexBuf(unsigned char *buf, int n)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i<n; i++) {
|
|
||||||
printf("%02x ", buf[i]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -86,6 +78,7 @@ static void printHexBuf(unsigned char *buf, int n)
|
|||||||
#define OPT_RESUME_POLLING 307
|
#define OPT_RESUME_POLLING 307
|
||||||
#define OPT_SET_POLL_INTERVAL 308
|
#define OPT_SET_POLL_INTERVAL 308
|
||||||
#define OPT_GET_POLL_INTERVAL 309
|
#define OPT_GET_POLL_INTERVAL 309
|
||||||
|
#define OPT_N64_MEMPAK_WRITE 310
|
||||||
|
|
||||||
struct option longopts[] = {
|
struct option longopts[] = {
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
@ -104,6 +97,7 @@ struct option longopts[] = {
|
|||||||
{ "outfile", 1, NULL, OPT_OUTFILE },
|
{ "outfile", 1, NULL, OPT_OUTFILE },
|
||||||
{ "set_poll_rate", 1, NULL, OPT_SET_POLL_INTERVAL },
|
{ "set_poll_rate", 1, NULL, OPT_SET_POLL_INTERVAL },
|
||||||
{ "get_poll_rate", 0, NULL, OPT_GET_POLL_INTERVAL },
|
{ "get_poll_rate", 0, NULL, OPT_GET_POLL_INTERVAL },
|
||||||
|
{ "n64_mempak_write", 1, NULL, OPT_N64_MEMPAK_WRITE },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -316,6 +310,11 @@ int main(int argc, char **argv)
|
|||||||
mempak_dump(hdl);
|
mempak_dump(hdl);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_N64_MEMPAK_WRITE:
|
||||||
|
printf("Input file: %s\n", optarg);
|
||||||
|
mempak_writeFromFile(hdl, optarg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_exchange) {
|
if (do_exchange) {
|
||||||
|
139
tool/mempak.c
139
tool/mempak.c
@ -2,6 +2,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "hexdump.h"
|
||||||
#include "gcn64.h"
|
#include "gcn64.h"
|
||||||
#include "gcn64lib.h"
|
#include "gcn64lib.h"
|
||||||
#include "mempak.h"
|
#include "mempak.h"
|
||||||
@ -104,20 +105,19 @@ int mempak_writeBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char data[3
|
|||||||
|
|
||||||
addr_crc = __calc_address_crc(addr);
|
addr_crc = __calc_address_crc(addr);
|
||||||
|
|
||||||
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
cmd[0] = N64_EXPANSION_WRITE;
|
||||||
cmd[1] = 3;
|
cmd[1] = addr_crc>>8; // Address high byte
|
||||||
cmd[2] = N64_EXPANSION_READ;
|
cmd[2] = addr_crc&0xff; // Address low byte
|
||||||
cmd[3] = addr_crc>>8; // Address high byte
|
memcpy(cmd + 3, data, 0x20);
|
||||||
cmd[4] = addr_crc&0xff; // Address low byte
|
cmdlen = 3 + 0x20;
|
||||||
memcpy(cmd + 5, data, 0x20);
|
|
||||||
|
|
||||||
cmdlen = 5 + 0x20;
|
n = gcn64lib_rawSiCommand(hdl, 0, cmd, cmdlen, cmd, sizeof(cmd));
|
||||||
|
if (n != 1) {
|
||||||
n = gcn64_exchange(hdl, cmd, cmdlen, cmd, sizeof(cmd));
|
printf("write block returned != 1 (%d)\n", n);
|
||||||
if (n != 35)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0x20;
|
return cmd[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
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])
|
||||||
@ -134,16 +134,6 @@ int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32]
|
|||||||
cmd[1] = addr_crc>>8; // Address high byte
|
cmd[1] = addr_crc>>8; // Address high byte
|
||||||
cmd[2] = addr_crc&0xff; // Address low byte
|
cmd[2] = addr_crc&0xff; // Address low byte
|
||||||
|
|
||||||
/*
|
|
||||||
cmd[0] = RQ_GCN64_RAW_SI_COMMAND;
|
|
||||||
cmd[1] = 3;
|
|
||||||
cmd[2] = N64_EXPANSION_READ;
|
|
||||||
cmd[3] = addr_crc>>8; // Address high byte
|
|
||||||
cmd[4] = addr_crc&0xff; // Address low byte
|
|
||||||
cmdlen = 5;
|
|
||||||
*/
|
|
||||||
//printf("Addr 0x%04x with crc -> 0x%04x\n", addr, addr_crc);
|
|
||||||
|
|
||||||
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 3, cmd, sizeof(cmd));
|
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 3, cmd, sizeof(cmd));
|
||||||
if (n != 33) {
|
if (n != 33) {
|
||||||
printf("Hey! %d\n", n);
|
printf("Hey! %d\n", n);
|
||||||
@ -169,16 +159,57 @@ int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32]
|
|||||||
int mempak_init(gcn64_hdl_t hdl)
|
int mempak_init(gcn64_hdl_t hdl)
|
||||||
{
|
{
|
||||||
unsigned char buf[0x20];
|
unsigned char buf[0x20];
|
||||||
|
int res;
|
||||||
|
|
||||||
memset(buf, 0xfe, 32);
|
memset(buf, 0xfe, 32);
|
||||||
mempak_writeBlock(hdl, 0x8000, buf);
|
res = mempak_writeBlock(hdl, 0x8001, buf);
|
||||||
memset(buf, 0x80, 32);
|
|
||||||
mempak_writeBlock(hdl, 0x8000, buf);
|
if (res == 0xe1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DUMP_SIZE 0x8000
|
||||||
|
|
||||||
|
int mempak_writeAll(gcn64_hdl_t hdl, unsigned char srcbuf[0x8000])
|
||||||
|
{
|
||||||
|
unsigned short addr;
|
||||||
|
unsigned char readback[0x20];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
for (addr = 0x0000; addr < DUMP_SIZE; addr+= 0x20)
|
||||||
|
{
|
||||||
|
printf("Writing address 0x%04x / 0x8000\r", addr); fflush(stdout);
|
||||||
|
res = mempak_writeBlock(hdl, addr, &srcbuf[addr]);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Write error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nwrite returned:0x %02x\n", res);
|
||||||
|
printHexBuf(&srcbuf[addr], res);
|
||||||
|
|
||||||
|
|
||||||
|
if (0x20 != mempak_readBlock(hdl, addr, readback)) {
|
||||||
|
fprintf(stderr, "readback failed\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Wrote: ");
|
||||||
|
printHexBuf(&srcbuf[addr], 0x20);
|
||||||
|
|
||||||
|
printf("Read: ");
|
||||||
|
printHexBuf(readback, 0x20);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("\nDone!\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DUMP_SIZE 0x8000
|
|
||||||
|
|
||||||
int mempak_readAll(gcn64_hdl_t hdl, unsigned char dstbuf[0x8000])
|
int mempak_readAll(gcn64_hdl_t hdl, unsigned char dstbuf[0x8000])
|
||||||
{
|
{
|
||||||
@ -236,7 +267,7 @@ int mempak_dumpToFile(gcn64_hdl_t hdl, const char *out_filename)
|
|||||||
int copies;
|
int copies;
|
||||||
|
|
||||||
printf("Init pak\n");
|
printf("Init pak\n");
|
||||||
mempak_init(hdl);
|
// mempak_init(hdl);
|
||||||
printf("Reading card...\n");
|
printf("Reading card...\n");
|
||||||
mempak_readAll(hdl, cardbuf);
|
mempak_readAll(hdl, cardbuf);
|
||||||
|
|
||||||
@ -261,3 +292,59 @@ int mempak_dumpToFile(gcn64_hdl_t hdl, const char *out_filename)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mempak_writeFromFile(gcn64_hdl_t hdl, const char *in_filename)
|
||||||
|
{
|
||||||
|
unsigned char cardbuf[0x8000];
|
||||||
|
FILE *fptr;
|
||||||
|
long file_size;
|
||||||
|
int i;
|
||||||
|
int num_images = -1;
|
||||||
|
long offset = 0;
|
||||||
|
|
||||||
|
fptr = fopen(in_filename, "rb");
|
||||||
|
if (!fptr) {
|
||||||
|
perror("fopen");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fptr, 0, SEEK_END);
|
||||||
|
file_size = ftell(fptr);
|
||||||
|
fseek(fptr, 0, SEEK_SET);
|
||||||
|
|
||||||
|
printf("File size: %ld bytes\n", file_size);
|
||||||
|
|
||||||
|
/* Raw binary images. Those can contain more than one card's data. For
|
||||||
|
* instance, Mupen64 seems to contain four saves. */
|
||||||
|
for (i=0; i<4; i++) {
|
||||||
|
if (file_size == 0x8000*i) {
|
||||||
|
num_images = i+1;
|
||||||
|
printf("MPK file Contains %d image(s)\n", num_images);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_images < 0) {
|
||||||
|
char header[11];
|
||||||
|
char *magic = "123-456-STD";
|
||||||
|
/* If the size is not a fixed multiple, it could be a .N64 file */
|
||||||
|
fread(header, 11, 1, fptr);
|
||||||
|
if (0 == memcmp(header, magic, sizeof(header))) {
|
||||||
|
printf(".N64 file detected\n");
|
||||||
|
// TODO : Extract comments and other info. from the header
|
||||||
|
offset = 0x1040; // Thanks to N-Rage`s Dinput8 Plugin sources
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fptr, offset, SEEK_SET);
|
||||||
|
fread(cardbuf, sizeof(cardbuf), 1, fptr);
|
||||||
|
fclose(fptr);
|
||||||
|
|
||||||
|
|
||||||
|
printf("Init pak\n");
|
||||||
|
mempak_init(hdl);
|
||||||
|
printf("Writing card...\n");
|
||||||
|
mempak_writeAll(hdl, cardbuf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,5 +2,5 @@
|
|||||||
int 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);
|
||||||
|
int mempak_writeFromFile(gcn64_hdl_t hdl, const char *in_filename);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user