From 792636269f94a15b9765e0f1c387289f573eacbd Mon Sep 17 00:00:00 2001 From: Kibak Yoon Date: Fri, 16 Jan 2015 22:37:18 +0900 Subject: [PATCH] capi-sensor: merge tizen 2.3 capi to public the features of tizen 2.3 Sensor API are the followings: * in Tizen 2.2, the API set was seperately for each sensor. so this API set(start, stop, setting interval and so on) was added when each sensor added. in Tizen 2.3, they are consolidated to 1 API set. sensor is managed by handle and enumeration type. ie. sensor_(accelerometer)_start() APIs -> sensor_listener_start(acc_handle) API - if new sensor type is added, simply fix only two lines. * added two APIs for getting sensor handle(s) ie. sensor_get_default_sensor, sensor_get_sensor_list APIs * added new sensors. ie. pressure sensor, ultraviolet sensor and so on. * removed some sensors. ie. motion sensor(managing it is moved to context-service) * cleaned up the code. see the doxygen for more information on those APIs: https://developer.tizen.org/dev-guide/2.3.0/org.tizen.mobile.native.apireference/group__CAPI__SYSTEM__SENSOR__MODULE.html Signed-off-by: Kibak Yoon Change-Id: I9a6b6a042075e941a2e6e4ee8d63149bbc463d01 --- AUTHORS | 1 - CMakeLists.txt | 74 +- LICENSE => LICENSE.APLv2 | 0 capi-system-sensor.manifest | 6 + capi-system-sensor.pc.in | 15 +- doc/sensor_doc.h | 129 ++ include/sensor_log.h | 57 + include/sensor_private.h | 149 +- include/sensors.h | 2480 +++++----------------- packaging/capi-system-sensor.manifest | 7 +- packaging/capi-system-sensor.spec | 44 +- phone_facedown.png | Bin 26918 -> 0 bytes phone_panning.png | Bin 29808 -> 0 bytes phone_snap.png | Bin 64576 -> 0 bytes src/{fusion_util.c => fusion_util.cpp} | 16 + src/{geomanetic_field.c => geomanetic_field.cpp} | 563 ++--- src/sensor.c | 1517 ------------- src/sensor.cpp | 802 +++++++ 18 files changed, 1909 insertions(+), 3951 deletions(-) delete mode 100644 AUTHORS rename LICENSE => LICENSE.APLv2 (100%) mode change 100755 => 100644 create mode 100644 capi-system-sensor.manifest create mode 100644 doc/sensor_doc.h create mode 100644 include/sensor_log.h mode change 100755 => 100644 include/sensors.h delete mode 100755 phone_facedown.png delete mode 100755 phone_panning.png delete mode 100755 phone_snap.png rename src/{fusion_util.c => fusion_util.cpp} (86%) rename src/{geomanetic_field.c => geomanetic_field.cpp} (91%) mode change 100755 => 100644 delete mode 100644 src/sensor.c create mode 100644 src/sensor.cpp diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 0a63eea..0000000 --- a/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Pius Lee diff --git a/CMakeLists.txt b/CMakeLists.txt index e65dd12..1da5d7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,75 +1,48 @@ - CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -SET(fw_name "capi-system-sensor") +PROJECT(capi-system-sensor) -PROJECT(${fw_name}) - -SET(CMAKE_INSTALL_PREFIX /usr) +# Setup for pkgconfig File +SET(fw_name "capi-system-sensor") SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(VERSION 1.0) -SET(INC_DIR include) -INCLUDE_DIRECTORIES(${INC_DIR}) - -SET(dependents "dlog sensor capi-base-common") -SET(pc_dependents "capi-base-common") +INCLUDE_DIRECTORIES(include) +# Build options INCLUDE(FindPkgConfig) -pkg_check_modules(${fw_name} REQUIRED ${dependents}) +pkg_check_modules(${fw_name} REQUIRED dlog sensor capi-base-common) + FOREACH(flag ${${fw_name}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror -g -fdump-rtl-expand") -SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") - -IF("${ARCH}" STREQUAL "arm") - ADD_DEFINITIONS("-DTARGET") -ENDIF("${ARCH}" STREQUAL "arm") - -ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") -ADD_DEFINITIONS("-DTIZEN_DEBUG") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC -Wall -Werror -g -fdump-rtl-expand") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++0x") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl, --rpath=${LIB_INSTALL_DIR}") -SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") +# Internal Logging Option +#ADD_DEFINITIONS("-DTIZEN_DEBUG") -aux_source_directory(src SOURCES) +# Complile Source files +AUX_SOURCE_DIRECTORY(src SOURCES) ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS}) - -SET_TARGET_PROPERTIES(${fw_name} - PROPERTIES - VERSION ${FULLVER} - SOVERSION ${MAJORVER} - CLEAN_DIRECT_OUTPUT 1 -) - -INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) -INSTALL( - DIRECTORY ${INC_DIR}/ DESTINATION include/system - FILES_MATCHING - PATTERN "*_private.h" EXCLUDE - PATTERN "${INC_DIR}/*.h" - ) - -SET(PC_NAME ${fw_name}) -SET(PC_REQUIRED ${pc_dependents}) -SET(PC_LDFLAGS -l${fw_name}) - -CONFIGURE_FILE( - ${fw_name}.pc.in - ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc - @ONLY -) +SET_TARGET_PROPERTIES(${fw_name} PROPERTIES VERSION ${FULLVER} SOVERSION ${MAJORVER} CLEAN_DIRECT_OUTPUT 1) +CONFIGURE_FILE(${fw_name}.pc.in ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc @ONLY) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) +INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries) +INSTALL(FILES include/sensors.h DESTINATION ${INCLUDE_INSTALL_DIR}/sensor) +# ### IF(UNIX) - ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) ADD_CUSTOM_COMMAND( - DEPENDS clean + DEPENDS clean COMMENT "distribution clean" COMMAND find - ARGS . + ARGS . -not -name config.cmake -and \( -name tester.c -or -name Testing -or @@ -90,6 +63,5 @@ ADD_CUSTOM_COMMAND( TARGET distclean VERBATIM ) - ENDIF(UNIX) diff --git a/LICENSE b/LICENSE.APLv2 old mode 100755 new mode 100644 similarity index 100% rename from LICENSE rename to LICENSE.APLv2 diff --git a/capi-system-sensor.manifest b/capi-system-sensor.manifest new file mode 100644 index 0000000..41a9320 --- /dev/null +++ b/capi-system-sensor.manifest @@ -0,0 +1,6 @@ + + + + + + diff --git a/capi-system-sensor.pc.in b/capi-system-sensor.pc.in index 3043220..2382fc8 100644 --- a/capi-system-sensor.pc.in +++ b/capi-system-sensor.pc.in @@ -1,15 +1,14 @@ - # Package Information for pkg-config prefix=@PREFIX@ -exec_prefix=/usr +exec_prefix=@PREFIX@/bin libdir=@LIB_INSTALL_DIR@ -includedir=/usr/include/system +includedir=@INCLUDE_INSTALL_DIR@/sensor -Name: @PC_NAME@ -Description: @PACKAGE_DESCRIPTION@ +Name: capi-system-sensor +Description: A sensor library Version: @VERSION@ -Requires: @PC_REQUIRED@ -Libs: -L${libdir} @PC_LDFLAGS@ -Cflags: -I${includedir} +Requires: capi-base-common +Libs: -L${libdir} -lcapi-system-sensor +Cflags: -I${includedir} diff --git a/doc/sensor_doc.h b/doc/sensor_doc.h new file mode 100644 index 0000000..4a9ab19 --- /dev/null +++ b/doc/sensor_doc.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __TIZEN_SYSTEM_SENSOR_DOC_H__ +#define __TIZEN_SYSTEM_SENSOR_DOC_H__ + + /** + * @ingroup CAPI_SYSTEM_FRAMEWORK + * @defgroup CAPI_SYSTEM_SENSOR_MODULE Sensor + * @brief The @ref CAPI_SYSTEM_SENSOR_MODULE API provides functions to start/stop sensors and receive sensor information. + * + * @section CAPI_SYSTEM_SENSOR_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_SYSTEM_SENSOR_MODULE_OVERVIEW Overview + * This Sensor API provides functions to make use of sensors in the + * device. A variety of hardware sensors are typically available on + * mobile devices. + * + * @section CAPI_SYSTEM_SENSOR_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - http://tizen.org/feature/sensor.accelerometer\n + * - http://tizen.org/feature/sensor.barometer\n + * - http://tizen.org/feature/sensor.gyroscope\n + * - http://tizen.org/feature/sensor.magnetometer\n + * - http://tizen.org/feature/sensor.photometer\n + * - http://tizen.org/feature/sensor.proximity\n + * - http://tizen.org/feature/sensor.tiltmeter\n + * - http://tizen.org/feature/sensor.ultraviolet\n + * - http://tizen.org/feature/sensor.temperature\n + * - http://tizen.org/feature/sensor.humidity\n + * - http://tizen.org/feature/sensor.linear_acceleration\n + * - http://tizen.org/feature/sensor.rotation_vector\n + * - http://tizen.org/feature/sensor.gravity\n + * + * It is recommended to design feature related codes in your application for reliability.\n + * + * You can check if a devrice supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n + * + * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n + * + * More details on featuring your application can be found from Feature Element. + * +*/ + +/** + * @ingroup CAPI_SYSTEM_SENSOR_MODULE + * @defgroup CAPI_SYSTEM_SENSOR_INFORMATION_MODULE Hardware Information + * @brief The @ref CAPI_SYSTEM_SENSOR_INFORMATION_MODULE API provides information about hardware. + * @section CAPI_SYSTEM_SENSOR_INFORMATION_MODULE_HEADER Required Header + * \#include + * @section CAPI_SYSTEM_SENSOR_INFORMATION_MODULE_OVERVIEW Overview + * This API provides functions for hardware features, such as name, vendor and other information + * @section CAPI_SYSTEM_SENSOR_INFORMATION_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - http://tizen.org/feature/sensor.accelerometer\n + * - http://tizen.org/feature/sensor.barometer\n + * - http://tizen.org/feature/sensor.gyroscope\n + * - http://tizen.org/feature/sensor.magnetometer\n + * - http://tizen.org/feature/sensor.photometer\n + * - http://tizen.org/feature/sensor.proximity\n + * - http://tizen.org/feature/sensor.tiltmeter\n + * - http://tizen.org/feature/sensor.ultraviolet\n + * - http://tizen.org/feature/sensor.temperature\n + * - http://tizen.org/feature/sensor.humidity\n + * - http://tizen.org/feature/sensor.linear_acceleration\n + * - http://tizen.org/feature/sensor.rotation_vector\n + * - http://tizen.org/feature/sensor.gravity\n + * + * It is recommended to design feature related codes in your application for reliability.\n + * + * You can check if a devrice supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n + * + * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n + * + * More details on featuring your application can be found from Feature Element. + * + */ + +/** + * @ingroup CAPI_SYSTEM_SENSOR_MODULE + * @defgroup CAPI_SYSTEM_SENSOR_UTILITY_MODULE Utility + * @brief The @ref CAPI_SYSTEM_SENSOR_UTILITY_MODULE API provides utility functions. + * @section CAPI_SYSTEM_SENSOR_UTILITY_MODULE_HEADER Required Header + * \#include + * @section CAPI_SYSTEM_SENSOR_UTILITY_MODULE_OVERVIEW Overview + * @section CAPI_SYSTEM_SENSOR_UTILITY_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - http://tizen.org/feature/sensor.accelerometer\n + * - http://tizen.org/feature/sensor.barometer\n + * - http://tizen.org/feature/sensor.gyroscope\n + * - http://tizen.org/feature/sensor.magnetometer\n + * - http://tizen.org/feature/sensor.photometer\n + * - http://tizen.org/feature/sensor.proximity\n + * - http://tizen.org/feature/sensor.tiltmeter\n + * - http://tizen.org/feature/sensor.ultraviolet\n + * - http://tizen.org/feature/sensor.temperature\n + * - http://tizen.org/feature/sensor.humidity\n + * - http://tizen.org/feature/sensor.linear_acceleration\n + * - http://tizen.org/feature/sensor.rotation_vector\n + * - http://tizen.org/feature/sensor.gravity\n + * + * It is recommended to design feature related codes in your application for reliability.\n + * + * You can check if a devrice supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n + * + * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n + * + * More details on featuring your application can be found from Feature Element. + * + * + */ + + +#endif // __TIZEN_SYSTEM_SENSORS_DOC_H__ diff --git a/include/sensor_log.h b/include/sensor_log.h new file mode 100644 index 0000000..5779dfd --- /dev/null +++ b/include/sensor_log.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SENSOR_LOG_H_ +#define _SENSOR_LOG_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define _DEBUG 1 + +#undef LOG_TAG +#define LOG_TAG "TIZEN_SYSTEM_SENSOR" + +#define _MSG_SENSOR_ERROR_IO_ERROR "Io Error" +#define _MSG_SENSOR_ERROR_INVALID_PARAMETER "Invalid Parameter" +#define _MSG_SENSOR_ERROR_OUT_OF_MEMORY "Out of Memory" +#define _MSG_SENSOR_ERROR_NOT_NEED_CALIBRATION "Not need calibration" +#define _MSG_SENSOR_ERROR_NOT_SUPPORTED "Not supported" +#define _MSG_SENSOR_ERROR_OPERATION_FAILED "Operation failed" + +#define _E_MSG(err) SLOGE(_MSG_##err "(0x%08x)", (err)) + +#ifdef _DEBUG + #define _E(fmt, args...) SLOGE(fmt, ##args) + #define _W(fmt, args...) SLOGW(fmt, ##args) + #define _I(fmt, args...) SLOGI(fmt, ##args) + #define _D(fmt, args...) SLOGD(fmt, ##args) +#else + #define _E(...) + #define _W(...) + #define _I(...) + #define _D(...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*_SENSOR_LOG_H_*/ diff --git a/include/sensor_private.h b/include/sensor_private.h index d699b50..6633db5 100644 --- a/include/sensor_private.h +++ b/include/sensor_private.h @@ -11,150 +11,29 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License. + * limitations under the License. */ - - - #ifndef __SENSOR_PRIVATE_H__ #define __SENSOR_PRIVATE_H__ +struct sensor_listener_s { + int id; + int type; + int option; + unsigned int magic; + void *sensor; + void *callback; + void *user_data; + void *accu_callback; + void *accu_user_data; +}; + #ifdef __cplusplus extern "C" { #endif -enum _sensor_ids_index{ - ID_ACCELEOMETER, - ID_GEOMAGNETIC, - ID_GYROSCOPE, - ID_LIGHT, - ID_PROXIMITY, - ID_MOTION, - ID_NUMBERS -}; - -#define CB_NUMBERS (SENSOR_LAST) -#define CALIB_CB_NUMBERS (SENSOR_ORIENTATION+1) -#define WAKEUP_CB_NUMBERS (SENSOR_DEVICE_ORIENTATION+1) -#define EMPTY_EVENT 0 - -struct sensor_handle_s { - int ids[ID_NUMBERS]; - int started[CB_NUMBERS]; - int sensor_option[CB_NUMBERS]; - - void* cb_func[CB_NUMBERS]; - void* cb_user_data[CB_NUMBERS]; - - void* calib_func[CALIB_CB_NUMBERS]; - void* calib_user_data[CALIB_CB_NUMBERS]; - - void* wakeup_func[WAKEUP_CB_NUMBERS]; - void* wakeup_user_data[WAKEUP_CB_NUMBERS]; -}; - -#define SENSOR_INIT(handle) \ -do { \ - handle->ids[ID_ACCELEOMETER] = -1; \ - handle->ids[ID_GEOMAGNETIC] = -1; \ - handle->ids[ID_GYROSCOPE] = -1; \ - handle->ids[ID_LIGHT] = -1; \ - handle->ids[ID_PROXIMITY] = -1; \ - handle->ids[ID_MOTION] = -1; \ - handle->started[SENSOR_ACCELEROMETER] = 0; \ - handle->started[SENSOR_GRAVITY] = 0; \ - handle->started[SENSOR_LINEAR_ACCELERATION] = 0; \ - handle->started[SENSOR_DEVICE_ORIENTATION] = 0; \ - handle->started[SENSOR_MAGNETIC] = 0; \ - handle->started[SENSOR_ORIENTATION] = 0; \ - handle->started[SENSOR_GYROSCOPE] = 0; \ - handle->started[SENSOR_LIGHT] = 0; \ - handle->started[SENSOR_PROXIMITY] = 0; \ - handle->started[SENSOR_MOTION_SNAP] = 0; \ - handle->started[SENSOR_MOTION_SHAKE] = 0; \ - handle->started[SENSOR_MOTION_DOUBLETAP] = 0; \ - handle->started[SENSOR_MOTION_PANNING] = 0; \ - handle->started[SENSOR_MOTION_PANNING_BROWSE] = 0; \ - handle->started[SENSOR_MOTION_TILT] = 0; \ - handle->started[SENSOR_MOTION_FACEDOWN] = 0; \ - handle->started[SENSOR_MOTION_DIRECTCALL] = 0; \ - handle->started[SENSOR_MOTION_SMART_ALERT] = 0; \ - handle->started[SENSOR_MOTION_NO_MOVE] = 0; \ - handle->sensor_option[SENSOR_ACCELEROMETER] = 0; \ - handle->sensor_option[SENSOR_GRAVITY] = 0; \ - handle->sensor_option[SENSOR_LINEAR_ACCELERATION] = 0; \ - handle->sensor_option[SENSOR_DEVICE_ORIENTATION] = 0; \ - handle->sensor_option[SENSOR_MAGNETIC] = 0; \ - handle->sensor_option[SENSOR_ORIENTATION] = 0; \ - handle->sensor_option[SENSOR_GYROSCOPE] = 0; \ - handle->sensor_option[SENSOR_LIGHT] = 0; \ - handle->sensor_option[SENSOR_PROXIMITY] = 0; \ - handle->sensor_option[SENSOR_MOTION_SNAP] = 0; \ - handle->sensor_option[SENSOR_MOTION_SHAKE] = 0; \ - handle->sensor_option[SENSOR_MOTION_DOUBLETAP] = 0; \ - handle->sensor_option[SENSOR_MOTION_PANNING] = 0; \ - handle->sensor_option[SENSOR_MOTION_PANNING_BROWSE] = 0; \ - handle->sensor_option[SENSOR_MOTION_TILT] = 0; \ - handle->sensor_option[SENSOR_MOTION_FACEDOWN] = 0; \ - handle->sensor_option[SENSOR_MOTION_DIRECTCALL] = 0; \ - handle->sensor_option[SENSOR_MOTION_SMART_ALERT] = 1; \ - handle->sensor_option[SENSOR_MOTION_NO_MOVE] = 0; \ - handle->cb_func[SENSOR_ACCELEROMETER] = NULL; \ - handle->cb_func[SENSOR_GRAVITY] = NULL; \ - handle->cb_func[SENSOR_LINEAR_ACCELERATION] = NULL; \ - handle->cb_func[SENSOR_DEVICE_ORIENTATION] = NULL; \ - handle->cb_func[SENSOR_MAGNETIC] = NULL; \ - handle->cb_func[SENSOR_ORIENTATION] = NULL; \ - handle->cb_func[SENSOR_GYROSCOPE] = NULL; \ - handle->cb_func[SENSOR_LIGHT] = NULL; \ - handle->cb_func[SENSOR_PROXIMITY] = NULL; \ - handle->cb_func[SENSOR_MOTION_SNAP] = NULL; \ - handle->cb_func[SENSOR_MOTION_SHAKE] = NULL; \ - handle->cb_func[SENSOR_MOTION_DOUBLETAP] = NULL; \ - handle->cb_func[SENSOR_MOTION_PANNING] = NULL; \ - handle->cb_func[SENSOR_MOTION_PANNING_BROWSE] = NULL; \ - handle->cb_func[SENSOR_MOTION_TILT] = NULL; \ - handle->cb_func[SENSOR_MOTION_FACEDOWN] = NULL; \ - handle->cb_func[SENSOR_MOTION_DIRECTCALL] = NULL; \ - handle->cb_func[SENSOR_MOTION_SMART_ALERT] = NULL; \ - handle->cb_func[SENSOR_MOTION_NO_MOVE] = NULL; \ - handle->cb_user_data[SENSOR_ACCELEROMETER] = NULL; \ - handle->cb_user_data[SENSOR_GRAVITY] = NULL; \ - handle->cb_user_data[SENSOR_LINEAR_ACCELERATION] = NULL; \ - handle->cb_user_data[SENSOR_DEVICE_ORIENTATION] = NULL; \ - handle->cb_user_data[SENSOR_MAGNETIC] = NULL; \ - handle->cb_user_data[SENSOR_ORIENTATION] = NULL; \ - handle->cb_user_data[SENSOR_GYROSCOPE] = NULL; \ - handle->cb_user_data[SENSOR_LIGHT] = NULL; \ - handle->cb_user_data[SENSOR_PROXIMITY] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_SNAP] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_SHAKE] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_DOUBLETAP] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_PANNING] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_PANNING_BROWSE] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_TILT] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_FACEDOWN] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_DIRECTCALL] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_SMART_ALERT] = NULL; \ - handle->cb_user_data[SENSOR_MOTION_NO_MOVE] = NULL; \ - handle->calib_func[SENSOR_ACCELEROMETER] = NULL; \ - handle->calib_func[SENSOR_GRAVITY] = NULL; \ - handle->calib_func[SENSOR_LINEAR_ACCELERATION] = NULL; \ - handle->calib_func[SENSOR_DEVICE_ORIENTATION] = NULL; \ - handle->calib_func[SENSOR_MAGNETIC] = NULL; \ - handle->calib_func[SENSOR_ORIENTATION] = NULL; \ - handle->calib_user_data[SENSOR_ACCELEROMETER] = NULL; \ - handle->calib_user_data[SENSOR_GRAVITY] = NULL; \ - handle->calib_user_data[SENSOR_LINEAR_ACCELERATION] = NULL; \ - handle->calib_user_data[SENSOR_DEVICE_ORIENTATION] = NULL; \ - handle->calib_user_data[SENSOR_MAGNETIC] = NULL; \ - handle->calib_user_data[SENSOR_ORIENTATION] = NULL; \ - handle->wakeup_func[SENSOR_ACCELEROMETER] = NULL; \ - handle->wakeup_user_data[SENSOR_ACCELEROMETER] = NULL;\ -}while(0) \ - float clamp(float v); int getAngleChange(float *R, float *prevR, float *angleChange); int quatToMatrix(float *quat, float *R); @@ -169,4 +48,4 @@ int setCoordinate(float latitude, float longitude, float altitude, float *declin } #endif -#endif // __SENSOR_PRIVATE_H__ +#endif // __SENSOR_PRIVATE_H__ diff --git a/include/sensors.h b/include/sensors.h old mode 100755 new mode 100644 index 7112d39..ccd291e --- a/include/sensors.h +++ b/include/sensors.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,12 +11,9 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License. + * limitations under the License. */ - - - #ifndef __SENSOR_H__ #define __SENSOR_H__ @@ -28,18 +25,58 @@ extern "C" #endif /** + * @file sensor.h + * @brief This file contains Sensor API related structures and enumerations. + */ + +/** * @addtogroup CAPI_SYSTEM_SENSOR_MODULE * @{ */ +#define MAX_VALUE_SIZE 16 +#ifndef TIZEN_ERROR_SENSOR +#define TIZEN_ERROR_SENSOR -0x02440000 +#endif +#ifndef TIZEN_ERROR_NOT_SUPPORTED +#define TIZEN_ERROR_NOT_SUPPORTED (TIZEN_ERROR_MIN_PLATFORM_ERROR+2) +#endif + /** * @brief The sensor handle. + * @details This handle indicates a specific sensor itself. + * @since_tizen 2.3 + */ +typedef void* sensor_h; + + +/** + * @brief The listener handle. + * @details This listener is an event listener used to receive sensor data asynchronously. + * @since_tizen 2.3 + */ +typedef struct sensor_listener_s *sensor_listener_h; + + +/** + * @brief The structure type containing information of an event. + * @details It holds information such as timestamp, accuracy, and sensor values. + * @since_tizen 2.3 + * + * @remarks If you use proximity sensor, see #sensor_proximity_e */ -typedef struct sensor_handle_s* sensor_h; +typedef struct +{ + int accuracy; /**< Accuracy */ + unsigned long long timestamp; /**< Timestamp */ + int value_count; /**< Count of values */ + float values[MAX_VALUE_SIZE]; /**< Sensor values */ +} sensor_event_s; /** -* @brief Enumerations of sensor data accuracy. -*/ + * @brief Enumeration for sensor data accuracy. + * @since_tizen 2.3 + */ typedef enum { SENSOR_DATA_ACCURACY_UNDEFINED = -1, /**< Undefined accuracy */ @@ -51,2179 +88,742 @@ typedef enum /** -* @brief Enumerations of error code for sensor. + * @brief Enumeration for sensor error. + * @since_tizen 2.3 */ typedef enum { - SENSOR_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + SENSOR_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ SENSOR_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O error */ SENSOR_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ - SENSOR_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_SYSTEM_CLASS | 0x02, /**< Out of memory */ - SENSOR_ERROR_NOT_NEED_CALIBRATION = TIZEN_ERROR_SYSTEM_CLASS | 0x03, /**< Sensor doesn't need calibration */ - SENSOR_ERROR_NOT_SUPPORTED = TIZEN_ERROR_SYSTEM_CLASS | 0x04, /**< Unsupported sensor in current device */ - SENSOR_ERROR_OPERATION_FAILED = TIZEN_ERROR_SYSTEM_CLASS | 0x06, /**< Operation failed */ - + SENSOR_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Unsupported sensor in the current device */ + SENSOR_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + SENSOR_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + SENSOR_ERROR_NOT_NEED_CALIBRATION = TIZEN_ERROR_SENSOR | 0x03, /**< Sensor doesn't need calibration */ + SENSOR_ERROR_OPERATION_FAILED = TIZEN_ERROR_SENSOR | 0x06, /**< Operation failed */ } sensor_error_e; +/** + * @brief Enumeration for proximity sensor. + * @since_tizen 2.3 + */ +typedef enum +{ + SENSOR_PROXIMITY_NEAR = 0, /**< The object is near */ + SENSOR_PROXIMITY_FAR = 5, /**< The object is far */ +} sensor_proximity_e; + /** -* @brief Enumerations of sensor type. -*/ + * @brief Enumeration for sensor types. + * @since_tizen 2.3 + */ typedef enum { + SENSOR_ALL = -1, /**< All sensors */ SENSOR_ACCELEROMETER, /**< Accelerometer */ - SENSOR_GRAVITY, /**< Gravity sensor */ + SENSOR_GRAVITY, /**< Gravity sensor */ SENSOR_LINEAR_ACCELERATION, /**< Linear acceleration sensor */ - SENSOR_DEVICE_ORIENTATION, /**< Device orientation sensor */ SENSOR_MAGNETIC, /**< Magnetic sensor */ + SENSOR_ROTATION_VECTOR, /**< Rotation Vector sensor */ SENSOR_ORIENTATION, /**< Orientation sensor */ SENSOR_GYROSCOPE, /**< Gyroscope sensor */ SENSOR_LIGHT, /**< Light sensor */ SENSOR_PROXIMITY, /**< Proximity sensor */ - SENSOR_MOTION_SNAP, /**< Snap motion sensor */ - SENSOR_MOTION_SHAKE, /**< Shake motion sensor */ - SENSOR_MOTION_DOUBLETAP, /**< Double tap motion sensor */ - SENSOR_MOTION_PANNING, /**< Panning motion sensor */ - SENSOR_MOTION_PANNING_BROWSE, /**< Panning browse motion sensor */ - SENSOR_MOTION_TILT, /**< Tilt motion sensor */ - SENSOR_MOTION_FACEDOWN, /**< Face to down motion sensor */ - SENSOR_MOTION_DIRECTCALL, /**< Direct call motion sensor */ - SENSOR_MOTION_SMART_ALERT, /**< Smart alert motion sensor */ - SENSOR_MOTION_NO_MOVE, /**< No move motion sensor */ - SENSOR_LAST /**< End of sensor enum values */ + SENSOR_PRESSURE, /**< Pressure sensor */ + SENSOR_ULTRAVIOLET, /**< Ultraviolet sensor */ + SENSOR_TEMPERATURE, /**< Temperature sensor */ + SENSOR_HUMIDITY, /**< Humidity sensor */ + SENSOR_LAST, /**< End of sensor enum values */ + SENSOR_CUSTOM = 10000 /**< Custom sensor */ } sensor_type_e; -/** - * @} - */ - - -/** - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_SNAP_MODULE - * @{ - */ - -/** - * @brief Enumerations of snap motion event. - */ -typedef enum -{ - SENSOR_MOTION_SNAP_NONE, /**< No Snap */ - SENSOR_MOTION_SNAP_RIGHT, /**< Snap right to left */ - SENSOR_MOTION_SNAP_LEFT, /**< Snap left to right */ - SENSOR_MOTION_SNAP_X_POSITIVE = SENSOR_MOTION_SNAP_RIGHT, /**< Snap to positive direction in X-axis, it is the same as @SENSOR_MOTION_SNAP_RIGHT */ - SENSOR_MOTION_SNAP_X_NEGATIVE = SENSOR_MOTION_SNAP_LEFT, /**< Snap to negative direction in X-axis, it is the same as @SENSOR_MOTION_SNAP_LEFT */ - SENSOR_MOTION_SNAP_Y_POSITIVE, /**< Snap to positive direction in Y-axis */ - SENSOR_MOTION_SNAP_Y_NEGATIVE, /**< Snap to Negative direction in Y-axis */ - SENSOR_MOTION_SNAP_Z_POSITIVE, /**< Snap to positive direction in Z-axis */ - SENSOR_MOTION_SNAP_Z_NEGATIVE, /**< Snap to Negative direction in Z-axis */ -} sensor_motion_snap_e; -/** - * @} - */ - -/** - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_SHAKE_MODULE - * @{ - */ /** - * @brief Enumerations of shake motion event. + * @brief Enumeration for sensor options. + * @since_tizen 2.3 */ +#ifndef __SENSOR_COMMON_H__ typedef enum { - SENSOR_MOTION_SHAKE_NONE, /**< No Shake */ - SENSOR_MOTION_SHAKE_DETECTED, /**< Shake motion detected */ - SENSOR_MOTION_SHAKE_CONTINUING, /**< Shake motion continuing */ - SENSOR_MOTION_SHAKE_FINISHED, /**< Shake motion finished */ - SENSOR_MOTION_SHAKE_BROKEN, /**< Shake motion broken */ -} sensor_motion_shake_e; -/** - * @} - */ - -/** - * @addtogroup CAPI_SYSTEM_SENSOR_MODULE - * @{ - */ - -/** - * @brief Called when the current sensor reading falls outside of a defined normal range. - * - * @details When something is artificially influencing, such as ferrous metal objects or - * electromagnetic fields (car electrical systems, automobile engines, steel pitons, etc.), this callback is called. - * One way of implementing this callback is to notice a user to make big 8-like gesture with device. - * - * @param[in] user_data The user data passed from the callback registration function - * - * @see sensor_magnetic_set_calibration_cb() - * @see sensor_magnetic_unset_calibration_cb() - * @see sensor_orientation_set_calibration_cb() - * @see sensor_orientation_unset_calibration_cb() - */ -typedef void (*sensor_calibration_cb)(void *user_data); - + SENSOR_OPTION_DEFAULT, /**< Does not receive data when the LCD is off and in the power save mode */ + SENSOR_OPTION_ON_IN_SCREEN_OFF, /**< Receives data when the LCD is off */ + SENSOR_OPTION_ON_IN_POWERSAVE_MODE, /**< Receives data in the power save mode */ + SENSOR_OPTION_ALWAYS_ON, /**< Receives data when the LCD is off and in the power save mode */ +} sensor_option_e; +#endif /** - * @brief Checks whether the given sensor type is available on a device. - * @details - * You need to check availability of a sensor first because this sensor may not be supported on the device. + * @brief Checks whether a given sensor type is available on a device. + * @details Availability of a sensor should be checked first because this sensor may not be supported on the device. + * @since_tizen 2.3 * * @param[in] type The sensor type to check - * @param[out] supported @c true if this sensor type is supported, otherwise @c false + * @param[out] supported If @c true this sensor type is supported, + * otherwise @c false * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter * */ int sensor_is_supported(sensor_type_e type, bool *supported); - /** - * @brief Gets data specification for a sensor type, except motion sensors. - * - * @remark When the given @a type is one of the motion sensors, this function returns #SENSOR_ERROR_INVALID_PARAMETER. + * @brief Gets a specific sensor handle. + * @since_tizen 2.3 * - * @param[in] type The sensor type to check - * @param[out] vendor The vendor name of the sensor - * @param[out] model The model name of the sensor - * @param[out] max The maximum range of the sensor in the sensor's unit - * @param[out] min The minimum range of the sensor in the sensor's unit - * @param[out] resolution The resolution of the sensor + * @param[in] type The sensor type + * @param[out] sensor The sensor handle * - * @return 0 on success, otherwise a negative error value. - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in current device - * - * @pre #sensor_is_supported() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_PERMISSION_DENIED Permission denied */ -int sensor_get_spec(sensor_type_e type, char** vendor, char** model, float *max, float *min, float *resolution); - +int sensor_get_default_sensor(sensor_type_e type, sensor_h *sensor); /** - * @brief Creates a sensor handle. + * @brief Gets a sensor list. + * @since_tizen 2.3 + * @remarks If you want to get a handle list of all sensors, + * use SENSOR_ALL type in sensor_type_e. + * @remarks The caller should explicitly free this list. * - * @remarks @a sensor must be released sensor_destroy() by you. + * @param[in] type The sensor type + * @param[out] list The sensor list + * @param[out] sensor_count The count of sensors * - * @param[out] sensor A new sensor handle to the sensors - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_OUT_OF_MEMORY Out of memory - * - * @see sensor_destroy() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_PERMISSION_DENIED Permission denied */ -int sensor_create(sensor_h *sensor); - +int sensor_get_sensor_list(sensor_type_e type, sensor_h **list, int *sensor_count); /** - * @brief Destroys the sensor handle and releases all its resources. - * - * @remark After this function is called, the attached sensor will be detached and - * the corresponding sensor connection will be released. + * @brief Called when a sensor event occurs. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @param[in] sensor The sensor handle + * @param[in] event The event information + * @param[in] data The user data passed from the callback registration function * - * @see sensor_create() + * @see sensor_create_listener() + * @see sensor_listener_set_event_cb() + * @see sensor_listener_unset_event_cb() */ -int sensor_destroy(sensor_h sensor); - +typedef void (*sensor_event_cb)(sensor_h sensor, sensor_event_s *event, void *data); /** - * @brief Starts sensor server for the given sensor handle and sensor type. - * @details - * After this function is called, sensor events will occur and - * the specific sensor type related callback function will be called. An application can read sensor data. - * - * @param[in] sensor The sensor handle - * @param[in] type The sensor type + * @brief Creates a sensor listener. + * @since_tizen 2.3 * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in current device - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @pre call sensor_create() before using this function. - * @post This function invokes sensor_calibration_cb(), sensor_accelerometer_event_cb(), sensor_magnetic_event_cb(), - * sensor_orientation_event_cb(), sensor_gyroscope_event_cb(), sensor_light_event_cb(), - * sensor_proximity_event_cb(), sensor_motion_snap_event_cb(), sensor_motion_shake_event_cb(), - * sensor_motion_doubletap_event_cb(), sensor_motion_panning_event_cb(), or sensor_motion_facedown_event_cb(). - * - * @see sensor_stop() - */ -int sensor_start(sensor_h sensor, sensor_type_e type); - - -/** - * @brief Stops sensor server for the given sensor handle and type. - * @details The given @a type event will not occur any more and the callback functions also won't be called. + * @remarks You must release @a listener using sensor_destroy_listener(). * - * @param[in] sensor The sensor handle - * @param[in] type The sensor type + * @param[in] sensor The sensor handle + * @param[out] listener A new listener handle * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_OUT_OF_MEMORY Out of memory * - * @see sensor_start() + * @see sensor_listener_set_event_cb() + * @see sensor_listener_set_interval() + * @see sensor_listener_set_max_batch_latency() + * @see sensor_listener_set_option() + * @see sensor_destroy_listener() */ -int sensor_stop(sensor_h sensor, sensor_type_e type); +int sensor_create_listener(sensor_h sensor, sensor_listener_h *listener); /** - * @brief Retrieve minimum and maximum interval time that can use to measuring specific sensor. + * @brief Destroys the sensor handle and releases all its resources. + * @since_tizen 2.3 * - * @param[in] type The sensor type - * @param[out] min The minimum interval time - * @param[out] max The maximum interval time + * @remarks After this function is called, the attached sensor is detached and + * the corresponding sensor connection is released. * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - */ -int sensor_get_delay_boundary(sensor_type_e type, int *min, int *max); - -/** - * @brief Retrieve whether supported or not supported the awaken from specific sensor. + * @param[in] listener The listener handle * - * @param[in] type The sensor type - * @param[out] supported @c true if this sensor type is supported, otherwise @c false + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @see sensor_create_listener() */ -int sensor_awake_is_supported(sensor_type_e type, bool *supported); +int sensor_destroy_listener(sensor_listener_h listener); /** - * @brief Set the awaken behavior from specific sensor. + * @brief Starts the sensor server for the given listener. * - * @param[in] sensor The sensor handle - * @param[in] type The sensor type - * @param[out] enable @c true if set enable the awaken behavior from the sensor, or @c false + * @details After this function is called, sensor events will occur and + * the specific sensor type related callback function will be called. An application can read sensor data. * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - */ -int sensor_awake_is_enabled(sensor_h sensor, sensor_type_e type, bool *enable); - -/** - * @brief Called when a device awaken. + * @since_tizen 2.3 * - * @param[in] user_data The user data passed from the callback registration function + * @param[in] listener The listener handle * - * @see sensor_awake_is_supported() - * @see sensor_awake_set() - * @see sensor_awake_set_cb() - * @see sensor_awake_unset_cb() - */ -typedef void (*sensor_awake_cb) (void *user_data); - -/** - * @brief Set the callback that called when device awaken. - * - * @param[in] sensor The sensor handle - * @param[in] type The sensor type - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - */ -int sensor_awake_set_cb(sensor_h sensor, sensor_type_e type, sensor_awake_cb callback, void* user_data); - -/** - * @brief Unset the callback that called when device awaken. - * - * @param[in] sensor The sensor handle - * @param[in] type The sensor type + * @pre Call sensor_create_listener() before using this function. * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @see sensor_listener_stop() */ -int sensor_awake_unset_cb(sensor_h sensor, sensor_type_e type); - +int sensor_listener_start(sensor_listener_h listener); /** - * @} + * @brief Stops the sensor server for the given listener. * - * @addtogroup CAPI_SYSTEM_SENSOR_ACCELEROMETER_MODULE - * @{ - */ - -/** - * @brief Called when an accelerometer event occurs. + * @details The given @a type event will not occur any more and the callback functions also won't be called. + * + * @since_tizen 2.3 * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] accuracy The accuracy of @a x, @a y, and @a z values - * @param[in] x The acceleration Gx on the x-axis in [m/s^2] - * @param[in] y The acceleration Gy on the y-axis in [m/s^2] - * @param[in] z The acceleration Gz on the z-axis in [m/s^2] - * @param[in] user_data The user data passed from the callback registration function + * @param[in] listener The listener handle * - * @pre sensor_start() will invoke this callback if you register this callback using sensor_accelerometer_set_cb(). + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error * - * @see sensor_accelerometer_set_cb() - * @see sensor_accelerometer_unset_cb() + * @see sensor_listener_start() */ -typedef void (*sensor_accelerometer_event_cb)( unsigned long long timestamp, - sensor_data_accuracy_e accuracy, float x, float y, float z, void *user_data); - +int sensor_listener_stop(sensor_listener_h listener); /** - * @brief Registers a callback function to be invoked when an accelerometer event occurs. + * @brief Registers a callback function to be invoked when a sensor event occurs. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered at (in milliseconds) \n - * If @a rate is zero, it uses default value(100ms) + * @param[in] listener The listener handle + * @param[in] interval_ms The interval at which sensor events are delivered (in milliseconds) \n + * If @a rate is zero, it uses the default value(100ms) * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @param[in] data The user data to be passed to the callback function * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_accelerometer_event_cb() will be invoked. + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed * - * @see sensor_accelerometer_event_cb() - * @see sensor_accelerometer_unset_cb() + * @see sensor_event_cb() + * @see sensor_listener_unset_event_cb() */ -int sensor_accelerometer_set_cb(sensor_h sensor, int interval_ms, sensor_accelerometer_event_cb callback, void *user_data); - +int sensor_listener_set_event_cb(sensor_listener_h listener, unsigned int interval_ms, sensor_event_cb callback, void *data); /** - * @brief Unregister the accelerometer callback function. + * @brief Unregisters the sensor callback function. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle + * @param[in] listener The listener handle * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed * - * @see sensor_accelerometer_set_cb() + * @see sensor_listener_set_event_cb() */ -int sensor_accelerometer_unset_cb(sensor_h sensor); +int sensor_listener_unset_event_cb(sensor_listener_h listener); /** - * @brief change the interval at accelerometer measurements. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. + * @brief Called when the accuracy of a sensor has changed. * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + * @details When something is artificially influencing, such as ferrous metal objects or + * electromagnetic fields (car electrical systems, automobile engines, steel pitons, and so on.), this callback is called. + * One way of implementing this callback is to instruct a user to make big 8-like gestures with the device. + * @since_tizen 2.3 * - * @see sensor_accelerometer_set_cb() + * @param[in] sensor The sensor handle + * @param[in] timestamp The time in milliseconds at which the event happened + * @param[in] accuracy The accuracy of this data + * @param[in] user_data The user data passed from the callback registration function */ -int sensor_accelerometer_set_interval(sensor_h sensor, int interval_ms); - +typedef void (*sensor_accuracy_changed_cb)(sensor_h sensor, unsigned long long timestamp, sensor_data_accuracy_e accuracy, void *data); /** - * @brief Gets sensor data from the accelerometer sensor. + * @brief Registers an accuracy callback function to be invoked when the accuracy of a sensor has changed. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[out] x The acceleration minus Gx on the x-axis in meters per second squared (m/s^2) - * @param[out] y The acceleration minus Gy on the y-axis in meters per second squared (m/s^2) - * @param[out] z The acceleration minus Gz on the z-axis in meters per second squared (m/s^2) - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @param[in] listener The listener handle + * @param[in] callback The callback function to register + * @param[in] data The user data to be passed to the callback function * - * @pre In order to read sensor data, an application should call sensor_start(). - */ -int sensor_accelerometer_read_data(sensor_h sensor, sensor_data_accuracy_e *accuracy, float *x, float *y, float *z); - - -/** - * @} + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed * - * @addtogroup CAPI_SYSTEM_SENSOR_GRAVITY_MODULE - * @{ + * @see sensor_accuracy_changed_cb() + * @see sensor_listener_unset_accuracy_cb() */ +int sensor_listener_set_accuracy_cb(sensor_listener_h listener, sensor_accuracy_changed_cb callback, void *data); /** - * @brief Called when an gravity event occurs. + * @brief Unregisters the sensor accuracy changed callback function. + * @since_tizen 2.3 * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] accuracy The accuracy of @a x, @a y, and @a z values - * @param[in] x g (9.8 m/s^2 = 1g) - * @param[in] y g (9.8 m/s^2 = 1g) - * @param[in] z g (9.8 m/s^2 = 1g) - * @param[in] user_data The user data passed from the callback registration function + * @param[in] listener The listener handle * - * @pre sensor_start() will invoke this callback if you register this callback using sensor_rotation_vector_set_cb(). + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed * - * @see sensor_gravity_set_cb() - * @see sensor_gravity_unset_cb() + * @see sensor_listener_set_accuracy_cb() */ -typedef void (*sensor_gravity_event_cb)(unsigned long long timestamp, - sensor_data_accuracy_e accuracy, float x, float y, float z, void *user_data); +int sensor_listener_unset_accuracy_cb(sensor_listener_h listener); /** - * @brief Registers a callback function to be invoked when an gravity event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered at (in milliseconds) \n - * If @a rate is zero, it uses default value(100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @brief Gets sensor data. + * @since_tizen 2.3 * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + * @param[in] listener The listener handle + * @param[out] event The event information * - * @post sensor_gravity_event_cb() will be invoked. + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error * - * @see sensor_gravity_event_cb() - * @see sensor_gravity_unset_cb() + * @pre In order to read sensor data, an application should call sensor_listener_start(). */ -int sensor_gravity_set_cb(sensor_h sensor, int interval_ms, sensor_gravity_event_cb callback, void* user_data); +int sensor_listener_read_data(sensor_listener_h listener, sensor_event_s *event); /** - * @brief Unregister the gravity callback function. + * @brief Changes the interval at sensor measurements. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + * @param[in] listener The listener handle + * @param[in] interval_ms The interval at which sensor events are delivered (in milliseconds) \n + * If @a rate is zero, it uses the default value(100ms) * - * @see sensor_gravity_set_cb() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_gravity_unset_cb(sensor_h sensor); +int sensor_listener_set_interval(sensor_listener_h listener, unsigned int interval_ms); /** - * @brief change the interval at gravity measurements. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. + * @brief Changes the max batch latency at sensor measurements. + * @since_tizen 2.3 * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + * @param[in] listener The listener handle + * @param[in] max_batch_latency The latency at which sensor events are delivered (in milliseconds) * - * @see sensor_gravity_set_cb() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_gravity_set_interval(sensor_h sensor, int interval_ms); +int sensor_listener_set_max_batch_latency(sensor_listener_h listener, unsigned int max_batch_latency); /** - * @brief Gets sensor data from the gravity sensor. + * @brief Changes the option of the sensor. + * @details If it is default, sensor data cannot be recieved when the LCD is off and in the power save mode. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[in] x g (9.8 m/s^2 = 1g) - * @param[in] y g (9.8 m/s^2 = 1g) - * @param[in] z g (9.8 m/s^2 = 1g) + * @param[in] listener The listener handle + * @param[in] option The sensor option * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_gravity_read_data(sensor_h sensor, sensor_data_accuracy_e* accuracy, float* x, float* y, float* z); - +int sensor_listener_set_option(sensor_listener_h listener, sensor_option_e option); /** * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_LINEAR_ACCELERATION_MODULE - * @{ */ /** - * @brief Called when an linear accleration event occurs. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] accuracy The accuracy of @a x, @a y, and @a z values - * @param[in] x The acceleration Gx on the x-axis in [m/s^2] not including gravity - * @param[in] y The acceleration Gy on the y-axis in [m/s^2] not including gravity - * @param[in] z The acceleration Gz on the z-axis in [m/s^2] not including gravity - * @param[in] user_data The user data passed from the callback registration function - * - * @pre sensor_start() will invoke this callback if you register this callback using sensor_linear_acceleration_set_cb(). - * - * @see sensor_linear_acceleration_set_cb() - * @see sensor_linear_acceleration_unset_cb() + * @addtogroup CAPI_SYSTEM_SENSOR_INFORMATION_MODULE + * @{ */ -typedef void (*sensor_linear_acceleration_event_cb)( unsigned long long timestamp, - sensor_data_accuracy_e accuracy, float x, float y, float z, void *user_data); /** - * @brief Registers a callback function to be invoked when an linear acceleration event occurs. + * @brief Gets the name of the sensor. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered at (in milliseconds) \n - * If @a rate is zero, it uses default value(100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @param[in] sensor The sensor handle + * @param[out] name The name of the sensor * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_linear_acceleration_event_cb() will be invoked. - * - * @see sensor_linear_acceleration_event_cb() - * @see sensor_linear_acceleration_unset_cb() + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_linear_acceleration_set_cb(sensor_h sensor, int interval_ms, sensor_linear_acceleration_event_cb callback, void *user_data); +int sensor_get_name(sensor_h sensor, char** name); /** - * @brief Unregister the linear acceleration callback function. + * @brief Gets the vendor of the sensor. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle + * @param[in] sensor The sensor handle + * @param[out] vendor The vendor of the sensor * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_linear_acceleration_set_cb() + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_linear_acceleration_unset_cb(sensor_h sensor); +int sensor_get_vendor(sensor_h sensor, char** vendor); /** - * @brief change the interval at linear acceleration measurements. - * + * @brief Gets the type of the sensor. + * @since_tizen 2.3 + * * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. + * @param[out] type The type of the sensor * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_linear_acceleration_set_cb() + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_linear_acceleration_set_interval(sensor_h sensor, int interval_ms); +int sensor_get_type(sensor_h sensor, sensor_type_e *type); /** - * @brief Gets sensor data from the linear acceleration sensor. + * @brief Gets the minimum range of the sensor. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[out] x The acceleration Gx on the x-axis in meters per second squared (m/s^2) not including gravity - * @param[out] y The acceleration Gy on the y-axis in meters per second squared (m/s^2) not including gravity - * @param[out] z The acceleration Gz on the z-axis in meters per second squared (m/s^2) not including gravity + * @param[in] sensor The sensor handle + * @param[out] min_range The minimum range * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_linear_acceleration_read_data(sensor_h sensor, sensor_data_accuracy_e *accuracy, float *x, float *y, float *z); - +int sensor_get_min_range(sensor_h sensor, float *min_range); /** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_DEVICE_ORIENTATION_MODULE - * @{ + * @brief Gets the maximum range of the sensor. + * @since_tizen 2.3 + * + * @param[in] sensor The sensor handle + * @param[out] max_range The maximum range + * + * @return 0 on success, otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ +int sensor_get_max_range(sensor_h sensor, float *max_range); /** - * @brief Called when an device orientation event occurs. - * - * @remark All values are angles in degrees. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] accuracy The accuracy of @a yaw, @a pitch, and @a roll values - * @param[in] yaw The rotation around z-axis [0 ~ 360], with positive values when the y-axis moves \n - * toward the x-axis - * @param[in] pitch The rotation around x-axis [-180 ~ 180], with positive values when the z-axis moves \n - * toward the y-axis - * @param[in] roll The rotation around y-axis [-90 ~ 90], with positive values when the x-axis moves \n - * toward the z-axis - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_device_orientation_set_cb(). - * @see sensor_device_orientation_set_cb() - * @see sensor_device_orientation_unset_cb() - */ -typedef void (*sensor_device_orientation_event_cb)( unsigned long long timestamp, - sensor_data_accuracy_e accuracy, float yaw, float pitch, float roll, void *user_data); - -/** - * @brief Registers a callback function to be invoked when an device orientation event occurs. + * @brief Gets the resolution of the sensor. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered in (in milliseconds) \n - * If @a interval_ms is zero, it uses default value (100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @param[in] sensor The sensor handle + * @param[out] resolution The resolution * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_device_orientation_event_cb() will be invoked. - * - * @see sensor_device_orientation_event_cb() - * @see sensor_device_orientation_unset_cb() -*/ -int sensor_device_orientation_set_cb(sensor_h sensor, int interval_ms, sensor_device_orientation_event_cb callback, void *user_data); + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + */ +int sensor_get_resolution(sensor_h sensor, float *resolution); /** - * @brief Unregister the device orientation callback function. + * @brief Gets the minimun interval of the sensor. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle + * @param[in] sensor The sensor handle + * @param[out] min_interval The minimum interval (in milliseconds) * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_device_orientation_set_cb() + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_device_orientation_unset_cb(sensor_h sensor); +int sensor_get_min_interval(sensor_h sensor, int *min_interval); /** - * @brief change the interval at device orientation measurements. - * + * @brief Gets the fifo count of the sensor. + * @since_tizen 2.3 + * * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. + * @param[out] fifo_count The fifo count * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_device_orientation_set_cb() + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_device_orientation_set_interval(sensor_h sensor, int interval_ms); +int sensor_get_fifo_count(sensor_h sensor, int *fifo_count); /** - * @brief Gets sensor data from the device orientation sensor. + * @brief Gets the maximum batch count of the sensor. + * @since_tizen 2.3 * - * @remark - * All values are angles in degrees. - * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[in] yaw The rotation around z-axis [0 ~ 360], with positive values when the y-axis moves \n - * toward the x-axis - * @param[out] pitch The rotation in degrees around x-axis [-180 ~ 180], with positive values when the \n - * z-axis moves toward the y-axis - * @param[out] roll The rotation in degrees around y-axis [-90 ~ 90], with positive values when the \n - * x-axis moves toward the z-axis + * @param[in] sensor The sensor handle + * @param[out] max_batch_count The maximum batch count * * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). - * @see sensor_start() + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * @retval #SENSOR_ERROR_IO_ERROR I/O error + * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed */ -int sensor_device_orientation_read_data(sensor_h sensor, sensor_data_accuracy_e *accuracy, float *yaw, float *pitch, float *roll); - - +int sensor_get_max_batch_count(sensor_h sensor, int *max_batch_count); /** * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MAGNETIC_MODULE - * @{ */ /** - * @brief Called when a magnetic event occurs. - * - * @remark @a x, @a y, and @a z values are in micro-Teslas(uT) and measure the ambient magnetic field in the X, Y and Z axis. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] accuracy The accuracy of @a x, @a y, and @a z values - * @param[in] x Micro-Tesla value from ambient magnetic field on the x-axis - * @param[in] y Micro-Tesla value from ambient magnetic field on the y-axis - * @param[in] z Micro-Tesla value from ambient magnetic field on the z-axis - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_magnetic_set_cb(). - * @see sensor_magnetic_set_cb() - * @see sensor_magnetic_unset_cb() - */ -typedef void (*sensor_magnetic_event_cb)( unsigned long long timestamp, - sensor_data_accuracy_e accuracy, float x, float y, float z, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a magnetic event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered in (in milliseconds) \n - * If @a interval_ms is zero, it uses default value (100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_magnetic_event_cb() will be invoked. - * - * @see sensor_magnetic_event_cb() - * @see sensor_magnetic_unset_cb() + * @addtogroup CAPI_SYSTEM_SENSOR_UTILITY_MODULE + * @{ */ -int sensor_magnetic_set_cb(sensor_h sensor, int interval_ms, sensor_magnetic_event_cb callback, void *user_data); /** - * @brief Unregister the magnetic callback function. + * @brief Enumeration of the axis used in #sensor_util_remap_coordinate_system. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_magnetic_set_cb() + * @see #sensor_util_remap_coordinate_system */ -int sensor_magnetic_unset_cb(sensor_h sensor); +typedef enum +{ + sensor_util_axis_minus_x, + sensor_util_axis_minus_y, + sensor_util_axis_minus_z, + sensor_util_axis_x, + sensor_util_axis_y, + sensor_util_axis_z, +} sensor_util_axis_e; /** - * @brief change the interval at magnetic sensor measurements. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_magnetic_set_cb() - */ -int sensor_magnetic_set_interval(sensor_h sensor, int interval_ms); + * @brief Gets the Inclination matrix "I" and Rotation matrix "R" transforming a vector from the device coordinate to the world's coordinate. + * + * @details [0 0 g] = R * gravity (g = magnitude of gravity) \n + * [0 m 0] = I * R * geomagnetic (m = magnitude of the geomagnetic field) \n + * R is the identity matrix when the device is aligned with the world's coordinate system, that is, when the device's X axis points towards the East, the Y axis points to the North Pole and the device is facing the sky. \n + * I is a rotation matrix transforming the geomagnetic vector into the same coordinate space as gravity (the world's coordinate space). I is a simple rotation around the X axis. \n + * @since_tizen 2.3 + * + * @remarks Parameters Gx, Gy, and Gz can be obtained from the values returned by #SENSOR_GRAVITY. \n + * Parameters Mx, My, and Mz can be obtained from the values returned by #SENSOR_MAGNETIC. + * Output parameter R and I are always returned as a 3x3 matrix array of 9 floats like this form: + *
+ *          { R[0], R[1], R[2],
+ *            R[3], R[4], R[5],
+ *            R[6], R[7], R[6] }
+ *          
+ * + * + * @param[in] Gx The X-axis gravity vector in the device's coordinate + * @param[in] Gy The Y-axis gravity vector in the device's coordinate + * @param[in] Gz The Z-axis gravity vector in the device's coordinate + * @param[in] Mx The X-axis geomagnetic vector in the device's coordinate + * @param[in] My The Y-axis geomagnetic vector in the device's coordinate + * @param[in] Mz The Z-axis geomagnetic vector in the device's coordinate + * @param[out] R The array of 9 floats that represent the rotation matrix "R" \n + * It can be null. + * @param[out] I The array of 9 floats that represent the inclination matrix "I" \n + * It can be null. + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + */ +int sensor_util_get_rotation_matrix(float Gx, float Gy, float Gz, + float Mx, float My, float Mz, + float R[], float I[]); /** - * @brief Gets sensor data from the magnetic sensor. + * @brief Converts a rotation vector to a rotation matrix. * - * @remark All values are in micro-Teslas (uT) and measure the ambient magnetic field in the X, Y and Z axis. + * @details Rotation vectors (Vx, Vy, Vz) can be obtained from #SENSOR_ROTATION_VECTOR. + * It returns a 9 element rotation matrix in the array R. R must have length as 9. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[out] x Micro-Tesla value on the x-axis - * @param[out] y Micro-Tesla value on the y-axis - * @param[out] z Micro-Tesla value on the z-axis - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). + * @param[in] Vx The X-axis rotation vector + * @param[in] Vy The Y-axis rotation vector + * @param[in] Vz The Z-axis rotation vector + * @param[out] R A 9 element rotation matrix in the array R that must have length as 9 * - * @see sensor_start() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device */ -int sensor_magnetic_read_data(sensor_h sensor, sensor_data_accuracy_e *accuracy, float *x, float *y, float *z); +int sensor_util_get_rotation_matrix_from_vector(float Vx, float Vy, float Vz, float R[]); /** - * @brief Registers a callback function to be invoked when the current sensor reading falls outside of a defined normal range. + * @brief Rotates the supplied rotation matrix so that it is expressed in a different coordinate system. + * + * @details This is typically used when an application needs to compute the three orientation angles of the device in a different coordinate system. + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @remarks inR and outR can be the same array, but this is not recommended for performance reasons. + * This returns an error when X and Y define the same axis. * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * @retval #SENSOR_ERROR_NOT_NEED_CALIBRATION Sensor doesn't need calibration + * @param[in] inR The rotation matrix (3x3) to be transformed + * @param[in] x The world axis and direction on which the X axis of the device is mapped + * @param[in] y The world axis and direction on which the Y axis of the device is mapped + * @param[out] outR The transformed rotation matrix (3x3) * - * @post sensor_calibration_cb() will be invoked. + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device * - * @see sensor_calibration_cb() - * @see sensor_magnetic_unset_calibration_cb() */ -int sensor_magnetic_set_calibration_cb(sensor_h sensor, sensor_calibration_cb callback, void *user_data); +int sensor_util_remap_coordinate_system(float inR[], sensor_util_axis_e x, sensor_util_axis_e y, float outR[]); /** - * @brief Unregisters the magnetic calibration callback function. + * @brief Computes the geomagnetic inclination angle in radians from the inclination matrix I returned by sensor_util_get_rotation_matrix(). + * @since_tizen 2.3 * - * @param[in] sensor The sensor handle + * @param[in] I The inclination matrix from sensor_util_get_rotation_matrix() + * @param[out] inclination The geomagnetic inclination angle in radians * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * @retval #SENSOR_ERROR_NOT_NEED_CALIBRATION Sensor doesn't need calibration - * @see sensor_magnetic_set_calibration_cb() - */ -int sensor_magnetic_unset_calibration_cb(sensor_h sensor); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_ORIENTATION_MODULE - * @{ + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device + * + * @see sensor_util_get_rotation_matrix() */ +int sensor_util_get_inclination(float I[], float* inclination); /** - * @brief Called when an orientation event occurs. - * - * @remark All values are angles in degrees. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] accuracy The accuracy of @a azimuth, @a pitch, and @a roll values - * @param[in] azimuth The angle between the magnetic north direction and the y-axis, around the z-axis [0 ~ 359]. \n - * 0 = North, 90 = East, 180 = South, 270 = West - * @param[in] pitch The rotation around x-axis [-180 ~ 180], with positive values when the z-axis moves \n - * toward the y-axis - * @param[in] roll The rotation around y-axis [-90 ~ 90], with positive values when the x-axis moves \n - * toward the z-axis - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_orientation_set_cb(). - * @see sensor_orientation_set_cb() - * @see sensor_orientation_unset_cb() - */ -typedef void (*sensor_orientation_event_cb)( unsigned long long timestamp, - sensor_data_accuracy_e accuracy, float azimuth, float pitch, float roll, void *user_data); - -/** - * @brief Registers a callback function to be invoked when an orientation event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered in (in milliseconds) \n - * If @a interval_ms is zero, it uses default value (100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @brief Computes the device's orientation based on the rotation matrix. * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + * @details When it returns, the array values are filled with the result: + * - values[0]: azimuth, rotation around the Z axis. + * - values[1]: pitch, rotation around the X axis. + * - values[2]: roll, rotation around the Y axis. + * @since_tizen 2.3 * - * @post sensor_orientation_event_cb() will be invoked. + * @remarks Parameter R must be an array of 9 floats from sensor_util_get_rotation_matrix() \n + * Returned values are always arrays of 3 floats. * - * @see sensor_orientation_event_cb() - * @see sensor_orientation_unset_cb() -*/ -int sensor_orientation_set_cb(sensor_h sensor, int interval_ms, sensor_orientation_event_cb callback, void *user_data); - -/** - * @brief Unregister the orientation callback function. + * @param[in] R A 9 element rotation matrix in the array + * @param[out] values An array of 3 floats to hold the result * - * @param[in] sensor The sensor handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed + * @see sensor_util_get_rotation_matrix() * - * @see sensor_orientation_set_cb() */ -int sensor_orientation_unset_cb(sensor_h sensor); +int sensor_util_get_orientation(float R[], float values[]); /** - * @brief Registers a callback function to be invoked when the current sensor reading falls outside of a defined normal range. + * @brief Computes the angle change between two rotation matrices. * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function + * @details Given a current rotation matrix (R) and a previous rotation matrix (prevR), it computes + * the rotation around the x,y, and z axes which transforms prevR to R. + * It outputs a 3 element vector containing the x,y, and z angle change at indexes 0, 1, and 2 respectively. \n + * @since_tizen 2.3 * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * @retval #SENSOR_ERROR_NOT_NEED_CALIBRATION Sensor doesn't need calibration + * @remarks Each input matrix is a 3x3 matrix like this form: + *
+ *          { R[0], R[1], R[2],
+ *            R[3], R[4], R[5],
+ *            R[6], R[7], R[6] }
+ *          
* - * @post sensor_calibration_cb() will be invoked. + * @param[in] R The current rotation matrix + * @param[in] prevR The previous rotation matrix + * @param[out] angleChange An array of floats in which the angle change is stored * - * @see sensor_orientation_set_calibration_cb() - * @see sensor_orientation_unset_calibration_cb() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device */ -int sensor_orientation_set_calibration_cb(sensor_h sensor, sensor_calibration_cb callback, void *user_data); +int sensor_util_get_angle_change(float R[], float prevR[], float angleChange[]); /** - * @brief Unregister the orientation calibration callback function. - * - * @param[in] sensor The sensor handle + * @brief Gets the declination of the horizontal component of the magnetic field from true north, in degrees. + * @since_tizen 2.3 * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * @retval #SENSOR_ERROR_NOT_NEED_CALIBRATION Sensor doesn't need calibration + * @param[in] latitude The latitude in geodetic coordinates + * @param[in] longitude The longitude in geodetic coordinates + * @param[in] altitude The altitude in geodetic coordinates + * @param[out] declination The declination of the horizontal component of the magnetic field in degrees * - * @see sensor_orientation_set_calibration_cb() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SENSOR_ERROR_NONE Successful + * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SENSOR_ERROR_NOT_SUPPORTED The sensor type is not supported in the current device */ -int sensor_orientation_unset_calibration_cb(sensor_h sensor); - +int sensor_util_get_declination(float latitude, float longitude, float altitude, float* declination); /** - * @brief change the interval at orientation measurements. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_orientation_set_cb() - */ -int sensor_orientation_set_interval(sensor_h sensor, int interval_ms); - -/** - * @brief Gets sensor data from the orientation sensor. - * - * @remark - * All values are angles in degrees. - * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[out] azimuth The angle in degrees between the magnetic north direction and the y-axis, \n - * around the z-axis [0 ~ 359]. 0=North, 90=East, 180=South, 270=West - * @param[out] pitch The rotation in degrees around x-axis [-180 ~ 180], with positive values when the \n - * z-axis moves toward the y-axis - * @param[out] roll The rotation in degrees around y-axis [-90 ~ 90], with positive values when the \n - * x-axis moves toward the z-axis - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). - * @see sensor_start() - */ -int sensor_orientation_read_data(sensor_h sensor, sensor_data_accuracy_e *accuracy, float *azimuth, float *pitch, float *roll); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_GYROSCOPE_MODULE - * @{ - */ - -/** - * @brief Called when a gyroscope event occurs. - * - * @remark - * Measure the rate of rotation around X, Y and Z axis in radians/second values. - * All values is observed by positive value in the counter-clockwise direction. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] accuracy The accuracy of @a x, @a y, and @a z values - * @param[in] x Angular speed around the x-axis in degree per second - * @param[in] y Angular speed around the y-axis in degree per second - * @param[in] z Angular speed around the z-axis in degree per second - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_gyroscope_set_cb(). - * @see sensor_gyroscope_set_cb() - * @see sensor_gyroscope_unset_cb() - */ -typedef void (*sensor_gyroscope_event_cb)( unsigned long long timestamp, - sensor_data_accuracy_e accuracy, float x, float y, float z, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a gyroscope event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered in (in milliseconds) \n - * If @a interval_ms is zero, it uses default value (100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_gyroscope_event_cb() will be invoked - * - * @see sensor_gyroscope_event_cb() - * @see sensor_gyroscope_unset_cb() - */ -int sensor_gyroscope_set_cb(sensor_h sensor, int interval_ms, sensor_gyroscope_event_cb callback, void *user_data); - -/** - * @brief Unregister the gyroscope callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_gyroscope_set_cb() - */ -int sensor_gyroscope_unset_cb(sensor_h sensor); - -/** - * @brief change the interval at gyroscope measurements. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_gyroscope_set_cb() - */ -int sensor_gyroscope_set_interval(sensor_h sensor, int interval_ms); - -/** - * @brief - * Gets sensor data from the gyroscope sensor. - * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[out] x The angular speed around the x-axis in degree per second - * @param[out] y The angular speed around the y-axis in degree per second - * @param[out] z The angular speed around the z-axis in degree per second - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). - * @see sensor_start() - */ -int sensor_gyroscope_read_data(sensor_h sensor, sensor_data_accuracy_e *accuracy, float *x, float *y, float *z); - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_LIGHT_MODULE - * @{ - */ - -/** - * @brief Called when a light event occurs. - * - * @remark - * You should use lux between min and max values obtained \n - * with #sensor_get_spec(). - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] lux The ambient light level in SI lux units \n - * @a lux is between min and max values obtained with #sensor_get_spec().\n - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_light_set_cb(). - * @see sensor_light_set_cb() - * @see sensor_light_unset_cb() - */ -typedef void (*sensor_light_event_cb)( unsigned long long timestamp, float lux, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a light event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered in (in milliseconds) \n - * If @a interval_ms is zero, it uses default value (100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_light_event_cb() will be invoked. - * - * @see sensor_light_event_cb() - * @see sensor_light_unset_cb() - */ -int sensor_light_set_cb(sensor_h sensor, int interval_ms, sensor_light_event_cb callback, void *user_data); - -/** - * @brief Unregister the light callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_light_set_cb() - */ -int sensor_light_unset_cb(sensor_h sensor); - -/** - * @brief change the interval at light sensor measurements. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_light_set_cb() - */ -int sensor_light_set_interval(sensor_h sensor, int interval_ms); - -/** - * @brief Gets sensor data from the light sensor. - * - * @remark - * You should use lux between min and max values obtained \n - * with #sensor_get_spec(). - * - * @param[in] sensor The sensor handle - * @param[out] lux The ambient light level in SI lux units \n - * @a lux is between min and max values obtained with #sensor_get_spec().\n - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @pre In order to read sensor data, an application should call sensor_start(). - * @see #sensor_data_accuracy_e - * @see sensor_start() - */ -int sensor_light_read_data(sensor_h sensor, float *lux); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_PROXIMITY_MODULE - * @{ - */ - -/** - * @brief Called when a proximity event occurs. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] distance The distance measured in centemeters - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_proximity_set_cb(). - * @see sensor_proximity_set_cb() - * @see sensor_proximity_unset_cb() - */ -typedef void (*sensor_proximity_event_cb)( unsigned long long timestamp, float distance, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a proximity event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered in (in milliseconds) \n - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_proximity_event_cb() will be invoked. - * - * @see sensor_proximity_event_cb() - * @see sensor_proximity_unset_cb() - */ -int sensor_proximity_set_cb(sensor_h sensor, int interval_ms, sensor_proximity_event_cb callback, void *user_data); - -/** - * @brief Unregister the proximity callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_proximity_set_cb() - */ -int sensor_proximity_unset_cb(sensor_h sensor); - -/** - * @brief change the interval at proximity measurements. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms in milliseconds. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_proximity_set_cb() - */ -int sensor_proximity_set_interval(sensor_h sensor, int interval_ms); - -/** - * @brief Gets sensor data from the Proximity sensor. - * - * @remark - * All values are angles in degrees. - * - * @param[in] sensor The sensor handle - * @param[out] distance The distance measured in centemeters - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). - * @see sensor_start() - */ -int sensor_proximity_read_data(sensor_h sensor, float *distance); - - -/** - * @} - * - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_MODULE - * @{ - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_SNAP_MODULE - * @{ - */ - -/** - * @brief Called when a snap motion event occurs. - * @image html phone_snap.png - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] snap The type of motion snap - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_snap_set_cb(). - * @see sensor_motion_snap_set_cb() - * @see sensor_motion_snap_unset_cb() - */ -typedef void (*sensor_motion_snap_event_cb) ( unsigned long long timestamp, sensor_motion_snap_e snap, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion snap event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_snap_event_cb() will be invoked. - * - * @see sensor_motion_snap_event_cb() - * @see sensor_motion_snap_unset_cb() - */ -int sensor_motion_snap_set_cb(sensor_h sensor, sensor_motion_snap_event_cb callback, void *user_data); - -/** - * @brief Unregister the snap callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_snap_set_cb() - */ -int sensor_motion_snap_unset_cb(sensor_h sensor); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_SHAKE_MODULE - * @{ - */ - -/** - * @brief Called when a shake motion event occurs. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] shake The type of motion shake - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_shake_set_cb(). - * @see sensor_motion_shake_set_cb() - * @see sensor_motion_shake_unset_cb() - */ -typedef void (*sensor_motion_shake_event_cb) ( unsigned long long timestamp, sensor_motion_shake_e shake, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion shake event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_shake_event_cb() will be invoked. - * - * @see sensor_motion_shake_event_cb() - * @see sensor_motion_shake_unset_cb() - */ -int sensor_motion_shake_set_cb(sensor_h sensor, sensor_motion_shake_event_cb callback, void *user_data); - -/** - * @brief Unregister the callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_shake_set_cb() - */ -int sensor_motion_shake_unset_cb(sensor_h sensor); - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_DOUBLETAP_MODULE - * @{ - */ - -/** - * @brief Called when a double tap motion event occurs. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_doubletap_set_cb(). - * @see sensor_motion_doubletap_set_cb() - * @see sensor_motion_doubletap_unset_cb() - */ -typedef void (*sensor_motion_doubletap_event_cb) ( unsigned long long timestamp, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion doubletap event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_doubletap_event_cb() will be invoked. - * - * @see sensor_motion_doubletap_event_cb() - * @see sensor_motion_doubletap_unset_cb() - */ -int sensor_motion_doubletap_set_cb(sensor_h sensor, sensor_motion_doubletap_event_cb callback, void *user_data); - -/** - * @brief Unregister the doubletap callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_doubletap_set_cb() - */ -int sensor_motion_doubletap_unset_cb(sensor_h sensor); - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_PANNING_MODULE - * @{ - */ - -/** - * @brief Called when a panning motion event occurs. - * @image html phone_panning.png - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] x 1/10 angle on x-axis - * @param[in] y 1/10 angle on y-axis - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_panning_set_cb(). - * @see sensor_motion_panning_set_cb() - * @see sensor_motion_panning_unset_cb() - */ -typedef void (*sensor_motion_panning_event_cb) ( unsigned long long timestamp, int x, int y, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion panning event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_panning_event_cb() will be invoked. - * - * @see sensor_motion_panning_event_cb() - * @see sensor_motion_panning_unset_cb() - */ -int sensor_motion_panning_set_cb(sensor_h sensor, sensor_motion_panning_event_cb callback, void *user_data); - -/** - * @brief Unregister the callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_panning_set_cb() - */ -int sensor_motion_panning_unset_cb(sensor_h sensor); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_PANNING_BROWSE_MODULE - * @{ - */ - -/** - * @brief Called when a panning browse motion event occurs. - * @image html phone_panning.png - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] x 1/10 angle on x-axis - * @param[in] y 1/10 angle on y-axis - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_panning_browse_set_cb(). - * @see sensor_motion_panning_browse_set_cb() - * @see sensor_motion_panning_browse_unset_cb() - */ -typedef void (*sensor_motion_panning_browse_event_cb) ( unsigned long long timestamp, int x, int y, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion panning browse event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_panning_browse_event_cb() will be invoked. - * - * @see sensor_motion_panning_browse_event_cb() - * @see sensor_motion_panning_browse_unset_cb() - */ -int sensor_motion_panning_browse_set_cb(sensor_h sensor, sensor_motion_panning_browse_event_cb callback, void *user_data); - -/** - * @brief Unregister the callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_panning_browse_set_cb() - */ -int sensor_motion_panning_browse_unset_cb(sensor_h sensor); - - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_TILT_MODULE - * @{ - */ - -/** - * @brief Called when a tilt motion event occurs. - * @image html phone_panning.png - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] x 1/10 angle on x-axis - * @param[in] y 1/10 angle on y-axis - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_tilt_set_cb(). - * @see sensor_motion_tilt_set_cb() - * @see sensor_motion_tilt_unset_cb() - */ -typedef void (*sensor_motion_tilt_event_cb) ( unsigned long long timestamp, int x, int y, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion tilt event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_tilt_event_cb() will be invoked. - * - * @see sensor_motion_tilt_event_cb() - * @see sensor_motion_tilt_unset_cb() - */ -int sensor_motion_tilt_set_cb(sensor_h sensor, sensor_motion_tilt_event_cb callback, void *user_data); - -/** - * @brief Unregister the callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_tilt_set_cb() - */ -int sensor_motion_tilt_unset_cb(sensor_h sensor); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_FACEDOWN_MODULE - * @{ - */ - -/** - * @brief Called when a facedown motion event occurs. - * @details - * This event occurs when device is flipped as follows: - * @image html phone_facedown.png - * This motion event will fire only when the device is flipped from face to back. - * It will not occur when the device is flipped from back to face. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_facedown_set_cb(). - * @see sensor_motion_facedown_set_cb() - * @see sensor_motion_facedown_unset_cb() - */ -typedef void (*sensor_motion_facedown_event_cb) ( unsigned long long timestamp, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion facedown event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_facedown_event_cb() will be invoked. - * - * @see sensor_motion_facedown_event_cb() - * @see sensor_motion_facedown_unset_cb() - */ -int sensor_motion_facedown_set_cb(sensor_h sensor, sensor_motion_facedown_event_cb callback, void *user_data); - -/** - * @brief Unregister the facedown callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_facedown_set_cb() - */ - -int sensor_motion_facedown_unset_cb(sensor_h sensor); - -/** - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_DIRECTCALL_MODULE - * @{ - */ - -/** - * @brief Called when a directcall motion event occurs. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_directcall_set_cb(). - * @see sensor_motion_directcall_set_cb() - * @see sensor_motion_directcall_unset_cb() - */ -typedef void (*sensor_motion_directcall_event_cb) ( unsigned long long timestamp, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion directcall event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_directcall_event_cb() will be invoked. - * - * @see sensor_motion_directcall_event_cb() - * @see sensor_motion_directcall_unset_cb() - */ -int sensor_motion_directcall_set_cb(sensor_h sensor, sensor_motion_directcall_event_cb callback, void *user_data); - -/** - * @brief Unregister the directcall callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_directcall_set_cb() - */ -int sensor_motion_directcall_unset_cb(sensor_h sensor); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_SMART_ALERT_MODULE - * @{ - */ - -/** - * @brief Called when a smart alert motion event occurs. - * @details - * This event occurs when device is picked up as follows: - * @image html phone_smart_alert.png - * This motion event will fire only when the device is picked up on desk or etc. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_smart_alert_set_cb(). - * @see sensor_motion_smart_alert_set_cb() - * @see sensor_motion_smart_alert_unset_cb() - */ -typedef void (*sensor_motion_smart_alert_event_cb) ( unsigned long long timestamp, void *user_data); - -/** - * @brief Registers a callback function to be invoked when a motion smart alert event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_smart_alert_event_cb() will be invoked. - * - * @see sensor_motion_smart_alert_event_cb() - * @see sensor_motion_smart_alert_unset_cb() - */ -int sensor_motion_smart_alert_set_cb(sensor_h sensor, sensor_motion_smart_alert_event_cb callback, void *user_data); - -/** - * @brief Unregister the smart alert callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_smart_alert_set_cb() - */ -int sensor_motion_smart_alert_unset_cb(sensor_h sensor); - - -/** - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_MOTION_NO_MOVE_MODULE - * @{ - */ - -/** - * @brief Called when a no move motion event occurs. - * @details - * This event occurs when device doesn't move - * @image html phone_no_move.png - * This motion event will fire only when the device doesn't move at any position during 1 or 2 seconds. - * - * @param[in] timestamp The time in nanosecond at which the event ahppened - * @param[in] user_data The user data passed from the callback registration function - * @pre sensor_start() will invoke this callback if you register this callback using sensor_motion_no_move_set_cb(). - * @see sensor_motion_no_move_set_cb() - * @see sensor_motion_no_move_unset_cb() - */ -typedef void (*sensor_motion_no_move_event_cb) ( unsigned long long timestamp, void *user_data); - - -/** - * @brief Registers a callback function to be invoked when a motion no move event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_motion_no_move_event_cb() will be invoked. - * - * @see sensor_motion_no_move_event_cb() - * @see sensor_motion_no_move_unset_cb() - */ -int sensor_motion_no_move_set_cb(sensor_h sensor, sensor_motion_no_move_event_cb callback, void *user_data); - - -/** - * @brief Unregister the no move callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_motion_no_move_set_cb() - */ -int sensor_motion_no_move_unset_cb(sensor_h sensor); - - -/** - * @} - * - * @} - * - * @addtogroup CAPI_SYSTEM_SENSOR_ROTATION_VECTOR_MODULE - * @{ - */ - -/** - * @brief Called when an rotation vector event occurs. - * @details - * The values of rotation vector represents orientation of the device as a combination of an angle and an axis. - * Each value of the rotation vector is not have unit. the x,y,z axis is same unit as accelerometer. - * - * @param[in] accuracy The accuracy of @a x, @a y, and @a z values - * @param[in] x x*sin(θ/2) - * @param[in] y y*sin(θ/2) - * @param[in] z z*sin(θ/2) - * @param[in] w cos(θ/2) - * @param[in] user_data The user data passed from the callback registration function - * - * @pre sensor_start() will invoke this callback if you register this callback using sensor_rotation_vector_set_cb(). - * - * @see sensor_rotation_vector_set_cb() - * @see sensor_rotation_vector_unset_cb() - */ -typedef void (*sensor_rotation_vector_event_cb)( - sensor_data_accuracy_e accuracy, float x, float y, float z, float w, void *user_data); - -/** - * @brief Registers a callback function to be invoked when an rotation vector event occurs. - * - * @param[in] sensor The sensor handle - * @param[in] interval_ms The interval sensor events are delivered at (in milliseconds) \n - * If @a rate is zero, it uses default value(100ms) - * @param[in] callback The callback function to register - * @param[in] user_data The user data to be passed to the callback function - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @post sensor_accelerometer_event_cb() will be invoked. - * - * @see sensor_accelerometer_event_cb() - * @see sensor_accelerometer_unset_cb() - */ -int sensor_rotation_vector_set_cb(sensor_h sensor, int interval_ms, sensor_rotation_vector_event_cb callback, void* user_data); - -/** - * @brief Unregister the rotation vector callback function. - * - * @param[in] sensor The sensor handle - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * @retval #SENSOR_ERROR_OPERATION_FAILED Operation failed - * - * @see sensor_rotation_vector_set_cb() - */ -int sensor_rotation_vector_unset_cb(sensor_h sensor); - -/** - * @brief Gets sensor data from the rotation vector sensor. - * - * @details - * The rotation vector sensor retrieves quaternion elements . \n - * Last three elements of the quaternion represents rotation vector. \n - * Each axis value of rotation vector is composed of the angle from magnitude equal to sin(θ/2) and the axis. \n - * The value of rotation vector in each axis don't have unit. the axis x,y and z have same unit as the acceleration sensor. - * - * - * - * @param[in] sensor The sensor handle - * @param[out] accuracy The accuracy of this data - * @param[in] x x*sin(θ/2) - * @param[in] y y*sin(θ/2) - * @param[in] z z*sin(θ/2) - * @param[in] w cos(θ/2) - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #SENSOR_ERROR_IO_ERROR I/O error - * - * @pre In order to read sensor data, an application should call sensor_start(). - */ -int sensor_rotation_vector_read_data(sensor_h sensor, sensor_data_accuracy_e* accuracy, float* x, float* y, float* z, float* w); -/** - * @} - */ - - -/** - * @addtogroup CAPI_SYSTEM_SENSOR_UTILITY_MODULE - * @{ - */ - -/** - * @brief Enumerations of Axis used in #sensor_util_remap_coordinate_system - * - * @see #sensor_util_remap_coordinate_system - */ -typedef enum -{ - sensor_util_axis_minus_x, - sensor_util_axis_minus_y, - sensor_util_axis_minus_z, - sensor_util_axis_x, - sensor_util_axis_y, - sensor_util_axis_z, -} sensor_util_axis_e; -/** - * @} - */ - -/** - * @brief - * Getting Inclination matrix "I" and Rotation matrix "R" transforming a vector from the device coordinate to the world's coordinate. - * - * @details - * [0 0 g] = R * gravity (g = magnitude of gravity) \n - * [0 m 0] = I * R * geomagnetic (m = magnitude of geomagnetic field) \n - * R is the identity matrix when the device is aligned with the world's coordinate system, that is, when the device's X axis points toward East, the Y axis points to the North Pole and the device is facing the sky. \n - * I is a rotation matrix transforming the geomagnetic vector into the same coordinate space as gravity (the world's coordinate space). I is a simple rotation around the X axis. \n - * - * @remark - * Parameter Gx, Gy, Gz can be got from the values returned by a #sensor_gravity_event_cb or #sensor_gravity_read_data. \n - * Parameter Mx, My, Mz can be got from the values returned by a #sensor_magnetic_event_cb or #sensor_magnetic_read_data. - * Output parameter R and I is always returned 3x3 matrix array of 9 floats like this form: - *
- * { R[0], R[1], R[2],
- *   R[3], R[4], R[5],
- *   R[6], R[7], R[6] }
- * 
- * - * - * @param[in] Gx X-axis gravity vector in the device's coordinate. - * @param[in] Gy Y-axis gravity vector in the device's coordinate. - * @param[in] Gz Z-axis gravity vector in the device's coordinate. - * @param[in] Mx X-axis geomagnetic vector in the device's coordinate. - * @param[in] My Y-axis geomagnetic vector in the device's coordinate. - * @param[in] Mz Z-axis geomagnetic vector in the device's coordinate. - * @param[out] R Array of 9 floats that represents the rotation matrix "R". It can be null. - * @param[out] I Array of 9 floats that represents the inclination matrix "I". It can be null. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - */ -int sensor_util_get_rotation_matrix(float Gx, float Gy, float Gz, - float Mx, float My, float Mz, - float R[], float I[]); - -/** - * @brief - * Convert a rotation vector to a rotation matrix. - * - * @details - * rotation vectors (Vx, Vy, Vz) can be got from #sensor_rotation_vector_event_cb or #sensor_rotation_vector_read_data. - * It returns a 9 elements rotation matrix in the array R. R must have langth 9. - * - * @param[in] Vx X-axis rotation vector. - * @param[in] Vy Y-axis rotation vector. - * @param[in] Vz Z-axis rotation vector. - * @param[out] R A 9 elements ration matrix in the array R that must have length 9. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * - * @see sensor_util_rotation_matrix3 - * @see sensor_util_rotation_matrix4 - */ -int sensor_util_get_rotation_matrix_from_vector(float Vx, float Vy, float Vz, float R[]); - -/** - * @brief - * Rotates the supplied rotation matrix so it is expressed in a different coordinate system. - * - * @details - * This is typically used when an application needs to compute the three orientation angles of the device in a different coordinate system. - * - * @remark - * inR and outR can be the same array, but it is not recommended for performance reason. - * Return error when X and Y defines the same axis. - * - * @param[in] inR the rotation matrix (3x3) to be transformed. Usually it is the matrix returned by get #sensor_util_rotation_matrix3 or #sensor_util_rotation_matrix4. - * @param[in] x defines on which world axis and direction the X axis of the device is mapped. - * @param[in] y defines on which world axis and direction the Y axis of the device is mapped. - * @param[out] outR the transformed rotation matrix (3x3). - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * - * @see sensor_util_rotation_matrix3 - * @see sensor_util_rotation_matrix4 - * @see sensor_util_rotation_matrix_from_vector - * @see sensor_util_rotation_matrix_from_quaternion - */ -int sensor_util_remap_coordinate_system(float inR[], sensor_util_axis_e x, sensor_util_axis_e y, float outR[]); - -/** - * @brief - * Computes the geomagnetic inclination angle in radians from the inclination matrix I returned by #sensor_util_get_rotation_matrix() - * - * @param[in] I inclination matrix from #sensor_util_get_rotation_matrix() - * @param[out] inclination The geomagnetic inclination angle in radians. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * - * @see sensor_util_get_rotation_matrix() - */ -int sensor_util_get_inclination(float I[], float* inclination); - -/** - * @brief - * Compute the device's orientation based on the rotation matrix - * - * @details - * When it returns, they array values is filled with the result: - * - values[0]: azimuth, rotation around the Z axis. - * - values[1]: pitch, rotation around the X axis. - * - values[2]: roll, rotation around the Y axis. - * - * @remark - * Parameter R must be array of 9 floats from #sensor_util_get_rotation_matrix() \n - * Returned values are always array of 3 floats. - * - * - * @param[in] R A 9 elements ration matrix in the array. - * @param[values] values An array of 3 floats to hold the result. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - * - * @see sensor_util_get_rotation_matrix() - * - */ -int sensor_util_get_orientation(float R[], float values[]); - -/** - * @brief - * Helper function to compute the angle change between two rotation matrices. - * - * @details - * Given a current rotation matrix (R) and a previous rotation matrix (prevR) computes - * the rotation around the x,y, and z axes which transforms prevR to R. - * outputs a 3 element vector containing the x,y, and z angle change at indexes 0, 1, and 2 respectively. \n - * - * @remark - * Each input matrix is 3x3 matrix like this form: - *
- * { R[0], R[1], R[2],
- *   R[3], R[4], R[5],
- *   R[6], R[7], R[6] }
- * 
- * - * @param[in] R current rotation matrix - * @param[in] prevR previous rotation matrix - * @param[out] angleChange an array of floats in which the angle change is stored - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - */ -int sensor_util_get_angle_change(float R[], float prevR[], float angleChange[]); - -/** - * @brief - * Getting the declination of the horizontal component of the magnetic field from true north, in degrees - * - * @param[in] latitude Latitude in geodetic coordinates - * @param[in] longitude Longitude in geodetic coordinates - * @param[in] altitude Altitude in geodetic coordinates - * @param[out] declination The declination of the horizontal component of the magnetic field in degrees. - * - * @return 0 on success, otherwise a negative error value - * @retval #SENSOR_ERROR_NONE Successful - * @retval #SENSOR_ERROR_INVALID_PARAMETER Invalid parameter - */ -int sensor_util_get_declination(float latitude, float longitude, float altitude, float* declination); - -/** - * @brief Determines whether or not to be near from proximity sensor's distance value. - * - * @remark - * This function can be used to determine the proximity to device from other object like human face. - * - * @param[in] distance Distance in centimeter from proximity sensor. - * @param[out] is_near proximity to device from other object. - */ -int sensor_util_is_near(float distance, bool *is_near); - -/** - * @brief Continues to sense even when LCD is off - * - * @param[in] sensor The sensor handle - * @param[out] type The sensor type - */ -int sensor_set_always_on(sensor_h sensor, sensor_type_e type); -/** - * @} - */ - - -/** - * - * @} + * @} */ #ifdef __cplusplus } #endif -#endif - +#endif /* __SENSOR_H__ */ diff --git a/packaging/capi-system-sensor.manifest b/packaging/capi-system-sensor.manifest index 017d22d..41a9320 100644 --- a/packaging/capi-system-sensor.manifest +++ b/packaging/capi-system-sensor.manifest @@ -1,5 +1,6 @@ - - - + + + + diff --git a/packaging/capi-system-sensor.spec b/packaging/capi-system-sensor.spec index ec13df6..3bf5636 100644 --- a/packaging/capi-system-sensor.spec +++ b/packaging/capi-system-sensor.spec @@ -1,57 +1,57 @@ Name: capi-system-sensor Summary: A Sensor library in TIZEN C API -Version: 0.1.17 +Version: 0.1.0 Release: 0 -Group: framework/system -License: Apache-2.0 +Group: System/API +License: Apache 2.0 Source0: %{name}-%{version}.tar.gz -Source1001: capi-system-sensor.manifest +Source1: capi-system-sensor.manifest + BuildRequires: cmake BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(sensor) BuildRequires: pkgconfig(capi-base-common) +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig %description -%{summary} +A Sensor Library in TIZEN C API package. %package devel Summary: A Sensor library in TIZEN C API (Development) -Group: framework/system +Group: System/Development Requires: %{name} = %{version}-%{release} %description devel -%{summary} - +A Sensor library in TIZEN C API package (Development). +%devel_desc %prep %setup -q -cp %{SOURCE1001} . - %build +cp %{SOURCE1} . MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` - -%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER} -DVERSION="%{version}" - -%__make %{?jobs:-j%jobs} - +%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER} +%__make %{?_smp_mflags} %install +rm -rf %{buildroot} %make_install %post -p /sbin/ldconfig %postun -p /sbin/ldconfig - %files -%manifest %{name}.manifest -%license LICENSE +%manifest capi-system-sensor.manifest %{_libdir}/libcapi-system-sensor.so.* +%license LICENSE.APLv2 %files devel -%manifest %{name}.manifest -%license LICENSE -%{_includedir}/system/sensors.h -%{_libdir}/pkgconfig/*.pc +%manifest capi-system-sensor.manifest +%license LICENSE.APLv2 %{_libdir}/libcapi-system-sensor.so +%{_libdir}/pkgconfig/*.pc +%{_includedir}/sensor/*.h + diff --git a/phone_facedown.png b/phone_facedown.png deleted file mode 100755 index 5a28ed3a30ab0d671c00d30807c7e76bda62b81c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26918 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 diff --git a/phone_panning.png b/phone_panning.png deleted file mode 100755 index d6f6f3961970f53b46c20b292543e5fb0cae3794..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29808 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 diff --git a/phone_snap.png b/phone_snap.png deleted file mode 100755 index bc239d5211f7d627b87b2186deaede849422e41c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64576 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 z 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 diff --git a/src/fusion_util.c b/src/fusion_util.cpp similarity index 86% rename from src/fusion_util.c rename to src/fusion_util.cpp index 119bb1e..2dc8f1b 100644 --- a/src/fusion_util.c +++ b/src/fusion_util.cpp @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include #include diff --git a/src/geomanetic_field.c b/src/geomanetic_field.cpp old mode 100755 new mode 100644 similarity index 91% rename from src/geomanetic_field.c rename to src/geomanetic_field.cpp index 7be8ba7..65cd52b --- a/src/geomanetic_field.c +++ b/src/geomanetic_field.cpp @@ -1,274 +1,289 @@ -#include -#include - -const float c[13][13] = { - {0.0, -29496.6, -3594.9, 3350.2, 3992.6, -1818.3, 1051.0, 2158.4, 1226.7, 512.8, -360.9, 1033.3, -1452.4, }, - {4944.4, -1586.3, 5241.4, -7122.5, 4476.4, 3631.5, 1296.8, -2663.8, 543.0, 1197.6, -1532.7, -699.6, -179.4, }, - {-4689.9, -498.9, 1445.0, 2385.6, 652.3, 1539.3, 1135.8, -136.1, -813.2, 369.4, 189.6, -859.0, 238.5, }, - {-490.5, 487.8, -424.2, 501.2, -746.9, -664.0, -1408.7, 927.7, -231.9, -431.5, -181.8, 557.5, 649.2, }, - {1584.9, -826.5, 343.7, -228.6, 66.1, -361.6, -124.4, 171.7, -516.0, 174.8, -23.4, -119.8, -292.1, }, - {453.4, 1451.7, -556.3, 0.0, 70.8, -5.5, 30.7, 64.2, 170.6, -417.8, 184.8, 79.2, 300.6, }, - {-393.2, 659.0, 612.7, -361.8, 7.2, 36.9, -52.3, 4.1, 74.8, -12.2, -12.4, -75.3, -20.8, }, - {-2053.7, -611.1, 133.1, 307.5, 43.2, -67.1, -2.1, 3.2, -35.3, 63.3, 44.1, 19.8, 58.5, }, - {737.3, -1121.6, 492.9, -465.2, 247.7, 48.1, -27.1, 1.1, -2.3, -22.0, 25.4, 41.0, -23.4, }, - {-2611.8, 1249.5, 1062.2, -405.9, -249.3, 139.2, 15.8, -15.8, 4.3, -6.2, -2.7, 0.9, -10.2, }, - {681.2, -21.1, 776.8, 514.2, -532.2, -41.3, -78.2, -16.4, -5.3, -4.9, -1.7, 1.9, 1.9, }, - {93.3, 695.4, -196.8, -431.1, 142.6, -37.6, -124.0, -29.6, -18.5, -5.2, -1.0, 2.2, -2.2, }, - {-807.3, 238.5, 1363.4, -1217.3, 167.0, 125.0, 0.0, 5.9, 7.7, -8.5, -0.6, 0.5, 0.0, }}; - - -const float cd[13][13] = { - {0.0, 11.6, -18.1, 1.0, -7.9, -7.9, -2.9, 2.7, -5.0, 0.0, 0.0, 0.0, 0.0, }, - {-25.9, 16.5, -7.6, -12.6, 12.7, 6.1, -3.8, -3.5, 6.7, -12.7, 0.0, 0.0, 0.0, }, - {-39.0, -10.2, 1.6, -5.6, -34.0, -13.8, -1.5, -17.4, -33.6, 0.0, -21.1, 0.0, 79.5, }, - {22.4, -7.6, -2.1, -6.1, 9.6, -4.7, 19.9, 26.6, 8.3, 24.9, 33.1, 32.8, 64.9, }, - {6.1, 10.6, 8.2, -0.6, -1.6, 2.0, -9.3, 4.9, -5.3, -22.6, 0.0, 0.0, -48.7, }, - {4.1, 13.8, 5.6, 8.9, -0.4, 0.7, -0.7, 1.9, 4.4, -10.1, -7.4, 0.0, 0.0, }, - {-3.8, -31.4, -4.0, -3.3, 1.2, 0.6, 1.1, -1.7, 2.1, 1.7, -8.3, 0.0, 0.0, }, - {24.8, 8.7, -2.0, -1.2, -4.9, -0.7, 0.2, 0.4, -1.5, -0.8, 0.0, 0.0, 0.0, }, - {-6.7, 11.2, 16.6, 10.7, 1.5, -0.7, 1.0, 0.2, 0.1, -1.0, -0.8, 0.0, 0.0, }, - {0.0, -21.7, 0.0, -5.6, 3.4, 0.0, -1.5, 0.8, 0.1, -0.1, -0.5, 0.0, 0.0, }, - {24.3, -21.1, 0.0, -11.7, -7.4, 0.0, -2.0, -1.6, 0.0, -0.1, -0.1, -0.3, 0.0, }, - {0.0, 40.9, 0.0, 24.0, 0.0, 9.4, 0.0, -2.3, -0.9, 0.0, -0.1, 0.0, -0.3, }, - {0.0, 0.0, 0.0, 0.0, 0.0, 20.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, }}; - -float g_declination = 0; -float g_inclination = 0; - -static void E0000(int IENTRY, int maxdeg, float alt,float glat,float glon, float time, float *dec, float *dip, float *ti, float *gv); - -int getDeclination(float *decl) -{ - if(decl == NULL) - return -1; - - *decl = g_declination; - - return 0; -} - -int getInclination(float *incl) -{ - if(incl == NULL) - return -1; - - *incl = g_inclination; - - return 0; -} - -int setCoordinate(float latitude, float longitude, float altitude, float *declination, float *inclination, int option) -{ - float dec, dip, ti, gv; - float h; - float rTd=0.017453292; - - E0000(0,12,0.0,0.0,0.0,0.0,NULL,NULL,NULL,NULL); - E0000(1,0,altitude,latitude,longitude,2,&dec,&dip,&ti,&gv); - - h=ti*(cos((dip*rTd))); - - /* deal with geographic and magnetic poles */ - - if (h < 100.0) /* at magnetic poles */ - { - dec = 0; - } - - if(option == 1) - { - if(declination != NULL) - *declination = dec; - if(inclination != NULL) - *inclination = dip; - } - else if( option == 0) - { - g_declination = dec; - g_inclination = dip; - } - - return 0; -} -/*************************************************************************/ - -static void E0000(int IENTRY, int maxdeg, float alt, float glat, float glon, float time, float *dec, float *dip, float *ti, float *gv) -{ - static int maxord,n,m,j,D1,D2,D3,D4; - static float tc[13][13],dp[13][13],snorm[169], - sp[13],cp[13],fn[13],fm[13],pp[13],k[13][13],pi,dtr,a,b,re, - a2,b2,c2,a4,b4,c4,flnmj,otime,oalt, - olat,olon,dt,rlon,rlat,srlon,srlat,crlon,crlat,srlat2, - crlat2,q,q1,q2,ct,st,r2,r,d,ca,sa,aor,ar,br,bt,bp,bpp, - par,temp1,temp2,parp,bx,by,bz,bh; - static float *p = snorm; - - switch(IENTRY){case 0: goto GEOMAG; case 1: goto GEOMG1;} - -GEOMAG: - maxord = 12; - sp[0] = 0.0; - cp[0] = *p = pp[0] = 1.0; - dp[0][0] = 0.0; - a = 6378.137; - b = 6356.7523142; - re = 6371.2; - a2 = a*a; - b2 = b*b; - c2 = a2-b2; - a4 = a2*a2; - b4 = b2*b2; - c4 = a4 - b4; - - *snorm = 1.0; - fm[0] = 0.0; - for (n=1; n<=maxord; n++) - { - *(snorm+n) = *(snorm+n-1)*(float)(2*n-1)/(float)n; - j = 2; - for (m=0,D1=1,D2=(n-m+D1)/D1; D2>0; D2--,m+=D1) - { - k[m][n] = (float)(((n-1)*(n-1))-(m*m))/(float)((2*n-1)*(2*n-3)); - if (m > 0) - { - flnmj = (float)((n-m+1)*j)/(float)(n+m); - *(snorm+n+m*13) = *(snorm+n+(m-1)*13)*sqrt(flnmj); - j = 1; - } - } - fn[n] = (float)(n+1); - fm[n] = (float)n; - } - k[1][1] = 0.0; - - otime = oalt = olat = olon = -1000.0; - - return; - - /*************************************************************************/ - -GEOMG1: - - dt = time; - pi = 3.14159265359; - dtr = pi/180.0; - rlon = glon*dtr; - rlat = glat*dtr; - srlon = sin(rlon); - srlat = sin(rlat); - crlon = cos(rlon); - crlat = cos(rlat); - srlat2 = srlat*srlat; - crlat2 = crlat*crlat; - sp[1] = srlon; - cp[1] = crlon; - - if (alt != oalt || glat != olat) - { - q = sqrt(a2-c2*srlat2); - q1 = alt*q; - q2 = ((q1+a2)/(q1+b2))*((q1+a2)/(q1+b2)); - ct = srlat/sqrt(q2*crlat2+srlat2); - st = sqrt(1.0-(ct*ct)); - r2 = (alt*alt)+2.0*q1+(a4-c4*srlat2)/(q*q); - r = sqrt(r2); - d = sqrt(a2*crlat2+b2*srlat2); - ca = (alt+d)/r; - sa = c2*crlat*srlat/(r*d); - } - if (glon != olon) - { - for (m=2; m<=maxord; m++) - { - sp[m] = sp[1]*cp[m-1]+cp[1]*sp[m-1]; - cp[m] = cp[1]*cp[m-1]-sp[1]*sp[m-1]; - } - } - aor = re/r; - ar = aor*aor; - br = bt = bp = bpp = 0.0; - for (n=1; n<=maxord; n++) - { - ar = ar*aor; - for (m=0,D3=1,D4=(n+m+D3)/D3; D4>0; D4--,m+=D3) - { - if (alt != oalt || glat != olat) - { - if (n == m) - { - *(p+n+m*13) = st**(p+n-1+(m-1)*13); - dp[m][n] = st*dp[m-1][n-1]+ct**(p+n-1+(m-1)*13); - goto S50; - } - if (n == 1 && m == 0) - { - *(p+n+m*13) = ct**(p+n-1+m*13); - dp[m][n] = ct*dp[m][n-1]-st**(p+n-1+m*13); - goto S50; - } - if (n > 1 && n != m) - { - if (m > n-2) *(p+n-2+m*13) = 0.0; - if (m > n-2) dp[m][n-2] = 0.0; - *(p+n+m*13) = ct**(p+n-1+m*13)-k[m][n]**(p+n-2+m*13); - dp[m][n] = ct*dp[m][n-1] - st**(p+n-1+m*13)-k[m][n]*dp[m][n-2]; - } - } -S50: - if (time != otime) - { - tc[m][n] = c[m][n]+dt*cd[m][n]; - if (m != 0) tc[n][m-1] = c[n][m-1]+dt*cd[n][m-1]; - } - - par = ar**(p+n+m*13); - if (m == 0) - { - temp1 = tc[m][n]*cp[m]; - temp2 = tc[m][n]*sp[m]; - } - else - { - temp1 = tc[m][n]*cp[m]+tc[n][m-1]*sp[m]; - temp2 = tc[m][n]*sp[m]-tc[n][m-1]*cp[m]; - } - bt = bt-ar*temp1*dp[m][n]; - bp += (fm[m]*temp2*par); - br += (fn[n]*temp1*par); - - if (st == 0.0 && m == 1) - { - if (n == 1) pp[n] = pp[n-1]; - else pp[n] = ct*pp[n-1]-k[m][n]*pp[n-2]; - parp = ar*pp[n]; - bpp += (fm[m]*temp2*parp); - } - } - } - if (st == 0.0) bp = bpp; - else bp /= st; - - bx = -bt*ca-br*sa; - by = bp; - bz = bt*sa-br*ca; - bh = sqrt((bx*bx)+(by*by)); - *ti = sqrt((bh*bh)+(bz*bz)); - *dec = atan2(by,bx)/dtr; - *dip = atan2(bz,bh)/dtr; - *gv = -999.0; - if (fabs(glat) >= 55.) - { - if (glat > 0.0 && glon >= 0.0) *gv = *dec-glon; - if (glat > 0.0 && glon < 0.0) *gv = *dec+fabs(glon); - if (glat < 0.0 && glon >= 0.0) *gv = *dec+glon; - if (glat < 0.0 && glon < 0.0) *gv = *dec-fabs(glon); - if (*gv > +180.0) *gv -= 360.0; - if (*gv < -180.0) *gv += 360.0; - } - otime = time; - oalt = alt; - olat = glat; - olon = glon; - return; -} - +/* + * This file is part of WMM source code. + * The original code is the WMM Source from National Oceanic And Atmospheric. + * + * See the license below for more details. + * + * The WMM source code is in the public domain and not licensed or under + * copyright. The information and software may be used freely by the public. + * As required by 17 U.S.C. 403, third parties producing copyrighted works + * consisting predominantly of the material produced by U.S. + * government agencies must provide notice with such work identifying the U.S. + * Government material incorporated and stating that such material is not + * subject to copyright protection. + */ + +#include +#include + +const float c[13][13] = { + {0.0, -29496.6, -3594.9, 3350.2, 3992.6, -1818.3, 1051.0, 2158.4, 1226.7, 512.8, -360.9, 1033.3, -1452.4, }, + {4944.4, -1586.3, 5241.4, -7122.5, 4476.4, 3631.5, 1296.8, -2663.8, 543.0, 1197.6, -1532.7, -699.6, -179.4, }, + {-4689.9, -498.9, 1445.0, 2385.6, 652.3, 1539.3, 1135.8, -136.1, -813.2, 369.4, 189.6, -859.0, 238.5, }, + {-490.5, 487.8, -424.2, 501.2, -746.9, -664.0, -1408.7, 927.7, -231.9, -431.5, -181.8, 557.5, 649.2, }, + {1584.9, -826.5, 343.7, -228.6, 66.1, -361.6, -124.4, 171.7, -516.0, 174.8, -23.4, -119.8, -292.1, }, + {453.4, 1451.7, -556.3, 0.0, 70.8, -5.5, 30.7, 64.2, 170.6, -417.8, 184.8, 79.2, 300.6, }, + {-393.2, 659.0, 612.7, -361.8, 7.2, 36.9, -52.3, 4.1, 74.8, -12.2, -12.4, -75.3, -20.8, }, + {-2053.7, -611.1, 133.1, 307.5, 43.2, -67.1, -2.1, 3.2, -35.3, 63.3, 44.1, 19.8, 58.5, }, + {737.3, -1121.6, 492.9, -465.2, 247.7, 48.1, -27.1, 1.1, -2.3, -22.0, 25.4, 41.0, -23.4, }, + {-2611.8, 1249.5, 1062.2, -405.9, -249.3, 139.2, 15.8, -15.8, 4.3, -6.2, -2.7, 0.9, -10.2, }, + {681.2, -21.1, 776.8, 514.2, -532.2, -41.3, -78.2, -16.4, -5.3, -4.9, -1.7, 1.9, 1.9, }, + {93.3, 695.4, -196.8, -431.1, 142.6, -37.6, -124.0, -29.6, -18.5, -5.2, -1.0, 2.2, -2.2, }, + {-807.3, 238.5, 1363.4, -1217.3, 167.0, 125.0, 0.0, 5.9, 7.7, -8.5, -0.6, 0.5, 0.0, }}; + + +const float cd[13][13] = { + {0.0, 11.6, -18.1, 1.0, -7.9, -7.9, -2.9, 2.7, -5.0, 0.0, 0.0, 0.0, 0.0, }, + {-25.9, 16.5, -7.6, -12.6, 12.7, 6.1, -3.8, -3.5, 6.7, -12.7, 0.0, 0.0, 0.0, }, + {-39.0, -10.2, 1.6, -5.6, -34.0, -13.8, -1.5, -17.4, -33.6, 0.0, -21.1, 0.0, 79.5, }, + {22.4, -7.6, -2.1, -6.1, 9.6, -4.7, 19.9, 26.6, 8.3, 24.9, 33.1, 32.8, 64.9, }, + {6.1, 10.6, 8.2, -0.6, -1.6, 2.0, -9.3, 4.9, -5.3, -22.6, 0.0, 0.0, -48.7, }, + {4.1, 13.8, 5.6, 8.9, -0.4, 0.7, -0.7, 1.9, 4.4, -10.1, -7.4, 0.0, 0.0, }, + {-3.8, -31.4, -4.0, -3.3, 1.2, 0.6, 1.1, -1.7, 2.1, 1.7, -8.3, 0.0, 0.0, }, + {24.8, 8.7, -2.0, -1.2, -4.9, -0.7, 0.2, 0.4, -1.5, -0.8, 0.0, 0.0, 0.0, }, + {-6.7, 11.2, 16.6, 10.7, 1.5, -0.7, 1.0, 0.2, 0.1, -1.0, -0.8, 0.0, 0.0, }, + {0.0, -21.7, 0.0, -5.6, 3.4, 0.0, -1.5, 0.8, 0.1, -0.1, -0.5, 0.0, 0.0, }, + {24.3, -21.1, 0.0, -11.7, -7.4, 0.0, -2.0, -1.6, 0.0, -0.1, -0.1, -0.3, 0.0, }, + {0.0, 40.9, 0.0, 24.0, 0.0, 9.4, 0.0, -2.3, -0.9, 0.0, -0.1, 0.0, -0.3, }, + {0.0, 0.0, 0.0, 0.0, 0.0, 20.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, }}; + +float g_declination = 0; +float g_inclination = 0; + +static void E0000(int IENTRY, int maxdeg, float alt,float glat,float glon, float time, float *dec, float *dip, float *ti, float *gv); + +int getDeclination(float *decl) +{ + if(decl == NULL) + return -1; + + *decl = g_declination; + + return 0; +} + +int getInclination(float *incl) +{ + if(incl == NULL) + return -1; + + *incl = g_inclination; + + return 0; +} + +int setCoordinate(float latitude, float longitude, float altitude, float *declination, float *inclination, int option) +{ + float dec, dip, ti, gv; + float h; + float rTd=0.017453292; + + E0000(0,12,0.0,0.0,0.0,0.0,NULL,NULL,NULL,NULL); + E0000(1,0,altitude,latitude,longitude,2,&dec,&dip,&ti,&gv); + + h=ti*(cos((dip*rTd))); + + /* deal with geographic and magnetic poles */ + + if (h < 100.0) /* at magnetic poles */ + { + dec = 0; + } + + if(option == 1) + { + if(declination != NULL) + *declination = dec; + if(inclination != NULL) + *inclination = dip; + } + else if( option == 0) + { + g_declination = dec; + g_inclination = dip; + } + + return 0; +} +/*************************************************************************/ + +static void E0000(int IENTRY, int maxdeg, float alt, float glat, float glon, float time, float *dec, float *dip, float *ti, float *gv) +{ + static int maxord,n,m,j,D1,D2,D3,D4; + static float tc[13][13],dp[13][13],snorm[169], + sp[13],cp[13],fn[13],fm[13],pp[13],k[13][13],pi,dtr,a,b,re, + a2,b2,c2,a4,b4,c4,flnmj,otime,oalt, + olat,olon,dt,rlon,rlat,srlon,srlat,crlon,crlat,srlat2, + crlat2,q,q1,q2,ct,st,r2,r,d,ca,sa,aor,ar,br,bt,bp,bpp, + par,temp1,temp2,parp,bx,by,bz,bh; + static float *p = snorm; + + switch(IENTRY){case 0: goto GEOMAG; case 1: goto GEOMG1;} + +GEOMAG: + maxord = 12; + sp[0] = 0.0; + cp[0] = *p = pp[0] = 1.0; + dp[0][0] = 0.0; + a = 6378.137; + b = 6356.7523142; + re = 6371.2; + a2 = a*a; + b2 = b*b; + c2 = a2-b2; + a4 = a2*a2; + b4 = b2*b2; + c4 = a4 - b4; + + *snorm = 1.0; + fm[0] = 0.0; + for (n=1; n<=maxord; n++) + { + *(snorm+n) = *(snorm+n-1)*(float)(2*n-1)/(float)n; + j = 2; + for (m=0,D1=1,D2=(n-m+D1)/D1; D2>0; D2--,m+=D1) + { + k[m][n] = (float)(((n-1)*(n-1))-(m*m))/(float)((2*n-1)*(2*n-3)); + if (m > 0) + { + flnmj = (float)((n-m+1)*j)/(float)(n+m); + *(snorm+n+m*13) = *(snorm+n+(m-1)*13)*sqrt(flnmj); + j = 1; + } + } + fn[n] = (float)(n+1); + fm[n] = (float)n; + } + k[1][1] = 0.0; + + otime = oalt = olat = olon = -1000.0; + + return; + + /*************************************************************************/ + +GEOMG1: + + dt = time; + pi = 3.14159265359; + dtr = pi/180.0; + rlon = glon*dtr; + rlat = glat*dtr; + srlon = sin(rlon); + srlat = sin(rlat); + crlon = cos(rlon); + crlat = cos(rlat); + srlat2 = srlat*srlat; + crlat2 = crlat*crlat; + sp[1] = srlon; + cp[1] = crlon; + + if (alt != oalt || glat != olat) + { + q = sqrt(a2-c2*srlat2); + q1 = alt*q; + q2 = ((q1+a2)/(q1+b2))*((q1+a2)/(q1+b2)); + ct = srlat/sqrt(q2*crlat2+srlat2); + st = sqrt(1.0-(ct*ct)); + r2 = (alt*alt)+2.0*q1+(a4-c4*srlat2)/(q*q); + r = sqrt(r2); + d = sqrt(a2*crlat2+b2*srlat2); + ca = (alt+d)/r; + sa = c2*crlat*srlat/(r*d); + } + if (glon != olon) + { + for (m=2; m<=maxord; m++) + { + sp[m] = sp[1]*cp[m-1]+cp[1]*sp[m-1]; + cp[m] = cp[1]*cp[m-1]-sp[1]*sp[m-1]; + } + } + aor = re/r; + ar = aor*aor; + br = bt = bp = bpp = 0.0; + for (n=1; n<=maxord; n++) + { + ar = ar*aor; + for (m=0,D3=1,D4=(n+m+D3)/D3; D4>0; D4--,m+=D3) + { + if (alt != oalt || glat != olat) + { + if (n == m) + { + *(p+n+m*13) = st**(p+n-1+(m-1)*13); + dp[m][n] = st*dp[m-1][n-1]+ct**(p+n-1+(m-1)*13); + goto S50; + } + if (n == 1 && m == 0) + { + *(p+n+m*13) = ct**(p+n-1+m*13); + dp[m][n] = ct*dp[m][n-1]-st**(p+n-1+m*13); + goto S50; + } + if (n > 1 && n != m) + { + if (m > n-2) *(p+n-2+m*13) = 0.0; + if (m > n-2) dp[m][n-2] = 0.0; + *(p+n+m*13) = ct**(p+n-1+m*13)-k[m][n]**(p+n-2+m*13); + dp[m][n] = ct*dp[m][n-1] - st**(p+n-1+m*13)-k[m][n]*dp[m][n-2]; + } + } +S50: + if (time != otime) + { + tc[m][n] = c[m][n]+dt*cd[m][n]; + if (m != 0) tc[n][m-1] = c[n][m-1]+dt*cd[n][m-1]; + } + + par = ar**(p+n+m*13); + if (m == 0) + { + temp1 = tc[m][n]*cp[m]; + temp2 = tc[m][n]*sp[m]; + } + else + { + temp1 = tc[m][n]*cp[m]+tc[n][m-1]*sp[m]; + temp2 = tc[m][n]*sp[m]-tc[n][m-1]*cp[m]; + } + bt = bt-ar*temp1*dp[m][n]; + bp += (fm[m]*temp2*par); + br += (fn[n]*temp1*par); + + if (st == 0.0 && m == 1) + { + if (n == 1) pp[n] = pp[n-1]; + else pp[n] = ct*pp[n-1]-k[m][n]*pp[n-2]; + parp = ar*pp[n]; + bpp += (fm[m]*temp2*parp); + } + } + } + if (st == 0.0) bp = bpp; + else bp /= st; + + bx = -bt*ca-br*sa; + by = bp; + bz = bt*sa-br*ca; + bh = sqrt((bx*bx)+(by*by)); + *ti = sqrt((bh*bh)+(bz*bz)); + *dec = atan2(by,bx)/dtr; + *dip = atan2(bz,bh)/dtr; + *gv = -999.0; + if (fabs(glat) >= 55.) + { + if (glat > 0.0 && glon >= 0.0) *gv = *dec-glon; + if (glat > 0.0 && glon < 0.0) *gv = *dec+fabs(glon); + if (glat < 0.0 && glon >= 0.0) *gv = *dec+glon; + if (glat < 0.0 && glon < 0.0) *gv = *dec-fabs(glon); + if (*gv > +180.0) *gv -= 360.0; + if (*gv < -180.0) *gv += 360.0; + } + otime = time; + oalt = alt; + olat = glat; + olon = glon; + return; +} + diff --git a/src/sensor.c b/src/sensor.c deleted file mode 100644 index 5133938..0000000 --- a/src/sensor.c +++ /dev/null @@ -1,1517 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _DEBUG 1 - -#ifdef _DEBUG -#undef LOG_TAG -#define LOG_TAG "TIZEN_SYSTEM_SENSOR" -#include -#include -static char* _DONT_USE_THIS_ARRAY_DIRECTLY[] = { - "ACCELEROMETER", - "GRAVITY", - "LINEAR_ACCELERATION", - "DEVICE_ORIENTATION", - "MAGNETIC", - "ORIENTATION", - "GYROSCOPE", - "LIGHT", - "PROXIMITY", - "MOTION_SNAP", - "MOTION_SHAKE", - "MOTION_DOUBLETAP", - "MOTION_PANNING", - "MOTION_PANNING_BROWSE", - "MOTION_TILT", - "MOTION_FACEDOWN", - "MOTION_DIRECTCALL", - "MOTION_SMART_ALERT", - "MOTION_NO_MOVE", - "LAST" -}; - -#define _MSG_SENSOR_ERROR_IO_ERROR "Io Error" -#define _MSG_SENSOR_ERROR_INVALID_PARAMETER "Invalid Parameter" -#define _MSG_SENSOR_ERROR_OUT_OF_MEMORY "Out of Memory" -#define _MSG_SENSOR_ERROR_NOT_NEED_CALIBRATION "Not need calibration" -#define _MSG_SENSOR_ERROR_NOT_SUPPORTED "Not supported" -#define _MSG_SENSOR_ERROR_OPERATION_FAILED "Operation failed" - -#define TYPE_NAME(type) _DONT_USE_THIS_ARRAY_DIRECTLY[type] - -#define DEBUG_PRINT(txt) LOGD("%s : " txt, __FUNCTION__) -#define DEBUG_PRINTF(fmt, ...) LOGD("%s : " fmt, __FUNCTION__, __VA_ARGS__) -#define ERROR_PRINT(err) LOGD("[%s]" _MSG_##err "(0x%08x)", __FUNCTION__, err) -#define ERROR_PRINTF(err, fmt, ...) LOGD("[%s]" _MSG_##err "(0x%08x) : " fmt, __FUNCTION__, err, __VA_ARGS__) -#else -#define TYPE_NAME(type) "" -#define DEBUG_PRINT(txt) -#define DEBUG_PRINTF(fmt, ...) -#define ERROR_PRINT(err) -#define ERROR_PRINTF(err) -#endif - -#define RETURN_VAL_IF(expr, err) \ - do { \ - if (expr) { \ - ERROR_PRINT(err); \ - return (err); \ - } \ - } while(0) - -#define RETURN_ERROR(err) \ - do { \ - ERROR_PRINT(err); \ - return err; \ - } while(0) - - -#define RETURN_IF_NOT_HANDLE(handle) \ - RETURN_VAL_IF(handle == NULL, SENSOR_ERROR_INVALID_PARAMETER) - -#define RETURN_IF_NOT_TYPE(type) \ - RETURN_VAL_IF(type >= SENSOR_LAST || type < 0, SENSOR_ERROR_INVALID_PARAMETER) - -#define RETURN_IF_MOTION_TYPE(type) \ - RETURN_VAL_IF(type >= SENSOR_MOTION_SNAP && type <= SENSOR_MOTION_NO_MOVE, SENSOR_ERROR_INVALID_PARAMETER) - -#define RETURN_IF_NOT_WAKEUP_TYPE(type) \ - RETURN_VAL_IF(type > SENSOR_DEVICE_ORIENTATION, SENSOR_ERROR_NOT_SUPPORTED) - -#define RETURN_IF_ERROR(val) \ - RETURN_VAL_IF(val < 0, val) - -#define MICROSECONDS(tv) ((tv.tv_sec * 1000000ll) + tv.tv_usec) - -sensor_data_accuracy_e _accu_table[] = { - SENSOR_ACCURACY_UNDEFINED, - SENSOR_ACCURACY_BAD, - SENSOR_ACCURACY_NORMAL, - SENSOR_ACCURACY_GOOD, - SENSOR_ACCURACY_VERYGOOD, -}; - -sensor_type_t _TYPE[] = { - ACCELEROMETER_SENSOR, - ACCELEROMETER_SENSOR, - ACCELEROMETER_SENSOR, - ACCELEROMETER_SENSOR, - GEOMAGNETIC_SENSOR, - GEOMAGNETIC_SENSOR, - GYROSCOPE_SENSOR, - LIGHT_SENSOR, - PROXIMITY_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, -}; - -int _DTYPE[] = { - ACCELEROMETER_BASE_DATA_SET, - ACCELEROMETER_GRAVITY_DATA_SET, - ACCELEROMETER_LINEAR_ACCELERATION_DATA_SET, - ACCELEROMETER_ORIENTATION_DATA_SET, - GEOMAGNETIC_RAW_DATA_SET, - GEOMAGNETIC_BASE_DATA_SET, - GYRO_BASE_DATA_SET, - LIGHT_LUX_DATA_SET, - PROXIMITY_DISTANCE_DATA_SET, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, - MOTION_SENSOR, -}; - -int _EVENT[] = { - ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME, - ACCELEROMETER_EVENT_GRAVITY_DATA_REPORT_ON_TIME, - ACCELEROMETER_EVENT_LINEAR_ACCELERATION_DATA_REPORT_ON_TIME, - ACCELEROMETER_EVENT_ORIENTATION_DATA_REPORT_ON_TIME, - GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME, - GEOMAGNETIC_EVENT_ATTITUDE_DATA_REPORT_ON_TIME, - GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME, - LIGHT_EVENT_LUX_DATA_REPORT_ON_TIME, - PROXIMITY_EVENT_DISTANCE_DATA_REPORT_ON_TIME, - MOTION_ENGINE_EVENT_SNAP, - MOTION_ENGINE_EVENT_SHAKE, - MOTION_ENGINE_EVENT_DOUBLETAP, - MOTION_ENGINE_EVENT_PANNING, - MOTION_ENGINE_EVENT_PANNING_BROWSE, - MOTION_ENGINE_EVENT_TILT, - MOTION_ENGINE_EVENT_TOP_TO_BOTTOM, - MOTION_ENGINE_EVENT_DIRECT_CALL, - MOTION_ENGINE_EVENT_SMART_ALERT, - MOTION_ENGINE_EVENT_NO_MOVE, -}; - -int _CALIBRATION[] = { - ACCELEROMETER_EVENT_CALIBRATION_NEEDED, - ACCELEROMETER_EVENT_CALIBRATION_NEEDED, - ACCELEROMETER_EVENT_CALIBRATION_NEEDED, - ACCELEROMETER_EVENT_CALIBRATION_NEEDED, - GEOMAGNETIC_EVENT_CALIBRATION_NEEDED, - GEOMAGNETIC_EVENT_CALIBRATION_NEEDED, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, -}; - - -int _WAKEUP[] = { - ACCELEROMETER_EVENT_SET_WAKEUP, - ACCELEROMETER_EVENT_SET_WAKEUP, - ACCELEROMETER_EVENT_SET_WAKEUP, - ACCELEROMETER_EVENT_SET_WAKEUP, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, - EMPTY_EVENT, -}; - -int _sensor_ids[] = { - ID_ACCELEOMETER, - ID_ACCELEOMETER, - ID_ACCELEOMETER, - ID_ACCELEOMETER, - ID_GEOMAGNETIC, - ID_GEOMAGNETIC, - ID_GYROSCOPE, - ID_LIGHT, - ID_PROXIMITY, - ID_MOTION, - ID_MOTION, - ID_MOTION, - ID_MOTION, - ID_MOTION, - ID_MOTION, - ID_MOTION, - ID_MOTION, - ID_MOTION, - ID_MOTION -}; - - - -#define _SID(id) (_sensor_ids[id]) -#define _ACCU(accuracy) (_accu_table[accuracy + 1]) - -static int _sensor_connect(sensor_h handle, sensor_type_e type) -{ - int id = 0; - bool support = true; - - RETURN_IF_NOT_TYPE(type); - - if(handle->ids[_SID(type)] < 0){ - sensor_is_supported(type, &support); - if(!support) - return SENSOR_ERROR_NOT_SUPPORTED; - - id = sf_connect(_TYPE[type]); - - DEBUG_PRINTF("%s sensor connect legacy=[%d] type=[%d]", TYPE_NAME(type), type, _TYPE[type]); - if(id < 0){ - return id == -2 ? SENSOR_ERROR_IO_ERROR : SENSOR_ERROR_OPERATION_FAILED; - } - DEBUG_PRINTF("%s sensor id created [%d]", TYPE_NAME(type), id); - handle->ids[_SID(type)] = id; - } - return SENSOR_ERROR_NONE; -} - -static void _sensor_callback (unsigned int event_type, sensor_event_data_t* event, void* udata) -{ - int i = 0; - int data_num = 0; - sensor_data_t *data = NULL; - sensor_panning_data_t *panning_data = NULL; - int motion = 0; - int nid = 0; - - struct timeval sv; - unsigned long long motion_time_stamp = 0; - - sensor_h sensor = (sensor_h)udata; - - switch(event_type) - { - case MOTION_ENGINE_EVENT_SNAP: - nid = SENSOR_MOTION_SNAP; - break; - case MOTION_ENGINE_EVENT_SHAKE: - nid = SENSOR_MOTION_SHAKE; - break; - case MOTION_ENGINE_EVENT_DOUBLETAP: - nid = SENSOR_MOTION_DOUBLETAP; - break; - case MOTION_ENGINE_EVENT_PANNING: - nid = SENSOR_MOTION_PANNING; - break; - case MOTION_ENGINE_EVENT_TILT: - nid = SENSOR_MOTION_TILT; - break; - case MOTION_ENGINE_EVENT_PANNING_BROWSE: - nid = SENSOR_MOTION_PANNING_BROWSE; - break; - case MOTION_ENGINE_EVENT_TOP_TO_BOTTOM: - nid = SENSOR_MOTION_FACEDOWN; - break; - case MOTION_ENGINE_EVENT_DIRECT_CALL: - nid = SENSOR_MOTION_DIRECTCALL; - break; - case MOTION_ENGINE_EVENT_SMART_ALERT: - nid = SENSOR_MOTION_SMART_ALERT; - break; - case MOTION_ENGINE_EVENT_NO_MOVE: - nid = SENSOR_MOTION_NO_MOVE; - break; - case ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME : - nid = SENSOR_ACCELEROMETER; - break; - case ACCELEROMETER_EVENT_GRAVITY_DATA_REPORT_ON_TIME : - nid = SENSOR_GRAVITY; - break; - case ACCELEROMETER_EVENT_LINEAR_ACCELERATION_DATA_REPORT_ON_TIME : - nid = SENSOR_LINEAR_ACCELERATION; - break; - case ACCELEROMETER_EVENT_ORIENTATION_DATA_REPORT_ON_TIME : - nid = SENSOR_DEVICE_ORIENTATION; - break; - case GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME : - nid = SENSOR_MAGNETIC; - break; - case GEOMAGNETIC_EVENT_ATTITUDE_DATA_REPORT_ON_TIME : - nid = SENSOR_ORIENTATION; - break; - case GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME : - nid = SENSOR_GYROSCOPE; - break; - case LIGHT_EVENT_LUX_DATA_REPORT_ON_TIME : - nid = SENSOR_LIGHT; - break; - case PROXIMITY_EVENT_DISTANCE_DATA_REPORT_ON_TIME : - nid = SENSOR_PROXIMITY; - break; - } - - if(sensor->cb_func[nid] == NULL || sensor->started[nid] == 0) - return; - - switch(event_type) - { - case MOTION_ENGINE_EVENT_SNAP: - case MOTION_ENGINE_EVENT_SHAKE: - motion = *(int*)event->event_data; - break; - case MOTION_ENGINE_EVENT_PANNING: - case MOTION_ENGINE_EVENT_TILT: - case MOTION_ENGINE_EVENT_PANNING_BROWSE: - panning_data = (sensor_panning_data_t *)event->event_data; - break; - case MOTION_ENGINE_EVENT_DOUBLETAP: - motion = *(int*)event->event_data; - if(motion != MOTION_ENGIEN_DOUBLTAP_DETECTION) - return; - break; - case MOTION_ENGINE_EVENT_TOP_TO_BOTTOM: - motion = *(int*)event->event_data; - if(motion != MOTION_ENGIEN_TOP_TO_BOTTOM_DETECTION) - return; - break; - case MOTION_ENGINE_EVENT_DIRECT_CALL: - motion = *(int*)event->event_data; - if(motion != MOTION_ENGINE_DIRECT_CALL_DETECTION) - return; - break; - case MOTION_ENGINE_EVENT_SMART_ALERT: - motion = *(int*)event->event_data; - if(motion != MOTION_ENGINE_SMART_ALERT_DETECTION) - return; - break; - case MOTION_ENGINE_EVENT_NO_MOVE: - motion = *(int*)event->event_data; - if(motion != MOTION_ENGINE_NO_MOVE_DETECTION) - return; - break; - case ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME : - case ACCELEROMETER_EVENT_GRAVITY_DATA_REPORT_ON_TIME : - case ACCELEROMETER_EVENT_LINEAR_ACCELERATION_DATA_REPORT_ON_TIME : - case ACCELEROMETER_EVENT_ORIENTATION_DATA_REPORT_ON_TIME : - case GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME : - case GEOMAGNETIC_EVENT_ATTITUDE_DATA_REPORT_ON_TIME : - case GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME : - case LIGHT_EVENT_LUX_DATA_REPORT_ON_TIME : - case PROXIMITY_EVENT_DISTANCE_DATA_REPORT_ON_TIME : - data = (sensor_data_t*)(event->event_data); - data_num = (event->event_data_size)/sizeof(sensor_data_t); - break; - /* - case PROXIMITY_EVENT_CHANGE_STATE : - proximity = *(int*)(event->event_data) == PROXIMITY_STATE_FAR ? 0 : 1; - break; - */ - default: - DEBUG_PRINTF("unknown typed sensor happen!! event=%d\n", event_type); - return; - - } - - switch(event_type) - { - case MOTION_ENGINE_EVENT_SNAP: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_snap_event_cb)sensor->cb_func[nid])(motion_time_stamp, motion, sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_SHAKE: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_shake_event_cb)sensor->cb_func[nid])(motion_time_stamp,motion, sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_DOUBLETAP: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_doubletap_event_cb)sensor->cb_func[nid])(motion_time_stamp,sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_TOP_TO_BOTTOM: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_facedown_event_cb)sensor->cb_func[nid])(motion_time_stamp,sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_PANNING: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_panning_event_cb)sensor->cb_func[nid])(motion_time_stamp,panning_data->x, panning_data->y, sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_TILT: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_tilt_event_cb)sensor->cb_func[nid])(motion_time_stamp,panning_data->x, panning_data->y, sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_PANNING_BROWSE: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_panning_browse_event_cb)sensor->cb_func[nid])(motion_time_stamp,panning_data->x, panning_data->y, sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_DIRECT_CALL: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_directcall_event_cb)sensor->cb_func[nid])(motion_time_stamp,sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_SMART_ALERT: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_smart_alert_event_cb)sensor->cb_func[nid])(motion_time_stamp,sensor->cb_user_data[nid]); - break; - case MOTION_ENGINE_EVENT_NO_MOVE: - gettimeofday(&sv, NULL); - motion_time_stamp = MICROSECONDS(sv); - ((sensor_motion_no_move_event_cb)sensor->cb_func[nid])(motion_time_stamp,sensor->cb_user_data[nid]); - break; - case ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp, _ACCU(data[i].data_accuracy), - data[i].values[0], data[i].values[1], data[i].values[2], - sensor->cb_user_data[nid]); - } - break; - case ACCELEROMETER_EVENT_GRAVITY_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp, _ACCU(data[i].data_accuracy), - data[i].values[0], data[i].values[1], data[i].values[2], - sensor->cb_user_data[nid]); - } - break; - case ACCELEROMETER_EVENT_LINEAR_ACCELERATION_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp, _ACCU(data[i].data_accuracy), - data[i].values[0], data[i].values[1], data[i].values[2], - sensor->cb_user_data[nid]); - } - break; - case ACCELEROMETER_EVENT_ORIENTATION_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp, _ACCU(data[i].data_accuracy), - data[i].values[0], data[i].values[1], data[i].values[2], - sensor->cb_user_data[nid]); - } - break; - case GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp,_ACCU(data[i].data_accuracy), - data[i].values[0], data[i].values[1], data[i].values[2], - sensor->cb_user_data[nid]); - } - break; - case GEOMAGNETIC_EVENT_ATTITUDE_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp,_ACCU(data[i].data_accuracy), - data[i].values[0], data[i].values[1], data[i].values[2], - sensor->cb_user_data[nid]); - } - break; - case GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp,_ACCU(data[i].data_accuracy), - data[i].values[0], data[i].values[1], data[i].values[2], - sensor->cb_user_data[nid]); - } - break; - case LIGHT_EVENT_LUX_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp, - data[i].values[0], - sensor->cb_user_data[nid]); - } - break; - case PROXIMITY_EVENT_DISTANCE_DATA_REPORT_ON_TIME : - for(i=0; icb_func[nid]) - (data[i].time_stamp, - data[i].values[0], - sensor->cb_user_data[nid]); - } - break; - } -} - -int sensor_is_supported(sensor_type_e type, bool* supported) -{ - DEBUG_PRINT("sensor_is_support"); - - RETURN_IF_NOT_TYPE(type); - - if(supported == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *supported = !(sf_is_sensor_event_available(_TYPE[type], _EVENT[type]) < 0); - DEBUG_PRINTF("%s sensor available function return [%d]", TYPE_NAME(type), *supported); - - return SENSOR_ERROR_NONE; -} - -int sensor_get_spec(sensor_type_e type, char** vendor, char** model, float* max, float* min, float* resolution) -{ - sensor_data_properties_t data_properties; - sensor_properties_t properties; - - DEBUG_PRINT("sensor_get_spec"); - - RETURN_IF_MOTION_TYPE(type); - - RETURN_IF_NOT_TYPE(type); - - if(sf_get_data_properties(_DTYPE[type], &data_properties) < 0) - RETURN_ERROR(SENSOR_ERROR_NOT_SUPPORTED); - - if(sf_get_properties(_TYPE[type], &properties) < 0) - RETURN_ERROR(SENSOR_ERROR_NOT_SUPPORTED); - - if(vendor != NULL) - *vendor = strdup(properties.sensor_vendor); - if(model != NULL) - *model = strdup(properties.sensor_name); - if(max != NULL) - *max = data_properties.sensor_max_range; - if(min != NULL) - *min = data_properties.sensor_min_range; - if(resolution != NULL) - *resolution = data_properties.sensor_resolution; - - DEBUG_PRINTF("success get %s's format max=%f, min=%f, res=%f\n", TYPE_NAME(type), (max) ? *max : 0,(min) ? *min : 0, (resolution) ? *resolution : 0); - - return SENSOR_ERROR_NONE; -} - - -int sensor_create(sensor_h* handle) -{ - struct sensor_handle_s* sensor = NULL; - - DEBUG_PRINT("sensor_create"); - - if(handle == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - sensor = (struct sensor_handle_s*)malloc( sizeof(struct sensor_handle_s) ); - if(sensor==NULL) - RETURN_ERROR(SENSOR_ERROR_OUT_OF_MEMORY); - else - { - SENSOR_INIT(sensor); - - *handle = (sensor_h)sensor; - - return SENSOR_ERROR_NONE; - } -} - -int sensor_destroy(sensor_h handle) -{ - - int i=0; - RETURN_IF_NOT_HANDLE(handle); - - DEBUG_PRINT("sensor_destroy"); - - for(i=0; iids[i] >= 0 ){ - if(sf_disconnect(handle->ids[i]) >= 0){ - handle->ids[i] = -1; - } - } - } - - free(handle); - handle = NULL; - - return SENSOR_ERROR_NONE; -} - -int sensor_start(sensor_h handle, sensor_type_e type) -{ - int err; - DEBUG_PRINT("sensor_start"); - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_NOT_TYPE(type); - - if( (err = _sensor_connect(handle, type)) != SENSOR_ERROR_NONE){ - return err; - } - - if (sf_start(handle->ids[_SID(type)], handle->sensor_option[type]) < 0) { - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - } else { - handle->started[type] = 1; - return SENSOR_ERROR_NONE; - } -} - -int sensor_stop(sensor_h handle, sensor_type_e type) -{ - DEBUG_PRINT("sensor_stop"); - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_NOT_TYPE(type); - if (sf_stop(handle->ids[_SID(type)]) < 0) { - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - } else { - handle->started[type] = 0; - return SENSOR_ERROR_NONE; - } -} - -static void _sensor_calibration (unsigned int event_type, sensor_event_data_t* event, void* udata) -{ - sensor_h sensor = (sensor_h)udata; - - switch (event_type) { - case ACCELEROMETER_EVENT_CALIBRATION_NEEDED: - if(sensor->calib_func[SENSOR_ACCELEROMETER] != NULL){ - ((sensor_calibration_cb)sensor->calib_func[SENSOR_ACCELEROMETER])(sensor->calib_user_data[SENSOR_ACCELEROMETER]); - } - break; - case GEOMAGNETIC_EVENT_CALIBRATION_NEEDED: - if(sensor->calib_func[SENSOR_MAGNETIC] != NULL){ - ((sensor_calibration_cb)sensor->calib_func[SENSOR_MAGNETIC])(sensor->calib_user_data[SENSOR_MAGNETIC]); - } - if(sensor->calib_func[SENSOR_ORIENTATION] != NULL){ - ((sensor_calibration_cb)sensor->calib_func[SENSOR_ORIENTATION])(sensor->calib_user_data[SENSOR_ORIENTATION]); - } - break; - default: - DEBUG_PRINTF("not calibration event happened in calibration callback!! event=%d", event_type); - return; - } -} - -static int _sensor_set_calibration_cb(sensor_h handle, sensor_type_e type, sensor_calibration_cb callback, void *user_data) -{ - int ret, err; - - DEBUG_PRINTF("%s sensor register calibration callback", TYPE_NAME(type)); - - RETURN_IF_NOT_HANDLE(handle); - switch(type){ - case SENSOR_ACCELEROMETER: - case SENSOR_GRAVITY: - case SENSOR_LINEAR_ACCELERATION: - case SENSOR_DEVICE_ORIENTATION: - case SENSOR_MAGNETIC: - case SENSOR_ORIENTATION: - break; - default: - RETURN_ERROR(SENSOR_ERROR_NOT_NEED_CALIBRATION); - } - - ret = sf_is_sensor_event_available( _TYPE[type], _CALIBRATION[type] ); - if (ret != 0 ){ - DEBUG_PRINTF("Unsupported calibration ret=[%d] error=[%d] legacy=[%d] type=[%d] cal_id=[%d]", ret, SENSOR_ERROR_NOT_NEED_CALIBRATION, type, _TYPE[type], _CALIBRATION[type]); - RETURN_ERROR(SENSOR_ERROR_NOT_NEED_CALIBRATION); - } - - if( (err = _sensor_connect(handle, type)) != SENSOR_ERROR_NONE){ - return err; - } - - handle->calib_func[type] = callback; - handle->calib_user_data[type] = user_data; - - DEBUG_PRINTF("type : %s / id : %d / event : %x ", TYPE_NAME(type), handle->ids[_SID(type)], _CALIBRATION[type]); - - ret = sf_register_event(handle->ids[_SID(type)], _CALIBRATION[type], NULL, _sensor_calibration, handle); - if(ret < 0){ - handle->calib_func[type] = NULL; - handle->calib_user_data[type] = NULL; - if(ret == -2) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - else - RETURN_ERROR(SENSOR_ERROR_OPERATION_FAILED); - } - - return SENSOR_ERROR_NONE; -} - -static int _sensor_unset_calibration_cb(sensor_h handle, sensor_type_e type) -{ - int ret; - - DEBUG_PRINTF("%s sensor register calibration callback", TYPE_NAME(type)); - - RETURN_IF_NOT_HANDLE(handle); - switch (type) { - case SENSOR_ACCELEROMETER: - case SENSOR_GRAVITY: - case SENSOR_LINEAR_ACCELERATION: - case SENSOR_DEVICE_ORIENTATION: - case SENSOR_MAGNETIC: - case SENSOR_ORIENTATION: - break; - default: - RETURN_ERROR(SENSOR_ERROR_NOT_NEED_CALIBRATION); - } - - if(handle->calib_func[type] == NULL) - return SENSOR_ERROR_NONE; - - ret = sf_unregister_event(handle->ids[_SID(type)], _CALIBRATION[type]); - - if (ret < 0){ - if(ret == -2) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - else - RETURN_ERROR(SENSOR_ERROR_OPERATION_FAILED); - } - - handle->calib_func[type] = NULL; - handle->calib_user_data[type] = NULL; - - return SENSOR_ERROR_NONE; -} - -static void _sensor_wakeup (unsigned int event_type, sensor_event_data_t* event, void* udata) -{ - sensor_h sensor = (sensor_h)udata; - - switch (event_type) { - case ACCELEROMETER_EVENT_SET_WAKEUP: - if(sensor->wakeup_func[SENSOR_ACCELEROMETER] != NULL){ - ((sensor_awake_cb)sensor->wakeup_func[SENSOR_ACCELEROMETER])(sensor->wakeup_user_data[SENSOR_ACCELEROMETER]); - } - break; - default: - DEBUG_PRINTF("not wakeup event happened in wakeup callback!! event=%d", event_type); - return; - } -} - -static int _sensor_set_wakeup_cb(sensor_h handle, sensor_type_e type, sensor_awake_cb callback, void *user_data) -{ - int ret, err; - - DEBUG_PRINTF("%s sensor register wakeup callback", TYPE_NAME(type)); - - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_NOT_WAKEUP_TYPE(type); - - ret = sf_is_sensor_event_available( _TYPE[type], _WAKEUP[type] ); - if (ret != 0 ){ - DEBUG_PRINTF("Unsupported wakeup ret=[%d] error=[%d] legacy=[%d] type=[%d] wakeup_id=[%d]", ret, SENSOR_ERROR_NOT_SUPPORTED, type, _TYPE[type], _WAKEUP[type]); - RETURN_ERROR(SENSOR_ERROR_NOT_SUPPORTED); - } - - if( (err = _sensor_connect(handle, type)) != SENSOR_ERROR_NONE){ - return err; - } - - handle->wakeup_func[type] = callback; - handle->wakeup_user_data[type] = user_data; - - DEBUG_PRINTF("type : %s / id : %d / event : %x ", TYPE_NAME(type), handle->ids[_SID(type)], _WAKEUP[type]); - - ret = sf_register_event(handle->ids[_SID(type)], _WAKEUP[type], NULL, _sensor_wakeup, handle); - if(ret < 0){ - handle->wakeup_func[type] = NULL; - handle->wakeup_user_data[type] = NULL; - if(ret == -2) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - else - RETURN_ERROR(SENSOR_ERROR_OPERATION_FAILED); - } - - return SENSOR_ERROR_NONE; -} - - -static int _sensor_unset_wakeup_cb(sensor_h handle, sensor_type_e type) -{ - int ret; - - DEBUG_PRINTF("%s sensor unregister wakeup callback", TYPE_NAME(type)); - - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_NOT_WAKEUP_TYPE(type); - - if(handle->wakeup_func[type] == NULL) - return SENSOR_ERROR_NONE; - - ret = sf_unregister_event(handle->ids[_SID(type)], _WAKEUP[type]); - - if (ret < 0){ - if(ret == -2) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - else - RETURN_ERROR(SENSOR_ERROR_OPERATION_FAILED); - } - - handle->wakeup_func[type] = NULL; - handle->wakeup_user_data[type] = NULL; - - return SENSOR_ERROR_NONE; -} - - -static int _sensor_change_data_cb (sensor_h handle, sensor_type_e type, int rate) -{ - int err = 0; - event_condition_t condition; - - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_NOT_TYPE(type); - - DEBUG_PRINTF("sensor change condition %s", TYPE_NAME(type)); - - if(rate < 0){ - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - } - - if(rate > 0){ - condition.cond_op = CONDITION_EQUAL; - condition.cond_value1 = rate; - } - - err = sf_change_event_condition(handle->ids[_SID(type)], _EVENT[type], (rate > 0 ? &condition : NULL)); - - DEBUG_PRINTF("%s sensor change condition function return [%d] event=[%d]", TYPE_NAME(type), err, _EVENT[type]); - - if(err < 0){ - if(err == -2) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - else - RETURN_ERROR(SENSOR_ERROR_OPERATION_FAILED); - } - - return SENSOR_ERROR_NONE; -} - -static int _sensor_set_data_cb (sensor_h handle, sensor_type_e type, int rate, void* cb, void* user_data) -{ - int err = 0; - event_condition_t condition; - - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_NOT_TYPE(type); - - DEBUG_PRINTF("sensor register callback %s", TYPE_NAME(type)); - - if(rate < 0){ - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - } - - if(rate > 0){ - condition.cond_op = CONDITION_EQUAL; - condition.cond_value1 = rate; - } - - handle->cb_func[type] = cb; - handle->cb_user_data[type] = user_data; - - if( (err = _sensor_connect(handle, type)) != SENSOR_ERROR_NONE){ - DEBUG_PRINTF("%s sensor connect error handle=[%d] legacy=[%d] err=[%d]", TYPE_NAME(type), handle, type, err); - return err; - } - - err = sf_register_event(handle->ids[_SID(type)], _EVENT[type], - (rate > 0 ? &condition : NULL), _sensor_callback, handle); - - DEBUG_PRINTF("%s sensor register function return [%d] event=[%x]", TYPE_NAME(type), err, _EVENT[type]); - - if(err < 0){ - handle->cb_func[type] = NULL; - handle->cb_user_data[type] = NULL; - if(err == -2) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - else - RETURN_ERROR(SENSOR_ERROR_OPERATION_FAILED); - } - - return SENSOR_ERROR_NONE; -} - -static int _sensor_unset_data_cb (sensor_h handle, sensor_type_e type) -{ - int error; - DEBUG_PRINTF("sensor unregister callback %s", TYPE_NAME(type)); - RETURN_IF_NOT_HANDLE(handle); - if (handle->ids[_SID(type)] < 0 ) - return SENSOR_ERROR_INVALID_PARAMETER; - - error = sf_unregister_event(handle->ids[_SID(type)], _EVENT[type]); - - if (error < 0){ - if(error == -2) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - else - RETURN_ERROR(SENSOR_ERROR_OPERATION_FAILED); - } - - handle->cb_func[type] = NULL; - handle->cb_user_data[type] = NULL; - return SENSOR_ERROR_NONE; -} - -int sensor_accelerometer_set_cb(sensor_h handle, int rate, sensor_accelerometer_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_ACCELEROMETER, rate, (void*) callback, user_data); -} - -int sensor_accelerometer_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_ACCELEROMETER); -} - -int sensor_gravity_set_cb(sensor_h handle, int rate, sensor_gravity_event_cb callback, void* user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_GRAVITY, rate, (void*) callback, user_data); -} - -int sensor_gravity_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_GRAVITY); -} - -int sensor_linear_acceleration_set_cb(sensor_h handle, int rate, sensor_linear_acceleration_event_cb callback, void* user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_LINEAR_ACCELERATION, rate, (void*) callback, user_data); -} - -int sensor_linear_acceleration_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_LINEAR_ACCELERATION); -} - -int sensor_device_orientation_set_cb(sensor_h handle, int rate, sensor_device_orientation_event_cb callback, void* user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_DEVICE_ORIENTATION, rate, (void*) callback, user_data); -} - -int sensor_device_orientation_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_DEVICE_ORIENTATION); -} - -int sensor_magnetic_set_cb(sensor_h handle, int rate, sensor_magnetic_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MAGNETIC, rate, (void*) callback, user_data); -} - -int sensor_magnetic_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MAGNETIC); -} - -int sensor_magnetic_set_calibration_cb(sensor_h handle, sensor_calibration_cb callback, void *user_data) -{ - return _sensor_set_calibration_cb(handle, SENSOR_MAGNETIC, callback, user_data); -} -int sensor_magnetic_unset_calibration_cb(sensor_h handle) -{ - return _sensor_unset_calibration_cb(handle, SENSOR_MAGNETIC); -} - -int sensor_orientation_set_cb(sensor_h handle, int rate, sensor_orientation_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_ORIENTATION, rate, (void*) callback, user_data); -} - -int sensor_orientation_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_ORIENTATION); -} -int sensor_orientation_set_calibration_cb(sensor_h handle, sensor_calibration_cb callback, void *user_data) -{ - return _sensor_set_calibration_cb(handle, SENSOR_ORIENTATION, callback, user_data); -} -int sensor_orientation_unset_calibration_cb(sensor_h handle) -{ - return _sensor_unset_calibration_cb(handle, SENSOR_ORIENTATION); -} - -int sensor_gyroscope_set_cb(sensor_h handle, int rate, sensor_gyroscope_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_GYROSCOPE, rate, (void*) callback, user_data); -} - -int sensor_gyroscope_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_GYROSCOPE); -} - -int sensor_light_set_cb(sensor_h handle, int rate, sensor_light_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_LIGHT, rate, (void*) callback, user_data); -} - -int sensor_light_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_LIGHT); -} - -int sensor_proximity_set_cb(sensor_h handle, int interval_ms, sensor_proximity_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_PROXIMITY, interval_ms, (void*) callback, user_data); -} - -int sensor_proximity_unset_cb(sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_PROXIMITY); -} - -static int _sensor_read_data(sensor_h handle, sensor_type_e type, - sensor_data_accuracy_e* accuracy, float* values, int values_size) -{ - int err = 0; - sensor_data_t data; - - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_MOTION_TYPE(type); - RETURN_IF_NOT_TYPE(type); - - DEBUG_PRINTF("sensor read data %s", TYPE_NAME(type)); - - if( (err = _sensor_connect(handle, type)) != SENSOR_ERROR_NONE) - return err; - if ( sf_get_data(handle->ids[_SID(type)], _DTYPE[type], &data) < 0 ) - { - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - } - - // this error will never happen. but it exist for more safe code.. - if(values_size > 12 || values_size < 0) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - if(accuracy != NULL) - *accuracy = _ACCU(data.data_accuracy); - memcpy(values, data.values, values_size * sizeof(float)); - - return SENSOR_ERROR_NONE; -} - -int sensor_accelerometer_read_data (sensor_h handle, - sensor_data_accuracy_e* accuracy, float* x, float* y, float* z) -{ - float values[3] = {0,0,0}; - int err = _sensor_read_data(handle, SENSOR_ACCELEROMETER, accuracy, values, 3); - if(err < 0) return err; - - if(x == NULL || y == NULL || z == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *x = values[0]; - *y = values[1]; - *z = values[2]; - - return SENSOR_ERROR_NONE; -} - -int sensor_gravity_read_data (sensor_h handle, - sensor_data_accuracy_e* accuracy, float* x, float* y, float* z) -{ - float values[3] = {0,0,0}; - int err = _sensor_read_data(handle, SENSOR_GRAVITY, accuracy, values, 3); - if(err < 0) return err; - - if(x == NULL || y == NULL || z == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *x = values[0]; - *y = values[1]; - *z = values[2]; - - return SENSOR_ERROR_NONE; -} - -int sensor_linear_acceleration_read_data (sensor_h handle, - sensor_data_accuracy_e* accuracy, float* x, float* y, float* z) -{ - float values[3] = {0,0,0}; - int err = _sensor_read_data(handle, SENSOR_LINEAR_ACCELERATION, accuracy, values, 3); - if(err < 0) return err; - - if(x == NULL || y == NULL || z == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *x = values[0]; - *y = values[1]; - *z = values[2]; - - return SENSOR_ERROR_NONE; -} - -int sensor_device_orientation_read_data (sensor_h handle, - sensor_data_accuracy_e* accuracy, float* yaw, float* pitch, float* roll) -{ - float values[3] = {0,0,0}; - int err = _sensor_read_data(handle, SENSOR_DEVICE_ORIENTATION, accuracy, values, 3); - if(err < 0) return err; - - if(yaw == NULL || pitch == NULL || roll == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *yaw = values[0]; - *pitch = values[1]; - *roll = values[2]; - - return SENSOR_ERROR_NONE; -} - -int sensor_magnetic_read_data (sensor_h handle, sensor_data_accuracy_e* accuracy, float* x, float* y, float* z) -{ - float values[3] = {0,0,0}; - int err = _sensor_read_data(handle, SENSOR_MAGNETIC, accuracy, values, 3); - if(err < 0) return err; - - if(x == NULL || y == NULL || z == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *x = values[0]; - *y = values[1]; - *z = values[2]; - - return SENSOR_ERROR_NONE; -} - -int sensor_orientation_read_data (sensor_h handle, sensor_data_accuracy_e* accuracy, float* azimuth, float* pitch, float* roll) -{ - float values[3] = {0,0,0}; - int err = _sensor_read_data(handle, SENSOR_ORIENTATION, accuracy, values, 3); - if(err < 0) return err; - - if(azimuth == NULL || pitch == NULL || roll == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *azimuth = values[0]; - *pitch = values[1]; - *roll = values[2]; - - return SENSOR_ERROR_NONE; -} - -int sensor_gyroscope_read_data (sensor_h handle, sensor_data_accuracy_e* accuracy, float* x, float* y, float* z) -{ - float values[3] = {0,0,0}; - int err = _sensor_read_data(handle, SENSOR_GYROSCOPE, accuracy, values, 3); - if(err < 0) return err; - - if(x == NULL || y == NULL || z == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *x = values[0]; - *y = values[1]; - *z = values[2]; - - return SENSOR_ERROR_NONE; -} - -int sensor_light_read_data (sensor_h handle, float* lux) -{ - float values[1] = {0}; - int err = _sensor_read_data(handle, SENSOR_LIGHT, NULL, values, 1); - if(err < 0) return err; - - if(lux == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *lux = values[0]; - - return SENSOR_ERROR_NONE; -} - -int sensor_proximity_read_data (sensor_h handle, float* distance) -{ - float values[1] = {0}; - int err = _sensor_read_data(handle, SENSOR_PROXIMITY, NULL, values, 1); - if(err < 0) return err; - - if(distance == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *distance = values[0]; - - return SENSOR_ERROR_NONE; -} - - -int sensor_motion_snap_set_cb (sensor_h handle, sensor_motion_snap_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_SNAP, 0, (void*) callback, user_data); -} - -int sensor_motion_snap_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_SNAP); -} - -int sensor_motion_shake_set_cb (sensor_h handle, sensor_motion_shake_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_SHAKE, 0, (void*) callback, user_data); -} - -int sensor_motion_shake_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_SHAKE); -} - -int sensor_motion_doubletap_set_cb (sensor_h handle, sensor_motion_doubletap_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_DOUBLETAP, 0, (void*) callback, user_data); -} - -int sensor_motion_doubletap_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_DOUBLETAP); -} - -int sensor_motion_panning_set_cb (sensor_h handle, sensor_motion_panning_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_PANNING, 0, (void*) callback, user_data); -} - -int sensor_motion_panning_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_PANNING); -} - -int sensor_motion_tilt_set_cb (sensor_h handle, sensor_motion_tilt_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_TILT, 0, (void*) callback, user_data); -} - -int sensor_motion_tilt_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_TILT); -} -int sensor_motion_panning_browse_set_cb (sensor_h handle, sensor_motion_panning_browse_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_PANNING_BROWSE, 0, (void*) callback, user_data); -} - -int sensor_motion_panning_browse_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_PANNING_BROWSE); -} - -int sensor_motion_facedown_set_cb (sensor_h handle, sensor_motion_facedown_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_FACEDOWN, 0, (void*) callback, user_data); -} - -int sensor_motion_facedown_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_FACEDOWN); -} - -int sensor_motion_directcall_set_cb (sensor_h handle, sensor_motion_directcall_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_DIRECTCALL, 0, (void*) callback, user_data); -} - -int sensor_motion_directcall_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_DIRECTCALL); -} - -int sensor_motion_smart_alert_set_cb (sensor_h handle, sensor_motion_smart_alert_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_SMART_ALERT, 0, (void*) callback, user_data); -} - -int sensor_motion_smart_alert_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_SMART_ALERT); -} - -int sensor_motion_no_move_set_cb (sensor_h handle, sensor_motion_no_move_event_cb callback, void *user_data) -{ - return _sensor_set_data_cb(handle, SENSOR_MOTION_NO_MOVE, 0, (void*) callback, user_data); -} - -int sensor_motion_no_move_unset_cb (sensor_h handle) -{ - return _sensor_unset_data_cb(handle, SENSOR_MOTION_NO_MOVE); -} - -int sensor_awake_unset_cb(sensor_h handle, sensor_type_e type) -{ - return _sensor_unset_wakeup_cb(handle, type); -} - -int sensor_awake_set_cb(sensor_h handle, sensor_type_e type, sensor_awake_cb callback, void* user_data) -{ - return _sensor_set_wakeup_cb(handle, type, callback, user_data); -} - -int sensor_awake_is_enabled(sensor_h handle, sensor_type_e type, bool *enable) -{ - RETURN_IF_NOT_TYPE(type); - RETURN_IF_NOT_WAKEUP_TYPE(type); - *enable = (handle->wakeup_func[type] != NULL) ? true : false; - - return SENSOR_ERROR_NONE; -} - -int sensor_awake_is_supported(sensor_type_e type, bool *supported) -{ - DEBUG_PRINT("sensor_is_support"); - - RETURN_IF_NOT_TYPE(type); - RETURN_IF_NOT_WAKEUP_TYPE(type); - - if(supported == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *supported = !(sf_is_sensor_event_available(_TYPE[type], _WAKEUP[type]) < 0); - DEBUG_PRINTF("%s sensor available function return [%d]", TYPE_NAME(type), *supported); - - return SENSOR_ERROR_NONE; -} - -int sensor_get_delay_boundary(sensor_type_e type, int *min, int *max) -{ - RETURN_ERROR(SENSOR_ERROR_NOT_SUPPORTED); -} - -int sensor_util_get_declination(float latitude, float longitude, float altitude, float *declination) -{ - if(declination == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - setCoordinate(latitude, longitude, altitude, declination, NULL, 1); - - return SENSOR_ERROR_NONE; -} - -int sensor_util_get_angle_change(float R[], float prevR[], float angleChange[]) -{ - if(-1 == getAngleChange(R, prevR, angleChange)) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - return SENSOR_ERROR_NONE; -} - -int sensor_util_get_orientation(float R[], float values[]) -{ - if(R == NULL || values == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - values[0] = (float)atan2(R[1], R[4]); - values[1] = (float)asin(-R[7]); - values[2] = (float)atan2(-R[6], R[8]); - - return SENSOR_ERROR_NONE; - -} - -int sensor_util_get_inclination(float I[], float* inclination) -{ - if(I == NULL || inclination == NULL) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - *inclination = atan2(I[5], I[4]); - - RETURN_ERROR(SENSOR_ERROR_NOT_SUPPORTED); -} - -int sensor_util_remap_coordinate_system(float inR[], sensor_util_axis_e x, sensor_util_axis_e y, float outR[]) -{ - if(-1 == remapCoordinateSystem(inR, x, y, outR)) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - return SENSOR_ERROR_NONE; -} - -int sensor_util_get_rotation_matrix_from_vector(float Vx, float Vy, float Vz, float R[]) -{ - float RV[4] = {0, Vx, Vy, Vz}; - - RV[0] = 1 - Vx * Vx - Vy*Vy - Vz*Vz; - RV[0] = (Vx > 0) ? (float)(sqrt(Vx)) : 0; - - if( -1 == quatToMatrix(RV, R)) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - return SENSOR_ERROR_NONE; -} - -int sensor_util_get_rotation_matrix(float Gx, float Gy, float Gz,float Mx, float My, float Mz,float R[], float I[]) -{ - float G[3] = {Gx, Gy, Gz}; - float M[3] = {Mx, My, Mz}; - - if(-1 == getRotationMatrix(G, M, R, I)) - RETURN_ERROR(SENSOR_ERROR_INVALID_PARAMETER); - - return SENSOR_ERROR_NONE; -} - - -int sensor_accelerometer_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_ACCELEROMETER, interval_ms); -} - -int sensor_gravity_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_ACCELEROMETER, interval_ms); -} - -int sensor_linear_acceleration_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_LINEAR_ACCELERATION, interval_ms); -} - -int sensor_device_orientation_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_DEVICE_ORIENTATION, interval_ms); -} - -int sensor_gyroscope_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_GYROSCOPE, interval_ms); -} - -int sensor_light_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_LIGHT, interval_ms); -} - -int sensor_magnetic_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_MAGNETIC, interval_ms); -} - -int sensor_orientation_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_ORIENTATION, interval_ms); -} - -int sensor_proximity_set_interval(sensor_h sensor, int interval_ms) -{ - return _sensor_change_data_cb(sensor, SENSOR_PROXIMITY, interval_ms); -} - -int sensor_set_always_on(sensor_h handle, sensor_type_e type) -{ - RETURN_IF_NOT_HANDLE(handle); - RETURN_IF_MOTION_TYPE(type); - RETURN_IF_NOT_TYPE(type); - - if(-1 == sf_change_sensor_option(handle->ids[_SID(type)], 1)) - RETURN_ERROR(SENSOR_ERROR_IO_ERROR); - - return SENSOR_ERROR_NONE; -} diff --git a/src/sensor.cpp b/src/sensor.cpp new file mode 100644 index 0000000..82c1956 --- /dev/null +++ b/src/sensor.cpp @@ -0,0 +1,802 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define RETURN_VAL_IF(expr, err) \ + do { \ + if (expr) { \ + _E_MSG(err); \ + return (err); \ + } \ + } while (0) + +#define RETURN_ERROR(err) \ + do { \ + _E_MSG(err); \ + return (err); \ + } while (0) + +#define SENSOR_SHIFT_TYPE 16 +#define SENSOR_UNDEFINED_ID -1 + +#define SENSOR_LISTENER_MAGIC 0xCAFECAFE + +sensor_type_t _TYPE[] = { + ACCELEROMETER_SENSOR, + GRAVITY_SENSOR, + LINEAR_ACCEL_SENSOR, + GEOMAGNETIC_SENSOR, + ROTATION_VECTOR_SENSOR, + ORIENTATION_SENSOR, + GYROSCOPE_SENSOR, + LIGHT_SENSOR, + PROXIMITY_SENSOR, + PRESSURE_SENSOR, + ULTRAVIOLET_SENSOR, + TEMPERATURE_SENSOR, + HUMIDITY_SENSOR, +}; + +static int sensor_connect (sensor_h sensor, sensor_listener_h listener) +{ + int id = SENSOR_UNDEFINED_ID; + int event_type; + sensor_type_t type; + bool support = false; + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + _D("called sensor_connect : listener[0x%x], sensor[0x%x]", listener, sensor); + + sensord_get_type(sensor, &type); + event_type = type << SENSOR_SHIFT_TYPE | 0x1; + + if (!sensord_is_supported_event_type(sensor, event_type, &support)) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!support) + return SENSOR_ERROR_NOT_SUPPORTED; + + id = sensord_connect(sensor); + + if (id < 0) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_connect: id[%d]", id); + + listener->id = id; + listener->type = type; + + return id; +} + +static sensor_type_t _sensor_type_to_internal_type(sensor_type_e type) +{ + return (type == SENSOR_ALL) ? ALL_SENSOR : _TYPE[type]; +} + +int sensor_is_supported(sensor_type_e type, bool *supported) +{ + sensor_t sensor; + bool _supported; + sensor_type_t internal_type; + + if (type < SENSOR_ALL || type > SENSOR_CUSTOM) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!supported) + return SENSOR_ERROR_INVALID_PARAMETER; + + _D("called sensor_is_supported : type[%d]", type); + + internal_type = _sensor_type_to_internal_type(type); + + sensor = sensord_get_sensor(internal_type); + _supported = false; + + if (sensor) + _supported = true; + + *supported = _supported; + + _D("success sensor(%d) is supported[%d] : sensor[0x%x]", + type, _supported, sensor); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_default_sensor(sensor_type_e type, sensor_h *sensor) +{ + sensor_t _sensor; + sensor_privilege_t privilege; + sensor_type_t internal_type; + + _D("called sensor_get_default_sensor : type[%d], sensor[0x%x]", type, sensor); + + if (type < SENSOR_ALL || type > SENSOR_CUSTOM) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensor) + return SENSOR_ERROR_INVALID_PARAMETER; + + internal_type = _sensor_type_to_internal_type(type); + + _sensor = sensord_get_sensor(internal_type); + + if (!_sensor) + return SENSOR_ERROR_NOT_SUPPORTED; + + sensord_get_privilege(_sensor, &privilege); + + if (privilege != SENSOR_PRIVILEGE_PUBLIC) + return SENSOR_ERROR_NOT_SUPPORTED; + + *sensor = _sensor; + + _D("success sensor_get_default_sensor sensor[0x%x]", _sensor); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_sensor_list(sensor_type_e type, sensor_h **list, int *sensor_count) +{ + sensor_h *_list = NULL; + int count; + sensor_type_t internal_type; + + _D("called sensor_get_list : type[%d]"); + + if (type < SENSOR_ALL || type > SENSOR_CUSTOM) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensor_count || !list) + return SENSOR_ERROR_INVALID_PARAMETER; + + internal_type = _sensor_type_to_internal_type(type); + + sensord_get_sensor_list(internal_type, &_list, &count); + + int i, j; + int count_public = 0; + + for (i = 0; i < count; ++i) { + sensor_privilege_t privilege; + + sensord_get_privilege(_list[i], &privilege); + if (privilege != SENSOR_PRIVILEGE_PUBLIC) + continue; + + count_public++; + } + + if (count_public == 0) { + free(_list); + return SENSOR_ERROR_NOT_SUPPORTED; + } + + *list = (sensor_h *) malloc((sizeof(int *)) * count_public); + + if (!*list) { + free(_list); + return SENSOR_ERROR_OUT_OF_MEMORY; + } + + for (i = 0, j = 0; i < count; ++i) { + sensor_privilege_t privilege; + + sensord_get_privilege(_list[i], &privilege); + if (privilege != SENSOR_PRIVILEGE_PUBLIC) + continue; + + *(*list + j) = _list[i]; + j++; + } + + free(_list); + + *sensor_count = count_public; + + _D("success sensor_get_list"); + + return SENSOR_ERROR_NONE; +} + +int sensor_create_listener(sensor_h sensor, sensor_listener_h *listener) +{ + struct sensor_listener_s *_listener; + int error; + + _D("called sensor_create_listener : listener[0x%x]", listener); + + if (!sensor || !listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + _listener = new(std::nothrow) struct sensor_listener_s; + + if (!_listener) + return SENSOR_ERROR_OUT_OF_MEMORY; + + error = sensor_connect(sensor, _listener); + + if (error < 0) { + delete (struct sensor_listener_s *)_listener; + return error; + } + + _listener->sensor = sensor; + _listener->option = SENSOR_OPTION_DEFAULT; + _listener->magic = SENSOR_LISTENER_MAGIC; + + *listener = (sensor_listener_h) _listener; + + _D("success sensor_create_listener"); + + return SENSOR_ERROR_NONE; +} + +int sensor_destroy_listener(sensor_listener_h listener) +{ + _D("called sensor_destroy : listener[0x%x]", listener); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + sensord_disconnect(listener->id); + listener->magic = 0; + + delete (sensor_listener_s *)listener; + + _D("success sensor_destroy"); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_start(sensor_listener_h listener) +{ + int id; + unsigned int option = 0; + + _D("called sensor_listener_start : listener[0x%x]", listener); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + option = listener->option; + + if (!sensord_start(id, option)) + return SENSOR_ERROR_OPERATION_FAILED; + + _E("success sensor_listener_start : id[%d]", id); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_stop(sensor_listener_h listener) +{ + int id; + + _D("called sensor_listener_stop : listener[0x%x]", listener); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + + if (!sensord_stop(id)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_listener_stop"); + + return SENSOR_ERROR_NONE; +} + +static void sensor_callback(sensor_t sensor, unsigned int event_type, sensor_data_t *data, void *user_data) +{ + sensor_event_s event; + sensor_listener_h listener; + listener = (sensor_listener_h)user_data; + + _D("success sensor_callback, sensor[%p] listener[%p] listener->callback[%p]", sensor, listener, listener->callback); + if (!sensor || !listener->callback) + return; + + event.accuracy = data->accuracy; + event.timestamp = data->timestamp; + event.value_count = data->value_count; + + for (int i = 0; i < data->value_count; ++i) + event.values[i] = data->values[i]; + + ((sensor_event_cb) listener->callback)(sensor, &event, listener->user_data); + return; +} + +int sensor_listener_set_event_cb(sensor_listener_h listener, + unsigned int interval, sensor_event_cb callback, void *user_data) +{ + int id; + unsigned int event_id; + + if (!listener || !callback) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + _D("called sensor_listener_set_event : listener[0x%x], interval[%d], callback[0x%x], user_data[0x%x], id[%d]", + listener, interval, callback, user_data, listener->id); + + id = listener->id; + event_id = (listener->type) << SENSOR_SHIFT_TYPE | 0x1; + + listener->callback = (void *)callback; + listener->user_data = user_data; + + if (!sensord_register_event(id, event_id, interval, 0, + sensor_callback, listener)) { + listener->callback = NULL; + listener->user_data = NULL; + + return SENSOR_ERROR_OPERATION_FAILED; + } + + _D("success sensor_listener_set_event"); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_unset_event_cb(sensor_listener_h listener) +{ + int id; + int type; + unsigned int event_id; + + _D("called sensor_unregister_event : listener[0x%x]", listener); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + type = (int)listener->type; + event_id = type << SENSOR_SHIFT_TYPE | 0x1; + + if (!sensord_unregister_event(id, event_id)) + return SENSOR_ERROR_OPERATION_FAILED; + + listener->callback = NULL; + listener->user_data = NULL; + + _D("success sensor_unregister_event"); + + return SENSOR_ERROR_NONE; +} + +static void accuracy_changed_callback(sensor_t sensor, + unsigned long long timestamp, int accuracy, void *data) +{ + sensor_listener_h listener = (sensor_listener_h)data; + + if (!sensor || !listener->accu_callback) + return; + + ((sensor_accuracy_changed_cb)listener->accu_callback) + (sensor, timestamp, (sensor_data_accuracy_e)accuracy, listener->accu_user_data); + + return; +} + +int sensor_listener_set_accuracy_cb(sensor_listener_h listener, + sensor_accuracy_changed_cb callback, void *data) +{ + int id; + + _E("called sensor_register_accuracy_cb : listener[0x%x], callback[0x%x], user_data[0x%x] cb[%p]", + listener, callback, data, accuracy_changed_callback); + + if (!listener || !callback) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + listener->accu_callback = (void *)callback; + listener->accu_user_data = data; + + if (!sensord_register_accuracy_cb(id, accuracy_changed_callback, listener)) { + listener->accu_callback = NULL; + listener->accu_user_data = NULL; + + return SENSOR_ERROR_OPERATION_FAILED; + } + + _D("success sensor_register_accuracy_cb"); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_unset_accuracy_cb(sensor_listener_h listener) +{ + int id; + + _D("called sensor_unregister_accuracy_cb : listener[0x%x]", listener); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + + if (!sensord_unregister_accuracy_cb(id)) + return SENSOR_ERROR_OPERATION_FAILED; + + listener->accu_callback = NULL; + listener->accu_user_data = NULL; + + _D("success sensor_unregister_accuracy_cb"); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_set_interval(sensor_listener_h listener, unsigned int interval) +{ + int id; + int type; + unsigned int event_id; + + _D("called sensor_set_interval : listener[0x%x], interval[%d]", listener, interval); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + type = (int)listener->type; + event_id = type << SENSOR_SHIFT_TYPE | 0x1; + + if (!sensord_change_event_interval(id, event_id, interval)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_set_interval"); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_set_max_batch_latency(sensor_listener_h listener, unsigned int max_batch_latency) +{ + _D("called sensor_set_max_batch_latency : listener[0x%x], max_batch_latency[%d]", listener, max_batch_latency); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_change_event_max_batch_latency(listener->id, max_batch_latency)) + return SENSOR_ERROR_NOT_SUPPORTED; + + _D("success sensor_set_max_batch_latency"); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_set_option(sensor_listener_h listener, sensor_option_e option) +{ + int id; + + _D("called sensor_set_option : listener[0x%x], option[%d]", listener, option); + + if (!listener) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + + if (!sensord_set_option(id, (int)option)) + return SENSOR_ERROR_OPERATION_FAILED; + + listener->option = option; + + _D("success sensor_set_option"); + + return SENSOR_ERROR_NONE; +} + +int sensor_listener_read_data(sensor_listener_h listener, sensor_event_s *event) +{ + int id; + int type; + sensor_data_t data; + unsigned int data_id; + + _D("called sensor_read_data : listener[0x%x]", listener); + + if (!listener || !event) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (listener->magic != SENSOR_LISTENER_MAGIC) + return SENSOR_ERROR_INVALID_PARAMETER; + + id = listener->id; + type = (int)listener->type; + data_id = type << SENSOR_SHIFT_TYPE | 0x1; + + if (!sensord_get_data(id, data_id, &data)) + return SENSOR_ERROR_OPERATION_FAILED; + + event->accuracy = data.accuracy; + event->timestamp = data.timestamp; + event->value_count = data.value_count; + + for (int i = 0; i < data.value_count; ++i) + event->values[i] = data.values[i]; + + _D("success sensor_read_data"); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_name(sensor_h sensor, char** name) +{ + _D("called sensor_get_name"); + + if (!sensor || !name) + return SENSOR_ERROR_INVALID_PARAMETER; + + *name = strdup(sensord_get_name(sensor)); + + _D("success sensor_get_vendor : [%s]", *name); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_vendor(sensor_h sensor, char** vendor) +{ + _D("called sensor_get_vendor"); + + if (!sensor || !vendor) + return SENSOR_ERROR_INVALID_PARAMETER; + + *vendor = strdup(sensord_get_vendor(sensor)); + + _D("success sensor_vendor : [%s]", *vendor); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_type(sensor_h sensor, sensor_type_e *type) +{ + sensor_type_t _type; + int type_size; + _D("called sensor_get_type"); + + if (!sensor || !type) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_get_type(sensor, &_type)) + return SENSOR_ERROR_OPERATION_FAILED; + + type_size = sizeof(_TYPE) / sizeof(sensor_type_t); + + for (int i = 0; i < type_size; ++i) { + if (_TYPE[i] == _type) { + *type = (sensor_type_e)i; + break; + } + } + + _D("success sensor_get_type : [%d]", *type); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_min_range(sensor_h sensor, float *min_range) +{ + _D("called sensor_get_min_range"); + + if (!sensor || !min_range) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_get_min_range(sensor, min_range)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_get_min_range : [%d]", *min_range); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_max_range(sensor_h sensor, float *max_range) +{ + _D("called sensor_get_max_range"); + + if (!sensor || !max_range) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_get_max_range(sensor, max_range)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_get_max_range : [%d]", *max_range); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_resolution(sensor_h sensor, float *resolution) +{ + _D("called sensor_get_resolution"); + + if (!sensor || !resolution) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_get_resolution(sensor, resolution)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_get_resolution : [%d]", *resolution); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_min_interval(sensor_h sensor, int *min_interval) +{ + _D("called sensor_get_min_interval"); + + if (!sensor || !min_interval) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_get_min_interval(sensor, min_interval)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_get_min_interval : [%d]", *min_interval); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_fifo_count(sensor_h sensor, int *fifo_count) +{ + _D("called sensor_get_fifo_count"); + + if (!sensor || !fifo_count) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_get_fifo_count(sensor, fifo_count)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_get_fifo_count : [%d]", *fifo_count); + + return SENSOR_ERROR_NONE; +} + +int sensor_get_max_batch_count(sensor_h sensor, int *max_batch_count) +{ + _D("called sensor_get_max_batch_count"); + + if (!sensor || !max_batch_count) + return SENSOR_ERROR_INVALID_PARAMETER; + + if (!sensord_get_max_batch_count(sensor, max_batch_count)) + return SENSOR_ERROR_OPERATION_FAILED; + + _D("success sensor_get_max_batch_count : [%d]", *max_batch_count); + + return SENSOR_ERROR_NONE; +} + +/* + * FUNCTIONS : SENSOR_UTIL_* + */ + +int sensor_util_get_declination (float latitude, float longitude, float altitude, float *declination) +{ + if (!declination) + return SENSOR_ERROR_INVALID_PARAMETER; + + setCoordinate (latitude, longitude, altitude, declination, NULL, 1); + + return SENSOR_ERROR_NONE; +} + +int sensor_util_get_angle_change (float R[], float prevR[], float angleChange[]) +{ + if (getAngleChange (R, prevR, angleChange) < 0) + return SENSOR_ERROR_INVALID_PARAMETER; + + return SENSOR_ERROR_NONE; +} + +int sensor_util_get_orientation (float R[], float values[]) +{ + if (!R || !values) + return SENSOR_ERROR_INVALID_PARAMETER; + + values[0] = (float) atan2 (R[1], R[4]); + values[1] = (float) asin (-R[7]); + values[2] = (float) atan2 (-R[6], R[8]); + + return SENSOR_ERROR_NONE; +} + +int sensor_util_get_inclination (float I[], float* inclination) +{ + if (!I || !inclination) + return SENSOR_ERROR_INVALID_PARAMETER; + + *inclination = atan2(I[5], I[4]); + + return SENSOR_ERROR_NONE; +} + +int sensor_util_remap_coordinate_system (float inR[], sensor_util_axis_e x, sensor_util_axis_e y, float outR[]) +{ + if (remapCoordinateSystem (inR, x, y, outR) < 0) + return SENSOR_ERROR_INVALID_PARAMETER; + + return SENSOR_ERROR_NONE; +} + +int sensor_util_get_rotation_matrix_from_vector (float Vx, float Vy, float Vz, float R[]) +{ + float RV[4] = {0, Vx, Vy, Vz}; + + RV[0] = 1 - Vx * Vx - Vy*Vy - Vz*Vz; + RV[0] = (Vx > 0) ? (float) (sqrt (Vx)) : 0; + + if (quatToMatrix(RV, R) < 0) + return SENSOR_ERROR_INVALID_PARAMETER; + + return SENSOR_ERROR_NONE; +} + +int sensor_util_get_rotation_matrix (float Gx, float Gy, float Gz,float Mx, float My, float Mz,float R[], float I[]) +{ + float G[3] = {Gx, Gy, Gz}; + float M[3] = {Mx, My, Mz}; + + if (getRotationMatrix (G, M, R, I) < 0) + return SENSOR_ERROR_INVALID_PARAMETER; + + return SENSOR_ERROR_NONE; +} + -- 2.7.4