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
34static 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};
51static SDL_Sensor *SDL_sensors = NULL;
52static SDL_bool SDL_updating_sensor = SDL_FALSE;
53static SDL_mutex *SDL_sensor_lock = NULL; /* This needs to support recursive locks */
54static SDL_atomic_t SDL_next_sensor_instance_id;
55
56void
57SDL_LockSensors(void)
58{
59 if (SDL_sensor_lock) {
60 SDL_LockMutex(SDL_sensor_lock);
61 }
62}
63
64void
65SDL_UnlockSensors(void)
66{
67 if (SDL_sensor_lock) {
68 SDL_UnlockMutex(SDL_sensor_lock);
69 }
70}
71
72
73int
74SDL_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 */
101int
102SDL_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 */
117SDL_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 */
126static SDL_bool
127SDL_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 */
151const char *
152SDL_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
167SDL_SensorType
168SDL_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
182int
183SDL_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
197SDL_SensorID
198SDL_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 */
219SDL_Sensor *
220SDL_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 */
291SDL_Sensor *
292SDL_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 */
309static int
310SDL_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 */
327const char *
328SDL_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 */
340SDL_SensorType
341SDL_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 */
353int
354SDL_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 */
366SDL_SensorID
367SDL_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 */
379int
380SDL_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 */
394void
395SDL_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
444void
445SDL_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
480int
481SDL_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
507void
508SDL_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