int main(int argc, char **argv) { int fd; int count; int index; struct termios oldtio,newtio; Uint8 buffer[257]; // temporary buffer for reads, largest response is a DATA response from an N64 DexDrive Uint32 length; DDType type; // detected type DDResponse response; char *tmp; Uint32 framesdump; // frames to dump (size of card) Uint32 framesize; // size of each frame Uint16 i, j; FILE *outfile; struct timespec wait; Uint32 barsize; // current length of the progress bar Uint32 barstep; // pages per each progress bar char char *animation; Uint32 animlength; char *serialport = "/dev/ttyUSB0"; char *memcardfile ="memcard.mcr"; int blinklight = FALSE; //animation = ".oOo. "; animation = "-\\|/"; animlength = strlen(animation); while((count = getopt (argc, argv, "bdf:hs:")) != -1) switch(count) { case 'b': blinklight = TRUE; break; case 'd': debug = TRUE; break; case 'f': memcardfile = optarg; break; case 'h': show_help(); exit(-1); break; case 's': serialport = optarg; break; case '?': if ((optopt == 'f')||(optopt == 'm')) fprintf(stderr, "Option '-%c' requires an argument.\n", optopt); else if (isprint (optopt)) fprintf(stderr, "Unknown option '-%c'.\n", optopt); else fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt); exit(-1); default: abort(); } if (debug) { fprintf(stdout, "DEBUG: serialport = %s, memcardfile = %s, blinklight = %d, debug = %d\n", serialport, memcardfile, blinklight, debug); } for (index = optind; index < argc; index++) { fprintf(stderr, "Non-option argument %s\n", argv[index]); exit(-1); } if (access(memcardfile, F_OK) == 0) { fprintf(stderr, "File %s already exist, aborting.\n", memcardfile); exit(-1); } fd = open(serialport, O_RDWR | O_NOCTTY ); if (fd < 0) { perror(serialport); cleanup(fd, oldtio, -1); } tcgetattr(fd,&oldtio); /* save current port settings */ bzero(&newtio, sizeof(newtio)); newtio.c_cflag = B38400 | CS8 | CLOCAL | CREAD ; // 38400 baud 8 bits no parity 1 stop bit newtio.c_iflag = IGNPAR | IXON | IXOFF; newtio.c_oflag = 0; /* set input mode (non-canonical, no echo,...) */ newtio.c_lflag = 0; newtio.c_cc[VTIME] = 100; //Some operations are slow so give the device //a lot of time to complete (10 seconds) newtio.c_cc[VMIN] = 0; //Get whatever is available by the timeout tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); response = DDInit(fd, buffer, &length); if(response != ID) { tmp = DDStrResponse(response); fprintf(stderr, "Couldn't initialize device: %s.\n", tmp); free(tmp); cleanup(fd, oldtio, -1); } if(length != 5) { fprintf(stderr, "Device returned incomplete init response.\n"); cleanup(fd, oldtio, -1); } else { tmp = HexOut(buffer, 5); fprintf(stdout, "Device initialized, returned %s\n", tmp); free(tmp); if(memcmp(&buffer[1], "PSX", 3) == 0) { fprintf(stdout, "Playstation DexDrive detected.\n"); type = PSX; framesdump = 0x400; framesize = 128; } else if(memcmp(&buffer[1], "N64", 3) == 0) { fprintf(stdout, "Nintendo 64 DexDrive detected.\n"); type = N64; framesdump = 0x80; framesize = 256; } else { fprintf(stderr, "Unknown DexDrive detected.\n"); cleanup(fd, oldtio, -1); } barstep = framesdump / BARMAXSIZE; } response = DDHandshake(fd); if(response == ERROR) { if(type == PSX) { fprintf(stdout, "Handshake returned expected ERROR response for a Playstation dexdrive.\n"); } else { fprintf(stderr, "N64 DexDrive returned ERROR in response to handshake.\n"); cleanup(fd, oldtio, -1); } } response = DDStatus(fd, buffer, &length); fprintf(stdout, "%s.\n", DDStrResponse(response)); switch(response) { case NOCARD: cleanup(fd, oldtio, -1); break; case CARD_NEW: break; case CARD: if(type == PSX && length == 1) { switch(buffer[0]) { case 0x00: fprintf(stdout, "Playstation DexDrive reports a successful write since last reset.\n"); break; case 0x10: fprintf(stdout, "Playstation DexDrive reports no successful writes since last reset.\n"); break; default: fprintf(stderr, "Playstation DexDrive returned an unknown status: %X.", buffer[0]); break; } } break; default: cleanup(fd, oldtio, -1); break; } outfile = fopen(memcardfile, "wb"); if(outfile == NULL) { fprintf(stderr, "Couldn't open file for writing.\n"); cleanup(fd, oldtio, -1); } wait.tv_sec = 0; wait.tv_nsec = 10000000; for(i = 0; i < framesdump; i++) { //print progress bar fputc('\r', stderr); fputc('|', stderr); barsize = i / barstep; for(j = 0; j < barsize; j++) { fputc('=', stderr); } for(j = 0; j < BARMAXSIZE - barsize; j++) { fputc('-', stderr); } fprintf(stderr, "| %c %i/%i", animation[i % animlength], i + 1, framesdump); if (debug) { fprintf(stdout, "\n"); } if (blinklight) { response = DDLight(fd, 1); } response = DDRead(fd, i, buffer, &length, framesize + 1); if(length < framesize + 1) { fprintf(stderr, "Incomplete DATA response, expected %d bytes, got %d.\n", framesize + 1, length); if (blinklight) { response = DDLight(fd, 0); } cleanup(fd, oldtio, -1); } switch(response) { case NOCARD: fprintf(stderr, "No card is inserted or card removed.\n"); if (blinklight) { response = DDLight(fd, 0); } cleanup(fd, oldtio, -1); break; case DATA: fwrite(buffer, sizeof(Uint8), framesize, outfile); break; default: tmp = DDStrResponse(response); fprintf(stderr, "Got an unexpected response: %s.\n", tmp); free(tmp); if (blinklight) { response = DDLight(fd, 0); } cleanup(fd, oldtio, -1); break; } if (blinklight) { response = DDLight(fd, 0); } nanosleep(&wait, NULL); } fclose(outfile); fprintf(stdout, "\nDump complete and saved as %s\n", memcardfile); cleanup(fd, oldtio, 0); }
int main(int argc, char **argv) { int fd; struct termios oldtio,newtio; Uint8 buffer[257]; // temporary buffer for reads, largest response is a DATA response from an N64 DexDrive Uint32 length; DDType type; // detected type DDResponse response; char *tmp; Uint32 framesdump; // frames to dump (size of card) Uint32 framesize; // size of each frame Uint16 i, j; FILE *outfile; struct timespec wait; Uint32 barsize; // current length of the progress bar Uint32 barstep; // pages per each progress bar char char *animation; Uint32 animlength; animation = ".oOo. "; animlength = strlen(animation); if(argc < 2) { fprintf(stderr, "USAGE: %s <serial device> [output file]\n", argv[0]); exit(-1); } else { fd = open(argv[1], O_RDWR | O_NOCTTY ); } if (fd < 0) { perror(argv[1]); cleanup(fd, oldtio, -1); } tcgetattr(fd,&oldtio); /* save current port settings */ bzero(&newtio, sizeof(newtio)); newtio.c_cflag = B38400 | CS8 | CLOCAL | CREAD ; // 38400 baud 8 bits no parity 1 stop bit newtio.c_iflag = IGNPAR | IXON | IXOFF; newtio.c_oflag = 0; /* set input mode (non-canonical, no echo,...) */ newtio.c_lflag = 0; newtio.c_cc[VTIME] = 100; //Some operations are slow so give the device //a lot of time to complete (10 seconds) newtio.c_cc[VMIN] = 0; //Get whatever is available by the timeout tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); response = DDInit(fd, buffer, &length); if(response != ID) { tmp = DDStrResponse(response); fprintf(stderr, "Couldn't initialize device: %s.\n", tmp); free(tmp); cleanup(fd, oldtio, -1); } if(length != 5) { fprintf(stderr, "Device returned incomplete init response.\n"); cleanup(fd, oldtio, -1); } else { tmp = HexOut(buffer, 5); fprintf(stderr, "Device initialized, returned %s\n", tmp); free(tmp); if(memcmp(&buffer[1], "PSX", 3) == 0) { fprintf(stderr, "Playstation DexDrive detected.\n"); type = PSX; framesdump = 0x400; framesize = 128; } else if(memcmp(&buffer[1], "N64", 3) == 0) { fprintf(stderr, "Nintendo 64 DexDrive detected.\n"); type = N64; framesdump = 0x80; framesize = 256; } else { fprintf(stderr, "Unknown DexDrive detected.\n"); cleanup(fd, oldtio, -1); } barstep = framesdump / BARMAXSIZE; } response = DDHandshake(fd); if(response == ERROR) { if(type == PSX) { fprintf(stderr, "Handshake returned expected ERROR response for a Playstation dexdrive.\n"); } else { fprintf(stderr, "N64 DexDrive returned ERROR in response to handshake.\n"); cleanup(fd, oldtio, -1); } } response = DDStatus(fd, buffer, &length); fprintf(stderr, "%s.\n", DDStrResponse(response)); switch(response) { case NOCARD: cleanup(fd, oldtio, -1); break; case CARD_NEW: break; case CARD: if(type == PSX && length == 1) { switch(buffer[0]) { case 0x00: fprintf(stderr, "Playstation DexDrive reports a successful write since last reset.\n"); break; case 0x10: fprintf(stderr, "Playstation DexDrive reports no successful writes since last reset.\n"); break; default: fprintf(stderr, "Playstation DexDrive returned an unknown status: %X.", buffer[0]); break; } } break; default: cleanup(fd, oldtio, -1); break; } if(argc > 2) { outfile = fopen(argv[1], "wb"); } else { outfile = fopen("memcard.bin", "wb"); } if(outfile == NULL) { fprintf(stderr, "Couldn't open file for writing.\n"); cleanup(fd, oldtio, -1); } wait.tv_sec = 0; wait.tv_nsec = 10000000; for(i = 0; i < framesdump; i++) { #ifndef DEBUG fputc('\r', stderr); fputc('|', stderr); barsize = i / barstep; for(j = 0; j < barsize; j++) { fputc('=', stderr); } for(j = 0; j < BARMAXSIZE - barsize; j++) { fputc('-', stderr); } fprintf(stderr, "| %c %i/%i", animation[i % animlength], i + 1, framesdump); #endif #ifdef BLINKLIGHT response = DDLight(fd, 1); #endif response = DDRead(fd, i, buffer, &length, framesize + 1); if(length < framesize + 1) { fprintf(stderr, "Incomplete DATA response, expected %d bytes, got %d.\n", framesize + 1, length); #ifdef BLINKLIGHT response = DDLight(fd, 0); #endif cleanup(fd, oldtio, -1); } switch(response) { case NOCARD: fprintf(stderr, "No card is inserted or card removed.\n"); #ifdef BLINKLIGHT response = DDLight(fd, 0); #endif cleanup(fd, oldtio, -1); break; case DATA: fwrite(buffer, sizeof(Uint8), framesize, outfile); break; default: tmp = DDStrResponse(response); fprintf(stderr, "Got an unexpected response: %s.\n", tmp); free(tmp); #ifdef BLINKLIGHT response = DDLight(fd, 0); #endif cleanup(fd, oldtio, -1); break; } #ifdef BLINKLIGHT response = DDLight(fd, 0); #endif nanosleep(&wait, NULL); } fclose(outfile); cleanup(fd, oldtio, 0); }