#include #include #include #include #include #include #include #include #include #include #include #define _POSIX_C_SOURCE 200809L #define ML_VENDOR_ID 0x0416 #define ML_DEVICE_ID 0x9391 #define ML_ACTION_FIRE 0x10 #define ML_ACTION_MOVE_DOWN 0x1 #define ML_ACTION_MOVE_LEFT 0x8 #define ML_ACTION_MOVE_RIGHT 0x4 #define ML_ACTION_MOVE_UP 0x2 #define ML_ACTION_STOP 0x0 #define ML_TIME_FIRING 4300 #define ML_X_DEADZONE 15 #define ML_Y_DEADZONE 15 static struct libusb_device_handle *devh; int mlbin_init_usb(void) { libusb_device **list; libusb_device *device = NULL; int count, ret, i; ret = libusb_init(NULL); if (ret < 0) { perror(""); printf("Couldn't initialize libusb => %d.\n", ret); goto error; } count = libusb_get_device_list(NULL, &list); if (count < 0) { printf("Couldn't get device list\n"); goto list_error; } for (i = 0; i < count; i++) { //Browse USB Devices list to find Missile Launcher struct libusb_device_descriptor desc; device = list[i]; libusb_get_device_descriptor(device, &desc); printf("Found a new device : %x:%x\n", desc.idVendor, desc.idProduct); if (desc.idVendor == ML_VENDOR_ID && desc.idProduct == ML_DEVICE_ID) //Check Missile Launcher identity break; device = NULL; } if (!device) { printf("Couldn't find the device\n"); goto not_found_error; } ret = libusb_open(device, &devh); if (ret) { printf("Couldn't open device: %d\n", ret); goto open_dev_error; } libusb_detach_kernel_driver(devh, 0); ret = libusb_claim_interface(devh, 0); if (ret < 0) { printf("Couldn't claim the interface : %d.\n", ret); goto if_error; } libusb_free_device_list(list, count); printf("Interface setup.\n"); return 0; if_error: libusb_close(devh); detach_error: open_dev_error: not_found_error: libusb_free_device_list(list, count); list_error: libusb_exit(NULL); error: exit(1); } int mlbin_free_usb(void) { libusb_release_interface(devh, 0); libusb_close(devh); libusb_exit(NULL); return 0; } void send_data(unsigned char action) { unsigned char data[] = {0x5f, action, 0xe0, 0xff, 0xfe}; libusb_control_transfer(devh, 0x21, 0x09, 0, 0, data, 5, 300); } int startup(int ac, char **argv, int *fd, int *calibration, int *verbose) { int i = 1; if (ac < 2) { printf("Usage : %s [--calibration] [-v]\n", argv[0]); return (0); } if ((*fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { printf("Unable to open %s\n", argv[1]); return (0); } while (i < ac) { if (!strcmp(argv[i], "--calibration")) *calibration = 1; else if (!strcmp(argv[i], "-v")) *verbose = 1; i++; } if (*calibration) { printf("Mode : Calibration\n"); printf("Press Nunchuk C button for start and exactly repress C when you hear second click\n"); } else { printf("Mode : Game\n"); printf("Change ML orientation with joystick\nLaunch missile one by one by clicking C button\nLaunch every missiles by pressing Z button\n"); } return (1); } void calibration_mode(struct input_event *evnt, int *fire, int *calibration) { //Calibration allows to synchronise missile launcher mechanism if (evnt->code == 306 && evnt->value && !(*fire)) { send_data(ML_ACTION_FIRE); *fire = 1; printf("Starting calibration ...\n"); } else if (evnt->code == 306 && evnt->value && *fire) { send_data(ML_ACTION_STOP); *fire = 0; printf("Calibration finished ...\n"); *calibration = 0; } } void game_mode(struct input_event evnt, int *fire, struct timeval *tv, int *fire_time, int *plus_time) { //Check every actions provided by input iface if (evnt.code == 306 && evnt.value) { //Z Button pressed if (*fire) { send_data(ML_ACTION_STOP); *fire = 0; } else { gettimeofday(tv, NULL); *fire_time = (tv->tv_sec) * 1000 + (tv->tv_usec) / 1000; //Get current time *plus_time = ML_TIME_FIRING; //Firing while 4,2s send_data(ML_ACTION_FIRE); *fire = 1; } } else if (evnt.code == 309 && evnt.value) { //C Button pressed if (*fire) { send_data(ML_ACTION_STOP); *fire = 0; } else { gettimeofday(tv, NULL); *fire_time = (tv->tv_sec) * 1000 + (tv->tv_usec) / 1000; send_data(ML_ACTION_FIRE); *plus_time = ML_TIME_FIRING * 3; //Same as one firing but while 12,6s for 3 missiles *fire = 1; } } else if (evnt.type == 3 && !evnt.code) { //X-axis Joystick moved if (evnt.value < (127 - ML_X_DEADZONE)) send_data(ML_ACTION_MOVE_LEFT); else if (evnt.value > (127 + ML_X_DEADZONE)) send_data(ML_ACTION_MOVE_RIGHT); else send_data(ML_ACTION_STOP); } else if (evnt.type == 3 && evnt.code) { //Y-axis Joystick moved if (evnt.value < (127 - ML_Y_DEADZONE)) send_data(ML_ACTION_MOVE_DOWN); else if (evnt.value > (127 + ML_Y_DEADZONE)) send_data(ML_ACTION_MOVE_UP); else send_data(ML_ACTION_STOP); } } void launch_app(int fd, int calibration, int verbose) { struct input_event evnt; int fire = 0, n; int fire_time = 0; struct timeval tv; int plus_time = 0; while (1) { gettimeofday(&tv, NULL); //Stop fire when ML fired one missile, based on time, 4,2 sec for one missile if (fire && ((tv.tv_sec) * 1000 + (tv.tv_usec) / 1000) >= fire_time + plus_time) { send_data(ML_ACTION_STOP); fire = 0; } n = read(fd, &evnt, sizeof(evnt)); //Read data received by ML if (n > 0) { if (calibration) calibration_mode(&evnt, &fire, &calibration); else { game_mode(evnt, &fire, &tv, &fire_time, &plus_time); if (verbose) //Debug Verbose printf("Readed : Type : %d - Code : %d - Value : %d\n", evnt.type, evnt.code, evnt.value); } } } } int main(int ac, char *argv[]) { int fd; int calibration = 0, verbose = 0; //Check usage, set calibration and verbose flags and open input device if (!startup(ac, argv, &fd, &calibration, &verbose)) return (0); mlbin_init_usb(); //LibUSB initialisation and search device send_data(ML_ACTION_STOP); launch_app(fd, calibration, verbose); //Launch main loop mlbin_free_usb(); close(fd); return (0); }