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