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