Geomagnetic Sensor file - Feature merge from devel/tizen branch 65/35365/3
authorAnkur <ankur29.garg@samsung.com>
Thu, 12 Feb 2015 14:02:03 +0000 (19:32 +0530)
committerAnkur <ankur29.garg@samsung.com>
Wed, 18 Feb 2015 06:10:47 +0000 (11:40 +0530)
This is second of the four patches being submitted to merge the changes from devel/tizen to tizen branch.
This contains the changes for adding geomagnetic rotation vector virtual sensor.

Build has been checked for armv7l and aarch64 for public repo.

Change-Id: Ie91229c349a452e8d24e7d831c258f1b9d26d72e

29 files changed:
packaging/sensord.spec
src/CMakeLists.txt
src/libsensord/CMakeLists.txt
src/libsensord/client_common.cpp
src/libsensord/sensor_geomag.h
src/libsensord/sensor_geomagnetic_rv.h [new file with mode: 0755]
src/libsensord/sensor_internal.h
src/libsensord/sensor_internal_deprecated.h
src/libsensord/sensor_light.h
src/libsensord/sensor_pressure.h
src/libsensord/sensor_proxi.h
src/libsensord/sensor_temperature.h
src/rotation_vector/CMakeLists.txt
src/rotation_vector/geomagnetic_rv/CMakeLists.txt [new file with mode: 0755]
src/rotation_vector/geomagnetic_rv/geomagnetic_rv_sensor.cpp [new file with mode: 0755]
src/rotation_vector/geomagnetic_rv/geomagnetic_rv_sensor.h [new file with mode: 0755]
src/sensor_fusion/design/documentation/equation/equation_13_updated.png [new file with mode: 0644]
src/sensor_fusion/design/documentation/sensor_fusion.htm
src/sensor_fusion/design/lib/axis_rot2quat.m [new file with mode: 0644]
src/sensor_fusion/design/lib/estimate_geomagnetic_rv.m
src/sensor_fusion/design/lib/estimate_orientation.m
src/sensor_fusion/design/lib/euler2quat.m [new file with mode: 0644]
src/sensor_fusion/design/sf_geomagnetic_rv.m
src/server/command_worker.cpp
src/server/permission_checker.cpp
src/server/permission_checker.h
src/shared/sensor_common.h
test/CMakeLists.txt
virtual_sensors.xml

index ecec809..e6d3ed6 100755 (executable)
@@ -28,6 +28,7 @@ BuildRequires:  pkgconfig(capi-system-info)
 %define gravity_state ON
 %define linear_accel_state ON
 %define rv_state ON
+%define geomagnetic_rv_state ON
 %define build_test_suite OFF
 
 %description
@@ -78,6 +79,7 @@ cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DACCEL=%{accel_state} \
        -DGEO=%{geo_state} -DPRESSURE=%{pressure_state} -DTEMPERATURE=%{temperature_state} \
        -DORIENTATION=%{orientation_state} -DGRAVITY=%{gravity_state} \
        -DLINEAR_ACCEL=%{linear_accel_state} -DRV=%{rv_state} \
+       -DGEOMAGNETIC_RV=%{geomagnetic_rv_state} \
        -DTEST_SUITE=%{build_test_suite} \
        -DLIBDIR=%{_libdir} -DINCLUDEDIR=%{_includedir}
 
@@ -145,6 +147,6 @@ systemctl daemon-reload
 %{_bindir}/temperature
 %{_bindir}/light
 %{_bindir}/rotation_vector
+%{_bindir}/geomagnetic_rv
 %license LICENSE.APLv2
 %endif
-
index 60b93e3..853ce97 100755 (executable)
@@ -38,7 +38,7 @@ IF("${ORIENTATION}" STREQUAL "ON")
 set(SENSOR_FUSION_ENABLE "1")
 set(ORIENTATION_ENABLE "1")
 ENDIF()
-IF("${RV}" STREQUAL "ON")
+IF("${GEOMAGNETIC_RV}" STREQUAL "ON")
 set(SENSOR_FUSION_ENABLE "1")
 ENDIF()
 IF("${GRAVITY}" STREQUAL "ON")
