1 /*
2 libgo2 - Support library for the ODROID-GO Advance
3 Copyright (C) 2020 OtherCrashOverride
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "input.h"
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stdint.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <dirent.h>
32 #include <stdbool.h>
33 #include <pthread.h>
34
35 #include <libevdev-1.0/libevdev/libevdev.h>
36 #include <linux/limits.h>
37
38
39 #define BATTERY_BUFFER_SIZE (128)
40
41 static const char* EVDEV_NAME = "/dev/input/by-path/platform-odroidgo2-joypad-event-joystick";
42 static const char* BATTERY_STATUS_NAME = "/sys/class/power_supply/battery/status";
43 static const char* BATTERY_CAPACITY_NAME = "/sys/class/power_supply/battery/capacity";
44
45
46 typedef struct go2_input
47 {
48 int fd;
49 struct libevdev* dev;
50 go2_gamepad_state_t current_state;
51 go2_gamepad_state_t pending_state;
52 pthread_mutex_t gamepadMutex;
53 pthread_t thread_id;
54 go2_battery_state_t current_battery;
55 pthread_t battery_thread;
56 bool terminating;
57 } go2_input_t;
58
59
battery_task(void * arg)60 static void* battery_task(void* arg)
61 {
62 go2_input_t* input = (go2_input_t*)arg;
63 int fd;
64 void* result = 0;
65 char buffer[BATTERY_BUFFER_SIZE + 1];
66 go2_battery_state_t battery;
67
68
69 memset(&battery, 0, sizeof(battery));
70
71
72 while(!input->terminating)
73 {
74 fd = open(BATTERY_STATUS_NAME, O_RDONLY);
75 if (fd > 0)
76 {
77 memset(buffer, 0, BATTERY_BUFFER_SIZE + 1);
78 ssize_t count = read(fd, buffer, BATTERY_BUFFER_SIZE);
79 if (count > 0)
80 {
81 //printf("BATT: buffer='%s'\n", buffer);
82
83 if (buffer[0] == 'D')
84 {
85 battery.status = Battery_Status_Discharging;
86 }
87 else if (buffer[0] == 'C')
88 {
89 battery.status = Battery_Status_Charging;
90 }
91 else if (buffer[0] == 'F')
92 {
93 battery.status = Battery_Status_Full;
94 }
95 else
96 {
97 battery.status = Battery_Status_Unknown;
98 }
99 }
100
101 close(fd);
102 }
103
104 fd = open(BATTERY_CAPACITY_NAME, O_RDONLY);
105 if (fd > 0)
106 {
107 memset(buffer, 0, BATTERY_BUFFER_SIZE + 1);
108 ssize_t count = read(fd, buffer, BATTERY_BUFFER_SIZE);
109 if (count > 0)
110 {
111 battery.level = atoi(buffer);
112 }
113 else
114 {
115 battery.level = 0;
116 }
117
118 close(fd);
119 }
120
121
122 pthread_mutex_lock(&input->gamepadMutex);
123
124 input->current_battery = battery;
125
126 pthread_mutex_unlock(&input->gamepadMutex);
127
128 //printf("BATT: status=%d, level=%d\n", input->current_battery.status, input->current_battery.level);
129
130 sleep(1);
131 }
132
133 //printf("BATT: exit.\n");
134 return result;
135 }
136
137
138
139
input_task(void * arg)140 static void* input_task(void* arg)
141 {
142 go2_input_t* input = (go2_input_t*)arg;
143
144 if (!input->dev) return NULL;
145
146 const int abs_x_max = 512; //libevdev_get_abs_maximum(input->dev, ABS_X);
147 const int abs_y_max = 512; //libevdev_get_abs_maximum(input->dev, ABS_Y);
148
149 //printf("abs: x_max=%d, y_max=%d\n", abs_x_max, abs_y_max);
150
151
152 // Get current state
153 input->pending_state.dpad.up = libevdev_get_event_value(input->dev, EV_KEY, BTN_DPAD_UP) ? ButtonState_Pressed : ButtonState_Released;
154 input->pending_state.dpad.down = libevdev_get_event_value(input->dev, EV_KEY, BTN_DPAD_DOWN) ? ButtonState_Pressed : ButtonState_Released;
155 input->pending_state.dpad.left = libevdev_get_event_value(input->dev, EV_KEY, BTN_DPAD_LEFT) ? ButtonState_Pressed : ButtonState_Released;
156 input->pending_state.dpad.right = libevdev_get_event_value(input->dev, EV_KEY, BTN_DPAD_RIGHT) ? ButtonState_Pressed : ButtonState_Released;
157
158 input->pending_state.buttons.a = libevdev_get_event_value(input->dev, EV_KEY, BTN_EAST) ? ButtonState_Pressed : ButtonState_Released;
159 input->pending_state.buttons.b = libevdev_get_event_value(input->dev, EV_KEY, BTN_SOUTH) ? ButtonState_Pressed : ButtonState_Released;
160 input->pending_state.buttons.x = libevdev_get_event_value(input->dev, EV_KEY, BTN_NORTH) ? ButtonState_Pressed : ButtonState_Released;
161 input->pending_state.buttons.y = libevdev_get_event_value(input->dev, EV_KEY, BTN_WEST) ? ButtonState_Pressed : ButtonState_Released;
162
163 input->pending_state.buttons.top_left = libevdev_get_event_value(input->dev, EV_KEY, BTN_TL) ? ButtonState_Pressed : ButtonState_Released;
164 input->pending_state.buttons.top_right = libevdev_get_event_value(input->dev, EV_KEY, BTN_TR) ? ButtonState_Pressed : ButtonState_Released;
165
166 input->current_state.buttons.f1 = libevdev_get_event_value(input->dev, EV_KEY, BTN_TRIGGER_HAPPY1) ? ButtonState_Pressed : ButtonState_Released;
167 input->current_state.buttons.f2 = libevdev_get_event_value(input->dev, EV_KEY, BTN_TRIGGER_HAPPY2) ? ButtonState_Pressed : ButtonState_Released;
168 input->current_state.buttons.f3 = libevdev_get_event_value(input->dev, EV_KEY, BTN_TRIGGER_HAPPY3) ? ButtonState_Pressed : ButtonState_Released;
169 input->current_state.buttons.f4 = libevdev_get_event_value(input->dev, EV_KEY, BTN_TRIGGER_HAPPY4) ? ButtonState_Pressed : ButtonState_Released;
170 input->current_state.buttons.f5 = libevdev_get_event_value(input->dev, EV_KEY, BTN_TRIGGER_HAPPY5) ? ButtonState_Pressed : ButtonState_Released;
171 input->current_state.buttons.f5 = libevdev_get_event_value(input->dev, EV_KEY, BTN_TRIGGER_HAPPY6) ? ButtonState_Pressed : ButtonState_Released;
172
173
174 // Events
175 while (!input->terminating)
176 {
177 /* EAGAIN is returned when the queue is empty */
178 struct input_event ev;
179 int rc = libevdev_next_event(input->dev, LIBEVDEV_READ_FLAG_BLOCKING, &ev);
180 if (rc == 0)
181 {
182 #if 0
183 printf("Gamepad Event: %s-%s(%d)=%d\n",
184 libevdev_event_type_get_name(ev.type),
185 libevdev_event_code_get_name(ev.type, ev.code), ev.code,
186 ev.value);
187 #endif
188
189 if (ev.type == EV_KEY)
190 {
191 go2_button_state_t state = ev.value ? ButtonState_Pressed : ButtonState_Released;
192
193 switch (ev.code)
194 {
195 case BTN_DPAD_UP:
196 input->pending_state.dpad.up = state;
197 break;
198 case BTN_DPAD_DOWN:
199 input->pending_state.dpad.down = state;
200 break;
201 case BTN_DPAD_LEFT:
202 input->pending_state.dpad.left = state;
203 break;
204 case BTN_DPAD_RIGHT:
205 input->pending_state.dpad.right = state;
206 break;
207
208 case BTN_EAST:
209 input->pending_state.buttons.a = state;
210 break;
211 case BTN_SOUTH:
212 input->pending_state.buttons.b = state;
213 break;
214 case BTN_NORTH:
215 input->pending_state.buttons.x = state;
216 break;
217 case BTN_WEST:
218 input->pending_state.buttons.y = state;
219 break;
220
221 case BTN_TL:
222 input->pending_state.buttons.top_left = state;
223 break;
224 case BTN_TR:
225 input->pending_state.buttons.top_right = state;
226 break;
227
228 case BTN_TRIGGER_HAPPY1:
229 input->pending_state.buttons.f1 = state;
230 break;
231 case BTN_TRIGGER_HAPPY2:
232 input->pending_state.buttons.f2 = state;
233 break;
234 case BTN_TRIGGER_HAPPY3:
235 input->pending_state.buttons.f3 = state;
236 break;
237 case BTN_TRIGGER_HAPPY4:
238 input->pending_state.buttons.f4 = state;
239 break;
240 case BTN_TRIGGER_HAPPY5:
241 input->pending_state.buttons.f5 = state;
242 break;
243 case BTN_TRIGGER_HAPPY6:
244 input->pending_state.buttons.f6 = state;
245 break;
246 }
247 }
248 else if (ev.type == EV_ABS)
249 {
250 switch (ev.code)
251 {
252 case ABS_X:
253 input->pending_state.thumb.x = ev.value / (float)abs_x_max;
254 break;
255 case ABS_Y:
256 input->pending_state.thumb.y = ev.value / (float)abs_y_max;
257 break;
258 }
259 }
260 else if (ev.type == EV_SYN)
261 {
262 pthread_mutex_lock(&input->gamepadMutex);
263
264 input->current_state = input->pending_state;
265
266 pthread_mutex_unlock(&input->gamepadMutex);
267 }
268 }
269 }
270
271 return NULL;
272 }
273
go2_input_create()274 go2_input_t* go2_input_create()
275 {
276 int rc = 1;
277
278 go2_input_t* result = malloc(sizeof(*result));
279 if (!result)
280 {
281 printf("malloc failed.\n");
282 goto out;
283 }
284
285 memset(result, 0, sizeof(*result));
286
287
288
289
290
291 result->fd = open(EVDEV_NAME, O_RDONLY);
292 if (result->fd < 0)
293 {
294 printf("Joystick: No gamepad found.\n");
295 }
296 else
297 {
298 rc = libevdev_new_from_fd(result->fd, &result->dev);
299 if (rc < 0) {
300 printf("Joystick: Failed to init libevdev (%s)\n", strerror(-rc));
301 goto err_00;
302 }
303
304 memset(&result->current_state, 0, sizeof(result->current_state));
305 memset(&result->pending_state, 0, sizeof(result->pending_state));
306
307
308 // printf("Input device name: \"%s\"\n", libevdev_get_name(result->dev));
309 // printf("Input device ID: bus %#x vendor %#x product %#x\n",
310 // libevdev_get_id_bustype(result->dev),
311 // libevdev_get_id_vendor(result->dev),
312 // libevdev_get_id_product(result->dev));
313
314 if(pthread_create(&result->thread_id, NULL, input_task, (void*)result) < 0)
315 {
316 printf("could not create input_task thread\n");
317 goto err_01;
318 }
319
320 if(pthread_create(&result->battery_thread, NULL, battery_task, (void*)result) < 0)
321 {
322 printf("could not create battery_task thread\n");
323 }
324
325 }
326
327 return result;
328
329
330 err_01:
331 libevdev_free(result->dev);
332
333 err_00:
334 close(result->fd);
335 free(result);
336
337 out:
338 return NULL;
339 }
340
go2_input_destroy(go2_input_t * input)341 void go2_input_destroy(go2_input_t* input)
342 {
343 input->terminating = true;
344
345 pthread_cancel(input->thread_id);
346
347 pthread_join(input->thread_id, NULL);
348 pthread_join(input->battery_thread, NULL);
349
350 libevdev_free(input->dev);
351 close(input->fd);
352 free(input);
353 }
354
go2_input_gamepad_read(go2_input_t * input,go2_gamepad_state_t * outGamepadState)355 void go2_input_gamepad_read(go2_input_t* input, go2_gamepad_state_t* outGamepadState)
356 {
357 pthread_mutex_lock(&input->gamepadMutex);
358
359 *outGamepadState = input->current_state;
360
361 pthread_mutex_unlock(&input->gamepadMutex);
362 }
363
go2_input_battery_read(go2_input_t * input,go2_battery_state_t * outBatteryState)364 void go2_input_battery_read(go2_input_t* input, go2_battery_state_t* outBatteryState)
365 {
366 pthread_mutex_lock(&input->gamepadMutex);
367
368 *outBatteryState = input->current_battery;
369
370 pthread_mutex_unlock(&input->gamepadMutex);
371 }
372