#include #include #include #include #include #include #include #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, 2000000) != 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); }