index 5b57251..0fe82f6 100755 (executable)
@@ -56,6 +56,7 @@ install(FILES sensor_gravity.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
 install(FILES sensor_linear_accel.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
 install(FILES sensor_orientation.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
 install(FILES sensor_rv.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
+install(FILES sensor_geomagnetic_rv.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
 install(FILES sensor_temperature.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
 install(FILES sensor_motion.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
 install(FILES sensor_deprecated.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sensor/)
index 22a74a4..831be17 100755 (executable)
@@ -41,6 +41,7 @@ log_element g_log_elements[] = {
        FILL_LOG_ELEMENT(LOG_ID_SENSOR_TYPE, ORIENTATION_SENSOR, 0, 1),
        FILL_LOG_ELEMENT(LOG_ID_SENSOR_TYPE, TEMPERATURE_SENSOR, 0, 1),
        FILL_LOG_ELEMENT(LOG_ID_SENSOR_TYPE, ROTATION_VECTOR_SENSOR, 0, 1),
+       FILL_LOG_ELEMENT(LOG_ID_SENSOR_TYPE, GEOMAGNETIC_RV_SENSOR, 0, 1),
 
        FILL_LOG_ELEMENT(LOG_ID_EVENT, GEOMAGNETIC_EVENT_CALIBRATION_NEEDED, 0, 1),
        FILL_LOG_ELEMENT(LOG_ID_EVENT, PROXIMITY_EVENT_CHANGE_STATE, 0,1),
@@ -61,6 +62,7 @@ log_element g_log_elements[] = {
        FILL_LOG_ELEMENT(LOG_ID_EVENT, PRESSURE_EVENT_RAW_DATA_REPORT_ON_TIME, 0, 10),
        FILL_LOG_ELEMENT(LOG_ID_EVENT, TEMPERATURE_EVENT_RAW_DATA_REPORT_ON_TIME, 0, 10),
        FILL_LOG_ELEMENT(LOG_ID_EVENT, ROTATION_VECTOR_EVENT_RAW_DATA_REPORT_ON_TIME, 0, 10),
+       FILL_LOG_ELEMENT(LOG_ID_EVENT, GEOMAGNETIC_RV_EVENT_RAW_DATA_REPORT_ON_TIME, 0, 10),
 
        FILL_LOG_ELEMENT(LOG_ID_DATA, ACCELEROMETER_BASE_DATA_SET, 0, 25),
        FILL_LOG_ELEMENT(LOG_ID_DATA, GYRO_BASE_DATA_SET, 0, 25),
index 7929a99..c3dfb51 100755 (executable)
@@ -41,7 +41,7 @@ enum geomag_data_id {
        GEOMAGNETIC_RAW_DATA_SET                = (GEOMAGNETIC_SENSOR << 16) | 0x0001,
 };
 
-enum geomag_evet_type {
+enum geomag_event_type {
        GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME       = (GEOMAGNETIC_SENSOR << 16) | 0x0001,
        GEOMAGNETIC_EVENT_CALIBRATION_NEEDED                    = (GEOMAGNETIC_SENSOR << 16) | 0x0002,
        GEOMAGNETIC_EVENT_UNPROCESSED_DATA_REPORT_ON_TIME       = (GEOMAGNETIC_SENSOR << 16) | 0x0003,
diff --git a/src/libsensord/sensor_geomagnetic_rv.h b/src/libsensord/sensor_geomagnetic_rv.h
new file mode 100755 (executable)
index 0000000..73106ae
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * libsensord
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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_GEOMAGNETIC_RV_H__
+#define __SENSOR_GEOMAGNETIC_RV_H__
+
+//! Pre-defined events for the geomagnetic rotation vector sensor
+//! Sensor Plugin developer can add more event to their own headers
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @defgroup SENSOR_GEOMAGNETIC_RV Rotation Vector Sensor
+ * @ingroup SENSOR_FRAMEWORK
+ *
+ * These APIs are used to control the Geomagnetic Rotation Vector sensor.
+ * @{
+ */
+
+enum geomagnetic_rv_event_type {
+       GEOMAGNETIC_RV_EVENT_RAW_DATA_REPORT_ON_TIME    = (GEOMAGNETIC_RV_SENSOR << 16) | 0x0001,
+};
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+//! End of a file
+
index 352154a..fcf11f7 100755 (executable)
@@ -51,6 +51,7 @@ extern "C"
 #include <sensor_linear_accel.h>
 #include <sensor_orientation.h>
 #include <sensor_rv.h>
+#include <sensor_geomagnetic_rv.h>
 #include <sensor_temperature.h>
 
 
index 69fa4ec..ee211d1 100755 (executable)
@@ -49,6 +49,7 @@ extern "C"
 #include <sensor_orientation.h>
 #include <sensor_temperature.h>
 #include <sensor_rv.h>
+#include <sensor_geomagnetic_rv.h>
 #include <sensor_motion.h>
 #include <sensor_deprecated.h>
 
index 1ddb87a..bd35fb3 100755 (executable)
@@ -41,7 +41,7 @@ enum light_data_id {
        LIGHT_BASE_DATA_SET     = (LIGHT_SENSOR << 16) | 0x0002,
 };
 
-enum light_evet_type {
+enum light_event_type {
        LIGHT_EVENT_LUX_DATA_REPORT_ON_TIME             = (LIGHT_SENSOR << 16) | 0x0001,
        LIGHT_EVENT_LEVEL_DATA_REPORT_ON_TIME   = (LIGHT_SENSOR << 16) | 0x0002,
        LIGHT_EVENT_CHANGE_LEVEL                                = (LIGHT_SENSOR << 16) | 0x0004,
index 5a113ed..dcf6b37 100755 (executable)
@@ -40,7 +40,7 @@ enum pressure_data_id {
        PRESSURE_BASE_DATA_SET          = (PRESSURE_SENSOR << 16) | 0x0001,
 };
 
-enum pressure_evet_type {
+enum pressure_event_type {
        PRESSURE_EVENT_RAW_DATA_REPORT_ON_TIME          = (PRESSURE_SENSOR << 16) | 0x0001,
 };
 
index f4aa971..e7e2270 100755 (executable)
@@ -38,7 +38,7 @@ enum proxi_data_id {
        PROXIMITY_DISTANCE_DATA_SET = (PROXIMITY_SENSOR << 16) | 0x0002,
 };
 
-enum proxi_evet_type {
+enum proxi_event_type {
        PROXIMITY_EVENT_CHANGE_STATE                                    = (PROXIMITY_SENSOR << 16) | 0x0001,
        PROXIMITY_EVENT_STATE_REPORT_ON_TIME                    = (PROXIMITY_SENSOR << 16) | 0x0002,
        PROXIMITY_EVENT_DISTANCE_DATA_REPORT_ON_TIME    = (PROXIMITY_SENSOR << 16) | 0x0004,
index 9ef6a2e..52b5730 100755 (executable)
@@ -40,7 +40,7 @@ enum temperature_data_id {
        TEMPERATURE_BASE_DATA_SET               = (TEMPERATURE_SENSOR << 16) | 0x0001,
 };
 
-enum temperature_evet_type {
+enum temperature_event_type {
        TEMPERATURE_EVENT_RAW_DATA_REPORT_ON_TIME               = (TEMPERATURE_SENSOR << 16) | 0x0001,
 };
 
index 7a527a7..3142605 100644 (file)
@@ -1,3 +1,6 @@
 IF("${RV}" STREQUAL "ON")
 add_subdirectory(rv)
 ENDIF()
+IF("${GEOMAGNETIC_RV}" STREQUAL "ON")
+add_subdirectory(geomagnetic_rv)
+ENDIF()
\ No newline at end of file
diff --git a/src/rotation_vector/geomagnetic_rv/CMakeLists.txt b/src/rotation_vector/geomagnetic_rv/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..36430ee
--- /dev/null
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 2.6)
+project(geomagnetic_rv CXX)
+
+SET(SENSOR_NAME geomagnetic_rv_sensor)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_SOURCE_DIR}/src/libsensord)
+include_directories(${CMAKE_SOURCE_DIR}/src/sensor_fusion)
+
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(geomagnetic_rv_pkgs REQUIRED vconf)
+
+FOREACH(flag ${geomagnetic_rv_pkgs_LDFLAGS})
+       SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
+ENDFOREACH(flag)
+
+FOREACH(flag ${geomagnetic_rv_pkgs_CFLAGS})
+       SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
+ENDFOREACH(flag)
+
+add_library(${SENSOR_NAME} SHARED
+               geomagnetic_rv_sensor.cpp
+)
+
+target_link_libraries(${SENSOR_NAME} ${geomagnetic_rv_pkgs_LDFLAGS} "-lm")
+
+install(TARGETS ${SENSOR_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/sensord)
diff --git a/src/rotation_vector/geomagnetic_rv/geomagnetic_rv_sensor.cpp b/src/rotation_vector/geomagnetic_rv/geomagnetic_rv_sensor.cpp
new file mode 100755 (executable)
index 0000000..ea5a446
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * sensord
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include <time.h>
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <common.h>
+#include <sf_common.h>
+#include <geomagnetic_rv_sensor.h>
+#include <sensor_plugin_loader.h>
+#include <orientation_filter.h>
+#include <cvirtual_sensor_config.h>
+
+#define SENSOR_NAME "GEOMAGNETIC_RV_SENSOR"
+#define SENSOR_TYPE_GEOMAGNETIC_RV             "GEOMAGNETIC_ROTATION_VECTOR"
+
+#define ACCELEROMETER_ENABLED 0x01
+#define GEOMAGNETIC_ENABLED 0x02
+#define GEOMAGNETIC_RV_ENABLED 3
+
+#define INITIAL_VALUE -1
+
+#define MS_TO_US 1000
+
+#define ELEMENT_NAME                                                                                   "NAME"
+#define ELEMENT_VENDOR                                                                                 "VENDOR"
+#define ELEMENT_RAW_DATA_UNIT                                                                  "RAW_DATA_UNIT"
+#define ELEMENT_DEFAULT_SAMPLING_TIME                                                  "DEFAULT_SAMPLING_TIME"
+#define ELEMENT_ACCEL_STATIC_BIAS                                                              "ACCEL_STATIC_BIAS"
+#define ELEMENT_GEOMAGNETIC_STATIC_BIAS                                                        "GEOMAGNETIC_STATIC_BIAS"
+#define ELEMENT_ACCEL_ROTATION_DIRECTION_COMPENSATION                  "ACCEL_ROTATION_DIRECTION_COMPENSATION"
+#define ELEMENT_GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION            "GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION"
+#define ELEMENT_ACCEL_SCALE                                                                            "ACCEL_SCALE"
+#define ELEMENT_GEOMAGNETIC_SCALE                                                              "GEOMAGNETIC_SCALE"
+#define ELEMENT_MAGNETIC_ALIGNMENT_FACTOR                                              "MAGNETIC_ALIGNMENT_FACTOR"
+
+void pre_process_data(sensor_data<float> &data_out, const float *data_in, float *bias, int *sign, float scale)
+{
+       data_out.m_data.m_vec[0] = sign[0] * (data_in[0] - bias[0]) / scale;
+       data_out.m_data.m_vec[1] = sign[1] * (data_in[1] - bias[1]) / scale;
+       data_out.m_data.m_vec[2] = sign[2] * (data_in[2] - bias[2]) / scale;
+}
+
+geomagnetic_rv_sensor::geomagnetic_rv_sensor()
+: m_accel_sensor(NULL)
+, m_magnetic_sensor(NULL)
+, m_accuracy(-1)
+, m_time(0)
+{
+       cvirtual_sensor_config &config = cvirtual_sensor_config::get_instance();
+
+       m_name = string(SENSOR_NAME);
+       register_supported_event(GEOMAGNETIC_RV_EVENT_RAW_DATA_REPORT_ON_TIME);
+       m_enable_geomagnetic_rv = 0;
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_VENDOR, m_vendor)) {
+               ERR("[VENDOR] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_vendor = %s", m_vendor.c_str());
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_DEFAULT_SAMPLING_TIME, &m_default_sampling_time)) {
+               ERR("[DEFAULT_SAMPLING_TIME] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_default_sampling_time = %d", m_default_sampling_time);
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_ACCEL_STATIC_BIAS, m_accel_static_bias, 3)) {
+               ERR("[ACCEL_STATIC_BIAS] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_accel_static_bias = (%f, %f, %f)", m_accel_static_bias[0], m_accel_static_bias[1], m_accel_static_bias[2]);
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_GEOMAGNETIC_STATIC_BIAS, m_geomagnetic_static_bias, 3)) {
+               ERR("[GEOMAGNETIC_STATIC_BIAS] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_geomagnetic_static_bias = (%f, %f, %f)", m_geomagnetic_static_bias[0], m_geomagnetic_static_bias[1], m_geomagnetic_static_bias[2]);
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_ACCEL_ROTATION_DIRECTION_COMPENSATION, m_accel_rotation_direction_compensation, 3)) {
+               ERR("[ACCEL_ROTATION_DIRECTION_COMPENSATION] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_accel_rotation_direction_compensation = (%d, %d, %d)", m_accel_rotation_direction_compensation[0], m_accel_rotation_direction_compensation[1], m_accel_rotation_direction_compensation[2]);
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION, m_geomagnetic_rotation_direction_compensation, 3)) {
+               ERR("[GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_geomagnetic_rotation_direction_compensation = (%d, %d, %d)", m_geomagnetic_rotation_direction_compensation[0], m_geomagnetic_rotation_direction_compensation[1], m_geomagnetic_rotation_direction_compensation[2]);
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_ACCEL_SCALE, &m_accel_scale)) {
+               ERR("[ACCEL_SCALE] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_accel_scale = %f", m_accel_scale);
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_GEOMAGNETIC_SCALE, &m_geomagnetic_scale)) {
+               ERR("[GEOMAGNETIC_SCALE] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_geomagnetic_scale = %f", m_geomagnetic_scale);
+
+       if (!config.get(SENSOR_TYPE_GEOMAGNETIC_RV, ELEMENT_MAGNETIC_ALIGNMENT_FACTOR, &m_magnetic_alignment_factor)) {
+               ERR("[MAGNETIC_ALIGNMENT_FACTOR] is empty\n");
+               throw ENXIO;
+       }
+
+       INFO("m_magnetic_alignment_factor = %d", m_magnetic_alignment_factor);
+
+       m_interval = m_default_sampling_time * MS_TO_US;
+
+}
+
+geomagnetic_rv_sensor::~geomagnetic_rv_sensor()
+{
+       INFO("geomagnetic_rv_sensor is destroyed!\n");
+}
+
+bool geomagnetic_rv_sensor::init()
+{
+       m_accel_sensor = sensor_plugin_loader::get_instance().get_sensor(ACCELEROMETER_SENSOR);
+       m_magnetic_sensor = sensor_plugin_loader::get_instance().get_sensor(GEOMAGNETIC_SENSOR);
+
+       if (!m_accel_sensor || !m_magnetic_sensor) {
+               ERR("Failed to load sensors,  accel: 0x%x, mag: 0x%x",
+                       m_accel_sensor, m_magnetic_sensor);
+               return false;
+       }
+
+       INFO("%s is created!\n", sensor_base::get_name());
+
+       return true;
+}
+
+sensor_type_t geomagnetic_rv_sensor::get_type(void)
+{
+       return GEOMAGNETIC_RV_SENSOR;
+}
+
+bool geomagnetic_rv_sensor::on_start(void)
+{
+       AUTOLOCK(m_mutex);
+
+       m_accel_sensor->add_client(ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME);
+       m_accel_sensor->add_interval((intptr_t)this, (m_interval/MS_TO_US), false);
+       m_accel_sensor->start();
+       m_magnetic_sensor->add_client(GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME);
+       m_magnetic_sensor->add_interval((intptr_t)this, (m_interval/MS_TO_US), false);
+       m_magnetic_sensor->start();
+
+       activate();
+       return true;
+}
+
+bool geomagnetic_rv_sensor::on_stop(void)
+{
+       AUTOLOCK(m_mutex);
+
+       m_accel_sensor->delete_client(ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME);
+       m_accel_sensor->delete_interval((intptr_t)this, false);
+       m_accel_sensor->stop();
+       m_magnetic_sensor->delete_client(GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME);
+       m_magnetic_sensor->delete_interval((intptr_t)this, false);
+       m_magnetic_sensor->stop();
+
+       deactivate();
+       return true;
+}
+
+bool geomagnetic_rv_sensor::add_interval(int client_id, unsigned int interval)
+{
+       AUTOLOCK(m_mutex);
+
+       m_accel_sensor->add_interval(client_id, interval, false);
+       m_magnetic_sensor->add_interval(client_id, interval, false);
+
+       return sensor_base::add_interval(client_id, interval, false);
+}
+
+bool geomagnetic_rv_sensor::delete_interval(int client_id)
+{
+       AUTOLOCK(m_mutex);
+
+       m_accel_sensor->delete_interval(client_id, false);
+       m_magnetic_sensor->delete_interval(client_id, false);
+
+       return sensor_base::delete_interval(client_id, false);
+}
+
+void geomagnetic_rv_sensor::synthesize(const sensor_event_t& event, vector<sensor_event_t> &outs)
+{
+       const float MIN_DELIVERY_DIFF_FACTOR = 0.75f;
+       unsigned long long diff_time;
+
+       sensor_event_t rv_event;
+       quaternion<float> quaternion_geo_rv;
+
+       if (event.event_type == ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME) {
+               diff_time = event.data.timestamp - m_time;
+
+               if (m_time && (diff_time < m_interval * MIN_DELIVERY_DIFF_FACTOR))
+                       return;
+
+               pre_process_data(m_accel, event.data.values, m_accel_static_bias, m_accel_rotation_direction_compensation, m_accel_scale);
+
+               m_accel.m_time_stamp = event.data.timestamp;
+
+               m_enable_geomagnetic_rv |= ACCELEROMETER_ENABLED;
+       }
+       else if (event.event_type == GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME) {
+               diff_time = event.data.timestamp - m_time;
+
+               if (m_time && (diff_time < m_interval * MIN_DELIVERY_DIFF_FACTOR))
+                       return;
+
+               pre_process_data(m_magnetic, event.data.values, m_geomagnetic_static_bias, m_geomagnetic_rotation_direction_compensation, m_geomagnetic_scale);
+
+               m_magnetic.m_time_stamp = event.data.timestamp;
+
+               m_enable_geomagnetic_rv |= GEOMAGNETIC_ENABLED;
+       }
+
+       if (m_enable_geomagnetic_rv == GEOMAGNETIC_RV_ENABLED) {
+               m_enable_geomagnetic_rv = 0;
+
+               m_orientation_filter.m_magnetic_alignment_factor = m_magnetic_alignment_factor;
+
+               {
+                       AUTOLOCK(m_fusion_mutex);
+                       quaternion_geo_rv = m_orientation_filter.get_geomagnetic_quaternion(m_accel, m_magnetic);
+               }
+
+               m_time = get_timestamp();
+
+               rv_event.sensor_id = get_id();
+               rv_event.event_type = GEOMAGNETIC_RV_EVENT_RAW_DATA_REPORT_ON_TIME;
+               rv_event.data.accuracy = SENSOR_ACCURACY_GOOD;
+               rv_event.data.timestamp = m_time;
+               rv_event.data.value_count = 4;
+               rv_event.data.values[0] = quaternion_geo_rv.m_quat.m_vec[1];
+               rv_event.data.values[1] = quaternion_geo_rv.m_quat.m_vec[2];
+               rv_event.data.values[2] = quaternion_geo_rv.m_quat.m_vec[3];
+               rv_event.data.values[3] = quaternion_geo_rv.m_quat.m_vec[0];
+
+               push(rv_event);
+       }
+
+       return;
+}
+
+int geomagnetic_rv_sensor::get_sensor_data(unsigned int event_type, sensor_data_t &data)
+{
+       sensor_data<float> accel;
+       sensor_data<float> magnetic;
+
+       sensor_data_t accel_data;
+       sensor_data_t magnetic_data;
+
+       quaternion<float> quaternion_geo_rv;
+
+       if (event_type != GEOMAGNETIC_RV_EVENT_RAW_DATA_REPORT_ON_TIME)
+               return -1;
+
+       m_accel_sensor->get_sensor_data(ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME, accel_data);
+       m_magnetic_sensor->get_sensor_data(GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME, magnetic_data);
+
+       pre_process_data(accel, accel_data.values, m_accel_static_bias, m_accel_rotation_direction_compensation, m_accel_scale);
+       pre_process_data(magnetic, magnetic_data.values, m_geomagnetic_static_bias, m_geomagnetic_rotation_direction_compensation, m_geomagnetic_scale);
+       accel.m_time_stamp = accel_data.timestamp;
+       magnetic.m_time_stamp = magnetic_data.timestamp;
+
+       m_orientation_filter.m_magnetic_alignment_factor = m_magnetic_alignment_factor;
+
+       {
+               AUTOLOCK(m_fusion_mutex);
+               quaternion_geo_rv = m_orientation_filter.get_geomagnetic_quaternion(m_accel, m_magnetic);
+       }
+
+       data.accuracy = SENSOR_ACCURACY_GOOD;
+       data.timestamp = m_time;
+       data.value_count = 4;
+       data.values[0] = quaternion_geo_rv.m_quat.m_vec[1];
+       data.values[1] = quaternion_geo_rv.m_quat.m_vec[2];
+       data.values[2] = quaternion_geo_rv.m_quat.m_vec[3];
+       data.values[3] = quaternion_geo_rv.m_quat.m_vec[0];
+
+       return 0;
+}
+
+bool geomagnetic_rv_sensor::get_properties(sensor_properties_s &properties)
+{
+       properties.vendor = m_vendor;
+       properties.name = SENSOR_NAME;
+       properties.min_range = -1;
+       properties.max_range = 1;
+       properties.resolution = 0.000001;
+       properties.fifo_count = 0;
+       properties.max_batch_count = 0;
+       properties.min_interval = 1;
+
+       return true;
+}
+
+extern "C" sensor_module* create(void)
+{
+       geomagnetic_rv_sensor *sensor;
+
+       try {
+               sensor = new(std::nothrow) geomagnetic_rv_sensor;
+       } catch (int err) {
+               ERR("Failed to create module, err: %d, cause: %s", err, strerror(err));
+               return NULL;
+       }
+
+       sensor_module *module = new(std::nothrow) sensor_module;
+       retvm_if(!module || !sensor, NULL, "Failed to allocate memory");
+
+       module->sensors.push_back(sensor);
+       return module;
+}
diff --git a/src/rotation_vector/geomagnetic_rv/geomagnetic_rv_sensor.h b/src/rotation_vector/geomagnetic_rv/geomagnetic_rv_sensor.h
new file mode 100755 (executable)
index 0000000..9f3bdb1
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * sensord
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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 _GEOMAGNETIC_RV_SENSOR_H_
+#define _GEOMAGNETIC_RV_SENSOR_H_
+
+#include <sensor_internal.h>
+#include <virtual_sensor.h>
+#include <orientation_filter.h>
+
+class geomagnetic_rv_sensor : public virtual_sensor {
+public:
+       geomagnetic_rv_sensor();
+       virtual ~geomagnetic_rv_sensor();
+
+       bool init(void);
+
+       void synthesize(const sensor_event_t &event, vector<sensor_event_t> &outs);
+
+       bool add_interval(int client_id, unsigned int interval);
+       bool delete_interval(int client_id);
+       bool get_properties(sensor_properties_s &properties);
+       sensor_type_t get_type(void);
+
+       int get_sensor_data(const unsigned int data_id, sensor_data_t &data);
+
+private:
+       sensor_base *m_accel_sensor;
+       sensor_base *m_magnetic_sensor;
+
+       sensor_data<float> m_accel;
+       sensor_data<float> m_magnetic;
+
+       cmutex m_value_mutex;
+
+       orientation_filter<float> m_orientation_filter;
+
+       unsigned int m_enable_geomagnetic_rv;
+
+       int m_accuracy;
+       unsigned long long m_time;
+       unsigned int m_interval;
+
+       string m_vendor;
+       string m_raw_data_unit;
+       int m_default_sampling_time;
+       float m_accel_static_bias[3];
+       float m_geomagnetic_static_bias[3];
+       int m_accel_rotation_direction_compensation[3];
+       int m_geomagnetic_rotation_direction_compensation[3];
+       float m_accel_scale;
+       float m_geomagnetic_scale;
+       int m_magnetic_alignment_factor;
+
+       bool on_start(void);
+       bool on_stop(void);
+};
+
+#endif /*_GEOMAGNETIC_RV_SENSOR_H_*/
diff --git a/src/sensor_fusion/design/documentation/equation/equation_13_updated.png b/src/sensor_fusion/design/documentation/equation/equation_13_updated.png
new file mode 100644 (file)
index 0000000..32f3f46
Binary files /dev/null and b/src/sensor_fusion/design/documentation/equation/equation_13_updated.png differ
index d2536c4..88c02db 100755 (executable)
@@ -248,7 +248,7 @@ as shown in (13).</p>
 
 <FIGURE>
 <center>
-<img src="./equation/equation_13.png" width="35%" height="3%">
+<img src="./equation/equation_13_updated.png" width="35%" height="5%">
 </center>
 </FIGURE>
 
diff --git a/src/sensor_fusion/design/lib/axis_rot2quat.m b/src/sensor_fusion/design/lib/axis_rot2quat.m
new file mode 100644 (file)
index 0000000..b2756f5
--- /dev/null
@@ -0,0 +1,26 @@
+% axis_rot2quat
+%
+% Copyright (c) 2015 Samsung Electronics Co., Ltd.
+%
+% 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.
+
+% Axis rotation to quaternion function
+%
+% - convert sensor rotation axis and angle values to quaternion
+function q = axis_rot2quat(axis, angle)
+       q0 = cos(angle/2);
+       q1 = -axis(1)*sin(angle/2);
+       q2 = -axis(2)*sin(angle/2);
+       q3 = -axis(3)*sin(angle/2);
+       q = [q0 q1 q2 q3];
+end
index 340f4d0..c49c511 100755 (executable)
@@ -1,6 +1,6 @@
-% estimate_gravity
+% estimate_geomagnetic_rv
 %
-% Copyright (c) 2014 Samsung Electronics Co., Ltd.
+% Copyright (c) 2015 Samsung Electronics Co., Ltd.
 %
 % Licensed under the Apache License, Version 2.0 (the "License");
 % you may not use this file except in compliance with the License.
 % See the License for the specific language governing permissions and
 % limitations under the License.
 
-% Gravitational Force Estimation function
+% Geomagnetic Rotation Vector Estimation function
 %
+% - Input orientation using only Accel and Geomagnetic sensors
 % - Orientation Estimation using estimate_orientation function
-% - Project the orientation on the device reference axes to obtain
-%   gravitational force on specific reference axes
-
+% - Output aiding system quaternion as geomagnetic rotation vector
 
 function [Quat_aid]  = estimate_geomagnetic_rv(Accel_data, Mag_data)
 
-GRAVITY = 9.80665;
-RAD2DEG = 57.2957795;
-
 BUFFER_SIZE = size(Accel_data,2);
 
-Gravity = zeros(3,BUFFER_SIZE);
-
-OR_driv = zeros(3,BUFFER_SIZE);
 Gyro_data = zeros(4,BUFFER_SIZE);
 
 Quat_driv = zeros(4,BUFFER_SIZE);
index 0094b04..60541a5 100755 (executable)
@@ -1,6 +1,6 @@
 % estimate_orientation
 %
-% Copyright (c) 2014 Samsung Electronics Co., Ltd.
+% Copyright (c) 2015 Samsung Electronics Co., Ltd.
 %
 % Licensed under the Apache License, Version 2.0 (the "License");
 % you may not use this file except in compliance with the License.
diff --git a/src/sensor_fusion/design/lib/euler2quat.m b/src/sensor_fusion/design/lib/euler2quat.m
new file mode 100644 (file)
index 0000000..8442aa1
--- /dev/null
@@ -0,0 +1,38 @@
+% euler2quat
+%
+% Copyright (c) 2015 Samsung Electronics Co., Ltd.
+%
+% 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.
+
+% Euler Angles to quaternion conversion
+%
+% - Implementation to convert orientation in terms of euler angles to quaternion
+
+function q = euler2quat(euler)
+       theta = euler(1);
+       phi = euler(2);
+       psi = euler(3);
+       R(1,1,1) = cos(psi)*cos(theta);
+       R(1,2,1) = -sin(psi)*cos(phi) + cos(psi)*sin(theta)*sin(phi);
+       R(1,3,1) = sin(psi)*sin(phi) + cos(psi)*sin(theta)*cos(phi);
+
+       R(2,1,1) = sin(psi)*cos(theta);
+       R(2,2,1) = cos(psi)*cos(phi) + sin(psi)*sin(theta)*sin(phi);
+       R(2,3,1) = -cos(psi)*sin(phi) + sin(psi)*sin(theta)*cos(phi);
+
+       R(3,1,1) = -sin(theta);
+       R(3,2,1) = cos(theta)*sin(phi);
+       R(3,3,1) = cos(theta)*cos(phi);
+
+       q = rot_mat2quat(R);
+end
\ No newline at end of file
index 78802eb..69bbdd5 100755 (executable)
@@ -75,16 +75,19 @@ hfig=(figure);
 scrsz = get(0,'ScreenSize');
 set(hfig,'position',scrsz);
 % Geomagnetic Rotation Vector Plot Results
+subplot(3,1,1)
 UA = Orientation_RV(1,:);
 p1 = plot(1:length(UA),UA(1,1:length(UA)),'k');
-hold on;
-grid on;
+legend(p1,'x-axis');
+title(['Pitch']);
+subplot(3,1,2)
 UA = Orientation_RV(2,:);
-p2 = plot(1:length(UA),UA(1,1:length(UA)),'b');
-hold on;
-grid on;
+p1 = plot(1:length(UA),UA(1,1:length(UA)),'b');
+legend(p1,'y-axis');
+title(['Roll']);
+subplot(3,1,3)
 UA = Orientation_RV(3,:);
-p3 = plot(1:length(UA),UA(1,1:length(UA)),'r');
-title(['Geomagnetic Rotation Vector']);
-legend([p1 p2 p3],'x-axis', 'y-axis', 'z-axis');
+p1 = plot(1:length(UA),UA(1,1:length(UA)),'r');
+legend(p1,'z-axis');
+title(['Yaw']);
 
index cd3edc9..c161171 100755 (executable)
 #include <string>
 #include <utility>
 #include <permission_checker.h>
+#include <set>
 
 using std::string;
 using std::make_pair;
+using std::set;
 
 command_worker::cmd_handler_t command_worker::m_cmd_handlers[];
 sensor_raw_data_map command_worker::m_sensor_raw_data_map;
@@ -847,21 +849,17 @@ csensor_event_dispatcher& command_worker::get_event_dispathcher(void)
 
 void insert_priority_list(unsigned int event_type)
 {
-       if (event_type == ORIENTATION_EVENT_RAW_DATA_REPORT_ON_TIME) {
+       if (event_type == ORIENTATION_EVENT_RAW_DATA_REPORT_ON_TIME ||
+                       event_type == LINEAR_ACCEL_EVENT_RAW_DATA_REPORT_ON_TIME ||
+                       event_type == GRAVITY_EVENT_RAW_DATA_REPORT_ON_TIME ||
+                       event_type == ROTATION_VECTOR_EVENT_RAW_DATA_REPORT_ON_TIME) {
                priority_list.insert(ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME);
                priority_list.insert(GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME);
                priority_list.insert(GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME);
-        }
-
-       if (event_type == LINEAR_ACCEL_EVENT_RAW_DATA_REPORT_ON_TIME) {
-               priority_list.insert(ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME);
-               priority_list.insert(GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME);
-               priority_list.insert(GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME);
-        }
+       }
 
-       if (event_type == GRAVITY_EVENT_RAW_DATA_REPORT_ON_TIME) {
+       if (event_type == GEOMAGNETIC_RV_EVENT_RAW_DATA_REPORT_ON_TIME) {
                priority_list.insert(ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME);
-               priority_list.insert(GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME);
                priority_list.insert(GEOMAGNETIC_EVENT_RAW_DATA_REPORT_ON_TIME);
-        }
+       }
 }
index aec5aef..ad05b02 100755 (executable)
 #define SECURITY_LIB "/usr/lib/libsecurity-server-client.so.1"
 
 permission_checker::permission_checker()
-: security_server_check_privilege_by_sockfd(NULL)
+: m_security_server_check_privilege_by_sockfd(NULL)
 , m_security_handle(NULL)
 , m_permission_set(0)
-
 {
        init();
 }
@@ -56,10 +55,10 @@ bool permission_checker::init_security_lib(void)
                return false;
        }
 
-       security_server_check_privilege_by_sockfd =
+       m_security_server_check_privilege_by_sockfd =
                (security_server_check_privilege_by_sockfd_t) dlsym(m_security_handle, "security_server_check_privilege_by_sockfd");
 
-       if (!security_server_check_privilege_by_sockfd) {
+       if (!m_security_server_check_privilege_by_sockfd) {
                ERR("Failed to load symbol");
                dlclose(m_security_handle);
                m_security_handle = NULL;
@@ -94,8 +93,8 @@ int permission_checker::get_permission(int sock_fd)
        for (unsigned int i = 0; i < m_permission_infos.size(); ++i) {
                if (!m_permission_infos[i]->need_to_check) {
                        permission |= m_permission_infos[i]->permission;
-               } else if ((m_permission_set & m_permission_infos[i]->permission) && security_server_check_privilege_by_sockfd) {
-                       if (security_server_check_privilege_by_sockfd(sock_fd, m_permission_infos[i]->name.c_str(), m_permission_infos[i]->access_right.c_str()) == 1) {
+               } else if ((m_permission_set & m_permission_infos[i]->permission) && m_security_server_check_privilege_by_sockfd) {
+                       if (m_security_server_check_privilege_by_sockfd(sock_fd, m_permission_infos[i]->name.c_str(), m_permission_infos[i]->access_right.c_str()) == 1) {
                                permission |= m_permission_infos[i]->permission;
                        }
                }
index 5121e41..ad94708 100755 (executable)
@@ -55,7 +55,7 @@ private:
        bool init_security_lib(void);
        void init();
 
-       security_server_check_privilege_by_sockfd_t security_server_check_privilege_by_sockfd;
+       security_server_check_privilege_by_sockfd_t m_security_server_check_privilege_by_sockfd;
        void *m_security_handle;
 
        permission_info_vector m_permission_infos;
index 311ca62..aae9081 100755 (executable)
@@ -63,6 +63,7 @@ typedef enum {
        GRAVITY_SENSOR,
        LINEAR_ACCEL_SENSOR,
        ROTATION_VECTOR_SENSOR,
+       GEOMAGNETIC_RV_SENSOR,
        ORIENTATION_SENSOR,
        PIR_SENSOR,
        PIR_LONG_SENSOR,
index 6fb5085..5d65116 100644 (file)
@@ -36,6 +36,7 @@ add_executable(pressure src/pressure.c)
 add_executable(temperature src/temperature.c)
 add_executable(light src/light.c)
 add_executable(rotation_vector src/rotation_vector.c)
+add_executable(geomagnetic_rv src/geomagnetic_rv.c)
 
 SET_TARGET_PROPERTIES(accelerometer PROPERTIES LINKER_LANGUAGE C)
 SET_TARGET_PROPERTIES(geomagnetic PROPERTIES LINKER_LANGUAGE C)
@@ -48,6 +49,7 @@ SET_TARGET_PROPERTIES(pressure PROPERTIES LINKER_LANGUAGE C)
 SET_TARGET_PROPERTIES(temperature PROPERTIES LINKER_LANGUAGE C)
 SET_TARGET_PROPERTIES(light PROPERTIES LINKER_LANGUAGE C)
 SET_TARGET_PROPERTIES(rotation_vector PROPERTIES LINKER_LANGUAGE C)
+SET_TARGET_PROPERTIES(geomagnetic_rv PROPERTIES LINKER_LANGUAGE C)
 
 target_link_libraries(accelerometer glib-2.0 dlog sensor)
 target_link_libraries(geomagnetic glib-2.0 dlog sensor)
@@ -60,6 +62,7 @@ target_link_libraries(pressure glib-2.0 dlog sensor)
 target_link_libraries(temperature glib-2.0 dlog sensor)
 target_link_libraries(light glib-2.0 dlog sensor)
 target_link_libraries(rotation_vector glib-2.0 dlog sensor)
+target_link_libraries(geomagnetic_rv glib-2.0 dlog sensor)
 
 INSTALL(TARGETS accelerometer DESTINATION /usr/bin/)
 INSTALL(TARGETS geomagnetic DESTINATION /usr/bin/)
@@ -72,4 +75,5 @@ INSTALL(TARGETS pressure DESTINATION /usr/bin/)
 INSTALL(TARGETS temperature DESTINATION /usr/bin/)
 INSTALL(TARGETS light DESTINATION /usr/bin/)
 INSTALL(TARGETS rotation_vector DESTINATION /usr/bin/)
+INSTALL(TARGETS geomagnetic_rv DESTINATION /usr/bin/)
 
index 1c20c0d..ab299df 100755 (executable)
                        <GEOMAGNETIC_SCALE value="1" />
                        <MAGNETIC_ALIGNMENT_FACTOR value="1" />
                </ROTATION_VECTOR>
+
+               <GEOMAGNETIC_ROTATION_VECTOR>
+                       <NAME value="GEOMAGNETIC_RV_SENSOR" />
+                       <VENDOR value="SAMSUNG" />
+                       <DEFAULT_SAMPLING_TIME value="100" />
+                       <ACCEL_STATIC_BIAS value1="0" value2="0" value3="0" />
+                       <GEOMAGNETIC_STATIC_BIAS value1="0" value2="0" value3="0" />
+                       <ACCEL_ROTATION_DIRECTION_COMPENSATION value1="-1" value2="-1" value3="-1" />
+                       <GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION value1="-1" value2="-1" value3="-1" />
+                       <ACCEL_SCALE value="1" />
+                       <GEOMAGNETIC_SCALE value="1" />
+                       <MAGNETIC_ALIGNMENT_FACTOR value="1" />
+               </GEOMAGNETIC_ROTATION_VECTOR>
        </DEVICE>
        <DEVICE type="Mobile-RD-PQ">
                <ORIENTATION>
                        <GEOMAGNETIC_SCALE value="1" />
                        <MAGNETIC_ALIGNMENT_FACTOR value="1" />
                </ROTATION_VECTOR>
+
+               <GEOMAGNETIC_ROTATION_VECTOR>
+                       <NAME value="GEOMAGNETIC_RV_SENSOR" />
+                       <VENDOR value="SAMSUNG" />
+                       <DEFAULT_SAMPLING_TIME value="100" />
+                       <ACCEL_STATIC_BIAS value1="0.098586" value2="0.18385" value3="0.274" />
+                       <GEOMAGNETIC_STATIC_BIAS value1="0" value2="-37.6" value3="37.6" />
+                       <ACCEL_ROTATION_DIRECTION_COMPENSATION value1="1" value2="1" value3="1" />
+                       <GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION value1="1" value2="-1" value3="1" />
+                       <ACCEL_SCALE value="1" />
+                       <GEOMAGNETIC_SCALE value="1" />
+                       <MAGNETIC_ALIGNMENT_FACTOR value="1" />
+               </GEOMAGNETIC_ROTATION_VECTOR>
        </DEVICE>
 </VIRTUAL_SENSOR>