2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <sys/types.h>
24 #include <linux/input.h>
25 #include <sys/ioctl.h>
30 #include <sensor_common.h>
31 #include <sensor_log.h>
33 #include "light_device.h"
35 #define MODEL_NAME "TMG399x"
38 #define MAX_RANGE 60000
40 #define RAW_DATA_UNIT 1
41 #define MIN_INTERVAL 200
42 #define MAX_BATCH_COUNT 0
44 #define SENSOR_NAME "SENSOR_LIGHT"
45 #define SENSOR_TYPE_LIGHT "LIGHT"
47 #define INPUT_NAME "light_sensor"
48 #define LIGHT_SENSORHUB_POLL_NODE_NAME "light_poll_delay"
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
61 #define min_t(a, b) (((a) < (b)) ? (a) : (b))
63 static sensor_info_t sensor_info = {
66 type: SENSOR_DEVICE_LIGHT,
67 event_type: (SENSOR_DEVICE_LIGHT << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
68 model_name: MODEL_NAME,
72 resolution: RAW_DATA_UNIT,
73 min_interval: MIN_INTERVAL,
74 max_batch_count: MAX_BATCH_COUNT,
75 wakeup_supported: false
78 light_device::light_device()
82 , m_polling_interval(1000)
84 , m_sensorhub_controlled(false)
86 const std::string sensorhub_interval_node_name = LIGHT_SENSORHUB_POLL_NODE_NAME;
88 node_info_query query;
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;
97 if (!util::get_node_info(query, info)) {
98 _E("Failed to get node info");
102 util::show_node_info(info);
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;
109 m_node_handle = open(m_data_node.c_str(), O_RDONLY);
111 if (m_node_handle < 0) {
112 _ERRNO(errno, _E, "light handle open fail for light device");
116 if (m_method != INPUT_EVENT_METHOD)
119 if (!util::set_monotonic_clock(m_node_handle))
122 update_value = [=]() {
123 return this->update_value_lux();
126 _I("light_device is created!");
129 light_device::~light_device()
131 close(m_node_handle);
134 _I("light_device is destroyed!");
137 int light_device::get_poll_fd()
139 return m_node_handle;
142 int light_device::get_sensors(const sensor_info_t **sensors)
144 *sensors = &sensor_info;
149 bool light_device::enable(uint32_t id)
151 util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_LIGHT_ENABLE_BIT);
152 set_interval(id, m_polling_interval);
155 _I("Enable light sensor");
159 bool light_device::disable(uint32_t id)
161 util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_LIGHT_ENABLE_BIT);
163 _I("Disable light sensor");
167 bool light_device::set_interval(uint32_t id, unsigned long val)
169 unsigned long long polling_interval_ns;
171 polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
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());
178 _I("Interval is changed from %dms to %dms", m_polling_interval, val);
179 m_polling_interval = val;
183 bool light_device::update_value_lux(void)
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;
192 struct input_event light_event;
193 _D("light event detection!");
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);
204 if (light_event.type == EV_REL) {
205 switch (light_event.code) {
207 raw_red = light_event.value - 1;
210 raw_green = light_event.value - 1;
213 raw_blue = light_event.value - 1;
216 raw_white = light_event.value - 1;
219 raw_ir_cmp = light_event.value - 1;
222 raw_amb_pga = light_event.value - 1;
225 _E("light_event event[type = %d, code = %d] is unknown.", light_event.type, light_event.code);
228 } else if (light_event.type == EV_SYN) {
230 fired_time = util::get_timestamp(&light_event.time);
232 _E("light_event event[type = %d, code = %d] is unknown.", light_event.type, light_event.code);
238 _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
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");
247 m_fired_time = fired_time;
249 _D("update_value_lux, lux : %d", m_lux);
254 int light_device::read_fd(uint32_t **ids)
256 if (!update_value()) {
257 _D("Failed to update value");
262 event_ids.push_back(sensor_info.id);
264 *ids = &event_ids[0];
266 return event_ids.size();
269 int light_device::get_data(uint32_t id, sensor_data_t **data, int *length)
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");
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;
282 *length = sizeof(sensor_data_t);
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)
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;
297 _E("Invalid a_gain value : %d", a_gain);
301 sat = min_t(MAX_ALS_VALUE, ((256 - a_time) << 10));
304 if (a_gain == 0 && (int)clear >= sat) {
307 double logvalue = log10(lux);
308 calculated_lux = (int)pow(10, (logvalue + GAB));
310 m_lux = (float)calculated_lux;
313 "RED : %d, GREEN : %d, BLUE : %d, CLEAR : %d,"
314 "Lux = %f, CCT = %f, sat = %d",
315 red, green, blue, clear, calculated_lux, m_cct, sat);
319 ir = red + green + blue - clear + 1;
326 gain = luxgain[a_gain];
330 cpl *= INTEGRATION_CYCLE;
337 /* remove ir from counts*/
345 _D("lux step1 = %lld\n", lux);
348 _D("lux step2 = %lld\n", lux);
351 _D("lux step3 = %lld\n", lux);
358 _D("lux_step4 = %lld, cpl = %d\n", lux, cpl);
366 cct = ((CT_Coef * bp1) / rp1) + CT_Offset;
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));
396 double logvalue = log10(lux);
397 calculated_lux = (int)pow(10, (logvalue + GAB));
400 m_lux = (float)calculated_lux;
404 _E("RED : %d, GREEN : %d, BLUE : %d, CLEAR : %d,"
405 " CALCULATED LUX : %f, CCT : %f"
406 " a_time = %d, gain = %d, ir=%d,"
407 " rp1=%d, gp1=%d, bp1=%d, cp1=%d, cpl=%d\n",
408 red, green, blue, clear,
411 rp1, gp1, bp1, cp1, cpl);