Arduino gameboy cart reader software, using https://github.com/insidegadgets/GBCartRead
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.4 KiB
144 lines
3.4 KiB
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <locale.h>
|
|
#include <libserialport.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#ifdef __GNUC__
|
|
#define A_UNUSED __attribute__((unused))
|
|
#else
|
|
#define A_UNUSED
|
|
#endif
|
|
|
|
struct sp_port *serial_guess_port(void)
|
|
{
|
|
struct sp_port **ports;
|
|
|
|
if (sp_list_ports(&ports) != SP_OK || ports[0] == NULL) {
|
|
puts("No serial devices detected");
|
|
return NULL;
|
|
}
|
|
|
|
if (ports[1] != NULL) {
|
|
puts("Please select a port");
|
|
return NULL;
|
|
}
|
|
|
|
return ports[0];
|
|
}
|
|
|
|
char *program_name;
|
|
|
|
void serial_error(char *message)
|
|
{
|
|
char *error = sp_last_error_message();
|
|
fprintf(stderr, "%s: %s: %s\n", program_name, message, error);
|
|
sp_free_error_message(error);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
program_name = argv[0];
|
|
setlocale(LC_ALL, "");
|
|
|
|
long save = 0;
|
|
if (argc > 1) {
|
|
save = strtol(argv[1], NULL, 0);
|
|
}
|
|
|
|
struct sp_port *port;
|
|
|
|
if (!(port = serial_guess_port())) return 1;
|
|
puts(sp_get_port_name(port));
|
|
|
|
if (sp_open(port, SP_MODE_READ_WRITE) != SP_OK ||
|
|
sp_set_baudrate(port, 500000) != SP_OK ||
|
|
sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE) != SP_OK) {
|
|
serial_error("Failed to open port");
|
|
return 1;
|
|
}
|
|
|
|
usleep(100000LL);
|
|
sp_flush(port, SP_BUF_BOTH);
|
|
|
|
fputs("Waiting for device... ", stdout);
|
|
fflush(stdout);
|
|
for (;;) {
|
|
char c = 0;
|
|
sp_blocking_write(port, &c, 1, 0);
|
|
if (sp_blocking_read(port, &c, 1, 1000) == 1) {
|
|
if (c == 0) {
|
|
puts("ROM OK!");
|
|
} else {
|
|
puts("ROM ERROR");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
char command = 1;
|
|
uint32_t address = 0x147;
|
|
uint32_t size = 3;
|
|
sp_blocking_write(port, &command, 1, 0);
|
|
sp_blocking_write(port, &address, 4, 0);
|
|
sp_blocking_write(port, &size, 4, 0);
|
|
|
|
sp_blocking_read(port, &command, 1, 0);
|
|
if (command != 0) {
|
|
puts("An error has occurred");
|
|
return 1;
|
|
}
|
|
|
|
char cart_type = 0;
|
|
sp_blocking_read(port, &cart_type, 1, 0);
|
|
printf("Cart type: %02X\n", cart_type);
|
|
|
|
char rom_size = 0;
|
|
sp_blocking_read(port, &rom_size, 1, 0);
|
|
printf("Rom size: %02X\n", rom_size);
|
|
|
|
char ram_size = 0;
|
|
sp_blocking_read(port, &ram_size, 1, 0);
|
|
printf("Ram size: %02X\n", ram_size);
|
|
|
|
command = save ? 3 : 2;
|
|
address = 0;
|
|
if (!save) {
|
|
size = 0x8000 << rom_size;
|
|
} else {
|
|
size = save;
|
|
}
|
|
sp_blocking_write(port, &command, 1, 0);
|
|
sp_blocking_write(port, &address, 4, 0);
|
|
sp_blocking_write(port, &size, 4, 0);
|
|
sp_blocking_read(port, &command, 1, 0);
|
|
if (command != 0) {
|
|
puts("An error has occurred");
|
|
return 1;
|
|
}
|
|
|
|
struct timeval begin, end;
|
|
gettimeofday(&begin, NULL);
|
|
|
|
FILE *file = fopen("out.bin", "w");
|
|
for (unsigned x = 0; x < size; x += 0x200) {
|
|
char c[0x200];
|
|
sp_blocking_read(port, &c, 0x200, 0);
|
|
if (!save) {
|
|
printf("\r%02X:%04X", x / 0x4000, x % 0x4000);
|
|
} else {
|
|
printf("\r%02X:%04X", x / 0x2000, x % 0x2000);
|
|
}
|
|
fflush(stdout);
|
|
fwrite(&c, 0x200, 1, file);
|
|
}
|
|
putchar('\n');
|
|
fclose(file);
|
|
|
|
gettimeofday(&end, NULL);
|
|
double dt = (double)end.tv_sec - begin.tv_sec + ((double)end.tv_usec - begin.tv_usec) / 1000000;
|
|
printf("Average speed: %f KB/s\n", size / 1000 / dt);
|
|
}
|
|
|