#include "../SDL_internal.h"
#include "SDL.h"
#include "SDL_atomic.h"
#include "SDL_events.h"
#include "SDL_syssensor.h"
#if !SDL_EVENTS_DISABLED
#include "../events/SDL_events_c.h"
#endif
static SDL_SensorDriver *SDL_sensor_drivers[] = {
#ifdef SDL_SENSOR_ANDROID
&SDL_ANDROID_SensorDriver,
#endif
#ifdef SDL_SENSOR_COREMOTION
&SDL_COREMOTION_SensorDriver,
#endif
#ifdef SDL_SENSOR_WINDOWS
&SDL_WINDOWS_SensorDriver,
#endif
#ifdef SDL_SENSOR_VITA
&SDL_VITA_SensorDriver,
#endif
#ifdef SDL_SENSOR_N3DS
&SDL_N3DS_SensorDriver,
#endif
#if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED)
&SDL_DUMMY_SensorDriver
#endif
};
static SDL_Sensor *SDL_sensors = NULL;
static SDL_bool SDL_updating_sensor = SDL_FALSE;
static SDL_mutex *SDL_sensor_lock = NULL;
static SDL_atomic_t SDL_next_sensor_instance_id;
void
SDL_LockSensors(void)
{
if (SDL_sensor_lock) {
SDL_LockMutex(SDL_sensor_lock);
}
}
void
SDL_UnlockSensors(void)
{
if (SDL_sensor_lock) {
SDL_UnlockMutex(SDL_sensor_lock);
}
}
int
SDL_SensorInit(void)
{
int i, status;
if (!SDL_sensor_lock) {
SDL_sensor_lock = SDL_CreateMutex();
}
#if !SDL_EVENTS_DISABLED
if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
return -1;
}
#endif
status = -1;
for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
if (SDL_sensor_drivers[i]->Init() >= 0) {
status = 0;
}
}
return status;
}
int
SDL_NumSensors(void)
{
int i, total_sensors = 0;
SDL_LockSensors();
for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
total_sensors += SDL_sensor_drivers[i]->GetCount();
}
SDL_UnlockSensors();
return total_sensors;
}
SDL_SensorID SDL_GetNextSensorInstanceID()
{
return SDL_AtomicIncRef(&SDL_next_sensor_instance_id);
}
static SDL_bool
SDL_GetDriverAndSensorIndex(int device_index, SDL_SensorDriver **driver, int *driver_index)
{
int i, num_sensors, total_sensors = 0;
if (device_index >= 0) {
for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
num_sensors = SDL_sensor_drivers[i]->GetCount();
if (device_index < num_sensors) {
*driver = SDL_sensor_drivers[i];
*driver_index = device_index;
return SDL_TRUE;
}
device_index -= num_sensors;
total_sensors += num_sensors;
}
}
SDL_SetError("There are %d sensors available", total_sensors);
return SDL_FALSE;
}
const char *
SDL_SensorGetDeviceName(int device_index)
{
SDL_SensorDriver *driver;
const char *name = NULL;
SDL_LockSensors();
if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) {
name = driver->GetDeviceName(device_index);
}
SDL_UnlockSensors();
return name;
}
SDL_SensorType
SDL_SensorGetDeviceType(int device_index)
{
SDL_SensorDriver *driver;
SDL_SensorType type = SDL_SENSOR_INVALID;
SDL_LockSensors();
if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) {
type = driver->GetDeviceType(device_index);
}
SDL_UnlockSensors();
return type;
}
int
SDL_SensorGetDeviceNonPortableType(int device_index)
{
SDL_SensorDriver *driver;
int type = -1;
SDL_LockSensors();
if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) {
type = driver->GetDeviceNonPortableType(device_index);
}
SDL_UnlockSensors();
return type;
}
SDL_SensorID
SDL_SensorGetDeviceInstanceID(int device_index)
{
SDL_SensorDriver *driver;
SDL_SensorID instance_id = -1;
SDL_LockSensors();
if (SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) {
instance_id = driver->GetDeviceInstanceID(device_index);
}
SDL_UnlockSensors();
return instance_id;
}
SDL_Sensor *
SDL_SensorOpen(int device_index)
{
SDL_SensorDriver *driver;
SDL_SensorID instance_id;
SDL_Sensor *sensor;
SDL_Sensor *sensorlist;
const char *sensorname = NULL;
SDL_LockSensors();
if (!SDL_GetDriverAndSensorIndex(device_index, &driver, &device_index)) {
SDL_UnlockSensors();
return NULL;
}
sensorlist = SDL_sensors;
instance_id = driver->GetDeviceInstanceID(device_index);
while (sensorlist) {
if (instance_id == sensorlist->instance_id) {
sensor = sensorlist;
++sensor->ref_count;
SDL_UnlockSensors();
return sensor;
}
sensorlist = sensorlist->next;
}
sensor = (SDL_Sensor *) SDL_calloc(sizeof(*sensor), 1);
if (sensor == NULL) {
SDL_OutOfMemory();
SDL_UnlockSensors();
return NULL;
}
sensor->driver = driver;
sensor->instance_id = instance_id;
sensor->type = driver->GetDeviceType(device_index);
sensor->non_portable_type = driver->GetDeviceNonPortableType(device_index);
if (driver->Open(sensor, device_index) < 0) {
SDL_free(sensor);
SDL_UnlockSensors();
return NULL;
}
sensorname = driver->GetDeviceName(device_index);
if (sensorname) {
sensor->name = SDL_strdup(sensorname);
} else {
sensor->name = NULL;
}
++sensor->ref_count;
sensor->next = SDL_sensors;
SDL_sensors = sensor;
SDL_UnlockSensors();
driver->Update(sensor);
return sensor;
}
SDL_Sensor *
SDL_SensorFromInstanceID(SDL_SensorID instance_id)
{
SDL_Sensor *sensor;
SDL_LockSensors();
for (sensor = SDL_sensors; sensor; sensor = sensor->next) {
if (sensor->instance_id == instance_id) {
break;
}
}
SDL_UnlockSensors();
return sensor;
}
static int
SDL_PrivateSensorValid(SDL_Sensor *sensor)
{
int valid;
if (sensor == NULL) {
SDL_SetError("Sensor hasn't been opened yet");
valid = 0;
} else {
valid = 1;
}
return valid;
}
const char *
SDL_SensorGetName(SDL_Sensor *sensor)
{
if (!SDL_PrivateSensorValid(sensor)) {
return NULL;
}
return sensor->name;
}
SDL_SensorType
SDL_SensorGetType(SDL_Sensor *sensor)
{
if (!SDL_PrivateSensorValid(sensor)) {
return SDL_SENSOR_INVALID;
}
return sensor->type;
}
int
SDL_SensorGetNonPortableType(SDL_Sensor *sensor)
{
if (!SDL_PrivateSensorValid(sensor)) {
return -1;
}
return sensor->non_portable_type;
}
SDL_SensorID
SDL_SensorGetInstanceID(SDL_Sensor *sensor)
{
if (!SDL_PrivateSensorValid(sensor)) {
return -1;
}
return sensor->instance_id;
}
int
SDL_SensorGetData(SDL_Sensor *sensor, float *data, int num_values)
{
return SDL_SensorGetDataWithTimestamp(sensor, NULL, data, num_values);
}
int
SDL_SensorGetDataWithTimestamp(SDL_Sensor *sensor, Uint64 *timestamp, float *data, int num_values)
{
if (!SDL_PrivateSensorValid(sensor)) {
return -1;
}
num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
SDL_memcpy(data, sensor->data, num_values*sizeof(*data));
if (timestamp) {
*timestamp = sensor->timestamp_us;
}
return 0;
}
void
SDL_SensorClose(SDL_Sensor *sensor)
{
SDL_Sensor *sensorlist;
SDL_Sensor *sensorlistprev;
if (!SDL_PrivateSensorValid(sensor)) {
return;
}
SDL_LockSensors();
if (--sensor->ref_count > 0) {
SDL_UnlockSensors();
return;
}
if (SDL_updating_sensor) {
SDL_UnlockSensors();
return;
}
sensor->driver->Close(sensor);
sensor->hwdata = NULL;
sensorlist = SDL_sensors;
sensorlistprev = NULL;
while (sensorlist) {
if (sensor == sensorlist) {
if (sensorlistprev) {
sensorlistprev->next = sensorlist->next;
} else {
SDL_sensors = sensor->next;
}
break;
}
sensorlistprev = sensorlist;
sensorlist = sensorlist->next;
}
SDL_free(sensor->name);
SDL_free(sensor);
SDL_UnlockSensors();
}
void
SDL_SensorQuit(void)
{
int i;
SDL_assert(!SDL_updating_sensor);
SDL_LockSensors();
while (SDL_sensors) {
SDL_sensors->ref_count = 1;
SDL_SensorClose(SDL_sensors);
}
for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
SDL_sensor_drivers[i]->Quit();
}
SDL_UnlockSensors();
#if !SDL_EVENTS_DISABLED
SDL_QuitSubSystem(SDL_INIT_EVENTS);
#endif
if (SDL_sensor_lock) {
SDL_DestroyMutex(SDL_sensor_lock);
SDL_sensor_lock = NULL;
}
}
int
SDL_PrivateSensorUpdate(SDL_Sensor *sensor, Uint64 timestamp_us, float *data, int num_values)
{
int posted;
num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
SDL_memcpy(sensor->data, data, num_values*sizeof(*data));
sensor->timestamp_us = timestamp_us;
posted = 0;
#if !SDL_EVENTS_DISABLED
if (SDL_GetEventState(SDL_SENSORUPDATE) == SDL_ENABLE) {
SDL_Event event;
event.type = SDL_SENSORUPDATE;
event.sensor.which = sensor->instance_id;
num_values = SDL_min(num_values, SDL_arraysize(event.sensor.data));
SDL_memset(event.sensor.data, 0, sizeof(event.sensor.data));
SDL_memcpy(event.sensor.data, data, num_values*sizeof(*data));
event.sensor.timestamp_us = timestamp_us;
posted = SDL_PushEvent(&event) == 1;
}
#endif
return posted;
}
void
SDL_SensorUpdate(void)
{
int i;
SDL_Sensor *sensor, *next;
if (!SDL_WasInit(SDL_INIT_SENSOR)) {
return;
}
SDL_LockSensors();
if (SDL_updating_sensor) {
SDL_UnlockSensors();
return;
}
SDL_updating_sensor = SDL_TRUE;
SDL_UnlockSensors();
for (sensor = SDL_sensors; sensor; sensor = sensor->next) {
sensor->driver->Update(sensor);
}
SDL_LockSensors();
SDL_updating_sensor = SDL_FALSE;
for (sensor = SDL_sensors; sensor; sensor = next) {
next = sensor->next;
if (sensor->ref_count <= 0) {
SDL_SensorClose(sensor);
}
}
for (i = 0; i < SDL_arraysize(SDL_sensor_drivers); ++i) {
SDL_sensor_drivers[i]->Detect();
}
SDL_UnlockSensors();
}