first commit
BIN
static/.39fmvg_m.jpg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
static/.39fmvg_s.jpg
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
static/.39fmvg_sq.jpg
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
static/.39fmvg_t.jpg
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/.N64_schema_s.jpg
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
static/.N64_schema_sq.jpg
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/.N64_schema_t.jpg
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
static/.Screenshot_2019-03-13_Database_Updater_m.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/.Screenshot_2019-03-13_Database_Updater_s.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
static/.Screenshot_2019-03-13_Database_Updater_sq.png
Normal file
After Width: | Height: | Size: 820 B |
BIN
static/.Screenshot_2019-03-13_Database_Updater_t.png
Normal file
After Width: | Height: | Size: 972 B |
BIN
static/.bird_internal_tables_s.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
static/.bird_internal_tables_sq.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
static/.bird_internal_tables_t.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
static/.hadopi_ip_test_m.jpg
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/.hadopi_ip_test_s.jpg
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
static/.hadopi_ip_test_sq.jpg
Normal file
After Width: | Height: | Size: 837 B |
BIN
static/.hadopi_ip_test_t.jpg
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/.n64bits_s.jpg
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
static/.n64bits_sq.jpg
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/.n64bits_t.jpg
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
static/.postfix_premier_tri_m.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/.postfix_premier_tri_s.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/.postfix_premier_tri_sq.png
Normal file
After Width: | Height: | Size: 898 B |
BIN
static/.postfix_premier_tri_t.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/.postfix_second_tri_m.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
static/.postfix_second_tri_s.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
static/.postfix_second_tri_sq.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/.postfix_second_tri_t.png
Normal file
After Width: | Height: | Size: 564 B |
BIN
static/.typing_m.png
Normal file
After Width: | Height: | Size: 253 KiB |
BIN
static/.typing_s.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
static/.typing_sq.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
static/.typing_t.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
static/.vpn_ideal_m.jpg
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
static/.vpn_ideal_s.jpg
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/.vpn_ideal_sq.jpg
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/.vpn_ideal_t.jpg
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/.vpn_ipsec_1tunnel_m.jpg
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
static/.vpn_ipsec_1tunnel_s.jpg
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
static/.vpn_ipsec_1tunnel_sq.jpg
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/.vpn_ipsec_1tunnel_t.jpg
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
static/.vpn_redondant_2_operateurs_m.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
static/.vpn_redondant_2_operateurs_s.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
static/.vpn_redondant_2_operateurs_sq.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
static/.vpn_redondant_2_operateurs_t.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
static/.vpn_reel_m.jpg
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
static/.vpn_reel_s.jpg
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
static/.vpn_reel_sq.jpg
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
static/.vpn_reel_t.jpg
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
static/2022/12/30_char_mon_cul.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
static/2022/12/736lvk.jpg
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
static/2022/12/smile_loud.jpg
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
static/2023/02/openwrt.jpg
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
static/2023/08/16A-plug.jpg
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
static/2023/08/Steckdose.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
static/2023/08/cable-de-recharge-pour-prise-domestique.jpg
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
static/2023/08/explain_meme.jpg
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
static/2023/08/t2t2.webp
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
static/2023/09/calculating_meme.jpg
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
static/2024/truenas_i_like_this.jpg
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
static/39fmvg.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
static/6bf7ab41-b09f-43c6-8849-cee9c5884201.webp
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
static/N64_schema.jpg
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
static/Screenshot_2019-03-13_Database_Updater.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
static/bird_internal_tables.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
static/hadopi_ip_test.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
static/jaime_vivre_dangereusement.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
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;
|
||||
}
|
303
static/mpkdumper.ino
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Nintendo 64 Memory Card Dumper
|
||||
* Written by Mortal (http://www.nintendojo.fr/)
|
||||
* Thanks to :
|
||||
* - Waffle (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?action=viewprofile;username=Waffle) for the n64cmd function. See this Arduino forum thread for info: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261980415
|
||||
* - Micah Dowty <micah@navi.cx> for the CRC address table algorithm. See http://svn.navi.cx/misc/trunk/wasabi/devices/cube64/notes/addr_encoder.py
|
||||
*
|
||||
* Connect N64 controller +3.3V line to Arduino 3.3V line
|
||||
* Connect N64 controller ground line to Arduino ground
|
||||
* Connect N64 controller data line to an Arduino I/O pin with a 1K pull-up resistor to 3.3V line
|
||||
*
|
||||
* Set Arduino pin used for data line in the follow three #defines:
|
||||
* Example for Arduino pin 9: N64_DATA_DDR = DDRB, N64_DATA_PIN = PINB, N64_DATA_PIN_NO = PINB1
|
||||
*/
|
||||
|
||||
#define N64_DATA_DDR DDRB
|
||||
#define N64_DATA_PIN PINB
|
||||
#define N64_DATA_PIN_NO PINB1
|
||||
|
||||
#include <util/delay.h>
|
||||
|
||||
/* based off the 'N64/Gamecube controller to USB adapter' by Raphaël Assénat (http://www.raphnet.net/electronique/gc_n64_usb/index_en.php)
|
||||
* modifications/improvements:
|
||||
* - adjusted timing for 16 MHz
|
||||
* - support writing variable length data
|
||||
* - receive variable length data directly packed into destination buffer
|
||||
*/
|
||||
uint8_t n64cmd(uint8_t rxdata[], uint8_t rxlen, uint8_t txdata[], uint8_t txlen) {
|
||||
uint8_t num = 0;
|
||||
uint8_t oldSREG = SREG;
|
||||
|
||||
cli();
|
||||
asm volatile(
|
||||
"nextByte%=: \n"
|
||||
" cpi %[txlen], 0 \n" // 1
|
||||
" breq done%= \n" // 1
|
||||
" dec %[txlen] \n" // 1
|
||||
" ld r16, z+ \n" // 2
|
||||
" ldi r17, 0x80 \n" // 1
|
||||
"nextBit%=: \n"
|
||||
" mov r18, r16 \n" // 1
|
||||
" and r18, r17 \n" // 1
|
||||
" breq send0%= \n" // 2
|
||||
" nop \n"
|
||||
|
||||
// 1us low, 1us high
|
||||
"send1%=: \n"
|
||||
" sbi %[ddr], %[pinNo] \n" // 2
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop \n" // 2
|
||||
" cbi %[ddr], %[pinNo] \n" // 2
|
||||
" ldi r19, 11 \n" // 1
|
||||
"lp1%=: dec r19 \n" // 1
|
||||
" brne lp1%= \n" // 2
|
||||
" lsr r17 \n" // 1
|
||||
" breq nextByte%= \n" // 1
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop \n" // 1
|
||||
" rjmp nextBit%= \n" // 2
|
||||
|
||||
// 3us low, 1us high
|
||||
"send0%=: sbi %[ddr], %[pinNo] \n" // 2
|
||||
" ldi r19, 15 \n" // 1
|
||||
"lp0%=: dec r19 \n" // 1
|
||||
" brne lp0%= \n" // 2
|
||||
" nop \n" // 1
|
||||
" cbi %[ddr], %[pinNo] \n" // 2
|
||||
" nop \n" // 1
|
||||
" lsr r17 \n" // 1
|
||||
" breq nextByte%= \n" // 1
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop \n" // 1
|
||||
" rjmp nextBit%= \n" // 2
|
||||
|
||||
// finished sending, sync up to the stop bit time
|
||||
"done%=: \n"
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop \n" // 3
|
||||
|
||||
// stop bit
|
||||
" sbi %[ddr], %[pinNo] \n" // 2
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop \n" // 2
|
||||
" cbi %[ddr], %[pinNo] \n"
|
||||
|
||||
// stop now if there's nothing to receive
|
||||
" cpi %[rxlen], 0 \n" // 1
|
||||
" breq end%= \n" // 1
|
||||
|
||||
// receiving
|
||||
" clr r18 \n" // 1 current byte
|
||||
" ldi r17, 0x80 \n" // 1 current bit
|
||||
"st%=: \n"
|
||||
" ldi r16, 0xff \n" // 1 setup timeout
|
||||
"waitFall%=: \n"
|
||||
" dec r16 \n" // 1
|
||||
" breq end%= \n" // 1
|
||||
" sbic %[pin], %[pinNo] \n" // 2
|
||||
" rjmp waitFall%= \n"
|
||||
|
||||
// wait about 2us to check the state
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
|
||||
" sbic %[pin], %[pinNo] \n" // 2
|
||||
" or r18, r17 \n"
|
||||
" lsr r17 \n" // 1
|
||||
" brne nextRxBit%= \n" // 2
|
||||
|
||||
"nextRxByte%=: \n"
|
||||
" st x+, r18 \n" // 2 store the value
|
||||
" inc %[num] \n" // 1 increase number of received bytes
|
||||
" cp %[rxlen], %[num] \n" // 1 check for finish
|
||||
" breq end%= \n" // 1
|
||||
" clr r18 \n" // 1
|
||||
" ldi r17, 0x80 \n" // 1
|
||||
|
||||
"nextRxBit%=: \n"
|
||||
" ldi r16, 0xff \n" // 1 setup timeout
|
||||
"waitHigh%=: \n"
|
||||
" dec r16 \n" // 1 decrement timeout
|
||||
" breq end%= \n" // 1 handle timeout condition
|
||||
" sbis %[pin], %[pinNo] \n" // 2
|
||||
" rjmp waitHigh%= \n"
|
||||
" rjmp st%= \n" // 2
|
||||
|
||||
"end%=: \n"
|
||||
: [num] "=r"(num)
|
||||
: [ddr] "I"(_SFR_IO_ADDR(N64_DATA_DDR)), [pin] "I"(_SFR_IO_ADDR(N64_DATA_PIN)), [pinNo] "I"(N64_DATA_PIN_NO),
|
||||
[rxdata] "x"(rxdata), [rxlen] "r"(rxlen),
|
||||
[txdata] "z"(txdata), [txlen] "r"(txlen), "0"(num)
|
||||
: "r16", "r17", "r18", "r19"
|
||||
);
|
||||
SREG = oldSREG;
|
||||
|
||||
_delay_us(100); // some commands leave the controller unresponsive for a while
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
* The N64 uses a CRC algorithm to address the memory card. Memory cards are using adress from 0x0000 to 0x7e80 on 32 octets boundaries (with 0x20 steps).
|
||||
* Input :
|
||||
* @encodedAddr = an array of 2 elements containing the upper and lower bytes of a memory card address system ;
|
||||
* @hAddr = a tiny int containing the non-encoded upper byte of a memory card address ;
|
||||
* @bAddr = a tiny int containing the non-encoded lower byte of a memory card address ;
|
||||
* Output :
|
||||
* - void
|
||||
*/
|
||||
void addrEncode (uint8_t* encodedAddr, uint8_t hAddr, uint8_t bAddr) {
|
||||
// calculate a 16 bits (2 bytes) address from 2 * 8 bits upper and lower addresses
|
||||
uint16_t addr = (hAddr<<8) + bAddr;
|
||||
// default CRC table
|
||||
uint8_t crc_table[11] = {0x15, 0x1F, 0x0B, 0x16, 0x19, 0x07, 0x0E, 0x1C, 0x0D, 0x1A, 0x01};
|
||||
// calculating the CRC address
|
||||
int _bit;
|
||||
for (_bit = 0; _bit < 11; _bit++) {
|
||||
if (addr & (1 << (_bit + 5))) {
|
||||
addr ^= crc_table[_bit];
|
||||
}
|
||||
}
|
||||
|
||||
// modifying the encodedAddr passed in argument
|
||||
encodedAddr[0] = addr >> 8;
|
||||
encodedAddr[1] = addr & 0x00ff;
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Generates every possible adress for the N64 memory card (from 0x0000 to 0x8000) and prints it on the Serial output under the format :
|
||||
* <address(2 bytes)>:<data(32 bytes)>
|
||||
*/
|
||||
void Backup () {
|
||||
// variables initialization
|
||||
int i, j, k;
|
||||
uint8_t command[40];
|
||||
uint8_t result[40];
|
||||
|
||||
// initializing the controller (perhaps useless)
|
||||
command[0] = 0x03;
|
||||
command[1] = 0x80;
|
||||
command[2] = 0x01;
|
||||
memset(command + 3, 0x80, 32);
|
||||
n64cmd(result, 1, command, 35);
|
||||
delay(100);
|
||||
|
||||
// the big loop !
|
||||
// it generates adresses with 0x20 steps
|
||||
for (i = 0x00; i < 0x80; i++) {
|
||||
for (j = 0x00; j < 0x100; j += 0x20) {
|
||||
char buffer[5];
|
||||
uint8_t addr[2];
|
||||
command[0] = 0x02; // read command
|
||||
addrEncode (addr, i, j); // encode addr
|
||||
command[1] = addr[0];
|
||||
command[2] = addr[1];
|
||||
|
||||
// returns 32 bytes of data and 1 byte of CRC
|
||||
// the data CRC is not yet implemented
|
||||
uint8_t num = n64cmd(result, 33, command, 3);
|
||||
|
||||
sprintf(buffer, "%02x%02x", i, j);
|
||||
Serial.print(buffer);
|
||||
|
||||
Serial.print(":");
|
||||
|
||||
for (k = 0; k < 32; k++) {
|
||||
sprintf(buffer, "%02x", result[k]);
|
||||
Serial.print(buffer);
|
||||
}
|
||||
|
||||
Serial.print('\n');
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
// signaling the end of dump with a \n
|
||||
Serial.print('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads Serial until a \n char is encountered. Parse the line with the same format as above (<address(2 bytes)>:<data(32 bytes)>), put it in a tiny int array and write it on the right memory spot.
|
||||
*/
|
||||
void Restore () {
|
||||
// variables initialization
|
||||
int i;
|
||||
uint8_t command[40];
|
||||
uint8_t result[40];
|
||||
|
||||
// initializing the controller (perhaps useless)
|
||||
command[0] = 0x03;
|
||||
command[1] = 0x80;
|
||||
command[2] = 0x01;
|
||||
memset(command + 3, 0x80, 32);
|
||||
n64cmd(result, 1, command, 35);
|
||||
delay(100);
|
||||
|
||||
while(1) {
|
||||
char buffer[100];
|
||||
// re-initialize the buffer
|
||||
memset(buffer, '\0', 100);
|
||||
if(Serial.available() > 0) {
|
||||
Serial.readBytesUntil('\n', buffer, 100);
|
||||
if (strlen(buffer) <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
command[0] = 0x03; // write command
|
||||
|
||||
char* poschar = buffer;
|
||||
uint8_t addr[2], encodedAddr[2];
|
||||
sscanf(poschar, "%02x", addr); // reads first byte
|
||||
poschar +=2;
|
||||
sscanf(poschar, "%02x", (addr + 1)); // reads second byte
|
||||
addrEncode (encodedAddr, addr[0], addr[1]); // encode addr
|
||||
|
||||
// concat command with encodedAddr
|
||||
command[1] = encodedAddr[0];
|
||||
command[2] = encodedAddr[1];
|
||||
|
||||
// position on first data byte, erasing ':' char
|
||||
poschar += 3;
|
||||
|
||||
// reads 32 byte of data and insert them into command vector
|
||||
for (i = 0; i < 32; i++) {
|
||||
sscanf(poschar, "%02x", (command + 3 + i));
|
||||
poschar += 2;
|
||||
}
|
||||
|
||||
n64cmd(result, 1, command, 35);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
char whattodo;
|
||||
if(Serial.available() > 0) {
|
||||
whattodo = Serial.read();
|
||||
switch(whattodo) {
|
||||
case 's':
|
||||
Backup();
|
||||
break;
|
||||
case 'r' :
|
||||
Restore();
|
||||
break;
|
||||
default:
|
||||
Serial.println("Error: wrong key !");
|
||||
}
|
||||
}
|
||||
}
|
BIN
static/n64bits.gif
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/postfix_premier_tri.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
static/postfix_second_tri.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
static/typing.png
Normal file
After Width: | Height: | Size: 3.6 MiB |
182
static/vibration.ino
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Nintendo 64 Controller to Arduino sketch
|
||||
* By Waffle (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?action=viewprofile;username=Waffle)
|
||||
* See this Arduino forum thread for info: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261980415
|
||||
*
|
||||
* Connect N64 controller +3.3V line to Arduino 3.3V line
|
||||
* Connect N64 controller ground line to Arduino ground
|
||||
* Connect N64 controller data line to an Arduino I/O pin with a 1K pull-up resistor to 3.3V line
|
||||
*
|
||||
* Set Arduino pin used for data line in the follow three #defines:
|
||||
* Example for Arduino pin 9: N64_DATA_DDR = DDRB, N64_DATA_PIN = PINB, N64_DATA_PIN_NO = PINB1
|
||||
*/
|
||||
|
||||
#define N64_DATA_DDR DDRB
|
||||
#define N64_DATA_PIN PINB
|
||||
#define N64_DATA_PIN_NO PINB1
|
||||
|
||||
#include <util/delay.h>
|
||||
|
||||
/* based off the 'N64/Gamecube controller to USB adapter' by Raphaël Assénat (http://www.raphnet.net/electronique/gc_n64_usb/index_en.php)
|
||||
* modifications/improvements:
|
||||
* - adjusted timing for 16 MHz
|
||||
* - support writing variable length data
|
||||
* - receive variable length data directly packed into destination buffer
|
||||
*/
|
||||
uint8_t n64cmd(uint8_t rxdata[], uint8_t rxlen, uint8_t txdata[], uint8_t txlen) {
|
||||
uint8_t num = 0;
|
||||
uint8_t oldSREG = SREG;
|
||||
|
||||
cli();
|
||||
asm volatile(
|
||||
"nextByte%=: \n"
|
||||
" cpi %[txlen], 0 \n" // 1
|
||||
" breq done%= \n" // 1
|
||||
" dec %[txlen] \n" // 1
|
||||
" ld r16, z+ \n" // 2
|
||||
" ldi r17, 0x80 \n" // 1
|
||||
"nextBit%=: \n"
|
||||
" mov r18, r16 \n" // 1
|
||||
" and r18, r17 \n" // 1
|
||||
" breq send0%= \n" // 2
|
||||
" nop \n"
|
||||
|
||||
// 1us low, 1us high
|
||||
"send1%=: \n"
|
||||
" sbi %[ddr], %[pinNo] \n" // 2
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop \n" // 2
|
||||
" cbi %[ddr], %[pinNo] \n" // 2
|
||||
" ldi r19, 11 \n" // 1
|
||||
"lp1%=: dec r19 \n" // 1
|
||||
" brne lp1%= \n" // 2
|
||||
" lsr r17 \n" // 1
|
||||
" breq nextByte%= \n" // 1
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop \n" // 1
|
||||
" rjmp nextBit%= \n" // 2
|
||||
|
||||
// 3us low, 1us high
|
||||
"send0%=: sbi %[ddr], %[pinNo] \n" // 2
|
||||
" ldi r19, 15 \n" // 1
|
||||
"lp0%=: dec r19 \n" // 1
|
||||
" brne lp0%= \n" // 2
|
||||
" nop \n" // 1
|
||||
" cbi %[ddr], %[pinNo] \n" // 2
|
||||
" nop \n" // 1
|
||||
" lsr r17 \n" // 1
|
||||
" breq nextByte%= \n" // 1
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop \n" // 1
|
||||
" rjmp nextBit%= \n" // 2
|
||||
|
||||
// finished sending, sync up to the stop bit time
|
||||
"done%=: \n"
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop \n" // 3
|
||||
|
||||
// stop bit
|
||||
" sbi %[ddr], %[pinNo] \n" // 2
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop \n" // 2
|
||||
" cbi %[ddr], %[pinNo] \n"
|
||||
|
||||
// stop now if there's nothing to receive
|
||||
" cpi %[rxlen], 0 \n" // 1
|
||||
" breq end%= \n" // 1
|
||||
|
||||
// receiving
|
||||
" clr r18 \n" // 1 current byte
|
||||
" ldi r17, 0x80 \n" // 1 current bit
|
||||
"st%=: \n"
|
||||
" ldi r16, 0xff \n" // 1 setup timeout
|
||||
"waitFall%=: \n"
|
||||
" dec r16 \n" // 1
|
||||
" breq end%= \n" // 1
|
||||
" sbic %[pin], %[pinNo] \n" // 2
|
||||
" rjmp waitFall%= \n"
|
||||
|
||||
// wait about 2us to check the state
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
" nop\nnop\nnop\nnop \n" // 4
|
||||
|
||||
" sbic %[pin], %[pinNo] \n" // 2
|
||||
" or r18, r17 \n"
|
||||
" lsr r17 \n" // 1
|
||||
" brne nextRxBit%= \n" // 2
|
||||
|
||||
"nextRxByte%=: \n"
|
||||
" st x+, r18 \n" // 2 store the value
|
||||
" inc %[num] \n" // 1 increase number of received bytes
|
||||
" cp %[rxlen], %[num] \n" // 1 check for finish
|
||||
" breq end%= \n" // 1
|
||||
" clr r18 \n" // 1
|
||||
" ldi r17, 0x80 \n" // 1
|
||||
|
||||
"nextRxBit%=: \n"
|
||||
" ldi r16, 0xff \n" // 1 setup timeout
|
||||
"waitHigh%=: \n"
|
||||
" dec r16 \n" // 1 decrement timeout
|
||||
" breq end%= \n" // 1 handle timeout condition
|
||||
" sbis %[pin], %[pinNo] \n" // 2
|
||||
" rjmp waitHigh%= \n"
|
||||
" rjmp st%= \n" // 2
|
||||
|
||||
"end%=: \n"
|
||||
: [num] "=r"(num)
|
||||
: [ddr] "I"(_SFR_IO_ADDR(N64_DATA_DDR)), [pin] "I"(_SFR_IO_ADDR(N64_DATA_PIN)), [pinNo] "I"(N64_DATA_PIN_NO),
|
||||
[rxdata] "x"(rxdata), [rxlen] "r"(rxlen),
|
||||
[txdata] "z"(txdata), [txlen] "r"(txlen), "0"(num)
|
||||
: "r16", "r17", "r18", "r19"
|
||||
);
|
||||
SREG = oldSREG;
|
||||
|
||||
_delay_us(100); // some commands leave the controller unresponsive for a while
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
uint8_t command[40];
|
||||
uint8_t result[40];
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
command[0] = 0x00;
|
||||
n64cmd(result, 3, command, 1);
|
||||
// logiquement, faudrait faire des vrais vérifs là maintenant, genre est-ce que le kit vibration est branché, etc…
|
||||
// initialisation du rumble pak
|
||||
command[0] = 0x03;
|
||||
command[1] = 0x80;
|
||||
command[2] = 0x01;
|
||||
memset(command + 3, 0x80, 32);
|
||||
n64cmd(result, 1, command, 35);
|
||||
Serial.println(result[0], HEX);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// vibration activée
|
||||
command[0] = 0x03;
|
||||
command[1] = 0xC0;
|
||||
command[2] = 0x1B;
|
||||
memset(command + 3, 0x01, 32);
|
||||
|
||||
n64cmd(result, 1, command, 35);
|
||||
|
||||
delay(1000);
|
||||
|
||||
// vibration désactivée
|
||||
memset(command + 3, 0x00, 32);
|
||||
|
||||
n64cmd(result, 1, command, 35);
|
||||
|
||||
delay(1000);
|
||||
}
|
BIN
static/vpn_ideal.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
static/vpn_ipsec_1tunnel.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
static/vpn_redondant_2_operateurs.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
static/vpn_reel.png
Normal file
After Width: | Height: | Size: 10 KiB |