Simple Directmedia Layer
at main 16 kB view raw
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2024 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_syssensor.h" 26 27#include "../events/SDL_events_c.h" 28#include "../joystick/SDL_gamepad_c.h" 29 30static SDL_SensorDriver *SDL_sensor_drivers[] = { 31#ifdef SDL_SENSOR_ANDROID 32 &SDL_ANDROID_SensorDriver, 33#endif 34#ifdef SDL_SENSOR_COREMOTION 35 &SDL_COREMOTION_SensorDriver, 36#endif 37#ifdef SDL_SENSOR_WINDOWS 38 &SDL_WINDOWS_SensorDriver, 39#endif 40#ifdef SDL_SENSOR_VITA 41 &SDL_VITA_SensorDriver, 42#endif 43#ifdef SDL_SENSOR_N3DS 44 &SDL_N3DS_SensorDriver, 45#endif 46#if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED) 47 &SDL_DUMMY_SensorDriver 48#endif 49}; 50 51#ifndef SDL_THREAD_SAFETY_ANALYSIS 52static 53#endif 54SDL_Mutex *SDL_sensor_lock = NULL; // This needs to support recursive locks 55static SDL_AtomicInt SDL_sensor_lock_pending; 56static int SDL_sensors_locked; 57static bool SDL_sensors_initialized; 58static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_sensor_lock) = NULL; 59 60#define CHECK_SENSOR_MAGIC(sensor, result) \ 61 if (!SDL_ObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR)) { \ 62 SDL_InvalidParamError("sensor"); \ 63 SDL_UnlockSensors(); \ 64 return result; \ 65 } 66 67bool SDL_SensorsInitialized(void) 68{ 69 return SDL_sensors_initialized; 70} 71 72void SDL_LockSensors(void) 73{ 74 (void)SDL_AtomicIncRef(&SDL_sensor_lock_pending); 75 SDL_LockMutex(SDL_sensor_lock); 76 (void)SDL_AtomicDecRef(&SDL_sensor_lock_pending); 77 78 ++SDL_sensors_locked; 79} 80 81void SDL_UnlockSensors(void) 82{ 83 bool last_unlock = false; 84 85 --SDL_sensors_locked; 86 87 if (!SDL_sensors_initialized) { 88 // NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks 89 if (!SDL_sensors_locked && SDL_GetAtomicInt(&SDL_sensor_lock_pending) == 0) { 90 last_unlock = true; 91 } 92 } 93 94 /* The last unlock after sensors are uninitialized will cleanup the mutex, 95 * allowing applications to lock sensors while reinitializing the system. 96 */ 97 if (last_unlock) { 98 SDL_Mutex *sensor_lock = SDL_sensor_lock; 99 100 SDL_LockMutex(sensor_lock); 101 { 102 SDL_UnlockMutex(SDL_sensor_lock); 103 104 SDL_sensor_lock = NULL; 105 } 106 SDL_UnlockMutex(sensor_lock); 107 SDL_DestroyMutex(sensor_lock); 108 } else { 109 SDL_UnlockMutex(SDL_sensor_lock); 110 } 111} 112 113bool SDL_SensorsLocked(void) 114{ 115 return (SDL_sensors_locked > 0); 116} 117 118void SDL_AssertSensorsLocked(void) 119{ 120 SDL_assert(SDL_SensorsLocked()); 121} 122 123bool SDL_InitSensors(void) 124{ 125 int i; 126 bool status; 127 128 // Create the sensor list lock 129 if (SDL_sensor_lock == NULL) { 130 SDL_sensor_lock = SDL_CreateMutex(); 131 } 132 133 if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) { 134 return false; 135 } 136 137 SDL_LockSensors(); 138 139 SDL_sensors_initialized = true; 140 141 status = false; 142 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { 143 if (SDL_sensor_drivers[i]->Init()) { 144 status = true; 145 } 146 } 147 148 SDL_UnlockSensors(); 149 150 if (!status) { 151 SDL_QuitSensors(); 152 } 153 154 return status; 155} 156 157bool SDL_SensorsOpened(void) 158{ 159 bool opened; 160 161 SDL_LockSensors(); 162 { 163 if (SDL_sensors != NULL) { 164 opened = true; 165 } else { 166 opened = false; 167 } 168 } 169 SDL_UnlockSensors(); 170 171 return opened; 172} 173 174SDL_SensorID *SDL_GetSensors(int *count) 175{ 176 int i, num_sensors, device_index; 177 int sensor_index = 0, total_sensors = 0; 178 SDL_SensorID *sensors; 179 180 SDL_LockSensors(); 181 { 182 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { 183 total_sensors += SDL_sensor_drivers[i]->GetCount(); 184 } 185 186 sensors = (SDL_SensorID *)SDL_malloc((total_sensors + 1) * sizeof(*sensors)); 187 if (sensors) { 188 if (count) { 189 *count = total_sensors; 190 } 191 192 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { 193 num_sensors = SDL_sensor_drivers[i]->GetCount(); 194 for (device_index = 0; device_index < num_sensors; ++device_index) { 195 SDL_assert(sensor_index < total_sensors); 196 sensors[sensor_index] = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index); 197 SDL_assert(sensors[sensor_index] > 0); 198 ++sensor_index; 199 } 200 } 201 SDL_assert(sensor_index == total_sensors); 202 sensors[sensor_index] = 0; 203 } else { 204 if (count) { 205 *count = 0; 206 } 207 } 208 } 209 SDL_UnlockSensors(); 210 211 return sensors; 212} 213 214/* 215 * Get the driver and device index for a sensor instance ID 216 * This should be called while the sensor lock is held, to prevent another thread from updating the list 217 */ 218static bool SDL_GetDriverAndSensorIndex(SDL_SensorID instance_id, SDL_SensorDriver **driver, int *driver_index) 219{ 220 int i, num_sensors, device_index; 221 222 if (instance_id > 0) { 223 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { 224 num_sensors = SDL_sensor_drivers[i]->GetCount(); 225 for (device_index = 0; device_index < num_sensors; ++device_index) { 226 SDL_SensorID sensor_id = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index); 227 if (sensor_id == instance_id) { 228 *driver = SDL_sensor_drivers[i]; 229 *driver_index = device_index; 230 return true; 231 } 232 } 233 } 234 } 235 SDL_SetError("Sensor %" SDL_PRIu32 " not found", instance_id); 236 return false; 237} 238 239/* 240 * Get the implementation dependent name of a sensor 241 */ 242const char *SDL_GetSensorNameForID(SDL_SensorID instance_id) 243{ 244 SDL_SensorDriver *driver; 245 int device_index; 246 const char *name = NULL; 247 248 SDL_LockSensors(); 249 if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { 250 name = SDL_GetPersistentString(driver->GetDeviceName(device_index)); 251 } 252 SDL_UnlockSensors(); 253 254 return name; 255} 256 257SDL_SensorType SDL_GetSensorTypeForID(SDL_SensorID instance_id) 258{ 259 SDL_SensorDriver *driver; 260 int device_index; 261 SDL_SensorType type = SDL_SENSOR_INVALID; 262 263 SDL_LockSensors(); 264 if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { 265 type = driver->GetDeviceType(device_index); 266 } 267 SDL_UnlockSensors(); 268 269 return type; 270} 271 272int SDL_GetSensorNonPortableTypeForID(SDL_SensorID instance_id) 273{ 274 SDL_SensorDriver *driver; 275 int device_index; 276 int type = -1; 277 278 SDL_LockSensors(); 279 if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { 280 type = driver->GetDeviceNonPortableType(device_index); 281 } 282 SDL_UnlockSensors(); 283 284 return type; 285} 286 287/* 288 * Open a sensor for use - the index passed as an argument refers to 289 * the N'th sensor on the system. This index is the value which will 290 * identify this sensor in future sensor events. 291 * 292 * This function returns a sensor identifier, or NULL if an error occurred. 293 */ 294SDL_Sensor *SDL_OpenSensor(SDL_SensorID instance_id) 295{ 296 SDL_SensorDriver *driver; 297 int device_index; 298 SDL_Sensor *sensor; 299 SDL_Sensor *sensorlist; 300 const char *sensorname = NULL; 301 302 SDL_LockSensors(); 303 304 if (!SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) { 305 SDL_UnlockSensors(); 306 return NULL; 307 } 308 309 sensorlist = SDL_sensors; 310 /* If the sensor is already open, return it 311 * it is important that we have a single sensor * for each instance id 312 */ 313 while (sensorlist) { 314 if (instance_id == sensorlist->instance_id) { 315 sensor = sensorlist; 316 ++sensor->ref_count; 317 SDL_UnlockSensors(); 318 return sensor; 319 } 320 sensorlist = sensorlist->next; 321 } 322 323 // Create and initialize the sensor 324 sensor = (SDL_Sensor *)SDL_calloc(1, sizeof(*sensor)); 325 if (!sensor) { 326 SDL_UnlockSensors(); 327 return NULL; 328 } 329 SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, true); 330 sensor->driver = driver; 331 sensor->instance_id = instance_id; 332 sensor->type = driver->GetDeviceType(device_index); 333 sensor->non_portable_type = driver->GetDeviceNonPortableType(device_index); 334 335 if (!driver->Open(sensor, device_index)) { 336 SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false); 337 SDL_free(sensor); 338 SDL_UnlockSensors(); 339 return NULL; 340 } 341 342 sensorname = driver->GetDeviceName(device_index); 343 if (sensorname) { 344 sensor->name = SDL_strdup(sensorname); 345 } else { 346 sensor->name = NULL; 347 } 348 349 // Add sensor to list 350 ++sensor->ref_count; 351 // Link the sensor in the list 352 sensor->next = SDL_sensors; 353 SDL_sensors = sensor; 354 355 driver->Update(sensor); 356 357 SDL_UnlockSensors(); 358 359 return sensor; 360} 361 362/* 363 * Find the SDL_Sensor that owns this instance id 364 */ 365SDL_Sensor *SDL_GetSensorFromID(SDL_SensorID instance_id) 366{ 367 SDL_Sensor *sensor; 368 369 SDL_LockSensors(); 370 for (sensor = SDL_sensors; sensor; sensor = sensor->next) { 371 if (sensor->instance_id == instance_id) { 372 break; 373 } 374 } 375 SDL_UnlockSensors(); 376 return sensor; 377} 378 379/* 380 * Get the properties associated with a sensor. 381 */ 382SDL_PropertiesID SDL_GetSensorProperties(SDL_Sensor *sensor) 383{ 384 SDL_PropertiesID result; 385 386 SDL_LockSensors(); 387 { 388 CHECK_SENSOR_MAGIC(sensor, 0); 389 390 if (sensor->props == 0) { 391 sensor->props = SDL_CreateProperties(); 392 } 393 result = sensor->props; 394 } 395 SDL_UnlockSensors(); 396 397 return result; 398} 399 400/* 401 * Get the friendly name of this sensor 402 */ 403const char *SDL_GetSensorName(SDL_Sensor *sensor) 404{ 405 const char *result; 406 407 SDL_LockSensors(); 408 { 409 CHECK_SENSOR_MAGIC(sensor, NULL); 410 411 result = SDL_GetPersistentString(sensor->name); 412 } 413 SDL_UnlockSensors(); 414 415 return result; 416} 417 418/* 419 * Get the type of this sensor 420 */ 421SDL_SensorType SDL_GetSensorType(SDL_Sensor *sensor) 422{ 423 SDL_SensorType result; 424 425 SDL_LockSensors(); 426 { 427 CHECK_SENSOR_MAGIC(sensor, SDL_SENSOR_INVALID); 428 429 result = sensor->type; 430 } 431 SDL_UnlockSensors(); 432 433 return result; 434} 435 436/* 437 * Get the platform dependent type of this sensor 438 */ 439int SDL_GetSensorNonPortableType(SDL_Sensor *sensor) 440{ 441 int result; 442 443 SDL_LockSensors(); 444 { 445 CHECK_SENSOR_MAGIC(sensor, -1); 446 447 result = sensor->non_portable_type; 448 } 449 SDL_UnlockSensors(); 450 451 return result; 452} 453 454/* 455 * Get the instance id for this opened sensor 456 */ 457SDL_SensorID SDL_GetSensorID(SDL_Sensor *sensor) 458{ 459 SDL_SensorID result; 460 461 SDL_LockSensors(); 462 { 463 CHECK_SENSOR_MAGIC(sensor, 0); 464 465 result = sensor->instance_id; 466 } 467 SDL_UnlockSensors(); 468 469 return result; 470} 471 472/* 473 * Get the current state of this sensor 474 */ 475bool SDL_GetSensorData(SDL_Sensor *sensor, float *data, int num_values) 476{ 477 SDL_LockSensors(); 478 { 479 CHECK_SENSOR_MAGIC(sensor, false); 480 481 num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); 482 SDL_memcpy(data, sensor->data, num_values * sizeof(*data)); 483 } 484 SDL_UnlockSensors(); 485 486 return true; 487} 488 489/* 490 * Close a sensor previously opened with SDL_OpenSensor() 491 */ 492void SDL_CloseSensor(SDL_Sensor *sensor) 493{ 494 SDL_Sensor *sensorlist; 495 SDL_Sensor *sensorlistprev; 496 497 SDL_LockSensors(); 498 { 499 CHECK_SENSOR_MAGIC(sensor,); 500 501 // First decrement ref count 502 if (--sensor->ref_count > 0) { 503 SDL_UnlockSensors(); 504 return; 505 } 506 507 SDL_DestroyProperties(sensor->props); 508 509 sensor->driver->Close(sensor); 510 sensor->hwdata = NULL; 511 SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false); 512 513 sensorlist = SDL_sensors; 514 sensorlistprev = NULL; 515 while (sensorlist) { 516 if (sensor == sensorlist) { 517 if (sensorlistprev) { 518 // unlink this entry 519 sensorlistprev->next = sensorlist->next; 520 } else { 521 SDL_sensors = sensor->next; 522 } 523 break; 524 } 525 sensorlistprev = sensorlist; 526 sensorlist = sensorlist->next; 527 } 528 529 // Free the data associated with this sensor 530 SDL_free(sensor->name); 531 SDL_free(sensor); 532 } 533 SDL_UnlockSensors(); 534} 535 536void SDL_QuitSensors(void) 537{ 538 int i; 539 540 SDL_LockSensors(); 541 542 // Stop the event polling 543 while (SDL_sensors) { 544 SDL_sensors->ref_count = 1; 545 SDL_CloseSensor(SDL_sensors); 546 } 547 548 // Quit the sensor setup 549 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { 550 SDL_sensor_drivers[i]->Quit(); 551 } 552 553 SDL_QuitSubSystem(SDL_INIT_EVENTS); 554 555 SDL_sensors_initialized = false; 556 557 SDL_UnlockSensors(); 558} 559 560// These are global for SDL_syssensor.c and SDL_events.c 561 562void SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values) 563{ 564 SDL_AssertSensorsLocked(); 565 566 // Allow duplicate events, for things like steps and heartbeats 567 568 // Update internal sensor state 569 num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); 570 SDL_memcpy(sensor->data, data, num_values * sizeof(*data)); 571 572 // Post the event, if desired 573 if (SDL_EventEnabled(SDL_EVENT_SENSOR_UPDATE)) { 574 SDL_Event event; 575 event.type = SDL_EVENT_SENSOR_UPDATE; 576 event.common.timestamp = timestamp; 577 event.sensor.which = sensor->instance_id; 578 num_values = SDL_min(num_values, SDL_arraysize(event.sensor.data)); 579 SDL_memset(event.sensor.data, 0, sizeof(event.sensor.data)); 580 SDL_memcpy(event.sensor.data, data, num_values * sizeof(*data)); 581 event.sensor.sensor_timestamp = sensor_timestamp; 582 SDL_PushEvent(&event); 583 } 584 585 SDL_GamepadSensorWatcher(timestamp, sensor->instance_id, sensor_timestamp, data, num_values); 586} 587 588void SDL_UpdateSensor(SDL_Sensor *sensor) 589{ 590 SDL_LockSensors(); 591 { 592 CHECK_SENSOR_MAGIC(sensor,); 593 594 sensor->driver->Update(sensor); 595 } 596 SDL_UnlockSensors(); 597} 598 599void SDL_UpdateSensors(void) 600{ 601 int i; 602 SDL_Sensor *sensor; 603 604 if (!SDL_WasInit(SDL_INIT_SENSOR)) { 605 return; 606 } 607 608 SDL_LockSensors(); 609 610 for (sensor = SDL_sensors; sensor; sensor = sensor->next) { 611 sensor->driver->Update(sensor); 612 } 613 614 /* this needs to happen AFTER walking the sensor list above, so that any 615 dangling hardware data from removed devices can be free'd 616 */ 617 for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) { 618 SDL_sensor_drivers[i]->Detect(); 619 } 620 621 SDL_UnlockSensors(); 622}