first commit
This commit is contained in:
241
static/mpkdumper.c
Normal file
241
static/mpkdumper.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* n64-arduino-serial.c
|
||||
* Communicates with mpkdumper to read and writes memory pak files from Arduino Serial
|
||||
* Written by Mortal (http://www.nintendojo.fr/) and released under WTFPL
|
||||
*
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
*
|
||||
*Everyone is permitted to copy and distribute verbatim or modified
|
||||
*copies of this license document, and changing it is allowed as long
|
||||
*as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
*TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* Standard input/output definitions */
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h> /* Standard types */
|
||||
#include <stdbool.h> /* Standard bool type */
|
||||
#include <string.h> /* String function definitions */
|
||||
#include <fcntl.h> /* File control definitions */
|
||||
#include <termios.h> /* POSIX terminal control definitions */
|
||||
#include <getopt.h>
|
||||
|
||||
void usage(void);
|
||||
int serialport_init(const char* serialport, int baud);
|
||||
|
||||
void usage(void) {
|
||||
printf("Usage: mpkdumper -p <serialport> [OPTIONS]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help Print this help message\n"
|
||||
" -s, --save=file Give a save order to the Arduino\n"
|
||||
" -r, --restore=file Give a restore order to the Arduino\n"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd_serial = 0, fd_file = 0;
|
||||
char serialport[256], filename[256];
|
||||
bool save = false;
|
||||
int baudrate = B115200;
|
||||
|
||||
if (argc==1) {
|
||||
usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* parse options */
|
||||
int option_index = 0, opt;
|
||||
static struct option loptions[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"port", required_argument, 0, 'p'},
|
||||
{"save", required_argument, 0, 's'},
|
||||
{"restore", required_argument, 0, 'r'}
|
||||
};
|
||||
|
||||
while(1) {
|
||||
opt = getopt_long (argc, argv, "hp:s:r:", loptions, &option_index);
|
||||
if (opt==-1) break;
|
||||
switch (opt) {
|
||||
case '0': break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'p':
|
||||
strcpy(serialport,optarg);
|
||||
fd_serial = serialport_init(serialport, baudrate);
|
||||
usleep (3000 * 1000); // wait for Arduino to reset
|
||||
if(fd_serial==-1) return -1;
|
||||
break;
|
||||
case 's':
|
||||
strcpy(filename,optarg);
|
||||
save = true;
|
||||
break;
|
||||
case 'r':
|
||||
strcpy(filename,optarg);
|
||||
save = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -p option is mandatory
|
||||
if(!fd_serial) {
|
||||
printf("-p option is mandatory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(save) { //save action is required
|
||||
char command = 's';
|
||||
char p = '\0';
|
||||
fd_file = open(filename, O_WRONLY | O_CREAT);
|
||||
if(!fd_file) {
|
||||
printf("Cannot open file for writing !");
|
||||
return -1;
|
||||
}
|
||||
|
||||
write(fd_serial, &command, 1);
|
||||
|
||||
usleep(5*1000);
|
||||
|
||||
while(1) {
|
||||
// read a char
|
||||
char c;
|
||||
int n = read(fd_serial, &c, 1);
|
||||
|
||||
if (n < 0) {
|
||||
// nothing read, skipping til next iteration
|
||||
continue;
|
||||
}
|
||||
|
||||
n = write(fd_file, &c, 1);
|
||||
|
||||
if (n < 0) {
|
||||
// write error on the file
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p == '\n' && c == '\n') { // 2 consecutives \n means EOF
|
||||
close(fd_serial);
|
||||
close(fd_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// saves previous value
|
||||
p = c;
|
||||
}
|
||||
|
||||
} else { // restore action is required
|
||||
char command = 'r';
|
||||
char p = '\0';
|
||||
fd_file = open(filename, O_RDONLY);
|
||||
if (!fd_file) {
|
||||
printf("Cannot open file for reading !");
|
||||
return -1;
|
||||
}
|
||||
|
||||
write(fd_serial, &command, 1);
|
||||
|
||||
usleep(5*1000);
|
||||
|
||||
while (1) {
|
||||
char c;
|
||||
|
||||
int n = read(fd_file, &c, 1);
|
||||
|
||||
if (n <= 0) {
|
||||
printf("Read error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if the line read is empty (just \n)
|
||||
if (p == '\n' && c == '\n') {
|
||||
close(fd_serial);
|
||||
close(fd_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(write(fd_serial, &c, 1) <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p = c;
|
||||
|
||||
// let the arduino breath (lots of calculation are done on Restore() function
|
||||
if (c == '\n') {
|
||||
usleep(25 * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
} // end main
|
||||
|
||||
// takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1")
|
||||
// and a baud rate (bps) and connects to that port at that speed and 8N1.
|
||||
// opens the port in fully raw mode so you can send binary data.
|
||||
// returns valid fd, or -1 on error
|
||||
int serialport_init(const char* serialport, int baud)
|
||||
{
|
||||
struct termios toptions;
|
||||
int fd;
|
||||
|
||||
//fprintf(stderr,"init_serialport: opening port %s @ %d bps\n",
|
||||
// serialport,baud);
|
||||
|
||||
fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (fd == -1) {
|
||||
perror("init_serialport: Unable to open port ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tcgetattr(fd, &toptions) < 0) {
|
||||
perror("init_serialport: Couldn't get term attributes");
|
||||
return -1;
|
||||
}
|
||||
speed_t brate = baud; // let you override switch below if needed
|
||||
switch(baud) {
|
||||
case 4800: brate=B4800; break;
|
||||
case 9600: brate=B9600; break;
|
||||
#ifdef B14400
|
||||
case 14400: brate=B14400; break;
|
||||
#endif
|
||||
case 19200: brate=B19200; break;
|
||||
#ifdef B28800
|
||||
case 28800: brate=B28800; break;
|
||||
#endif
|
||||
case 38400: brate=B38400; break;
|
||||
case 57600: brate=B57600; break;
|
||||
case 115200: brate=B115200; break;
|
||||
}
|
||||
cfsetispeed(&toptions, brate);
|
||||
cfsetospeed(&toptions, brate);
|
||||
|
||||
toptions.c_cflag =CS8|CREAD|CLOCAL; // turn on READ & ignore ctrl lines
|
||||
toptions.c_iflag = 0; // turn off s/w flow ctrl
|
||||
|
||||
toptions.c_lflag = 0;
|
||||
toptions.c_oflag = 0; // make raw
|
||||
|
||||
// see: http://unixwiz.net/techtips/termios-vmin-vtime.html
|
||||
toptions.c_cc[VMIN] = 0;
|
||||
toptions.c_cc[VTIME] = 20;
|
||||
|
||||
if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
|
||||
perror("init_serialport: Couldn't set term attributes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
Reference in New Issue
Block a user