1/*
2 * Copyright (C) 2008 The Android Open Source Project
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#include <fcntl.h>
18#include <errno.h>
19#include <math.h>
20#include <poll.h>
21#include <unistd.h>
22#include <dirent.h>
23#include <sys/select.h>
24#include <cutils/log.h>
25
26#include "LightSensor.h"
27
28/*****************************************************************************/
29
30LightSensor::LightSensor()
31    : SensorBase(NULL, "lightsensor-level"),
32      mEnabled(0),
33      mInputReader(4),
34      mHasPendingEvent(false)
35{
36    mPendingEvent.version = sizeof(sensors_event_t);
37    mPendingEvent.sensor = ID_L;
38    mPendingEvent.type = SENSOR_TYPE_LIGHT;
39    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
40
41    if (data_fd) {
42        strcpy(input_sysfs_path, "/sys/class/input/");
43        strcat(input_sysfs_path, input_name);
44        strcat(input_sysfs_path, "/device/");
45        input_sysfs_path_len = strlen(input_sysfs_path);
46        enable(0, 1);
47    }
48}
49
50LightSensor::~LightSensor() {
51    if (mEnabled) {
52        enable(0, 0);
53    }
54}
55
56int LightSensor::setDelay(int32_t handle, int64_t ns)
57{
58    int fd;
59    strcpy(&input_sysfs_path[input_sysfs_path_len], "poll_delay");
60    fd = open(input_sysfs_path, O_RDWR);
61    if (fd >= 0) {
62        char buf[80];
63        sprintf(buf, "%lld", ns);
64        write(fd, buf, strlen(buf)+1);
65        close(fd);
66        return 0;
67    }
68    return -1;
69}
70
71int LightSensor::enable(int32_t handle, int en)
72{
73    int flags = en ? 1 : 0;
74    if (flags != mEnabled) {
75        int fd;
76        strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
77        fd = open(input_sysfs_path, O_RDWR);
78        if (fd >= 0) {
79            char buf[2];
80            int err;
81            buf[1] = 0;
82            if (flags) {
83                buf[0] = '1';
84            } else {
85                buf[0] = '0';
86            }
87            err = write(fd, buf, sizeof(buf));
88            close(fd);
89            mEnabled = flags;
90            return 0;
91        }
92        return -1;
93    }
94    return 0;
95}
96
97bool LightSensor::hasPendingEvents() const {
98    return mHasPendingEvent;
99}
100
101int LightSensor::readEvents(sensors_event_t* data, int count)
102{
103    if (count < 1)
104        return -EINVAL;
105
106    if (mHasPendingEvent) {
107        mHasPendingEvent = false;
108        mPendingEvent.timestamp = getTimestamp();
109        *data = mPendingEvent;
110        return mEnabled ? 1 : 0;
111    }
112
113    ssize_t n = mInputReader.fill(data_fd);
114    if (n < 0)
115        return n;
116
117    int numEventReceived = 0;
118    input_event const* event;
119
120    while (count && mInputReader.readEvent(&event)) {
121        int type = event->type;
122        if (type == EV_ABS) {
123            if (event->code == EVENT_TYPE_LIGHT) {
124                // Convert adc value to lux assuming:
125                // I = 10 * log(Ev) uA
126                // R = 47kOhm
127                // Max adc value 4095 = 3.3V
128                // 1/4 of light reaches sensor
129                mPendingEvent.light = powf(10, event->value * (330.0f / 4095.0f / 47.0f)) * 4;
130            }
131        } else if (type == EV_SYN) {
132            mPendingEvent.timestamp = timevalToNano(event->time);
133            if (mEnabled) {
134                *data++ = mPendingEvent;
135                count--;
136                numEventReceived++;
137            }
138        } else {
139            ALOGE("LightSensor: unknown event (type=%d, code=%d)",
140                    type, event->code);
141        }
142        mInputReader.next();
143    }
144
145    return numEventReceived;
146}
147