A project to connect a genesis controller to USB via an Arduino board.
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.
 
 
 

207 lines
5.6 KiB

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/uinput.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
//List of button definitons and whatnot
#define START 0x01
#define WEST 0x02
#define EAST 0x08
#define SOUTH 0x04
#define DPAD_LEFT 0x10
#define DPAD_RIGHT 0x20
#define DPAD_DOWN 0x40
#define DPAD_UP 0x80
#define SELECT 0x100
#define LEFT_TRIGGER 0x200
#define NORTH 0x400
#define RIGHT_TRIGGER 0x800
//#define DEBUG_MODE 0x1337
//#define CONTROLLER_MODE 0x420
//A list that will hold the button offsets in a sequential order
int buttons_list[] = {
START,WEST,EAST,SOUTH, // 0 - 3
DPAD_LEFT,DPAD_RIGHT,DPAD_DOWN,DPAD_UP, // 4 - 7
SELECT,LEFT_TRIGGER,NORTH,RIGHT_TRIGGER // 8 - 11
};
#ifdef DEBUG_MODE
//1-letter names for buttons
char debug_names[] = "TWESLRDUMZNC";
#endif
//Actual mappings for the buttons, in the same order as in buttons_list
#ifdef CONTROLLER_MODE
//Mappings that are binding the controller as a joystick instead of a keyboard
int mappings[] = {
BTN_START,BTN_WEST,BTN_EAST,BTN_SOUTH,
BTN_DPAD_LEFT,BTN_DPAD_RIGHT,BTN_DPAD_DOWN,BTN_DPAD_UP,
BTN_SELECT,BTN_TL,BTN_NORTH,BTN_TR
};
#else
//Mappings that correspond to a particular subset of keyboard keys
int mappings[] = {
KEY_ESC,KEY_A,KEY_D,KEY_S,
KEY_LEFT,KEY_RIGHT,KEY_DOWN,KEY_UP,
KEY_X,KEY_Z,KEY_W,KEY_C
};
#endif
int input;
int uinput_fd;
//a bit of stolen code to make things work
void emit(int fd, int type, int code, int val) {
struct input_event ie;
ie.type = type;
ie.code = code;
ie.value = val;
/* timestamp values below are ignored */
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
write(fd, &ie, sizeof(ie));
}
void bye(int signum) {
//wait some more just because we want all the events that are happening to happen before we close everything.
sleep(1);
printf("Exit signal received - destroying the uinput device.\n");
close(input);
ioctl(uinput_fd, UI_DEV_DESTROY);
sleep(1);
close(uinput_fd);
exit(0);
};
int set_interface_attribs(int fd, int speed, int parity) {
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
printf("Error %d from tcget",errno);
return -1;
}
cfsetospeed(&tty, speed);
cfsetispeed(&tty, speed);
tty.c_lflag = 0;
tty.c_cflag |= CRTSCTS | CS8 | CLOCAL | CREAD;
tty.c_iflag = IGNPAR;
tty.c_oflag = 0;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error %d when setting up tty", errno);
return -1;
}
return 0;
}
int set_blocking(int fd, int should_block) {
struct termios tty;
memset (&tty, 0, sizeof(tty));
if(tcgetattr(fd, &tty) != 0) {
printf("Error %d from tcget", errno);
return -1;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error %d from tcset", errno);
return -1;
}
return 0;
}
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("Usage: driver <input device>\n");
return 1;
}
//Open tty device for reading
input = open(argv[1], O_RDWR | O_NOCTTY | O_SYNC);
if (!input) {
printf("Unable to open device %s for reading: %s\n",argv[1],strerror(errno));
return errno;
}
set_interface_attribs(input, B9600, 0);
set_blocking(input, 1);
//Create uinput configuration struct and open /dev/uinput
struct uinput_setup usetup;
uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
//Add this to gracefully close uinput_fd and input
signal(SIGINT, bye);
ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY);
for (int k = 0; k < 12; k++) {
ioctl(uinput_fd, UI_SET_KEYBIT, mappings[k]);
}
//Clear struct, set vendor and product.
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x041e;
usetup.id.product = 0x1003;
strcpy(usetup.name,"Macrohard YBox 2pi LPT2USB controller");
//Call setup
if (ioctl(uinput_fd, UI_DEV_SETUP, &usetup)) {
perror("UI_DEV_SETUP");
printf("Note: This might have been the result of not running the program as root\n");
return 1;
}
if (ioctl(uinput_fd, UI_DEV_CREATE)) {
perror("UI_DEV_CREATE");
return 1;
}
//Wait for some time so that uinput has time to setup stuff
sleep(1);
short unsigned int buffer[2];
short unsigned int prev_state = 0x0;
short unsigned int changes = 0x0;
short unsigned int current_state = 0x0;
//Main loop
while(1) {
read(input, buffer, 2);
current_state = ~buffer[0];
changes = prev_state ^ current_state;
if (changes != 0) {
#ifdef DEBUG_MODE
printf("State hash: %u\n",current_state);
printf("Recieved message: %u\n",buffer[0]);
#endif
for (int k = 0; k < 12; k++) {
if (changes & buttons_list[k]) {
emit(uinput_fd, EV_KEY, mappings[k], (current_state & buttons_list[k]) > 0);
emit(uinput_fd, EV_SYN, SYN_REPORT, 0);
#ifdef DEBUG_MODE
printf("Internal key name: %c\n",debug_names[k]);
printf("Key state: %u\n",(current_state & buttons_list[k]) > 0);
printf("Key mapping: %u\n",mappings[k]);
#endif
}
}
#ifdef DEBUG_MODE
printf("-------\n");
fflush(stdout);
#endif
}
prev_state = current_state;
}
//haha what a loser can't even get here because while true do loop
return 0;
}