0bac151c185bdb8ff6d92db51d7b6cb632bca1c0
[platform/core/system/sensord.git] / src / fusion / fusion_sensor.cpp
1 /*
2  * sensord
3  *
4  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <math.h>
25 #include <time.h>
26 #include <sys/types.h>
27 #include <dlfcn.h>
28 #include <common.h>
29 #include <sf_common.h>
30 #include <fusion_sensor.h>
31 #include <sensor_plugin_loader.h>
32 #include <orientation_filter.h>
33 #include <cvirtual_sensor_config.h>
34 #include <algorithm>
35
36 #define SENSOR_NAME "FUSION_SENSOR"
37 #define SENSOR_TYPE_FUSION              "FUSION"
38
39 #define ACCELEROMETER_ENABLED 0x01
40 #define GYROSCOPE_ENABLED 0x02
41 #define GEOMAGNETIC_ENABLED 0x04
42 #define GAMING_RV_ENABLED 3
43 #define GEOMAGNETIC_RV_ENABLED 5
44 #define ORIENTATION_ENABLED 7
45 #define ROTATION_VECTOR_ENABLED 7
46
47 #define INITIAL_VALUE -1
48
49 #define MS_TO_US 1000
50 #define MIN_DELIVERY_DIFF_FACTOR 0.75f
51
52 #define PI 3.141593
53 #define AZIMUTH_OFFSET_DEGREES 360
54 #define AZIMUTH_OFFSET_RADIANS (2 * PI)
55
56 #define ELEMENT_NAME                                                                                    "NAME"
57 #define ELEMENT_VENDOR                                                                                  "VENDOR"
58 #define ELEMENT_RAW_DATA_UNIT                                                                   "RAW_DATA_UNIT"
59 #define ELEMENT_DEFAULT_SAMPLING_TIME                                                   "DEFAULT_SAMPLING_TIME"
60 #define ELEMENT_ACCEL_STATIC_BIAS                                                               "ACCEL_STATIC_BIAS"
61 #define ELEMENT_GYRO_STATIC_BIAS                                                                "GYRO_STATIC_BIAS"
62 #define ELEMENT_GEOMAGNETIC_STATIC_BIAS                                                 "GEOMAGNETIC_STATIC_BIAS"
63 #define ELEMENT_ACCEL_ROTATION_DIRECTION_COMPENSATION                   "ACCEL_ROTATION_DIRECTION_COMPENSATION"
64 #define ELEMENT_GYRO_ROTATION_DIRECTION_COMPENSATION                    "GYRO_ROTATION_DIRECTION_COMPENSATION"
65 #define ELEMENT_GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION             "GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION"
66 #define ELEMENT_ACCEL_SCALE                                                                             "ACCEL_SCALE"
67 #define ELEMENT_GYRO_SCALE                                                                              "GYRO_SCALE"
68 #define ELEMENT_GEOMAGNETIC_SCALE                                                               "GEOMAGNETIC_SCALE"
69 #define ELEMENT_MAGNETIC_ALIGNMENT_FACTOR                                               "MAGNETIC_ALIGNMENT_FACTOR"
70 #define ELEMENT_PITCH_ROTATION_COMPENSATION                                             "PITCH_ROTATION_COMPENSATION"
71 #define ELEMENT_ROLL_ROTATION_COMPENSATION                                              "ROLL_ROTATION_COMPENSATION"
72 #define ELEMENT_AZIMUTH_ROTATION_COMPENSATION                                   "AZIMUTH_ROTATION_COMPENSATION"
73
74 void pre_process_data(sensor_data<float> &data_out, const float *data_in, float *bias, int *sign, float scale)
75 {
76         data_out.m_data.m_vec[0] = sign[0] * (data_in[0] - bias[0]) / scale;
77         data_out.m_data.m_vec[1] = sign[1] * (data_in[1] - bias[1]) / scale;
78         data_out.m_data.m_vec[2] = sign[2] * (data_in[2] - bias[2]) / scale;
79 }
80
81 fusion_sensor::fusion_sensor()
82 : m_accel_sensor(NULL)
83 , m_gyro_sensor(NULL)
84 , m_magnetic_sensor(NULL)
85 , m_time(0)
86 {
87         cvirtual_sensor_config &config = cvirtual_sensor_config::get_instance();
88         m_name = string(SENSOR_NAME);
89         m_enable_fusion = 0;
90
91         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_VENDOR, m_vendor)) {
92                 ERR("[VENDOR] is empty\n");
93                 throw ENXIO;
94         }
95
96         INFO("m_vendor = %s", m_vendor.c_str());
97
98         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_RAW_DATA_UNIT, m_raw_data_unit)) {
99                 ERR("[RAW_DATA_UNIT] is empty\n");
100                 throw ENXIO;
101         }
102
103         INFO("m_raw_data_unit = %s", m_raw_data_unit.c_str());
104
105         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_DEFAULT_SAMPLING_TIME, &m_default_sampling_time)) {
106                 ERR("[DEFAULT_SAMPLING_TIME] is empty\n");
107                 throw ENXIO;
108         }
109
110         INFO("m_default_sampling_time = %d", m_default_sampling_time);
111
112         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_ACCEL_STATIC_BIAS, m_accel_static_bias, 3)) {
113                 ERR("[ACCEL_STATIC_BIAS] is empty\n");
114                 throw ENXIO;
115         }
116
117         INFO("m_accel_static_bias = (%f, %f, %f)", m_accel_static_bias[0], m_accel_static_bias[1], m_accel_static_bias[2]);
118
119         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_GYRO_STATIC_BIAS, m_gyro_static_bias,3)) {
120                 ERR("[GYRO_STATIC_BIAS] is empty\n");
121                 throw ENXIO;
122         }
123
124         INFO("m_gyro_static_bias = (%f, %f, %f)", m_gyro_static_bias[0], m_gyro_static_bias[1], m_gyro_static_bias[2]);
125
126         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_GEOMAGNETIC_STATIC_BIAS, m_geomagnetic_static_bias, 3)) {
127                 ERR("[GEOMAGNETIC_STATIC_BIAS] is empty\n");
128                 throw ENXIO;
129         }
130
131         INFO("m_geomagnetic_static_bias = (%f, %f, %f)", m_geomagnetic_static_bias[0], m_geomagnetic_static_bias[1], m_geomagnetic_static_bias[2]);
132
133         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_ACCEL_ROTATION_DIRECTION_COMPENSATION, m_accel_rotation_direction_compensation, 3)) {
134                 ERR("[ACCEL_ROTATION_DIRECTION_COMPENSATION] is empty\n");
135                 throw ENXIO;
136         }
137
138         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]);
139
140         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_GYRO_ROTATION_DIRECTION_COMPENSATION, m_gyro_rotation_direction_compensation, 3)) {
141                 ERR("[GYRO_ROTATION_DIRECTION_COMPENSATION] is empty\n");
142                 throw ENXIO;
143         }
144
145         INFO("m_gyro_rotation_direction_compensation = (%d, %d, %d)", m_gyro_rotation_direction_compensation[0], m_gyro_rotation_direction_compensation[1], m_gyro_rotation_direction_compensation[2]);
146
147         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION, m_geomagnetic_rotation_direction_compensation, 3)) {
148                 ERR("[GEOMAGNETIC_ROTATION_DIRECTION_COMPENSATION] is empty\n");
149                 throw ENXIO;
150         }
151
152         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]);
153
154         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_ACCEL_SCALE, &m_accel_scale)) {
155                 ERR("[ACCEL_SCALE] is empty\n");
156                 throw ENXIO;
157         }
158
159         INFO("m_accel_scale = %f", m_accel_scale);
160
161         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_GYRO_SCALE, &m_gyro_scale)) {
162                 ERR("[GYRO_SCALE] is empty\n");
163                 throw ENXIO;
164         }
165
166         INFO("m_gyro_scale = %f", m_gyro_scale);
167
168         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_GEOMAGNETIC_SCALE, &m_geomagnetic_scale)) {
169                 ERR("[GEOMAGNETIC_SCALE] is empty\n");
170                 throw ENXIO;
171         }
172
173         INFO("m_geomagnetic_scale = %f", m_geomagnetic_scale);
174
175         if (!config.get(SENSOR_TYPE_FUSION, ELEMENT_MAGNETIC_ALIGNMENT_FACTOR, &m_magnetic_alignment_factor)) {
176                 ERR("[MAGNETIC_ALIGNMENT_FACTOR] is empty\n");
177                 throw ENXIO;
178         }
179
180         INFO("m_magnetic_alignment_factor = %d", m_magnetic_alignment_factor);
181
182         m_interval = m_default_sampling_time * MS_TO_US;
183
184         m_accel_ptr = m_gyro_ptr = m_magnetic_ptr = NULL;
185 }
186
187 fusion_sensor::~fusion_sensor()
188 {
189         INFO("fusion_sensor is destroyed!\n");
190 }
191
192 bool fusion_sensor::init(void)
193 {
194         m_accel_sensor = sensor_plugin_loader::get_instance().get_sensor(ACCELEROMETER_SENSOR);
195         m_gyro_sensor = sensor_plugin_loader::get_instance().get_sensor(GYROSCOPE_SENSOR);
196         m_magnetic_sensor = sensor_plugin_loader::get_instance().get_sensor(GEOMAGNETIC_SENSOR);
197
198         if (!m_accel_sensor) {
199                 ERR("Failed to load accel sensor: 0x%x", m_accel_sensor);
200                 return false;
201         }
202
203         if (!m_gyro_sensor)
204                 INFO("Failed to load gyro sensor: 0x%x", m_gyro_sensor);
205
206         if (!m_magnetic_sensor)
207                 INFO("Failed to load geomagnetic sensor: 0x%x", m_magnetic_sensor);
208
209         INFO("%s is created!", sensor_base::get_name());
210         return true;
211 }
212
213 sensor_type_t fusion_sensor::get_type(void)
214 {
215         return FUSION_SENSOR;
216 }
217
218 bool fusion_sensor::on_start(void)
219 {
220         AUTOLOCK(m_mutex);
221         activate();
222         return true;
223 }
224
225 bool fusion_sensor::on_stop(void)
226 {
227         AUTOLOCK(m_mutex);
228         deactivate();
229         return true;
230 }
231
232 bool fusion_sensor::add_interval(int client_id, unsigned int interval)
233 {
234         bool retval;
235
236         AUTOLOCK(m_mutex);
237         retval = sensor_base::add_interval(client_id, interval, false);
238
239         m_interval = sensor_base::get_interval(client_id, false);
240
241         if (m_interval != 0)
242                 retval = true;
243
244         return retval;
245 }
246
247 bool fusion_sensor::delete_interval(int client_id)
248 {
249         bool retval;
250
251         AUTOLOCK(m_mutex);
252         retval = sensor_base::delete_interval(client_id, false);
253
254         m_interval = sensor_base::get_interval(client_id, false);
255
256         if (m_interval != 0)
257                 retval = true;
258
259         return retval;
260 }
261
262 void fusion_sensor::synthesize(const sensor_event_t &event, vector<sensor_event_t> &outs)
263 {
264         unsigned long long diff_time;
265         euler_angles<float> euler_orientation;
266
267         if (event.event_type == ACCELEROMETER_RAW_DATA_EVENT) {
268                 diff_time = event.data.timestamp - m_time;
269
270                 if (m_time && (diff_time < m_interval * MIN_DELIVERY_DIFF_FACTOR))
271                         return;
272
273                 pre_process_data(m_accel, event.data.values, m_accel_static_bias, m_accel_rotation_direction_compensation, m_accel_scale);
274
275                 m_accel.m_time_stamp = event.data.timestamp;
276
277                 m_accel_ptr = &m_accel;
278
279                 m_enable_fusion |= ACCELEROMETER_ENABLED;
280         }
281
282         if (sensor_base::is_supported(FUSION_ORIENTATION_ENABLED) ||
283                         sensor_base::is_supported(FUSION_ROTATION_VECTOR_ENABLED) ||
284                         sensor_base::is_supported(FUSION_GEOMAGNETIC_ROTATION_VECTOR_ENABLED)) {
285                 if (event.event_type == GEOMAGNETIC_RAW_DATA_EVENT) {
286                         diff_time = event.data.timestamp - m_time;
287
288                         if (m_time && (diff_time < m_interval * MIN_DELIVERY_DIFF_FACTOR))
289                                 return;
290
291                         pre_process_data(m_magnetic, event.data.values, m_geomagnetic_static_bias, m_geomagnetic_rotation_direction_compensation, m_geomagnetic_scale);
292
293                         m_magnetic.m_time_stamp = event.data.timestamp;
294
295                         m_magnetic_ptr = &m_magnetic;
296
297                         m_enable_fusion |= GEOMAGNETIC_ENABLED;
298                 }
299         }
300
301         if (sensor_base::is_supported(FUSION_ORIENTATION_ENABLED) ||
302                         sensor_base::is_supported(FUSION_ROTATION_VECTOR_ENABLED) ||
303                         sensor_base::is_supported(FUSION_GAMING_ROTATION_VECTOR_ENABLED)) {
304                 if (event.event_type == GYROSCOPE_RAW_DATA_EVENT) {
305                                 diff_time = event.data.timestamp - m_time;
306
307                                 if (m_time && (diff_time < m_interval * MIN_DELIVERY_DIFF_FACTOR))
308                                         return;
309
310                                 pre_process_data(m_gyro, event.data.values, m_gyro_static_bias, m_gyro_rotation_direction_compensation, m_gyro_scale);
311
312                                 m_gyro.m_time_stamp = event.data.timestamp;
313
314                                 m_gyro_ptr = &m_gyro;
315
316                                 m_enable_fusion |= GYROSCOPE_ENABLED;
317                 }
318         }
319
320         if ((m_enable_fusion == ORIENTATION_ENABLED && sensor_base::is_supported(FUSION_ORIENTATION_ENABLED)) ||
321                         (m_enable_fusion == ROTATION_VECTOR_ENABLED && sensor_base::is_supported(FUSION_ROTATION_VECTOR_ENABLED)) ||
322                         (m_enable_fusion == GAMING_RV_ENABLED && sensor_base::is_supported(FUSION_GAMING_ROTATION_VECTOR_ENABLED)) ||
323                         (m_enable_fusion == GEOMAGNETIC_RV_ENABLED && sensor_base::is_supported(FUSION_GEOMAGNETIC_ROTATION_VECTOR_ENABLED))) {
324                 sensor_event_t fusion_event;
325                 m_enable_fusion = 0;
326
327                 m_orientation_filter.m_magnetic_alignment_factor = m_magnetic_alignment_factor;
328
329                 m_orientation_filter.get_device_orientation(m_accel_ptr, m_gyro_ptr, m_magnetic_ptr);
330
331                 m_time = get_timestamp();
332                 fusion_event.sensor_id = get_id();
333                 fusion_event.event_type = FUSION_EVENT;
334                 fusion_event.data.accuracy = SENSOR_ACCURACY_GOOD;
335                 fusion_event.data.timestamp = m_time;
336                 fusion_event.data.value_count = 4;
337                 fusion_event.data.values[0] = m_orientation_filter.m_quaternion.m_quat.m_vec[0];
338                 fusion_event.data.values[1] = m_orientation_filter.m_quaternion.m_quat.m_vec[1];
339                 fusion_event.data.values[2] = m_orientation_filter.m_quaternion.m_quat.m_vec[2];
340                 fusion_event.data.values[3] = m_orientation_filter.m_quaternion.m_quat.m_vec[3];
341
342                 m_accel_ptr = m_gyro_ptr = m_magnetic_ptr = NULL;
343
344                 push(fusion_event);
345         }
346
347         return;
348 }
349
350 int fusion_sensor::get_sensor_data(const unsigned int event_type, sensor_data_t &data)
351 {
352         sensor_data<float> accel;
353         sensor_data<float> gyro;
354         sensor_data<float> magnetic;
355
356         sensor_data_t accel_data;
357         sensor_data_t gyro_data;
358         sensor_data_t magnetic_data;
359
360         euler_angles<float> euler_orientation;
361
362         if (event_type != FUSION_ORIENTATION_ENABLED ||
363                         event_type != FUSION_ROTATION_VECTOR_ENABLED ||
364                         event_type != FUSION_GAMING_ROTATION_VECTOR_ENABLED ||
365                         event_type != FUSION_GEOMAGNETIC_ROTATION_VECTOR_ENABLED)
366                 return -1;
367
368         m_accel_sensor->get_sensor_data(ACCELEROMETER_RAW_DATA_EVENT, accel_data);
369         pre_process_data(accel, accel_data.values, m_accel_static_bias, m_accel_rotation_direction_compensation, m_accel_scale);
370         accel.m_time_stamp = accel_data.timestamp;
371
372         if (event_type == FUSION_ORIENTATION_ENABLED ||
373                         event_type == FUSION_ROTATION_VECTOR_ENABLED ||
374                         event_type == FUSION_GAMING_ROTATION_VECTOR_ENABLED)
375         {
376                 m_gyro_sensor->get_sensor_data(GYROSCOPE_RAW_DATA_EVENT, gyro_data);
377                 pre_process_data(gyro, gyro_data.values, m_gyro_static_bias, m_gyro_rotation_direction_compensation, m_gyro_scale);
378                 gyro.m_time_stamp = gyro_data.timestamp;
379         }
380
381         if (event_type == FUSION_ORIENTATION_ENABLED ||
382                         event_type == FUSION_ROTATION_VECTOR_ENABLED ||
383                         event_type == FUSION_GEOMAGNETIC_ROTATION_VECTOR_ENABLED)
384         {
385                 m_magnetic_sensor->get_sensor_data(GEOMAGNETIC_RAW_DATA_EVENT, magnetic_data);
386                 pre_process_data(magnetic, magnetic_data.values, m_geomagnetic_static_bias, m_geomagnetic_rotation_direction_compensation, m_geomagnetic_scale);
387                 magnetic.m_time_stamp = magnetic_data.timestamp;
388         }
389
390         m_orientation_filter_poll.m_magnetic_alignment_factor = m_magnetic_alignment_factor;
391
392         if (event_type == FUSION_ORIENTATION_ENABLED || event_type == FUSION_ROTATION_VECTOR_ENABLED)
393                 m_orientation_filter_poll.get_device_orientation(&accel, &gyro, &magnetic);
394         else if (event_type == FUSION_GAMING_ROTATION_VECTOR_ENABLED)
395                 m_orientation_filter_poll.get_device_orientation(&accel, &gyro, NULL);
396         else if (event_type == FUSION_GEOMAGNETIC_ROTATION_VECTOR_ENABLED)
397                 m_orientation_filter_poll.get_device_orientation(&accel, NULL, &magnetic);
398
399         data.accuracy = SENSOR_ACCURACY_GOOD;
400         data.timestamp = get_timestamp();
401         data.value_count = 4;
402         data.values[0] = m_orientation_filter_poll.m_quaternion.m_quat.m_vec[0];
403         data.values[1] = m_orientation_filter_poll.m_quaternion.m_quat.m_vec[1];
404         data.values[2] = m_orientation_filter_poll.m_quaternion.m_quat.m_vec[2];
405         data.values[3] = m_orientation_filter_poll.m_quaternion.m_quat.m_vec[3];
406
407         return 0;
408 }
409
410 bool fusion_sensor::get_properties(sensor_properties_s &properties)
411 {
412         properties.min_range = 0;
413         properties.max_range = 0;
414         properties.resolution = 0;
415         properties.vendor = m_vendor;
416         properties.name = SENSOR_NAME;
417         properties.min_interval = 0;
418         properties.fifo_count = 0;
419         properties.max_batch_count = 0;
420
421         return true;
422 }
423
424 extern "C" sensor_module* create(void)
425 {
426         fusion_sensor *sensor;
427
428         try {
429                 sensor = new(std::nothrow) fusion_sensor;
430         } catch (int err) {
431                 ERR("Failed to create module, err: %d, cause: %s", err, strerror(err));
432                 return NULL;
433         }
434
435         sensor_module *module = new(std::nothrow) sensor_module;
436         retvm_if(!module || !sensor, NULL, "Failed to allocate memory");
437
438         module->sensors.push_back(sensor);
439         return module;
440 }