Document which bits are clutch and brake, respectively
[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
139                 /* Brake sets bits 0 and 1 (value 3) in byte 4 */
140                 ev.code = BTN_TRIGGER;
141                 ev.value = !(!(frm.data[4] & 3));
142                 write(fd_uinput, &ev, sizeof(ev));
143
144                 /* Clutch sets bit 2 (value 4) in byte 6 */
145                 ev.code = BTN_THUMB;
146                 ev.value = !(!(frm.data[6] & 4));
147                 write(fd_uinput, &ev, sizeof(ev));
148                 break;
149
150         case 0x3c3:
151                 /* Translate absolute wheel position.
152                  * It's a signed 16-bit integer in the first two bytes
153                  * of a 0x3c3 frame, indicating how far it is turned.
154                  * Zero means we're driving straight.
155                  * The next two bytes are the angular speed of the wheel
156                  * being turned, but we don't care about that here.
157                  */
158                 wheel_pos = *((short*)(&frm.data[0]));
159                 printf("Wheel position: %i\n", wheel_pos);
160
161                 /* Clamp the wheel position around the zero point.
162                  * This is to avoid excessive wear of the wheels of the
163                  * parked car as well as of the whole steering mechanism.
164                  */
165                 if (wheel_pos >= 0) {
166                         wheel_pos = MIN(255, wheel_pos);
167                 } else {
168                         /* The first negative value next to zero is
169                          * -32768. So we have to invert this to -1
170                          * instead of -32768, -2 instead of -32767, etc.
171                          */
172                         wheel_pos = 0 - (wheel_pos + 32768);
173                         wheel_pos = MAX(-256, wheel_pos);
174                 }
175                 printf("Wheel position (clamped): %i\n", wheel_pos);
176
177                 /* Report the change in wheel position as the X axis */
178                 ev.type = EV_ABS;
179                 ev.code = ABS_X;
180                 ev.value = wheel_pos;
181                 ret = write(fd_uinput, &ev, sizeof(ev));
182
183                 /* Report a dummy Y axis for programs that expect it */
184                 ev.code = ABS_Y;
185                 ev.value = 0;
186                 ret = write(fd_uinput, &ev, sizeof(ev));
187                 break;
188         }
189
190         /* Flush the uinput events we just generated */
191         ev.type = EV_SYN;
192         ev.code = SYN_REPORT;
193         ev.value = 0;
194         write(fd_uinput, &ev, sizeof(ev));
195 }
196
197
198
199
200 int main(int argc, char **argv)
201 {
202         int fd_can;
203         int fd_uinput;
204
205         if (argc < 2) {
206                 printf("Usage: %s <can-interface>\n", argv[0]);
207                 printf("\n");
208                 printf("Example: %s can0\n", argv[0]);
209                 return 1;
210         }
211
212
213         fd_can = init_can(argv[1]);
214         if (fd_can < 0)
215                 return 1;
216
217         fd_uinput = init_uinput();
218         if (fd_uinput < 0)
219                 return 1;
220
221
222         for (;;)
223                 receive_one(fd_can, fd_uinput);
224
225
226         ioctl(fd_uinput, UI_DEV_DESTROY);
227
228         return 0;
229 }