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