9b23ea5c6d9ad939611183854a3fdab7f5b62bcc
[platform/core/system/sensord.git] / src / plugins / geo / geo_sensor_hal.cpp
1 /*
2  * geo_sensor_hal
3  *
4  * Copyright (c) 2014 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 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <dirent.h>
22 #include <linux/input.h>
23 #include <csensor_config.h>
24 #include <geo_sensor_hal.h>
25 #include <sys/ioctl.h>
26 #include <fstream>
27
28 using std::ifstream;
29 using std::string;
30
31 #define SENSOR_TYPE_MAGNETIC    "MAGNETIC"
32 #define ELEMENT_NAME                            "NAME"
33 #define ELEMENT_VENDOR                  "VENDOR"
34 #define ELEMENT_RAW_DATA_UNIT   "RAW_DATA_UNIT"
35 #define ELEMENT_MIN_RANGE               "MIN_RANGE"
36 #define ELEMENT_MAX_RANGE               "MAX_RANGE"
37 #define ATTR_VALUE                              "value"
38
39 geo_sensor_hal::geo_sensor_hal()
40 : m_x(0)
41 , m_y(0)
42 , m_z(0)
43 , m_hdst(0)
44 , m_fired_time(0)
45 , m_node_handle(-1)
46 , m_polling_interval(POLL_1HZ_MS)
47 {
48         const string sensorhub_interval_node_name = "mag_poll_delay";
49         csensor_config &config = csensor_config::get_instance();
50
51         node_info_query query;
52         node_info info;
53
54         if (!find_model_id(SENSOR_TYPE_MAGNETIC, m_model_id)) {
55                 ERR("Failed to find model id");
56                 throw ENXIO;
57         }
58
59         query.sensorhub_controlled = m_sensorhub_controlled = is_sensorhub_controlled(sensorhub_interval_node_name);
60         query.sensor_type = SENSOR_TYPE_MAGNETIC;
61         query.key = "geomagnetic_sensor";
62         query.iio_enable_node_name = "geomagnetic_enable";
63         query.sensorhub_interval_node_name = sensorhub_interval_node_name;
64
65         bool error = get_node_info(query, info);
66
67         query.key = "magnetic_sensor";
68         error |= get_node_info(query, info);
69
70         if (!error) {
71                 ERR("Failed to get node info");
72                 throw ENXIO;
73         }
74
75         show_node_info(info);
76
77         m_data_node = info.data_node_path;
78         m_enable_node = info.enable_node_path;
79         m_interval_node = info.interval_node_path;
80
81         if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_VENDOR, m_vendor)) {
82                 ERR("[VENDOR] is empty\n");
83                 throw ENXIO;
84         }
85
86         INFO("m_vendor = %s", m_vendor.c_str());
87
88         if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_NAME, m_chip_name)) {
89                 ERR("[NAME] is empty\n");
90                 throw ENXIO;
91         }
92
93         INFO("m_chip_name = %s\n",m_chip_name.c_str());
94
95         double min_range;
96
97         if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_MIN_RANGE, min_range)) {
98                 ERR("[MIN_RANGE] is empty\n");
99                 throw ENXIO;
100         }
101
102         m_min_range = (float)min_range;
103         INFO("m_min_range = %f\n",m_min_range);
104
105         double max_range;
106
107         if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_MAX_RANGE, max_range)) {
108                 ERR("[MAX_RANGE] is empty\n");
109                 throw ENXIO;
110         }
111
112         m_max_range = (float)max_range;
113         INFO("m_max_range = %f\n",m_max_range);
114
115         double raw_data_unit;
116
117         if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) {
118                 ERR("[RAW_DATA_UNIT] is empty\n");
119                 throw ENXIO;
120         }
121
122         m_raw_data_unit = (float)(raw_data_unit);
123
124         if ((m_node_handle = open(m_data_node.c_str(),O_RDWR)) < 0) {
125                 ERR("Failed to open handle(%d)", m_node_handle);
126                 throw ENXIO;
127         }
128
129         int clockId = CLOCK_MONOTONIC;
130         if (ioctl(m_node_handle, EVIOCSCLOCKID, &clockId) != 0)
131                 ERR("Fail to set monotonic timestamp for %s", m_data_node.c_str());
132
133         INFO("m_raw_data_unit = %f\n", m_raw_data_unit);
134         INFO("geo_sensor_hal is created!\n");
135
136 }
137
138 geo_sensor_hal::~geo_sensor_hal()
139 {
140         close(m_node_handle);
141         m_node_handle = -1;
142
143         INFO("geo_sensor is destroyed!\n");
144 }
145
146 string geo_sensor_hal::get_model_id(void)
147 {
148         return m_model_id;
149 }
150
151 sensor_hal_type_t geo_sensor_hal::get_type(void)
152 {
153         return SENSOR_HAL_TYPE_GEOMAGNETIC;
154 }
155
156 bool geo_sensor_hal::enable(void)
157 {
158         AUTOLOCK(m_mutex);
159
160         set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_GEOMAGNETIC_ENABLE_BIT);
161         set_interval(m_polling_interval);
162
163         m_fired_time = 0;
164         INFO("Geo sensor real starting");
165         return true;
166 }
167
168 bool geo_sensor_hal::disable(void)
169 {
170         AUTOLOCK(m_mutex);
171
172         set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_GEOMAGNETIC_ENABLE_BIT);
173
174         INFO("Geo sensor real stopping");
175         return true;
176 }
177
178 bool geo_sensor_hal::set_interval(unsigned long val)
179 {
180         unsigned long long polling_interval_ns;
181
182         AUTOLOCK(m_mutex);
183
184         polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
185
186         if (!set_node_value(m_interval_node, polling_interval_ns)) {
187                 ERR("Failed to set polling resource: %s\n", m_interval_node.c_str());
188                 return false;
189         }
190
191         INFO("Interval is changed from %dms to %dms]", m_polling_interval, val);
192         m_polling_interval = val;
193         return true;
194 }
195
196 bool geo_sensor_hal::update_value(bool wait)
197 {
198         int geo_raw[4] = {0,};
199         bool x,y,z,hdst;
200         int read_input_cnt = 0;
201         const int INPUT_MAX_BEFORE_SYN = 10;
202         unsigned long long fired_time = 0;
203         bool syn = false;
204
205         x = y = z = hdst = false;
206
207         struct input_event geo_input;
208         DBG("geo event detection!");
209
210         while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
211                 int len = read(m_node_handle, &geo_input, sizeof(geo_input));
212                 if (len != sizeof(geo_input)) {
213                         ERR("geo_file read fail, read_len = %d\n",len);
214                         return false;
215                 }
216
217                 ++read_input_cnt;
218
219                 if (geo_input.type == EV_REL) {
220                         switch (geo_input.code) {
221                                 case REL_RX:
222                                         geo_raw[0] = (int)geo_input.value;
223                                         x = true;
224                                         break;
225                                 case REL_RY:
226                                         geo_raw[1] = (int)geo_input.value;
227                                         y = true;
228                                         break;
229                                 case REL_RZ:
230                                         geo_raw[2] = (int)geo_input.value;
231                                         z = true;
232                                         break;
233                                 case REL_HWHEEL:
234                                         geo_raw[3] = (int)geo_input.value;
235                                         hdst = true;
236                                         break;
237                                 default:
238                                         ERR("geo_input event[type = %d, code = %d] is unknown.", geo_input.type, geo_input.code);
239                                         return false;
240                                         break;
241                         }
242                 } else if (geo_input.type == EV_SYN) {
243                         syn = true;
244                         fired_time = get_timestamp(&geo_input.time);
245                 } else {
246                         ERR("geo_input event[type = %d, code = %d] is unknown.", geo_input.type, geo_input.code);
247                         return false;
248                 }
249         }
250
251         AUTOLOCK(m_value_mutex);
252
253         if (x)
254                 m_x =  geo_raw[0];
255         if (y)
256                 m_y =  geo_raw[1];
257         if (z)
258                 m_z =  geo_raw[2];
259         if (hdst)
260                 m_hdst = geo_raw[3] - 1; /* accuracy bias: -1 */
261
262         m_fired_time = fired_time;
263
264         DBG("m_x = %d, m_y = %d, m_z = %d, m_hdst = %d, time = %lluus", m_x, m_y, m_z, m_hdst, m_fired_time);
265
266         return true;
267 }
268
269 bool geo_sensor_hal::is_data_ready(bool wait)
270 {
271         bool ret;
272         ret = update_value(wait);
273         return ret;
274 }
275
276 int geo_sensor_hal::get_sensor_data(sensor_data_t &data)
277 {
278         data.accuracy = (m_hdst == 1) ? 0 : m_hdst; /* hdst 0 and 1 are needed to calibrate */
279         data.timestamp = m_fired_time;
280         data.value_count = 3;
281         data.values[0] = (float)m_x;
282         data.values[1] = (float)m_y;
283         data.values[2] = (float)m_z;
284         return 0;
285 }
286
287 bool geo_sensor_hal::get_properties(sensor_properties_s &properties)
288 {
289         properties.name = m_chip_name;
290         properties.vendor = m_vendor;
291         properties.min_range = m_min_range;
292         properties.max_range = m_max_range;
293         properties.min_interval = 1;
294         properties.resolution = m_raw_data_unit;
295         properties.fifo_count = 0;
296         properties.max_batch_count = 0;
297         return true;
298 }
299
300 extern "C" sensor_module* create(void)
301 {
302         geo_sensor_hal *sensor;
303
304         try {
305                 sensor = new(std::nothrow) geo_sensor_hal;
306         } catch (int err) {
307                 ERR("Failed to create module, err: %d, cause: %s", err, strerror(err));
308                 return NULL;
309         }
310
311         sensor_module *module = new(std::nothrow) sensor_module;
312         retvm_if(!module || !sensor, NULL, "Failed to allocate memory");
313
314         module->sensors.push_back(sensor);
315         return module;
316 }