Fixing build error with new dlog format
[platform/adaptation/tm2/sensor-hal-tm2.git] / src / light / light_device.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <math.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23
24 #include <linux/input.h>
25 #include <sys/ioctl.h>
26 #include <poll.h>
27
28 #include <macro.h>
29 #include <util.h>
30 #include <sensor_common.h>
31 #include <sensor_log.h>
32
33 #include "light_device.h"
34
35 #define MODEL_NAME "TMG399x"
36 #define VENDOR "AMS"
37 #define MIN_RANGE 0
38 #define MAX_RANGE 60000
39 #define RESOLUTION 1
40 #define RAW_DATA_UNIT 1
41 #define MIN_INTERVAL 200
42 #define MAX_BATCH_COUNT 0
43
44 #define SENSOR_NAME "SENSOR_LIGHT"
45 #define SENSOR_TYPE_LIGHT               "LIGHT"
46
47 #define INPUT_NAME      "light_sensor"
48 #define LIGHT_SENSORHUB_POLL_NODE_NAME "light_poll_delay"
49
50 #define BIAS 1
51 #define D_Factor 1190
52 #define R_Coef   360
53 #define G_Coef   1000
54 #define B_Coef   0
55 #define CT_Coef  (3343)
56 #define CT_Offset         (1596)
57 #define INTEGRATION_CYCLE 278
58 #define MAX_LUX_VALUE     150000
59 #define MAX_ALS_VALUE     0xFFFF
60 #define GAB (0.15)
61 #define min_t(a, b) (((a) < (b)) ? (a) : (b))
62
63 static sensor_info_t sensor_info = {
64         id: 0x1,
65         name: SENSOR_NAME,
66         type: SENSOR_DEVICE_LIGHT,
67         event_type: (SENSOR_DEVICE_LIGHT << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
68         model_name: MODEL_NAME,
69         vendor: VENDOR,
70         min_range: MIN_RANGE,
71         max_range: MAX_RANGE,
72         resolution: RAW_DATA_UNIT,
73         min_interval: MIN_INTERVAL,
74         max_batch_count: MAX_BATCH_COUNT,
75         wakeup_supported: false
76 };
77
78 light_device::light_device()
79 : m_node_handle(-1)
80 , m_lux(-1)
81 , m_cct(-1)
82 , m_polling_interval(1000)
83 , m_fired_time(0)
84 , m_sensorhub_controlled(false)
85 {
86         const std::string sensorhub_interval_node_name = LIGHT_SENSORHUB_POLL_NODE_NAME;
87
88         node_info_query query;
89         node_info info;
90
91         query.sensorhub_controlled = m_sensorhub_controlled = true;
92         query.sensor_type = SENSOR_TYPE_LIGHT;
93         query.key = INPUT_NAME;
94         query.iio_enable_node_name = "light_enable";
95         query.sensorhub_interval_node_name = sensorhub_interval_node_name;
96
97         if (!util::get_node_info(query, info)) {
98                 _E("Failed to get node info");
99                 throw ENXIO;
100         }
101
102         util::show_node_info(info);
103
104         m_method = info.method;
105         m_data_node = info.data_node_path;
106         m_enable_node = info.enable_node_path;
107         m_interval_node = info.interval_node_path;
108
109         m_node_handle = open(m_data_node.c_str(), O_RDONLY);
110
111         if (m_node_handle < 0) {
112                 _ERRNO(errno, _E, "light handle open fail for light device");
113                 throw ENXIO;
114         }
115
116         if (m_method != INPUT_EVENT_METHOD)
117                 throw ENXIO;
118
119         if (!util::set_monotonic_clock(m_node_handle))
120                 throw ENXIO;
121
122         update_value = [=]() {
123                 return this->update_value_lux();
124         };
125
126         _I("light_device is created!");
127 }
128
129 light_device::~light_device()
130 {
131         close(m_node_handle);
132         m_node_handle = -1;
133
134         _I("light_device is destroyed!");
135 }
136
137 int light_device::get_poll_fd()
138 {
139         return m_node_handle;
140 }
141
142 int light_device::get_sensors(const sensor_info_t **sensors)
143 {
144         *sensors = &sensor_info;
145
146         return 1;
147 }
148
149 bool light_device::enable(uint32_t id)
150 {
151         util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_LIGHT_ENABLE_BIT);
152         set_interval(id, m_polling_interval);
153
154         m_fired_time = 0;
155         _I("Enable light sensor");
156         return true;
157 }
158
159 bool light_device::disable(uint32_t id)
160 {
161         util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_LIGHT_ENABLE_BIT);
162
163         _I("Disable light sensor");
164         return true;
165 }
166
167 bool light_device::set_interval(uint32_t id, unsigned long val)
168 {
169         unsigned long long polling_interval_ns;
170
171         polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
172
173         if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
174                 _E("Failed to set polling resource: %s", m_interval_node.c_str());
175                 return false;
176         }
177
178         _I("Interval is changed from %lu ms to %lu ms", m_polling_interval, val);
179         m_polling_interval = val;
180         return true;
181 }
182
183 bool light_device::update_value_lux(void)
184 {
185         size_t raw_red = 0, raw_green = 0, raw_blue = 0, raw_white = 0;
186         size_t raw_ir_cmp = 0, raw_amb_pga = 0;
187         int read_input_cnt = 0;
188         const int INPUT_MAX_BEFORE_SYN = 10;
189         unsigned long long fired_time = 0;
190         bool syn = false;
191
192         struct input_event light_event;
193         _D("light event detection!");
194
195         while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
196                 int len = read(m_node_handle, &light_event, sizeof(light_event));
197                 if (len != sizeof(light_event)) {
198                         _E("light_file read fail, read_len = %d\n", len);
199                         return false;
200                 }
201
202                 ++read_input_cnt;
203
204                 if (light_event.type == EV_REL) {
205                         switch (light_event.code) {
206                         case REL_HWHEEL:
207                                 raw_red = light_event.value - 1;
208                                 break;
209                         case REL_DIAL:
210                                 raw_green = light_event.value - 1;
211                                 break;
212                         case REL_WHEEL:
213                                 raw_blue = light_event.value - 1;
214                                 break;
215                         case REL_MISC:
216                                 raw_white = light_event.value - 1;
217                                 break;
218                         case REL_RY:
219                                 raw_ir_cmp = light_event.value - 1;
220                                 break;
221                         case REL_RZ:
222                                 raw_amb_pga = light_event.value - 1;
223                                 break;
224                         default:
225                                 _E("light_event event[type = %d, code = %d] is unknown.", light_event.type, light_event.code);
226                                 return false;
227                         }
228                 } else if (light_event.type == EV_SYN) {
229                         syn = true;
230                         fired_time = util::get_timestamp(&light_event.time);
231                 } else {
232                         _E("light_event event[type = %d, code = %d] is unknown.", light_event.type, light_event.code);
233                         return false;
234                 }
235         }
236
237         if (syn == false) {
238                 _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
239                 return false;
240         }
241
242         if (!compute_lux_tmg399x(raw_red, raw_green, raw_blue, raw_white, raw_ir_cmp, raw_amb_pga)) {
243                 _E("Failed to compute lux");
244                 return false;
245         }
246
247         m_fired_time = fired_time;
248
249         _D("update_value_lux, lux : %d", m_lux);
250
251         return true;
252 }
253
254 int light_device::read_fd(uint32_t **ids)
255 {
256         if (!update_value()) {
257                 _D("Failed to update value");
258                 return false;
259         }
260
261         event_ids.clear();
262         event_ids.push_back(sensor_info.id);
263
264         *ids = &event_ids[0];
265
266         return event_ids.size();
267 }
268
269 int light_device::get_data(uint32_t id, sensor_data_t **data, int *length)
270 {
271         sensor_data_t *sensor_data;
272         sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
273         retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
274
275         sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
276         sensor_data->timestamp = m_fired_time;
277         sensor_data->value_count = 2;
278         sensor_data->values[0] = m_lux;
279         sensor_data->values[1] = m_cct;
280
281         *data = sensor_data;
282         *length = sizeof(sensor_data_t);
283
284         return 0;
285 }
286
287 bool light_device::compute_lux_tmg399x(size_t red, size_t green, size_t blue, size_t clear, size_t a_time, size_t a_gain)
288 {
289         const int luxgain[4] = {1, 4, 16, 64};
290         size_t rp1, gp1, bp1, cp1;
291         int64_t lux = 0, calculated_lux = 0;
292         size_t cct, cpl, gain;
293         int ir;
294         int sat;
295
296         if (a_gain > 3) {
297                 _E("Invalid a_gain value : %zu", a_gain);
298                 return false;
299         }
300
301         sat = min_t(MAX_ALS_VALUE, ((256 - a_time) << 10));
302         sat = sat * 7 / 10;
303
304         if (a_gain == 0 && (int)clear >= sat)    {
305                 lux = MAX_LUX_VALUE;
306                 cct = 5800;
307                 double logvalue = log10(lux);
308                 calculated_lux = (int)pow(10, (logvalue + GAB));
309
310                 m_lux = (float)calculated_lux;
311                 m_cct  = (float)cct;
312                 _D("Saturation!!!"
313                                 "RED : %zu, GREEN : %zu, BLUE : %zu, CLEAR : %zu,"
314                                 "Lux = %f, CCT = %f, sat = %d",
315                                 red, green, blue, clear, calculated_lux, m_cct, sat);
316                 return true;
317         }
318
319         ir = red + green + blue - clear + 1;
320
321         if (ir < 0)
322                 ir = 0;
323         else
324                 ir >>= 1;
325
326         gain = luxgain[a_gain];
327
328         /* calculate cpl */
329         cpl = 256 - a_time;
330         cpl *= INTEGRATION_CYCLE;
331         cpl *= 10;
332         cpl *= gain;
333
334         if (!cpl)
335                 cpl = 1;
336
337         /* remove ir from counts*/
338         rp1 = red - ir;
339         gp1 = green - ir;
340         bp1 = blue - ir;
341         cp1 = clear - ir;
342
343         if ((int)red > ir)
344                 lux += R_Coef * rp1;
345         _D("lux step1 = %lld\n", lux);
346         if ((int)green > ir)
347                 lux += G_Coef * gp1;
348         _D("lux step2 = %lld\n", lux);
349         if ((int)blue > ir)
350                 lux -= B_Coef * bp1;
351         _D("lux step3 = %lld\n", lux);
352
353         if (lux < 0)
354                 lux = 0;
355
356         lux *= D_Factor;
357         lux /= cpl;
358         _D("lux_step4 = %lld, cpl = %d\n", lux, cpl);
359
360         if (lux < 0)
361                 lux = 0;
362
363         if (rp1 < 1)
364                 rp1 = 1;
365
366         cct = ((CT_Coef * bp1) / rp1) + CT_Offset;
367
368         if (lux < 6) {
369                 calculated_lux = lux;
370         } else if (lux < 31) {
371                 double logvalue = log10(lux);
372                 calculated_lux = (int)pow(10, (logvalue + GAB));
373         } else if (lux < 60) {
374                 calculated_lux = (int64_t)log2(pow(lux - 30, 8)) + 46;
375         } else if (lux < 130) {
376                 calculated_lux = (int64_t)log2(pow(lux - 59, 10)) + 120;
377         } else if (lux < 240) {
378                 calculated_lux = (int64_t)log2(pow(lux - 129, 20)) + 200;
379         } else if (lux < 360) {
380                 calculated_lux = (int64_t)log2(pow(lux - 239, 16)) + 400;
381         } else if (lux < 570) {
382                 calculated_lux = (int64_t)log2(pow(lux - 359, 27)) + 600;
383         } else if (lux < 790) {
384                 calculated_lux = (int64_t)log2(pow(lux - 569, 28)) + 900;
385         } else if (lux < 1140) {
386                 calculated_lux = (int64_t)log2(pow(lux - 789, 37)) + 1300;
387         } else if (lux < 1620) {
388                 calculated_lux = (int64_t)log2(pow(lux - 1139, 55)) + 1800;
389         } else if (lux < 2370) {
390                 calculated_lux = (int64_t)log2(pow(lux - 1619, 99)) + 2400;
391         } else if (lux < 3550) {
392                 calculated_lux = (int64_t)log2(pow(lux - 2369, 100)) + 4000;
393         } else if (lux < 6600) {
394                 calculated_lux = (int64_t)((log2(pow(lux - 3549, 50)) + 6000) * pow(lux - 3549, 0.0435));
395         } else {
396                 double logvalue = log10(lux);
397                 calculated_lux = (int)pow(10, (logvalue + GAB));
398         }
399
400         m_lux = (float)calculated_lux;
401         m_cct = (float)cct;
402
403         if (lux == 0) {
404                 _E("RED : %zu, GREEN : %zu, BLUE : %zu, CLEAR : %zu,"
405                                 " CALCULATED LUX : %f, CCT : %f"
406                                 " a_time = %zu, gain = %zu, ir=%d,"
407                                 " rp1=%zu, gp1=%zu, bp1=%zu, cp1=%zu, cpl=%zu\n",
408                                 red, green, blue, clear,
409                                 m_lux, m_cct,
410                                 a_time, gain, ir,
411                                 rp1, gp1, bp1, cp1, cpl);
412         }
413
414         return true;
415 }
416