From 53bf76ad9ab9d20fcd449f0b462b9358a93e949d Mon Sep 17 00:00:00 2001 From: norly Date: Fri, 24 Aug 2018 00:00:08 +0200 Subject: [PATCH] Initial import --- Makefile | 7 ++ can2joy.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 Makefile create mode 100644 can2joy.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b6d0925 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +can2joy: can2joy.c + gcc -o $@ -O $^ -Wall -Wextra + + +.PHONY: clean +clean: + rm -f can2joy diff --git a/can2joy.c b/can2joy.c new file mode 100644 index 0000000..47fb5cb --- /dev/null +++ b/can2joy.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + + +static int init_can(char *ifname) +{ + struct sockaddr_can addr; + struct ifreq ifr; + int fd_can; + + /* Open CAN socket */ + fd_can = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (fd_can < 0) { + perror("socket"); + return fd_can; + } + + /* Get CAN interfaces's index by name */ + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(fd_can, SIOCGIFINDEX, &ifr) < 0) { + perror("SIOCGIFINDEX"); + return -1; + } + + /* Bind CAN interface by index */ + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + if (bind(fd_can, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + return -1; + } + + return fd_can; +} + + +static int init_uinput() +{ + struct uinput_user_dev uidev; + int fd_uinput; + + /* Open uinput */ + fd_uinput = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + if(fd_uinput < 0) { + perror("open (/dev/uinput)"); + return fd_uinput; + } + + /* Register push buttons A, B */ + ioctl(fd_uinput, UI_SET_EVBIT, EV_KEY); + ioctl(fd_uinput, UI_SET_KEYBIT, BTN_TRIGGER); + ioctl(fd_uinput, UI_SET_KEYBIT, BTN_THUMB); + + /* Register absolute axes X, Y */ + ioctl(fd_uinput, UI_SET_EVBIT, EV_ABS); + ioctl(fd_uinput, UI_SET_ABSBIT, ABS_X); + ioctl(fd_uinput, UI_SET_ABSBIT, ABS_Y); + + /* Create a virtual input device ID */ + memset(&uidev, 0, sizeof(uidev)); + strncpy(uidev.name, "can2joy", UINPUT_MAX_NAME_SIZE); + uidev.id.bustype = BUS_USB; + uidev.id.vendor = 0x1234; + uidev.id.product = 0xfedc; + uidev.id.version = 1; + write(fd_uinput, &uidev, sizeof(uidev)); + + /* Set min/max values for axes */ + uidev.absmin[ABS_X] = 255; + uidev.absmax[ABS_X] = -256; + uidev.absmin[ABS_Y] = -1; + uidev.absmax[ABS_Y] = 1; + write(fd_uinput, &uidev, sizeof(uidev)); + + /* Let uinput rip */ + ioctl(fd_uinput, UI_DEV_CREATE); + + return fd_uinput; +} + + + +static void receive_one(int fd_can, int fd_uinput) +{ + struct can_frame frm; + struct sockaddr_can addr; + int ret; + socklen_t len; + struct input_event ev; + short wheel_pos; + + memset(&ev, 0, sizeof(ev)); + + ret = recvfrom(fd_can, &frm, sizeof(struct can_frame), 0, + (struct sockaddr *)&addr, &len); + if (ret < 0) { + perror("recvfrom"); + exit(1); + } + + switch(frm.can_id) { + case 0x35b: + /* Check clutch and brake pedal. + * We only read one bit for each, so don't expect fine + * control of your simulated Lamborghini! + */ + ev.type = EV_KEY; + ev.code = BTN_TRIGGER; + ev.value = !(!(frm.data[4] & 3)); + write(fd_uinput, &ev, sizeof(ev)); + + ev.code = BTN_THUMB; + ev.value = !(!(frm.data[6] & 4)); + write(fd_uinput, &ev, sizeof(ev)); + break; + + case 0x3c3: + /* Translate absolute wheel position. + * It's a signed 16-bit integer in the first two bytes + * of a 0x3c3 frame, indicating how far it is turned. + * Zero means we're driving straight. + * The next two bytes are the angular speed of the wheel + * being turned, but we don't care about that here. + */ + wheel_pos = *((short*)(&frm.data[0])); + printf("Wheel position: %i\n", wheel_pos); + + /* Clamp the wheel position around the zero point. + * This is to avoid excessive wear of the wheels of the + * parked car as well as of the whole steering mechanism. + */ + if (wheel_pos >= 0) { + wheel_pos = MIN(255, wheel_pos); + } else { + /* The first negative value next to zero is + * -32768. So we have to invert this to -1 + * instead of -32768, -2 instead of -32767, etc. + */ + wheel_pos = 0 - (wheel_pos + 32768); + wheel_pos = MAX(-256, wheel_pos); + } + printf("Wheel position (clamped): %i\n", wheel_pos); + + /* Report the change in wheel position as the X axis */ + ev.type = EV_ABS; + ev.code = ABS_X; + ev.value = wheel_pos; + ret = write(fd_uinput, &ev, sizeof(ev)); + + /* Report a dummy Y axis for programs that expect it */ + ev.code = ABS_Y; + ev.value = 0; + ret = write(fd_uinput, &ev, sizeof(ev)); + break; + } + + /* Flush the uinput events we just generated */ + ev.type = EV_SYN; + ev.code = SYN_REPORT; + ev.value = 0; + write(fd_uinput, &ev, sizeof(ev)); +} + + + + +int main(int argc, char **argv) +{ + int fd_can; + int fd_uinput; + + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + printf("\n"); + printf("Example: %s can0\n", argv[0]); + return 1; + } + + + fd_can = init_can(argv[1]); + if (fd_can < 0) + return 1; + + fd_uinput = init_uinput(); + if (fd_uinput < 0) + return 1; + + + for (;;) + receive_one(fd_can, fd_uinput); + + + ioctl(fd_uinput, UI_DEV_DESTROY); + + return 0; +} -- 2.30.2