4 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
26 #include <sys/types.h>
29 #include <sensor_log.h>
30 #include <sensor_types.h>
32 #include <sensor_common.h>
33 #include <virtual_sensor.h>
34 #include <gravity_sensor.h>
35 #include <sensor_loader.h>
36 #include <fusion_util.h>
38 #define SENSOR_NAME "SENSOR_GRAVITY"
40 #define GRAVITY 9.80665
42 #define PHASE_ACCEL_READY 0x01
43 #define PHASE_GYRO_READY 0x02
44 #define PHASE_FUSION_READY 0x03
45 #define US_PER_SEC 1000000
46 #define MS_PER_SEC 1000
47 #define INV_ANGLE -1000
52 #define DEG2RAD(x) ((x) * M_PI / 180.0)
53 #define NORM(x, y, z) sqrt((x)*(x) + (y)*(y) + (z)*(z))
54 #define ARCTAN(x, y) ((x) == 0 ? 0 : (y) != 0 ? atan2((x), (y)) : (x) > 0 ? M_PI/2.0 : -M_PI/2.0)
56 gravity_sensor::gravity_sensor()
58 , m_accel_sensor(NULL)
69 gravity_sensor::~gravity_sensor()
71 _I("gravity_sensor is destroyed!\n");
74 bool gravity_sensor::init()
76 /* Acc (+ Gyro) fusion */
77 m_accel_sensor = sensor_loader::get_instance().get_sensor(ACCELEROMETER_SENSOR);
79 if (!m_accel_sensor) {
80 _E("cannot load accelerometer sensor_hal[%s]", get_name());
84 m_gyro_sensor = sensor_loader::get_instance().get_sensor(GYROSCOPE_SENSOR);
86 _I("%s (%s) is created!\n", get_name(), m_gyro_sensor ? "Acc+Gyro Fusion" : "LowPass Acc");
90 sensor_type_t gravity_sensor::get_type(void)
92 return GRAVITY_SENSOR;
95 unsigned int gravity_sensor::get_event_type(void)
97 return GRAVITY_EVENT_RAW_DATA_REPORT_ON_TIME;
100 const char* gravity_sensor::get_name(void)
105 bool gravity_sensor::get_sensor_info(sensor_info &info)
107 info.set_type(get_type());
108 info.set_id(get_id());
109 info.set_privilege(SENSOR_PRIVILEGE_PUBLIC); // FIXME
110 info.set_name("Gravity Sensor");
111 info.set_vendor("Samsung Electronics");
112 info.set_min_range(-19.6);
113 info.set_max_range(19.6);
114 info.set_resolution(0.01);
115 info.set_min_interval(1);
116 info.set_fifo_count(0);
117 info.set_max_batch_count(0);
118 info.set_supported_event(get_event_type());
119 info.set_wakeup_supported(false);
124 void gravity_sensor::synthesize(const sensor_event_t& event)
126 /* If the rotation vector sensor is available */
128 synthesize_rv(event);
132 /* If both Acc & Gyro are available */
134 synthesize_fusion(event);
138 /* If only Acc is available */
139 synthesize_lowpass(event);
142 void gravity_sensor::synthesize_rv(const sensor_event_t& event)
144 if (!m_fusion->is_data_ready())
147 sensor_event_t *gravity_event;
149 float x, y, z, w, heading_accuracy;
152 if (!m_fusion->get_rotation_vector(x, y, z, w, heading_accuracy, accuracy)) {
153 _E("Failed to get rotation vector");
157 unsigned long long timestamp = m_fusion->get_data_timestamp();
159 if (!check_sampling_time(timestamp))
162 float rotation[4] = {x, y, z, w};
164 if (!rotation_to_gravity(rotation, gravity)) {
165 _D("Invalid rotation_vector: [%10f] [%10f] [%10f] [%10f]", x, y, z, w);
169 gravity_event = (sensor_event_t *)malloc(sizeof(sensor_event_t));
170 if (!gravity_event) {
171 _E("Failed to allocate memory");
174 gravity_event->data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
175 if (!gravity_event->data) {
176 _E("Failed to allocate memory");
181 gravity_event->sensor_id = get_id();
182 gravity_event->event_type = GRAVITY_EVENT_RAW_DATA_REPORT_ON_TIME;
183 gravity_event->data_length = sizeof(sensor_data_t);
184 gravity_event->data->accuracy = accuracy;
185 gravity_event->data->timestamp = m_fusion->get_data_timestamp();
186 gravity_event->data->value_count = 3;
187 gravity_event->data->values[0] = gravity[0];
188 gravity_event->data->values[1] = gravity[1];
189 gravity_event->data->values[2] = gravity[2];
192 m_time = event.data->timestamp;
196 m_accuracy = accuracy;
199 void gravity_sensor::synthesize_lowpass(const sensor_event_t& event)
201 if (event.event_type != ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME)
204 sensor_event_t *gravity_event;
205 float x, y, z, norm, alpha, tau, err;
207 norm = NORM(event.data->values[0], event.data->values[1], event.data->values[2]);
208 x = event.data->values[0] / norm * GRAVITY;
209 y = event.data->values[1] / norm * GRAVITY;
210 z = event.data->values[2] / norm * GRAVITY;
213 err = fabs(norm - GRAVITY) / GRAVITY;
214 tau = (err < 0.1 ? TAU_LOW : err > 0.9 ? TAU_HIGH : TAU_MID);
215 alpha = tau / (tau + (float)(event.data->timestamp - m_time) / US_PER_SEC);
216 x = alpha * m_x + (1 - alpha) * x;
217 y = alpha * m_y + (1 - alpha) * y;
218 z = alpha * m_z + (1 - alpha) * z;
219 norm = NORM(x, y, z);
220 x = x / norm * GRAVITY;
221 y = y / norm * GRAVITY;
222 z = z / norm * GRAVITY;
225 gravity_event = (sensor_event_t *)malloc(sizeof(sensor_event_t));
226 if (!gravity_event) {
227 _E("Failed to allocate memory");
230 gravity_event->data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
231 if (!gravity_event->data) {
232 _E("Failed to allocate memory");
237 gravity_event->sensor_id = get_id();
238 gravity_event->event_type = GRAVITY_EVENT_RAW_DATA_REPORT_ON_TIME;
239 gravity_event->data_length = sizeof(sensor_data_t);
240 gravity_event->data->accuracy = event.data->accuracy;
241 gravity_event->data->timestamp = event.data->timestamp;
242 gravity_event->data->value_count = 3;
243 gravity_event->data->values[0] = x;
244 gravity_event->data->values[1] = y;
245 gravity_event->data->values[2] = z;
248 m_time = event.data->timestamp;
252 m_accuracy = event.data->accuracy;
255 void gravity_sensor::synthesize_fusion(const sensor_event_t& event)
257 sensor_event_t *gravity_event;
259 if (event.event_type == ACCELEROMETER_EVENT_RAW_DATA_REPORT_ON_TIME) {
260 fusion_set_accel(event);
261 m_fusion_phase |= PHASE_ACCEL_READY;
262 } else if (event.event_type == GYROSCOPE_EVENT_RAW_DATA_REPORT_ON_TIME) {
263 fusion_set_gyro(event);
264 m_fusion_phase |= PHASE_GYRO_READY;
267 if (m_fusion_phase != PHASE_FUSION_READY)
272 fusion_update_angle();
273 fusion_get_gravity();
275 gravity_event = (sensor_event_t *)malloc(sizeof(sensor_event_t));
276 if (!gravity_event) {
277 _E("Failed to allocate memory");
280 gravity_event->data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
281 if (!gravity_event->data) {
282 _E("Failed to allocate memory");
287 gravity_event->sensor_id = get_id();
288 gravity_event->event_type = GRAVITY_EVENT_RAW_DATA_REPORT_ON_TIME;
289 gravity_event->data_length = sizeof(sensor_data_t);
290 gravity_event->data->accuracy = m_accuracy;
291 gravity_event->data->timestamp = m_time;
292 gravity_event->data->value_count = 3;
293 gravity_event->data->values[0] = m_x;
294 gravity_event->data->values[1] = m_y;
295 gravity_event->data->values[2] = m_z;
299 void gravity_sensor::fusion_set_accel(const sensor_event_t& event)
301 double x = event.data->values[0];
302 double y = event.data->values[1];
303 double z = event.data->values[2];
305 m_accel_mag = NORM(x, y, z);
307 m_angle_n[0] = ARCTAN(z, y);
308 m_angle_n[1] = ARCTAN(x, z);
309 m_angle_n[2] = ARCTAN(y, x);
311 m_accuracy = event.data->accuracy;
312 m_time_new = event.data->timestamp;
314 _D("AccIn: (%f, %f, %f)", x/m_accel_mag, y/m_accel_mag, z/m_accel_mag);
317 void gravity_sensor::fusion_set_gyro(const sensor_event_t& event)
319 m_velocity[0] = -DEG2RAD(event.data->values[0]);
320 m_velocity[1] = -DEG2RAD(event.data->values[1]);
321 m_velocity[2] = -DEG2RAD(event.data->values[2]);
323 m_time_new = event.data->timestamp;
326 void gravity_sensor::fusion_update_angle()
328 _D("AngleIn: (%f, %f, %f)", m_angle_n[0], m_angle_n[1], m_angle_n[2]);
329 _D("AngAccl: (%f, %f, %f)", m_velocity[0], m_velocity[1], m_velocity[2]);
330 _D("Angle : (%f, %f, %f)", m_angle[0], m_angle[1], m_angle[2]);
332 if (m_angle[0] == INV_ANGLE) {
334 m_angle[0] = m_angle_n[0];
335 m_angle[1] = m_angle_n[1];
336 m_angle[2] = m_angle_n[2];
338 complementary(m_time_new - m_time);
341 _D("Angle' : (%f, %f, %f)", m_angle[0], m_angle[1], m_angle[2]);
344 void gravity_sensor::fusion_get_gravity()
346 double x = 0, y = 0, z = 0;
350 /* Rotating along y-axis then z-axis */
351 vec[0][2] = cos(m_angle[1]);
352 vec[0][0] = sin(m_angle[1]);
353 vec[0][1] = vec[0][0] * tan(m_angle[2]);
355 /* Rotating along z-axis then x-axis */
356 vec[1][0] = cos(m_angle[2]);
357 vec[1][1] = sin(m_angle[2]);
358 vec[1][2] = vec[1][1] * tan(m_angle[0]);
360 /* Rotating along x-axis then y-axis */
361 vec[2][1] = cos(m_angle[0]);
362 vec[2][2] = sin(m_angle[0]);
363 vec[2][0] = vec[2][2] * tan(m_angle[1]);
366 for (int i = 0; i < 3; ++i) {
367 norm = NORM(vec[i][0], vec[i][1], vec[i][2]);
376 norm = NORM(x, y, z);
378 m_x = x / norm * GRAVITY;
379 m_y = y / norm * GRAVITY;
380 m_z = z / norm * GRAVITY;
384 void gravity_sensor::complementary(unsigned long long time_diff)
386 double err = fabs(m_accel_mag - GRAVITY) / GRAVITY;
387 double tau = (err < 0.1 ? TAU_LOW : err > 0.9 ? TAU_HIGH : TAU_MID);
388 double delta_t = (double)time_diff/ US_PER_SEC;
389 double alpha = tau / (tau + delta_t);
391 _D("mag, err, tau, dt, alpha = %f, %f, %f, %f, %f", m_accel_mag, err, tau, delta_t, alpha);
393 m_angle[0] = complementary(m_angle[0], m_angle_n[0], m_velocity[0], delta_t, alpha);
394 m_angle[1] = complementary(m_angle[1], m_angle_n[1], m_velocity[1], delta_t, alpha);
395 m_angle[2] = complementary(m_angle[2], m_angle_n[2], m_velocity[2], delta_t, alpha);
398 double gravity_sensor::complementary(double angle, double angle_in, double vel, double delta_t, double alpha)
401 angle = angle + vel * delta_t;
402 s = alpha * sin(angle) + (1 - alpha) * sin(angle_in);
403 c = alpha * cos(angle) + (1 - alpha) * cos(angle_in);
407 int gravity_sensor::get_data(sensor_data_t **data, int *length)
409 /* if It is batch sensor, remains can be 2+ */
412 sensor_data_t *sensor_data;
413 sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
415 sensor_data->accuracy = m_accuracy;
416 sensor_data->timestamp = m_time;
417 sensor_data->value_count = 3;
418 sensor_data->values[0] = m_x;
419 sensor_data->values[1] = m_y;
420 sensor_data->values[2] = m_z;
423 *length = sizeof(sensor_data_t);
428 bool gravity_sensor::set_batch_latency(unsigned long latency)
433 bool gravity_sensor::set_wakeup(int wakeup)
438 bool gravity_sensor::on_start(void)
444 m_accel_sensor->start();
447 m_gyro_sensor->start();
451 m_angle[0] = INV_ANGLE;
456 bool gravity_sensor::on_stop(void)
462 m_accel_sensor->stop();
465 m_gyro_sensor->stop();
472 bool gravity_sensor::add_interval(int client_id, unsigned int interval, bool is_processor)
475 m_fusion->set_interval(FUSION_EVENT_AGM, client_id, interval);
478 m_accel_sensor->add_interval(client_id, interval, true);
481 m_gyro_sensor->add_interval(client_id, interval, true);
483 return sensor_base::add_interval(client_id, interval, is_processor);
486 bool gravity_sensor::delete_interval(int client_id, bool is_processor)
489 m_fusion->unset_interval(FUSION_EVENT_AGM, client_id);
492 m_accel_sensor->delete_interval(client_id, true);
495 m_gyro_sensor->delete_interval(client_id, true);
497 return sensor_base::delete_interval(client_id, is_processor);
500 bool gravity_sensor::set_interval(unsigned long interval)
502 m_interval = interval;
506 bool gravity_sensor::rotation_to_gravity(const float *rotation, float *gravity)
510 if (quat_to_matrix(rotation, R) < 0)
513 gravity[0] = R[6] * GRAVITY;
514 gravity[1] = R[7] * GRAVITY;
515 gravity[2] = R[8] * GRAVITY;
520 bool gravity_sensor::check_sampling_time(unsigned long long timestamp)
522 const float MIN_DELIVERY_DIFF_FACTOR = 0.75f;
523 const int MS_TO_US = 1000;
526 diff_time = timestamp - m_time;
528 if (m_time && (diff_time < m_interval * MS_TO_US * MIN_DELIVERY_DIFF_FACTOR))