src/sensor/SDL_sensor.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 21 Oct 2018 22:40:17 -0400
changeset 12345 50e1cca28b39
parent 12242 df7260f149f2
child 12422 9091b20040cf
permissions -rw-r--r--
wasapi/win32: Sort initial device lists by device GUID.

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