Path: blob/master/thirdparty/sdl/sensor/SDL_sensor.c
10279 views
/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/20#include "SDL_internal.h"2122// This is the sensor API for Simple DirectMedia Layer2324#include "SDL_syssensor.h"2526#include "../events/SDL_events_c.h"27#include "../joystick/SDL_gamepad_c.h"2829static SDL_SensorDriver *SDL_sensor_drivers[] = {30#ifdef SDL_SENSOR_ANDROID31&SDL_ANDROID_SensorDriver,32#endif33#ifdef SDL_SENSOR_COREMOTION34&SDL_COREMOTION_SensorDriver,35#endif36#ifdef SDL_SENSOR_WINDOWS37&SDL_WINDOWS_SensorDriver,38#endif39#ifdef SDL_SENSOR_VITA40&SDL_VITA_SensorDriver,41#endif42#ifdef SDL_SENSOR_N3DS43&SDL_N3DS_SensorDriver,44#endif45#if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED)46&SDL_DUMMY_SensorDriver47#endif48};4950#ifndef SDL_THREAD_SAFETY_ANALYSIS51static52#endif53SDL_Mutex *SDL_sensor_lock = NULL; // This needs to support recursive locks54static SDL_AtomicInt SDL_sensor_lock_pending;55static int SDL_sensors_locked;56static bool SDL_sensors_initialized;57static SDL_Sensor *SDL_sensors SDL_GUARDED_BY(SDL_sensor_lock) = NULL;5859#define CHECK_SENSOR_MAGIC(sensor, result) \60if (!SDL_ObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR)) { \61SDL_InvalidParamError("sensor"); \62SDL_UnlockSensors(); \63return result; \64}6566bool SDL_SensorsInitialized(void)67{68return SDL_sensors_initialized;69}7071void SDL_LockSensors(void)72{73(void)SDL_AtomicIncRef(&SDL_sensor_lock_pending);74SDL_LockMutex(SDL_sensor_lock);75(void)SDL_AtomicDecRef(&SDL_sensor_lock_pending);7677++SDL_sensors_locked;78}7980void SDL_UnlockSensors(void)81{82bool last_unlock = false;8384--SDL_sensors_locked;8586if (!SDL_sensors_initialized) {87// NOTE: There's a small window here where another thread could lock the mutex after we've checked for pending locks88if (!SDL_sensors_locked && SDL_GetAtomicInt(&SDL_sensor_lock_pending) == 0) {89last_unlock = true;90}91}9293/* The last unlock after sensors are uninitialized will cleanup the mutex,94* allowing applications to lock sensors while reinitializing the system.95*/96if (last_unlock) {97SDL_Mutex *sensor_lock = SDL_sensor_lock;9899SDL_LockMutex(sensor_lock);100{101SDL_UnlockMutex(SDL_sensor_lock);102103SDL_sensor_lock = NULL;104}105SDL_UnlockMutex(sensor_lock);106SDL_DestroyMutex(sensor_lock);107} else {108SDL_UnlockMutex(SDL_sensor_lock);109}110}111112bool SDL_SensorsLocked(void)113{114return (SDL_sensors_locked > 0);115}116117void SDL_AssertSensorsLocked(void)118{119SDL_assert(SDL_SensorsLocked());120}121122bool SDL_InitSensors(void)123{124int i;125bool status;126127// Create the sensor list lock128if (SDL_sensor_lock == NULL) {129SDL_sensor_lock = SDL_CreateMutex();130}131132if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) {133return false;134}135136SDL_LockSensors();137138SDL_sensors_initialized = true;139140status = false;141for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {142if (SDL_sensor_drivers[i]->Init()) {143status = true;144}145}146147SDL_UnlockSensors();148149if (!status) {150SDL_QuitSensors();151}152153return status;154}155156bool SDL_SensorsOpened(void)157{158bool opened;159160SDL_LockSensors();161{162if (SDL_sensors != NULL) {163opened = true;164} else {165opened = false;166}167}168SDL_UnlockSensors();169170return opened;171}172173SDL_SensorID *SDL_GetSensors(int *count)174{175int i, num_sensors, device_index;176int sensor_index = 0, total_sensors = 0;177SDL_SensorID *sensors;178179SDL_LockSensors();180{181for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {182total_sensors += SDL_sensor_drivers[i]->GetCount();183}184185sensors = (SDL_SensorID *)SDL_malloc((total_sensors + 1) * sizeof(*sensors));186if (sensors) {187if (count) {188*count = total_sensors;189}190191for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {192num_sensors = SDL_sensor_drivers[i]->GetCount();193for (device_index = 0; device_index < num_sensors; ++device_index) {194SDL_assert(sensor_index < total_sensors);195sensors[sensor_index] = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index);196SDL_assert(sensors[sensor_index] > 0);197++sensor_index;198}199}200SDL_assert(sensor_index == total_sensors);201sensors[sensor_index] = 0;202} else {203if (count) {204*count = 0;205}206}207}208SDL_UnlockSensors();209210return sensors;211}212213/*214* Get the driver and device index for a sensor instance ID215* This should be called while the sensor lock is held, to prevent another thread from updating the list216*/217static bool SDL_GetDriverAndSensorIndex(SDL_SensorID instance_id, SDL_SensorDriver **driver, int *driver_index)218{219int i, num_sensors, device_index;220221if (instance_id > 0) {222for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {223num_sensors = SDL_sensor_drivers[i]->GetCount();224for (device_index = 0; device_index < num_sensors; ++device_index) {225SDL_SensorID sensor_id = SDL_sensor_drivers[i]->GetDeviceInstanceID(device_index);226if (sensor_id == instance_id) {227*driver = SDL_sensor_drivers[i];228*driver_index = device_index;229return true;230}231}232}233}234SDL_SetError("Sensor %" SDL_PRIu32 " not found", instance_id);235return false;236}237238/*239* Get the implementation dependent name of a sensor240*/241const char *SDL_GetSensorNameForID(SDL_SensorID instance_id)242{243SDL_SensorDriver *driver;244int device_index;245const char *name = NULL;246247SDL_LockSensors();248if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {249name = SDL_GetPersistentString(driver->GetDeviceName(device_index));250}251SDL_UnlockSensors();252253return name;254}255256SDL_SensorType SDL_GetSensorTypeForID(SDL_SensorID instance_id)257{258SDL_SensorDriver *driver;259int device_index;260SDL_SensorType type = SDL_SENSOR_INVALID;261262SDL_LockSensors();263if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {264type = driver->GetDeviceType(device_index);265}266SDL_UnlockSensors();267268return type;269}270271int SDL_GetSensorNonPortableTypeForID(SDL_SensorID instance_id)272{273SDL_SensorDriver *driver;274int device_index;275int type = -1;276277SDL_LockSensors();278if (SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {279type = driver->GetDeviceNonPortableType(device_index);280}281SDL_UnlockSensors();282283return type;284}285286/*287* Open a sensor for use - the index passed as an argument refers to288* the N'th sensor on the system. This index is the value which will289* identify this sensor in future sensor events.290*291* This function returns a sensor identifier, or NULL if an error occurred.292*/293SDL_Sensor *SDL_OpenSensor(SDL_SensorID instance_id)294{295SDL_SensorDriver *driver;296int device_index;297SDL_Sensor *sensor;298SDL_Sensor *sensorlist;299const char *sensorname = NULL;300301SDL_LockSensors();302303if (!SDL_GetDriverAndSensorIndex(instance_id, &driver, &device_index)) {304SDL_UnlockSensors();305return NULL;306}307308sensorlist = SDL_sensors;309/* If the sensor is already open, return it310* it is important that we have a single sensor * for each instance id311*/312while (sensorlist) {313if (instance_id == sensorlist->instance_id) {314sensor = sensorlist;315++sensor->ref_count;316SDL_UnlockSensors();317return sensor;318}319sensorlist = sensorlist->next;320}321322// Create and initialize the sensor323sensor = (SDL_Sensor *)SDL_calloc(1, sizeof(*sensor));324if (!sensor) {325SDL_UnlockSensors();326return NULL;327}328SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, true);329sensor->driver = driver;330sensor->instance_id = instance_id;331sensor->type = driver->GetDeviceType(device_index);332sensor->non_portable_type = driver->GetDeviceNonPortableType(device_index);333334if (!driver->Open(sensor, device_index)) {335SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false);336SDL_free(sensor);337SDL_UnlockSensors();338return NULL;339}340341sensorname = driver->GetDeviceName(device_index);342if (sensorname) {343sensor->name = SDL_strdup(sensorname);344} else {345sensor->name = NULL;346}347348// Add sensor to list349++sensor->ref_count;350// Link the sensor in the list351sensor->next = SDL_sensors;352SDL_sensors = sensor;353354driver->Update(sensor);355356SDL_UnlockSensors();357358return sensor;359}360361/*362* Find the SDL_Sensor that owns this instance id363*/364SDL_Sensor *SDL_GetSensorFromID(SDL_SensorID instance_id)365{366SDL_Sensor *sensor;367368SDL_LockSensors();369for (sensor = SDL_sensors; sensor; sensor = sensor->next) {370if (sensor->instance_id == instance_id) {371break;372}373}374SDL_UnlockSensors();375return sensor;376}377378/*379* Get the properties associated with a sensor.380*/381SDL_PropertiesID SDL_GetSensorProperties(SDL_Sensor *sensor)382{383SDL_PropertiesID result;384385SDL_LockSensors();386{387CHECK_SENSOR_MAGIC(sensor, 0);388389if (sensor->props == 0) {390sensor->props = SDL_CreateProperties();391}392result = sensor->props;393}394SDL_UnlockSensors();395396return result;397}398399/*400* Get the friendly name of this sensor401*/402const char *SDL_GetSensorName(SDL_Sensor *sensor)403{404const char *result;405406SDL_LockSensors();407{408CHECK_SENSOR_MAGIC(sensor, NULL);409410result = SDL_GetPersistentString(sensor->name);411}412SDL_UnlockSensors();413414return result;415}416417/*418* Get the type of this sensor419*/420SDL_SensorType SDL_GetSensorType(SDL_Sensor *sensor)421{422SDL_SensorType result;423424SDL_LockSensors();425{426CHECK_SENSOR_MAGIC(sensor, SDL_SENSOR_INVALID);427428result = sensor->type;429}430SDL_UnlockSensors();431432return result;433}434435/*436* Get the platform dependent type of this sensor437*/438int SDL_GetSensorNonPortableType(SDL_Sensor *sensor)439{440int result;441442SDL_LockSensors();443{444CHECK_SENSOR_MAGIC(sensor, -1);445446result = sensor->non_portable_type;447}448SDL_UnlockSensors();449450return result;451}452453/*454* Get the instance id for this opened sensor455*/456SDL_SensorID SDL_GetSensorID(SDL_Sensor *sensor)457{458SDL_SensorID result;459460SDL_LockSensors();461{462CHECK_SENSOR_MAGIC(sensor, 0);463464result = sensor->instance_id;465}466SDL_UnlockSensors();467468return result;469}470471/*472* Get the current state of this sensor473*/474bool SDL_GetSensorData(SDL_Sensor *sensor, float *data, int num_values)475{476SDL_LockSensors();477{478CHECK_SENSOR_MAGIC(sensor, false);479480num_values = SDL_min(num_values, SDL_arraysize(sensor->data));481SDL_memcpy(data, sensor->data, num_values * sizeof(*data));482}483SDL_UnlockSensors();484485return true;486}487488/*489* Close a sensor previously opened with SDL_OpenSensor()490*/491void SDL_CloseSensor(SDL_Sensor *sensor)492{493SDL_Sensor *sensorlist;494SDL_Sensor *sensorlistprev;495496SDL_LockSensors();497{498CHECK_SENSOR_MAGIC(sensor,);499500// First decrement ref count501if (--sensor->ref_count > 0) {502SDL_UnlockSensors();503return;504}505506SDL_DestroyProperties(sensor->props);507508sensor->driver->Close(sensor);509sensor->hwdata = NULL;510SDL_SetObjectValid(sensor, SDL_OBJECT_TYPE_SENSOR, false);511512sensorlist = SDL_sensors;513sensorlistprev = NULL;514while (sensorlist) {515if (sensor == sensorlist) {516if (sensorlistprev) {517// unlink this entry518sensorlistprev->next = sensorlist->next;519} else {520SDL_sensors = sensor->next;521}522break;523}524sensorlistprev = sensorlist;525sensorlist = sensorlist->next;526}527528// Free the data associated with this sensor529SDL_free(sensor->name);530SDL_free(sensor);531}532SDL_UnlockSensors();533}534535void SDL_QuitSensors(void)536{537int i;538539SDL_LockSensors();540541// Stop the event polling542while (SDL_sensors) {543SDL_sensors->ref_count = 1;544SDL_CloseSensor(SDL_sensors);545}546547// Quit the sensor setup548for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {549SDL_sensor_drivers[i]->Quit();550}551552SDL_QuitSubSystem(SDL_INIT_EVENTS);553554SDL_sensors_initialized = false;555556SDL_UnlockSensors();557}558559// These are global for SDL_syssensor.c and SDL_events.c560561void SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values)562{563SDL_AssertSensorsLocked();564565// Allow duplicate events, for things like steps and heartbeats566567// Update internal sensor state568num_values = SDL_min(num_values, SDL_arraysize(sensor->data));569SDL_memcpy(sensor->data, data, num_values * sizeof(*data));570571// Post the event, if desired572if (SDL_EventEnabled(SDL_EVENT_SENSOR_UPDATE)) {573SDL_Event event;574event.type = SDL_EVENT_SENSOR_UPDATE;575event.common.timestamp = timestamp;576event.sensor.which = sensor->instance_id;577num_values = SDL_min(num_values, SDL_arraysize(event.sensor.data));578SDL_memset(event.sensor.data, 0, sizeof(event.sensor.data));579SDL_memcpy(event.sensor.data, data, num_values * sizeof(*data));580event.sensor.sensor_timestamp = sensor_timestamp;581SDL_PushEvent(&event);582}583584SDL_GamepadSensorWatcher(timestamp, sensor->instance_id, sensor_timestamp, data, num_values);585}586587void SDL_UpdateSensor(SDL_Sensor *sensor)588{589SDL_LockSensors();590{591CHECK_SENSOR_MAGIC(sensor,);592593sensor->driver->Update(sensor);594}595SDL_UnlockSensors();596}597598void SDL_UpdateSensors(void)599{600int i;601SDL_Sensor *sensor;602603if (!SDL_WasInit(SDL_INIT_SENSOR)) {604return;605}606607SDL_LockSensors();608609for (sensor = SDL_sensors; sensor; sensor = sensor->next) {610sensor->driver->Update(sensor);611}612613/* this needs to happen AFTER walking the sensor list above, so that any614dangling hardware data from removed devices can be free'd615*/616for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {617SDL_sensor_drivers[i]->Detect();618}619620SDL_UnlockSensors();621}622623624