*
* All sensor types known by Eeze Sensor. This list of types include real
* physical types like proximity or light as well as "aggregated" types like
- * facedown or doubletap.
+ * facedown or doubletap. All types with MOTION in their name can be used as
+ * real events coming from the underlying system. This is not supported on all
+ * systems.
*
* @since 1.8
*/
*
* Event types used to register ecore_event_handler on. These events are used
* for #eeze_sensor_async_read to deliver read out data. It is also used for
- * generated events like facedown or shake.
+ * generated events like facedown or shake. Subscribing to these events in your
+ * application allowsyou to react on these changes in an efficient way without
+ * polling for new updates and wasting power and computing cycles.
*
* @since 1.8
* @{
* to do. Create the object from the type and everything else the operates on
* this object.
*
+ * This also takes into account what runtime modules are loaded and handles
+ * them in a given priority to pick up the best sensor source for your sensor
+ * object.
+ *
* @since 1.8
*/
EAPI Eeze_Sensor_Obj *eeze_sensor_new(Eeze_Sensor_Type type);
* @brief Free a sensor object.
* @param sens Sensor object to operate on.
*
- * Free an sensor object when it is no longer needed.
+ * Free an sensor object when it is no longer needed. Always use this function
+ * to cleanup unused sensor objects.
*
* @since 1.8
*/
* This function reads sensor data from the device and fills the sensor object
* with the data. This call is synchronous and blocks until the data is read out
* and updated in the sensor object. For simple applications this is fine and
- * the easiest way to use the API.
+ * the easiest way to use the API. A more efficient way is to use
+ * #eeze_sensor_async_read which allows the sensor readout to happen in the
+ * background and the application would check the timestamp of the data to
+ * determine how recent the data is.
*
* @since 1.8
*/
*
* This function reads sensor data from the device and fills the sensor object
* with the data. The read is done asynchronously and thus does not block after
- * calling. Instead the given callback function is called once the read is
- * finished and the object filled.
+ * calling. Instead the given the application can determine how recent the
+ * values are from the timestamp value that can be accessed through
+ * #eeze_sensor_timestamp_get.
+ *
+ * This function is more efficient but needs a bit more work in the application.
+ * An easier way is to use the synchronous #eeze_sensor_read functions. The
+ * downside of it is that it blocks until the data was read out from the
+ * physical sensor. That might be a long time depending on the hardware and its
+ * interface.
*
* @since 1.8
*/
Eeze_Sensor *g_handle;
-/* Priority order for modules. The one with the highest order of the available ones will be used.
- * This in good enough for now as we only have two modules and one is a test harness anyway. If the
- * number of modules grows we might re-think the priority handling, but we should do this when the
- * need arise.
+/* Priority order for modules. The one with the highest order of the available
+ * ones will be used. This in good enough for now as we only have two modules
+ * and one is a test harness anyway. If the number of modules grows we might
+ * re-think the priority handling, but we should do this when the need arise.
*/
static const char *_module_priority[] = {
"tizen",
NULL
};
+/* Search through the list of loaded module and return the one with the highest
+ * priority.
+ */
Eeze_Sensor_Module *
_highest_priority_module_get(void)
{
return NULL;
}
+/* Utility function to take the given sensor type and get the matching sensor
+ * object from the highest priority module.
+ */
EAPI Eeze_Sensor_Obj *
eeze_sensor_obj_get(Eeze_Sensor_Type sensor_type)
{
/* Check for available runtime modules and load them. In some cases the
* un-installed modules to be used from the local build dir. Coverage check
* is one of these items. We do load the modules from the builddir if the
- * environment is set. Normal case is to use installed modules from system */
+ * environment is set. Normal case is to use installed modules from system
+ */
if (getenv("EEZE_USE_IN_TREE_MODULES"))
g_handle->modules_array = eina_module_list_get(NULL, PACKAGE_BUILD_DIR "/src/modules/.libs/", 0, NULL, NULL);
else
ERR("No modules found!");
return;
}
-
eina_module_list_load(g_handle->modules_array);
}
g_handle->modules_array = NULL;
}
+/* This function is offered to the modules to register itself after they have
+ * been loaded in initialized. They stay in the hash funtion until they
+ * unregister themself.
+ */
Eina_Bool
eeze_sensor_module_register(const char *name, Eeze_Sensor_Module *mod)
{
return eina_hash_add(g_handle->modules, name, module);
}
+/* This function is offered to the modules to unregsiter itself. When requested
+ * we remove them safely from the hash.
+ */
Eina_Bool
eeze_sensor_module_unregister(const char *name)
{
return eina_hash_del(g_handle->modules, name, NULL);
}
+/* Create a new sensor object for a given sensor type. This functions allocates
+ * the needed memory and links it with the matching sensor from the loaded
+ * modules. It also does an initial synchronous read to fill the sensor object
+ * with values.
+ * Make sure to use the eeze_sensor_free function to remove this sensor object
+ * when it is no longer needed.
+ */
EAPI Eeze_Sensor_Obj *
eeze_sensor_new(Eeze_Sensor_Type type)
{
if (!module->read) return NULL;
+ /* The read is asynchronous here as we want to make sure that the sensor
+ * object has valid data when created. As we give back cached values we
+ * have a race condition when we do a asynchronous read here and the
+ * application asks for cached data before the reply came in. This logic has
+ * the downside that the sensor creation takes longer. But that is only a
+ *initial cost.
+ */
if (module->read(sens->type, sens))
- {
- return sens;
- }
- else
- return NULL;
+ return sens;
+
+ return NULL;
}
+/* Free sensor object created with eeze_sensor_new */
EAPI void
eeze_sensor_free(Eeze_Sensor_Obj *sens)
{
free(sens);
}
+/* All of the below getter function do access the cached data from the last
+ * sensor read. It is way faster this way but also means that the timestamp
+ * should be checked to ensure recent data if needed.
+ */
EAPI Eina_Bool
eeze_sensor_accuracy_get(Eeze_Sensor_Obj *sens, int *accuracy)
{
return EINA_TRUE;
}
+/* Synchronous read. Blocked until the data was readout from the hardware
+ * sensor
+ */
EAPI Eina_Bool
eeze_sensor_read(Eeze_Sensor_Obj *sens)
{
return EINA_FALSE;
}
+/* Asynchronous read. Schedule a new read out that will update the cached values
+ * as soon as it arrives.
+ */
EAPI Eina_Bool
eeze_sensor_async_read(Eeze_Sensor_Obj *sens, void *user_data)
{
g_handle->modules = eina_hash_string_small_new(NULL);
if (!g_handle->modules) return EINA_FALSE;
+ /* Make sure we create new ecore event types before using them */
EEZE_SENSOR_EVENT_SNAP = ecore_event_type_new();
EEZE_SENSOR_EVENT_SHAKE = ecore_event_type_new();
EEZE_SENSOR_EVENT_DOUBLETAP = ecore_event_type_new();
EEZE_SENSOR_EVENT_FACEDOWN = ecore_event_type_new();
EEZE_SENSOR_EVENT_ACCELEROMETER = ecore_event_type_new();
+ /* Core is ready so we can load the modules from disk now */
eeze_sensor_modules_load();
return EINA_TRUE;
}
-
#ifdef CRI
#undef CRI
#endif
-
#ifdef ERR
#undef ERR
#endif
Eina_List *sensor_list; /**< List of sensor objects attached to the module */
} Eeze_Sensor_Module;
+/**
+ * @brief Register a module to eeze_sensor core.
+ * @param name Module name used for reference internally.
+ * @param mod Sensor module to be registered.
+ * @return EINA_TRUE is the module was successfully registered. EINA_FALSE is not.
+ *
+ * Private functions for modules to register itself to eeze sensor core to
+ * advertise their functionality. These registered modules will then be accessed
+ * based on a priority that is currently hardcoded in the code. Once more module
+ * are available we need to re-consider this approach.
+ *
+ * @since 1.8
+ */
Eina_Bool eeze_sensor_module_register(const char *name, Eeze_Sensor_Module *mod);
+
+/**
+ * @brief Unregister a module from eeze_sensor core.
+ * @param name Module name used for reference internally.
+ * @return EINA_TRUE is the module was successfully unregistered. EINA_FALSE is not.
+ *
+ * Private functions for modules to unregister itself from eeze sensor core.
+ *
+ * @since 1.8
+ */
Eina_Bool eeze_sensor_module_unregister(const char *name);
#endif // EEZE_SENSOR_PRIVATE_H
#include <Eeze_Sensor.h>
#include "eeze_sensor_private.h"
-/* This small Eeze_Sensor module is meant to be used as a test harness for developing. It does not
- * gather any real data from hardware sensors. It uses fixed values for the data, but provides the
- * correct timestamp value.
+/* This small Eeze_Sensor module is meant to be used as a test harness for
+ * developing. It does not gather any real data from hardware sensors. It uses
+ * fixed values for the data, but provides the correct timestamp value.
*/
Eeze_Sensor_Module *esensor_module;
Eina_Bool
fake_init(void)
{
- /* Set a list with fake sensors */
+ /* For the fake module we prepare a list with all potential sensors. Even if
+ * we only have a small subset at the moment.
+ */
Eeze_Sensor_Type type;
for (type = 0; type <= EEZE_SENSOR_TYPE_LAST; type++)
return EINA_TRUE;
}
+/* We don't have anything to clear when we get unregistered from the core here.
+ * This is different in other modules.
+ */
Eina_Bool
fake_shutdown(void)
{
case EEZE_SENSOR_TYPE_MAGNETIC:
case EEZE_SENSOR_TYPE_ORIENTATION:
case EEZE_SENSOR_TYPE_GYROSCOPE:
- obj->accuracy = 0;
+ /* This is only a test harness so we supply hardcoded values here */
+ obj->accuracy = -1;
obj->data[0] = 7;
obj->data[1] = 23;
obj->data[2] = 42;
case EEZE_SENSOR_TYPE_PROXIMITY:
case EEZE_SENSOR_TYPE_BAROMETER:
case EEZE_SENSOR_TYPE_TEMPERATURE:
- obj->accuracy = 0;
+ obj->accuracy = -1;
obj->data[0] = 7;
gettimeofday(&tv, NULL);
obj->timestamp = ((tv.tv_sec * 1000000) + tv.tv_usec);
case EEZE_SENSOR_TYPE_MAGNETIC:
case EEZE_SENSOR_TYPE_ORIENTATION:
case EEZE_SENSOR_TYPE_GYROSCOPE:
- obj->accuracy = 0;
+ obj->accuracy = -1;
obj->data[0] = 7;
obj->data[1] = 23;
obj->data[2] = 42;
case EEZE_SENSOR_TYPE_PROXIMITY:
case EEZE_SENSOR_TYPE_BAROMETER:
case EEZE_SENSOR_TYPE_TEMPERATURE:
- obj->accuracy = 0;
+ obj->accuracy = -1;
obj->data[0] = 7;
gettimeofday(&tv, NULL);
obj->timestamp = ((tv.tv_sec * 1000000) + tv.tv_usec);
ERR("Not possible to set a callback for this sensor type.");
return EINA_FALSE;
}
-
return EINA_TRUE;
}
+/* This function gets called when the module is loaded from the disk. Its the
+ * entry point to anything in this module. After settign ourself up we register
+ * into the core of eeze sensor to make our functionality available.
+ */
Eina_Bool
sensor_fake_init(void)
{
esensor_module = calloc(1, sizeof(Eeze_Sensor_Module));
if (!esensor_module) return EINA_FALSE;
+ /* Setup our function pointers to allow the core accessing this modules
+ * functions
+ */
esensor_module->init = fake_init;
esensor_module->shutdown = fake_shutdown;
esensor_module->read = fake_read;
ERR("Failed to register fake module.");
return EINA_FALSE;
}
-
return EINA_TRUE;
}
+/* Cleanup when the module gets unloaded. Unregister ourself from the core to
+ * avoid calls into a not loaded module.
+ */
void
sensor_fake_shutdown(void)
{
#include "eeze_sensor_private.h"
Eeze_Sensor_Module *esensor_module;
-sensor_h sensor_handle; // Tizen sensor handle
+/* Tizen sensor handle */
+sensor_h sensor_handle;
+/* The Tizen sensor type ENUM has shown to not be stable regarding its
+ * numbering scheme so we better translate between the Tizen types and the
+ * ones we use here.
+ */
static sensor_type_e
eeze_to_tizen(Eeze_Sensor_Type type)
{
}
}
+/* All following callback function work with the same scheme.
+ * They are callbacks coming in from the tizen system sensor library. With the
+ * data we receive we update the matching sensor object to always have the
+ * latest data available. That includes updating the timestamp to show when the
+ * data was measured from the underlying system.
+ * After that we send out an ecore event to let all interested parties now that
+ * new data is available and then stop the sensor server to safe power. It will be
+ * started again the next time data gets requested.
+ */
void
accelerometer_cb(unsigned long long timestamp, sensor_data_accuracy_e accuracy, float x, float y, float z, void *user_data)
{
ERR("No matching sensor object found in list.");
return;
}
- obj->accuracy = 0;
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->data[0] = lux;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_LIGHT, obj, NULL, NULL);
ERR("No matching sensor object found in list.");
return;
}
- obj->accuracy = 0;
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->data[0] = distance;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_PROXIMITY, obj, NULL, NULL);
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->data[0] = snap;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_SNAP, obj, NULL, NULL);
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->data[0] = shake;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_SHAKE, obj, NULL, NULL);
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->data[0] = x;
obj->data[1] = y;
obj->timestamp = timestamp;
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_FACEDOWN, obj, NULL, NULL);
+ /* We are not stopping the sensor here because we want to keep it as a motion
+ * event coming in at any time.
+ */
}
void
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_DOUBLETAP, obj, NULL, NULL);
+ /* We are not stopping the sensor here because we want to keep it as a motion
+ * event coming in at any time.
+ */
}
void
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
obj->accuracy = -1;
obj->data[0] = lux;
obj->timestamp = timestamp;
ERR("No matching sensor object found in list.");
return;
}
- obj->accuracy = -1;
+ /* We have to set this ourselves because we don't get it for this type */
+ bj->accuracy = -1;
obj->data[0] = distance;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_PROXIMITY, obj, NULL, NULL);
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
obj->accuracy = -1;
obj->data[0] = snap;
obj->timestamp = timestamp;
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
obj->accuracy = -1;
obj->data[0] = shake;
obj->timestamp = timestamp;
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
obj->accuracy = -1;
obj->data[0] = x;
obj->data[1] = y;
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_FACEDOWN, obj, NULL, NULL);
sensor_stop(sensor_handle, eeze_to_tizen(EEZE_SENSOR_TYPE_MOTION_FACEDOWN));
ERR("No matching sensor object found in list.");
return;
}
+ /* We have to set this ourselves because we don't get it for this type */
+ obj->accuracy = -1;
obj->timestamp = timestamp;
ecore_event_add(EEZE_SENSOR_EVENT_DOUBLETAP, obj, NULL, NULL);
sensor_stop(sensor_handle, eeze_to_tizen(EEZE_SENSOR_TYPE_MOTION_DOUBLETAP));
}
+/* Synchronous read function for sensor data. It uses the blocking calls to read
+ * out the data and returns after it finishes the readout. Be aware that this
+ * might take quite some time depending on the sensor and how it is connected to
+ * the system. Normally it is better to use the asynchronous reading functions.
+ */
Eina_Bool
eeze_sensor_tizen_read(Eeze_Sensor_Type sensor_type, Eeze_Sensor_Obj *lobj)
{
type = eeze_to_tizen(sensor_type);
+ /* Don't attempt to do anything if the sensor is not available on the system
+ * we are running on.
+ */
sensor_is_supported(type, &supported);
if (!supported)
{
case SENSOR_LIGHT:
sensor_light_read_data(sensor_handle, &lux);
+ /* As we do not get any accuracy value from the system we go with -1 */
obj->accuracy = -1;
obj->data[0] = lux;
obj->timestamp = 0;
case SENSOR_PROXIMITY:
sensor_proximity_read_data(sensor_handle, &distance);
+ /* As we do not get any accuracy value from the system we go with -1 */
obj->accuracy = -1;
obj->data[0] = distance;
obj->timestamp = 0;
}
#endif
+/* For the asynchronous reads we only start the sensor her and trigger the
+ * readout. The callbacks above are actually taking care about putting the data
+ * into the matching sensor objects and informing all subscribers with an ecore
+ * event. The public API function does actually return right away with the cached
+ * data. This is handled in the core and not in the different modules though.
+ */
Eina_Bool
eeze_sensor_tizen_async_read(Eeze_Sensor_Type sensor_type, void *user_data)
{
return EINA_TRUE;
}
+/* Go through all potential Tizen sensor and test if they are available on the
+ * system we are running on. If yes, create a matching sensor object and put it
+ * the list of available sensor for the core.
+ */
static void
eeze_sensor_tizen_sensors_find(void)
{
}
}
+/* Cleanup when getting the shutdown callback from core */
Eina_Bool
eeze_sensor_tizen_shutdown(void)
{
ERR("Failing to destroy sensor handle.");
return EINA_FALSE;
}
-
return EINA_TRUE;
}
+/* Callback from core once we registered as a module. Create the Tizen sensor
+ * handle and find all available sensors.
+ */
Eina_Bool
eeze_sensor_tizen_init(void)
{
return EINA_TRUE;
}
+/* This function gets called when the module is loaded from the disk. Its the
+ * entry point to anything in this module. After setting ourself up we register
+ * into the core of eeze sensor to make our functionality available.
+ */
Eina_Bool
sensor_tizen_init(void)
{
ERR("Failed to register tizen module");
return EINA_FALSE;
}
-
return EINA_TRUE;
}
+/* Cleanup when the module gets unloaded. Unregister ourself from the core to
+ * avoid calls into a not loaded module.
+ */
void
sensor_tizen_shutdown(void)
{