1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "../SDL_internal.h" |
22 | |
23 | /* This is the sensor API for Simple DirectMedia Layer */ |
24 | |
25 | #include "SDL.h" |
26 | #include "SDL_atomic.h" |
27 | #include "SDL_events.h" |
28 | #include "SDL_syssensor.h" |
29 | |
30 | #if !SDL_EVENTS_DISABLED |
31 | #include "../events/SDL_events_c.h" |
32 | #endif |
33 | |
34 | static SDL_SensorDriver *SDL_sensor_drivers[] = { |
35 | #ifdef SDL_SENSOR_ANDROID |
36 | &SDL_ANDROID_SensorDriver, |
37 | #endif |
38 | #ifdef SDL_SENSOR_COREMOTION |
39 | &SDL_COREMOTION_SensorDriver, |
40 | #endif |
41 | #ifdef SDL_SENSOR_WINDOWS |
42 | &SDL_WINDOWS_SensorDriver, |
43 | #endif |
44 | #if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED) |
45 | &SDL_DUMMY_SensorDriver |
46 | #endif |
47 | #if defined(SDL_SENSOR_VITA) |
48 | &SDL_VITA_SensorDriver |
49 | #endif |
50 | }; |
51 | static SDL_Sensor *SDL_sensors = NULL; |
52 | static SDL_bool SDL_updating_sensor = SDL_FALSE; |
53 | static SDL_mutex *SDL_sensor_lock = NULL; /* This needs to support recursive locks */ |
54 | static SDL_atomic_t SDL_next_sensor_instance_id; |
55 | |
56 | void |
57 | SDL_LockSensors(void) |
58 | { |
59 | if (SDL_sensor_lock) { |
60 | SDL_LockMutex(SDL_sensor_lock); |
61 | } |
62 | } |
63 | |
64 | void |
65 | SDL_UnlockSensors(void) |
66 | { |
67 | if (SDL_sensor_lock) { |
68 | SDL_UnlockMutex(SDL_sensor_lock); |
69 | } |
70 | } |
71 | |
72 | |
73 | int |
74 | SDL_SensorInit(void) |
75 | { |
76 | int i, status; |
77 | |
78 | /* Create the sensor list lock */ |
79 | if (!SDL_sensor_lock) { |
80 | SDL_sensor_lock = SDL_CreateMutex(); |
81 | } |
82 | |
83 | #if !SDL_EVENTS_DISABLED |
84 | if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) { |
85 | return -1; |
86 | } |
87 | #endif /* !SDL_EVENTS_DISABLED */ |
88 | |
89 | status = -1; |
90 | for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { |
91 | if (SDL_sensor_drivers[i]->Init() >= 0) { |
92 | status = 0; |
93 | } |
94 | } |
95 | return status; |
96 | } |
97 | |
98 | /* |
99 | * Count the number of sensors attached to the system |
100 | */ |
101 | int |
102 | SDL_NumSensors(void) |
103 | { |
104 | int i, total_sensors = 0; |
105 | SDL_LockSensors(); |
106 | for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { |
107 | total_sensors += SDL_sensor_drivers[i]->GetCount(); |
108 | } |
109 | SDL_UnlockSensors(); |
110 | return total_sensors; |
111 | } |
112 | |
113 | /* |
114 | * Return the next available sensor instance ID |
115 | * This may be called by drivers from multiple threads, unprotected by any locks |
116 | */ |
117 | SDL_SensorID SDL_GetNextSensorInstanceID() |
118 | { |
119 | return SDL_AtomicIncRef(&SDL_next_sensor_instance_id); |
120 | } |
121 | |
122 | /* |
123 | * Get the driver and device index for an API device index |
124 | * This should be called while the sensor lock is held, to prevent another thread from updating the list |
125 | */ |
126 | static SDL_bool |
127 | SDL_GetDriverAndSensorIndex(int device_index, SDL_SensorDriver **driver, int *driver_index) |
128 | { |
129 | int i, num_sensors, total_sensors = 0; |
130 | |
131 | if (device_index >= 0) { |
132 | for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { |
133 | num_sensors = SDL_sensor_drivers[i]->GetCount(); |
134 | if (device_index < num_sensors) { |
135 | *driver = SDL_sensor_drivers[i]; |
136 | *driver_index = device_index; |
137 | return SDL_TRUE; |
138 | } |
139 | device_index -= num_sensors; |
140 | total_sensors += num_sensors; |
141 | } |
142 | } |
143 | |
144 | SDL_SetError("There are %d sensors available" , total_sensors); |
145 | return SDL_FALSE; |
146 | } |
147 | |
148 | /* |
149 | * Get the implementation dependent name of a sensor |
150 | */ |
151 | const char * |
152 | SDL_SensorGetDeviceName(int device_index) |
153 | { |
154 | SDL_SensorDriver *driver; |
155 | const char *name = NULL; |
156 | |
157 | SDL_LockSensors(); |
158 | if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) { |
159 | name = driver->GetDeviceName(device_index); |
160 | } |
161 | SDL_UnlockSensors(); |
162 | |
163 | /* FIXME: Really we should reference count this name so it doesn't go away after unlock */ |
164 | return name; |
165 | } |
166 | |
167 | SDL_SensorType |
168 | SDL_SensorGetDeviceType(int device_index) |
169 | { |
170 | SDL_SensorDriver *driver; |
171 | SDL_SensorType type = SDL_SENSOR_INVALID; |
172 | |
173 | SDL_LockSensors(); |
174 | if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) { |
175 | type = driver->GetDeviceType(device_index); |
176 | } |
177 | SDL_UnlockSensors(); |
178 | |
179 | return type; |
180 | } |
181 | |
182 | int |
183 | SDL_SensorGetDeviceNonPortableType(int device_index) |
184 | { |
185 | SDL_SensorDriver *driver; |
186 | int type = -1; |
187 | |
188 | SDL_LockSensors(); |
189 | if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) { |
190 | type = driver->GetDeviceNonPortableType(device_index); |
191 | } |
192 | SDL_UnlockSensors(); |
193 | |
194 | return type; |
195 | } |
196 | |
197 | SDL_SensorID |
198 | SDL_SensorGetDeviceInstanceID(int device_index) |
199 | { |
200 | SDL_SensorDriver *driver; |
201 | SDL_SensorID instance_id = -1; |
202 | |
203 | SDL_LockSensors(); |
204 | if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) { |
205 | instance_id = driver->GetDeviceInstanceID(device_index); |
206 | } |
207 | SDL_UnlockSensors(); |
208 | |
209 | return instance_id; |
210 | } |
211 | |
212 | /* |
213 | * Open a sensor for use - the index passed as an argument refers to |
214 | * the N'th sensor on the system. This index is the value which will |
215 | * identify this sensor in future sensor events. |
216 | * |
217 | * This function returns a sensor identifier, or NULL if an error occurred. |
218 | */ |
219 | SDL_Sensor * |
220 | SDL_SensorOpen(int device_index) |
221 | { |
222 | SDL_SensorDriver *driver; |
223 | SDL_SensorID instance_id; |
224 | SDL_Sensor *sensor; |
225 | SDL_Sensor *sensorlist; |
226 | const char *sensorname = NULL; |
227 | |
228 | SDL_LockSensors(); |
229 | |
230 | if (!SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) { |
231 | SDL_UnlockSensors(); |
232 | return NULL; |
233 | } |
234 | |
235 | sensorlist = SDL_sensors; |
236 | /* If the sensor is already open, return it |
237 | * it is important that we have a single sensor * for each instance id |
238 | */ |
239 | instance_id = driver->GetDeviceInstanceID(device_index); |
240 | while (sensorlist) { |
241 | if (instance_id == sensorlist->instance_id) { |
242 | sensor = sensorlist; |
243 | ++sensor->ref_count; |
244 | SDL_UnlockSensors(); |
245 | return sensor; |
246 | } |
247 | sensorlist = sensorlist->next; |
248 | } |
249 | |
250 | /* Create and initialize the sensor */ |
251 | sensor = (SDL_Sensor *) SDL_calloc(sizeof(*sensor), 1); |
252 | if (sensor == NULL) { |
253 | SDL_OutOfMemory(); |
254 | SDL_UnlockSensors(); |
255 | return NULL; |
256 | } |
257 | sensor->driver = driver; |
258 | sensor->instance_id = instance_id; |
259 | sensor->type = driver->GetDeviceType(device_index); |
260 | sensor->non_portable_type = driver->GetDeviceNonPortableType(device_index); |
261 | |
262 | if (driver->Open(sensor, device_index) < 0) { |
263 | SDL_free(sensor); |
264 | SDL_UnlockSensors(); |
265 | return NULL; |
266 | } |
267 | |
268 | sensorname = driver->GetDeviceName(device_index); |
269 | if (sensorname) { |
270 | sensor->name = SDL_strdup(sensorname); |
271 | } else { |
272 | sensor->name = NULL; |
273 | } |
274 | |
275 | /* Add sensor to list */ |
276 | ++sensor->ref_count; |
277 | /* Link the sensor in the list */ |
278 | sensor->next = SDL_sensors; |
279 | SDL_sensors = sensor; |
280 | |
281 | SDL_UnlockSensors(); |
282 | |
283 | driver->Update(sensor); |
284 | |
285 | return sensor; |
286 | } |
287 | |
288 | /* |
289 | * Find the SDL_Sensor that owns this instance id |
290 | */ |
291 | SDL_Sensor * |
292 | SDL_SensorFromInstanceID(SDL_SensorID instance_id) |
293 | { |
294 | SDL_Sensor *sensor; |
295 | |
296 | SDL_LockSensors(); |
297 | for (sensor = SDL_sensors; sensor; sensor = sensor->next) { |
298 | if (sensor->instance_id == instance_id) { |
299 | break; |
300 | } |
301 | } |
302 | SDL_UnlockSensors(); |
303 | return sensor; |
304 | } |
305 | |
306 | /* |
307 | * Checks to make sure the sensor is valid. |
308 | */ |
309 | static int |
310 | SDL_PrivateSensorValid(SDL_Sensor * sensor) |
311 | { |
312 | int valid; |
313 | |
314 | if (sensor == NULL) { |
315 | SDL_SetError("Sensor hasn't been opened yet" ); |
316 | valid = 0; |
317 | } else { |
318 | valid = 1; |
319 | } |
320 | |
321 | return valid; |
322 | } |
323 | |
324 | /* |
325 | * Get the friendly name of this sensor |
326 | */ |
327 | const char * |
328 | SDL_SensorGetName(SDL_Sensor * sensor) |
329 | { |
330 | if (!SDL_PrivateSensorValid(sensor)) { |
331 | return NULL; |
332 | } |
333 | |
334 | return sensor->name; |
335 | } |
336 | |
337 | /* |
338 | * Get the type of this sensor |
339 | */ |
340 | SDL_SensorType |
341 | SDL_SensorGetType(SDL_Sensor * sensor) |
342 | { |
343 | if (!SDL_PrivateSensorValid(sensor)) { |
344 | return SDL_SENSOR_INVALID; |
345 | } |
346 | |
347 | return sensor->type; |
348 | } |
349 | |
350 | /* |
351 | * Get the platform dependent type of this sensor |
352 | */ |
353 | int |
354 | SDL_SensorGetNonPortableType(SDL_Sensor * sensor) |
355 | { |
356 | if (!SDL_PrivateSensorValid(sensor)) { |
357 | return -1; |
358 | } |
359 | |
360 | return sensor->non_portable_type; |
361 | } |
362 | |
363 | /* |
364 | * Get the instance id for this opened sensor |
365 | */ |
366 | SDL_SensorID |
367 | SDL_SensorGetInstanceID(SDL_Sensor * sensor) |
368 | { |
369 | if (!SDL_PrivateSensorValid(sensor)) { |
370 | return -1; |
371 | } |
372 | |
373 | return sensor->instance_id; |
374 | } |
375 | |
376 | /* |
377 | * Get the current state of this sensor |
378 | */ |
379 | int |
380 | SDL_SensorGetData(SDL_Sensor * sensor, float *data, int num_values) |
381 | { |
382 | if (!SDL_PrivateSensorValid(sensor)) { |
383 | return -1; |
384 | } |
385 | |
386 | num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); |
387 | SDL_memcpy(data, sensor->data, num_values*sizeof(*data)); |
388 | return 0; |
389 | } |
390 | |
391 | /* |
392 | * Close a sensor previously opened with SDL_SensorOpen() |
393 | */ |
394 | void |
395 | SDL_SensorClose(SDL_Sensor * sensor) |
396 | { |
397 | SDL_Sensor *sensorlist; |
398 | SDL_Sensor *sensorlistprev; |
399 | |
400 | if (!SDL_PrivateSensorValid(sensor)) { |
401 | return; |
402 | } |
403 | |
404 | SDL_LockSensors(); |
405 | |
406 | /* First decrement ref count */ |
407 | if (--sensor->ref_count > 0) { |
408 | SDL_UnlockSensors(); |
409 | return; |
410 | } |
411 | |
412 | if (SDL_updating_sensor) { |
413 | SDL_UnlockSensors(); |
414 | return; |
415 | } |
416 | |
417 | sensor->driver->Close(sensor); |
418 | sensor->hwdata = NULL; |
419 | |
420 | sensorlist = SDL_sensors; |
421 | sensorlistprev = NULL; |
422 | while (sensorlist) { |
423 | if (sensor == sensorlist) { |
424 | if (sensorlistprev) { |
425 | /* unlink this entry */ |
426 | sensorlistprev->next = sensorlist->next; |
427 | } else { |
428 | SDL_sensors = sensor->next; |
429 | } |
430 | break; |
431 | } |
432 | sensorlistprev = sensorlist; |
433 | sensorlist = sensorlist->next; |
434 | } |
435 | |
436 | SDL_free(sensor->name); |
437 | |
438 | /* Free the data associated with this sensor */ |
439 | SDL_free(sensor); |
440 | |
441 | SDL_UnlockSensors(); |
442 | } |
443 | |
444 | void |
445 | SDL_SensorQuit(void) |
446 | { |
447 | int i; |
448 | |
449 | /* Make sure we're not getting called in the middle of updating sensors */ |
450 | SDL_assert(!SDL_updating_sensor); |
451 | |
452 | SDL_LockSensors(); |
453 | |
454 | /* Stop the event polling */ |
455 | while (SDL_sensors) { |
456 | SDL_sensors->ref_count = 1; |
457 | SDL_SensorClose(SDL_sensors); |
458 | } |
459 | |
460 | /* Quit the sensor setup */ |
461 | for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { |
462 | SDL_sensor_drivers[i]->Quit(); |
463 | } |
464 | |
465 | SDL_UnlockSensors(); |
466 | |
467 | #if !SDL_EVENTS_DISABLED |
468 | SDL_QuitSubSystem(SDL_INIT_EVENTS); |
469 | #endif |
470 | |
471 | if (SDL_sensor_lock) { |
472 | SDL_DestroyMutex(SDL_sensor_lock); |
473 | SDL_sensor_lock = NULL; |
474 | } |
475 | } |
476 | |
477 | |
478 | /* These are global for SDL_syssensor.c and SDL_events.c */ |
479 | |
480 | int |
481 | SDL_PrivateSensorUpdate(SDL_Sensor *sensor, float *data, int num_values) |
482 | { |
483 | int posted; |
484 | |
485 | /* Allow duplicate events, for things like steps and heartbeats */ |
486 | |
487 | /* Update internal sensor state */ |
488 | num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); |
489 | SDL_memcpy(sensor->data, data, num_values*sizeof(*data)); |
490 | |
491 | /* Post the event, if desired */ |
492 | posted = 0; |
493 | #if !SDL_EVENTS_DISABLED |
494 | if (SDL_GetEventState(SDL_SENSORUPDATE) == SDL_ENABLE) { |
495 | SDL_Event event; |
496 | event.type = SDL_SENSORUPDATE; |
497 | event.sensor.which = sensor->instance_id; |
498 | num_values = SDL_min(num_values, SDL_arraysize(event.sensor.data)); |
499 | SDL_memset(event.sensor.data, 0, sizeof(event.sensor.data)); |
500 | SDL_memcpy(event.sensor.data, data, num_values*sizeof(*data)); |
501 | posted = SDL_PushEvent(&event) == 1; |
502 | } |
503 | #endif /* !SDL_EVENTS_DISABLED */ |
504 | return posted; |
505 | } |
506 | |
507 | void |
508 | SDL_SensorUpdate(void) |
509 | { |
510 | int i; |
511 | SDL_Sensor *sensor, *next; |
512 | |
513 | if (!SDL_WasInit(SDL_INIT_SENSOR)) { |
514 | return; |
515 | } |
516 | |
517 | SDL_LockSensors(); |
518 | |
519 | if (SDL_updating_sensor) { |
520 | /* The sensors are already being updated */ |
521 | SDL_UnlockSensors(); |
522 | return; |
523 | } |
524 | |
525 | SDL_updating_sensor = SDL_TRUE; |
526 | |
527 | /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */ |
528 | SDL_UnlockSensors(); |
529 | |
530 | for (sensor = SDL_sensors; sensor; sensor = sensor->next) { |
531 | sensor->driver->Update(sensor); |
532 | } |
533 | |
534 | SDL_LockSensors(); |
535 | |
536 | SDL_updating_sensor = SDL_FALSE; |
537 | |
538 | /* If any sensors were closed while updating, free them here */ |
539 | for (sensor = SDL_sensors; sensor; sensor = next) { |
540 | next = sensor->next; |
541 | if (sensor->ref_count <= 0) { |
542 | SDL_SensorClose(sensor); |
543 | } |
544 | } |
545 | |
546 | /* this needs to happen AFTER walking the sensor list above, so that any |
547 | dangling hardware data from removed devices can be free'd |
548 | */ |
549 | for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { |
550 | SDL_sensor_drivers[i]->Detect(); |
551 | } |
552 | |
553 | SDL_UnlockSensors(); |
554 | } |
555 | |
556 | /* vi: set ts=4 sw=4 expandtab: */ |
557 | |