Add GPLv2
[can2joy.git] / can2joy.c
1 /* This file is part of can2joy.
2  *
3  * can2joy is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License 2 as
5  * published by the Free Software Foundation.
6
7  * can2joy is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11
12  * You should have received a copy of the GNU General Public License
13  * along with can2joy. If not, see <http://www.gnu.org/licenses/>.
14  */
15 #include <fcntl.h>
16 #include <linux/can.h>
17 #include <linux/can/raw.h>
18 #include <linux/input.h>
19 #include <linux/uinput.h>
20 #include <net/if.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29
30 #define MIN(x, y) ((x) < (y) ? (x) : (y))
31 #define MAX(x, y) ((x) > (y) ? (x) : (y))
32
33
34 static int init_can(char *ifname)
35 {
36         struct sockaddr_can addr;
37         struct ifreq ifr;
38         int fd_can;
39
40         /* Open CAN socket */
41         fd_can = socket(PF_CAN, SOCK_RAW, CAN_RAW);
42         if (fd_can < 0) {
43                 perror("socket");
44                 return fd_can;
45         }
46
47         /* Get CAN interfaces's index by name */
48         strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
49         if (ioctl(fd_can, SIOCGIFINDEX, &ifr) < 0) {
50                 perror("SIOCGIFINDEX");
51                 return -1;
52         }
53
54         /* Bind CAN interface by index */
55         memset(&addr, 0, sizeof(addr));
56         addr.can_family = AF_CAN;
57         addr.can_ifindex = ifr.ifr_ifindex;
58         if (bind(fd_can, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
59                 perror("bind");
60                 return -1;
61         }
62
63         return fd_can;
64 }
65
66
67 static int init_uinput()
68 {
69         struct uinput_user_dev uidev;
70         int fd_uinput;
71
72         /* Open uinput */
73         fd_uinput = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
74         if(fd_uinput < 0) {
75                 perror("open (/dev/uinput)");
76                 return fd_uinput;
77         }
78
79         /* Register push buttons A, B */
80         ioctl(fd_uinput, UI_SET_EVBIT, EV_KEY);
81         ioctl(fd_uinput, UI_SET_KEYBIT, BTN_TRIGGER);
82         ioctl(fd_uinput, UI_SET_KEYBIT, BTN_THUMB);
83
84         /* Register absolute axes X, Y */
85         ioctl(fd_uinput, UI_SET_EVBIT, EV_ABS);
86         ioctl(fd_uinput, UI_SET_ABSBIT, ABS_X);
87         ioctl(fd_uinput, UI_SET_ABSBIT, ABS_Y);
88
89         /* Create a virtual input device ID */
90         memset(&uidev, 0, sizeof(uidev));
91         strncpy(uidev.name, "can2joy", UINPUT_MAX_NAME_SIZE);
92         uidev.id.bustype = BUS_USB;
93         uidev.id.vendor  = 0x1234;
94         uidev.id.product = 0xfedc;
95         uidev.id.version = 1;
96         write(fd_uinput, &uidev, sizeof(uidev));
97
98         /* Set min/max values for axes */
99         uidev.absmin[ABS_X] = 255;
100         uidev.absmax[ABS_X] = -256;
101         uidev.absmin[ABS_Y] = -1;
102         uidev.absmax[ABS_Y] = 1;
103         write(fd_uinput, &uidev, sizeof(uidev));
104
105         /* Let uinput rip */
106         ioctl(fd_uinput, UI_DEV_CREATE);
107
108         return fd_uinput;
109 }
110
111
112
113 static void receive_one(int fd_can, int fd_uinput)
114 {
115         struct can_frame frm;
116         struct sockaddr_can addr;
117         int ret;
118         socklen_t len;
119         struct input_event ev;
120         short wheel_pos;
121
122         memset(&ev, 0, sizeof(ev));
123
124         ret = recvfrom(fd_can, &frm, sizeof(struct can_frame), 0,
125         (struct sockaddr *)&addr, &len);
126         if (ret < 0) {
127         perror("recvfrom");
128         exit(1);
129         }
130
131         switch(frm.can_id) {
132         case 0x35b:
133                 /* Check clutch and brake pedal.
134                  * We only read one bit for each, so don't expect fine
135                  * control of your simulated Lamborghini!
136                  */
137                 ev.type = EV_KEY;
138                 ev.code = BTN_TRIGGER;
139                 ev.value = !(!(frm.data[4] & 3));
140                 write(fd_uinput, &ev, sizeof(ev));
141
142                 ev.code = BTN_THUMB;
143                 ev.value = !(!(frm.data[6] & 4));
144                 write(fd_uinput, &ev, sizeof(ev));
145                 break;
146
147         case 0x3c3:
148                 /* Translate absolute wheel position.
149                  * It's a signed 16-bit integer in the first two bytes
150                  * of a 0x3c3 frame, indicating how far it is turned.
151                  * Zero means we're driving straight.
152                  * The next two bytes are the angular speed of the wheel
153                  * being turned, but we don't care about that here.
154                  */
155                 wheel_pos = *((short*)(&frm.data[0]));
156                 printf("Wheel position: %i\n", wheel_pos);
157
158                 /* Clamp the wheel position around the zero point.
159                  * This is to avoid excessive wear of the wheels of the
160                  * parked car as well as of the whole steering mechanism.
161                  */
162                 if (wheel_pos >= 0) {
163                         wheel_pos = MIN(255, wheel_pos);
164                 } else {
165                         /* The first negative value next to zero is
166                          * -32768. So we have to invert this to -1
167                          * instead of -32768, -2 instead of -32767, etc.
168                          */
169                         wheel_pos = 0 - (wheel_pos + 32768);
170                         wheel_pos = MAX(-256, wheel_pos);
171                 }
172                 printf("Wheel position (clamped): %i\n", wheel_pos);
173
174                 /* Report the change in wheel position as the X axis */
175                 ev.type = EV_ABS;
176                 ev.code = ABS_X;
177                 ev.value = wheel_pos;
178                 ret = write(fd_uinput, &ev, sizeof(ev));
179
180                 /* Report a dummy Y axis for programs that expect it */
181                 ev.code = ABS_Y;
182                 ev.value = 0;
183                 ret = write(fd_uinput, &ev, sizeof(ev));
184                 break;
185         }
186
187         /* Flush the uinput events we just generated */
188         ev.type = EV_SYN;
189         ev.code = SYN_REPORT;
190         ev.value = 0;
191         write(fd_uinput, &ev, sizeof(ev));
192 }
193
194
195
196
197 int main(int argc, char **argv)
198 {
199         int fd_can;
200         int fd_uinput;
201
202         if (argc < 2) {
203                 printf("Usage: %s <can-interface>\n", argv[0]);
204                 printf("\n");
205                 printf("Example: %s can0\n", argv[0]);
206                 return 1;
207         }
208
209
210         fd_can = init_can(argv[1]);
211         if (fd_can < 0)
212                 return 1;
213
214         fd_uinput = init_uinput();
215         if (fd_uinput < 0)
216                 return 1;
217
218
219         for (;;)
220                 receive_one(fd_can, fd_uinput);
221
222
223         ioctl(fd_uinput, UI_DEV_DESTROY);
224
225         return 0;
226 }