diff --git a/tool/Makefile b/tool/Makefile index aa18b2f..9b77c0d 100644 --- a/tool/Makefile +++ b/tool/Makefile @@ -2,13 +2,13 @@ CC=gcc LD=$(CC) CFLAGS=-Wall -g `pkg-config hidapi-hidraw --cflags` -LDFLAGS=`pkg-config hidapi-hidraw --libs` +LDFLAGS=`pkg-config hidapi-hidraw --libs` -g PREFIX=/usr/local PROG=gcn64ctl -OBJS=main.o gcn64.o mempak.o gcn64lib.o hexdump.o +OBJS=main.o gcn64.o mempak.o gcn64lib.o hexdump.o gc2n64_adapter.o .PHONY : clean install diff --git a/tool/gc2n64_adapter.c b/tool/gc2n64_adapter.c new file mode 100644 index 0000000..24edd71 --- /dev/null +++ b/tool/gc2n64_adapter.c @@ -0,0 +1,204 @@ +#include +#include +#include "gcn64lib.h" +#include "gc2n64_adapter.h" +#include "hexdump.h" + +int gc2n64_adapter_echotest(gcn64_hdl_t hdl, int verbose) +{ + unsigned char cmd[35]; + unsigned char buf[64]; + int i, n; + + cmd[0] = 'R'; + cmd[1] = 0x00; // echo + for (i=0; i<33; i++) { + cmd[i+2] = 'A'+i; + } + + n = gcn64lib_rawSiCommand(hdl, 0, cmd, 35, buf, 35); + if (n<0) { + return n; + } + + if (verbose) { + printf(" Sent [%d]: ", 35); printHexBuf(cmd, 35); + printf("Received [%d]: ", n); printHexBuf(buf, n); + if (!memcmp(cmd, buf, 35)) { + printf("Test OK\n"); + } else { + printf("Test failed\n"); + } + } + + return memcmp(cmd, buf, 32); +} + +int gc2n64_adapter_getMapping(gcn64_hdl_t hdl, int id) +{ + unsigned char buf[64]; + unsigned char cmd[4]; + int n; + int mapping_size; + + cmd[0] = 'R'; + cmd[1] = 0x02; // Get mapping + cmd[2] = id; + cmd[3] = 0; // chunk 0 (size) + + n = gcn64lib_rawSiCommand(hdl, 0, cmd, 4, buf, 4); + if (n<0) + return n; + + if (n == 1) { + int i, pos; + mapping_size = buf[0]; + printf("Mapping %d size: %d\n", id, mapping_size); + + for (pos=0, i=0; posin_bootloader) { + printf("gc_to_n64 adapter info: {\n"); + + printf("\tDefault mapping id: %d\n", inf->app.default_mapping_id); + printf("\tDeadzone enabled: %d\n", inf->app.deadzone_enabled); + printf("\tOld v1.5 conversion: %d\n", inf->app.old_v1_5_conversion); + printf("\tFirmware version: %s\n", inf->app.version); + } else { + printf("gc_to_n64 adapter in bootloader mode: {\n"); + + printf("\tBootloader firmware version: %s\n", inf->bootldr.version); + printf("\tMCU page size: %d bytes\n", inf->bootldr.mcu_page_size); + printf("\tBootloader code start address: 0x%04x\n", inf->bootldr.bootloader_start_address); + } + + printf("}\n"); +} + +int gc2n64_adapter_getInfo(gcn64_hdl_t hdl, struct gc2n64_adapter_info *inf) +{ + unsigned char buf[64]; + int n; + + buf[0] = 'R'; + buf[1] = 0x01; // Get device info + + n = gcn64lib_rawSiCommand(hdl, 0, buf, 2, buf, sizeof(buf)); + if (n<0) + return n; + + if (n > 0) { + if (!inf) + return 0; + + inf->in_bootloader = buf[0]; + + if (!inf->in_bootloader) { + inf->app.default_mapping_id = buf[2]; + inf->app.deadzone_enabled = buf[3]; + inf->app.old_v1_5_conversion = buf[4]; + inf->app.version[sizeof(inf->app.version)-1]=0; + strncpy(inf->app.version, (char*)buf+10, sizeof(inf->app.version)-1); + } else { + inf->bootldr.mcu_page_size = buf[1]; + inf->bootldr.bootloader_start_address = buf[2] << 8 | buf[3]; + inf->bootldr.version[sizeof(inf->bootldr.version)-1]=0; + strncpy(inf->bootldr.version, (char*)buf+10, sizeof(inf->bootldr.version)-1); + } + + } else { + printf("No answer (old version?)\n"); + return -1; + } + + return 0; +} + +int gc2n64_adapter_boot_eraseAll(gcn64_hdl_t hdl) +{ + unsigned char buf[64]; + int n; + + buf[0] = 'R'; + buf[1] = 0xf0; + + n = gcn64lib_rawSiCommand(hdl, 0, buf, 2, buf, sizeof(buf)); + if (n<0) + return n; + + if (n != 3) { + fprintf(stderr, "Invalid answer\n"); + return -1; + } + + return 0; +} + +int gc2n64_adapter_boot_readBlock(gcn64_hdl_t hdl, unsigned int block_id, unsigned char dst[32]) +{ + unsigned char buf[64]; + int n; + + buf[0] = 'R'; + buf[1] = 0xf1; + buf[2] = block_id >> 8; + buf[3] = block_id & 0xff; + + n = gcn64lib_rawSiCommand(hdl, 0, buf, 4, buf, sizeof(buf)); + if (n<0) + return n; + + if (n != 32) { + fprintf(stderr, "Invalid answer\n"); + return -1; + } + + memcpy(dst, buf, 32); + + return 0; +} + +int gc2n64_adapter_dumpFlash(gcn64_hdl_t hdl) +{ + int i; + unsigned char buf[0x2000]; + + // Atmega8 : 128 pages of 32 words (64 bytes). 8K. + for (i=0; i<0x2000; i+= 32) + { + gc2n64_adapter_boot_readBlock(hdl, i/32, buf + i); + printf("0x%04x: ", i); + printHexBuf(buf + i, 32); + } + return 0; +} + +int gc2n64_adapter_updateFirmware(gcn64_hdl_t hdl, const char *hexfile) +{ + return 0; +} + diff --git a/tool/gc2n64_adapter.h b/tool/gc2n64_adapter.h new file mode 100644 index 0000000..7a2f5e9 --- /dev/null +++ b/tool/gc2n64_adapter.h @@ -0,0 +1,37 @@ +#ifndef _gc2n64_adapter_h__ +#define _gc2n64_adapter_h__ + +#include "gcn64.h" + +struct gc2n64_adapter_info_app { + unsigned char default_mapping_id; + unsigned char deadzone_enabled; + unsigned char old_v1_5_conversion; + char version[16]; +}; + +struct gc2n64_adapter_info_bootloader { + char version[16]; + unsigned char mcu_page_size; + unsigned short bootloader_start_address; +}; + +struct gc2n64_adapter_info { + int in_bootloader; + union { + struct gc2n64_adapter_info_app app; + struct gc2n64_adapter_info_bootloader bootldr; + }; +}; + +int gc2n64_adapter_echotest(gcn64_hdl_t hdl, int verbosee); +int gc2n64_adapter_getInfo(gcn64_hdl_t hdl, struct gc2n64_adapter_info *inf); +void gc2n64_adapter_printInfo(struct gc2n64_adapter_info *inf); +int gc2n64_adapter_boot_eraseAll(gcn64_hdl_t hdl); +int gc2n64_adapter_boot_readBlock(gcn64_hdl_t hdl, unsigned int block_id, unsigned char dst[32]); +int gc2n64_adapter_dumpFlash(gcn64_hdl_t hdl); +int gc2n64_adapter_updateFirmware(gcn64_hdl_t hdl, const char *hexfile); + + +#endif // _gc2n64_adapter_h__ + diff --git a/tool/gcn64lib.c b/tool/gcn64lib.c index f65e40c..b0c785c 100644 --- a/tool/gcn64lib.c +++ b/tool/gcn64lib.c @@ -59,6 +59,7 @@ int gcn64lib_suspendPolling(gcn64_hdl_t hdl, unsigned char suspend) 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]; + unsigned char rep[3 + 64]; int cmdlen, rx_len, n; cmd[0] = RQ_GCN64_RAW_SI_COMMAND; @@ -67,13 +68,12 @@ int gcn64lib_rawSiCommand(gcn64_hdl_t hdl, unsigned char channel, unsigned char memcpy(cmd+3, tx, tx_len); cmdlen = 3 + tx_len; - n = gcn64_exchange(hdl, cmd, cmdlen, rx, max_rx); + n = gcn64_exchange(hdl, cmd, cmdlen, rep, sizeof(rep)); if (n<0) return n; - rx_len = rx[2]; - - memmove(rx, rx + 3, rx_len); + rx_len = rep[2]; + memcpy(rx, rep + 3, rx_len); return rx_len; } @@ -113,29 +113,3 @@ int gcn64lib_8bit_scan(gcn64_hdl_t hdl, unsigned char min, unsigned char max) return 0; } -int gcn64lib_raphnet_gc_to_n64_getInfo(gcn64_hdl_t hdl) -{ - unsigned char buf[64]; - int n; - - buf[0] = 'R'; - buf[1] = 0x01; // Get device info - - n = gcn64lib_rawSiCommand(hdl, 0, buf, 2, buf, sizeof(buf)); - if (n<0) - return n; - - if (n > 0) { - printf("gc_to_n64 adapter info: {\n"); - printf("\tFirmware version: %s\n", buf+10); - printf("\tDefault mapping id: %d\n", buf[0]); - printf("\tDeadzone enabled: %d\n", buf[1]); - printf("\tOld v1.5 conversion: %d\n", buf[2]); - printf("}\n"); - } else { - printf("No answer (old version?)\n"); - } - - return 0; -} - diff --git a/tool/gcn64lib.h b/tool/gcn64lib.h index ab1e362..7e76699 100644 --- a/tool/gcn64lib.h +++ b/tool/gcn64lib.h @@ -10,6 +10,5 @@ int gcn64lib_rawSiCommand(gcn64_hdl_t hdl, unsigned char channel, unsigned char int gcn64lib_8bit_scan(gcn64_hdl_t hdl, unsigned char min, unsigned char max); int gcn64lib_16bit_scan(gcn64_hdl_t hdl, unsigned short min, unsigned short max); -int gcn64lib_raphnet_gc_to_n64_getInfo(gcn64_hdl_t hdl); #endif // _gcn64_lib_h__ diff --git a/tool/main.c b/tool/main.c index 4ca00d9..302ffa1 100644 --- a/tool/main.c +++ b/tool/main.c @@ -28,6 +28,7 @@ #include "version.h" #include "gcn64.h" #include "gcn64lib.h" +#include "gc2n64_adapter.h" #include "mempak.h" #include "../requests.h" #include "../gcn64_protocol.h" @@ -65,6 +66,8 @@ static void printUsage(void) printf("\n"); printf("GC to N64 adapter commands: (For GC to N64 adapter connected to GC/N64 to USB adapter)\n"); printf(" --gc_to_n64_info Display info on adapter (version, config, etc)\n"); + printf(" --gc_to_n64_echotest Perform a communication test\n"); + printf(" --gc_to_n64_update file.hex Update GC to N64 adapter firmware\n"); printf("\n"); printf("Development/Experimental/Research commands: (use at your own risk)\n"); printf(" --si_8bit_scan Try all possible 1-byte commands, to see which one a controller responds to.\n"); @@ -89,6 +92,8 @@ static void printUsage(void) #define OPT_SI8BIT_SCAN 311 #define OPT_SI16BIT_SCAN 312 #define OPT_GC_TO_N64_INFO 313 +#define OPT_GC_TO_N64_TEST 314 +#define OPT_GC_TO_N64_UPDATE 315 struct option longopts[] = { { "help", 0, NULL, 'h' }, @@ -111,6 +116,8 @@ struct option longopts[] = { { "si_8bit_scan", 0, NULL, OPT_SI8BIT_SCAN }, { "si_16bit_scan", 0, NULL, OPT_SI16BIT_SCAN }, { "gc_to_n64_info", 0, NULL, OPT_GC_TO_N64_INFO }, + { "gc_to_n64_echotest", 0, NULL, OPT_GC_TO_N64_TEST }, + { "gc_to_n64_update", 1, NULL, OPT_GC_TO_N64_UPDATE }, { }, }; @@ -339,7 +346,23 @@ int main(int argc, char **argv) break; case OPT_GC_TO_N64_INFO: - gcn64lib_raphnet_gc_to_n64_getInfo(hdl); + { + struct gc2n64_adapter_info inf; + + gc2n64_adapter_getInfo(hdl, &inf); + gc2n64_adapter_printInfo(&inf); + } + break; + + case OPT_GC_TO_N64_TEST: + n = gc2n64_adapter_echotest(hdl, 1); + if (n != 0) { + return -1; + } + break; + + case OPT_GC_TO_N64_UPDATE: + gc2n64_adapter_updateFirmware(hdl, optarg); break; }