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