--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(sensor-hal-n4 CXX)
+INCLUDE(GNUInstallDirs)
+
+SET(ACCEL "ON")
+SET(GYRO "ON")
+SET(GYRO_UNCAL "ON")
+SET(PROXIMITY "ON")
+SET(LIGHT "ON")
+SET(GEOMAG "ON")
+SET(GEOMAG_UNCAL "OFF")
+SET(HRM_RAW "ON")
+SET(HRM "ON")
+SET(RV "OFF")
+SET(PRESSURE "ON")
+SET(PIR "OFF")
+SET(PIR_LONG "OFF")
+SET(TEMPERATURE "OFF")
+SET(HUMIDITY "OFF")
+SET(TEMP_HUMIDITY "OFF")
+SET(ULTRAVIOLET "ON")
+SET(DUST "OFF")
+SET(GSR "OFF")
+SET(SENSORHUB "OFF")
+
+# Common Options
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2 -omit-frame-pointer -std=gnu++0x")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-section -Wl,--print-gc-section")
+MESSAGE("FLAGS: ${CMAKE_CXX_FLAGS}")
+MESSAGE("FLAGS: ${CMAKE_EXE_LINKER_FLAGS}")
+
+# Internal Debugging Options
+#ADD_DEFINITIONS(-Wall -g -D_DEBUG)
+
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(HAL_PKGS REQUIRED dlog)
+
+FOREACH(flag ${HAL_PKGS_CFLAGS})
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
+FILE(GLOB SRCS src/*.cpp)
+
+IF("${ACCEL}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/accel/*.cpp)
+ADD_DEFINITIONS(-DENABLE_ACCEL)
+ENDIF()
+
+IF("${GYRO}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/gyro/*.cpp)
+ADD_DEFINITIONS(-DENABLE_GYRO)
+ENDIF()
+
+IF("${GYRO_UNCAL}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/gyro_uncal/*.cpp)
+ADD_DEFINITIONS(-DENABLE_GYRO_UNCAL)
+ENDIF()
+
+IF("${PROXIMITY}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/proxi/*.cpp)
+ADD_DEFINITIONS(-DENABLE_PROXIMITY)
+ENDIF()
+
+IF("${LIGHT}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/light/*.cpp)
+ADD_DEFINITIONS(-DENABLE_LIGHT)
+ENDIF()
+
+IF("${GEOMAG}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/geomag/*.cpp)
+ADD_DEFINITIONS(-DENABLE_GEOMAG)
+ENDIF()
+
+IF("${GEOMAG_UNCAL}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/geo_uncal/*.cpp)
+ADD_DEFINITIONS(-DENABLE_GEOMAG_UNCAL)
+ENDIF()
+
+IF("${HRM_RAW}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/hrm_raw/*.cpp)
+ADD_DEFINITIONS(-DENABLE_HRM_RAW)
+ENDIF()
+
+IF("${HRM}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/hrm/*.cpp)
+ADD_DEFINITIONS(-DENABLE_HRM)
+ENDIF()
+
+IF("${RV}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/rv/*.cpp)
+ADD_DEFINITIONS(-DENABLE_RV)
+ENDIF()
+
+IF("${PRESSURE}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/pressure/*.cpp)
+ADD_DEFINITIONS(-DENABLE_PRESSURE)
+ENDIF()
+
+IF("${PIR}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/pir/*.cpp)
+ADD_DEFINITIONS(-DENABLE_PIR)
+ENDIF()
+
+IF("${PIR_LONG}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/pir_long/*.cpp)
+ADD_DEFINITIONS(-DENABLE_PIR_LONG)
+ENDIF()
+
+IF("${TEMPERATURE}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/temperature/*.cpp)
+ADD_DEFINITIONS(-DENABLE_TEMPERATURE)
+ENDIF()
+
+IF("${HUMIDITY}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/humidity/*.cpp)
+ADD_DEFINITIONS(-DENABLE_HUMIDITY)
+ENDIF()
+
+IF("${TEMP_HUMIDITY}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/temp_humidity/*.cpp)
+ADD_DEFINITIONS(-DENABLE_TEMP_HUMIDITY)
+ENDIF()
+
+IF("${ULTRAVIOLET}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/ultraviolet/*.cpp)
+ADD_DEFINITIONS(-DENABLE_ULTRAVIOLET)
+ENDIF()
+
+IF("${DUST}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/dust/*.cpp)
+ADD_DEFINITIONS(-DENABLE_DUST)
+ENDIF()
+
+IF("${GSR}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/gsr/*.cpp)
+ADD_DEFINITIONS(-DENABLE_GSR)
+ENDIF()
+
+IF("${SENSORHUB}" STREQUAL "ON")
+FILE(GLOB_RECURSE SRCS ${SRCS} src/sensorhub/*.cpp)
+ADD_DEFINITIONS(-DENABLE_SENSORHUB)
+ENDIF()
+
+MESSAGE("Sources: ${SRCS}")
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${HAL_PKGS_LDFLAGS})
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.APLv2 DESTINATION share/license RENAME ${PROJECT_NAME})
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/lib/sensor)
--- /dev/null
+Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
--- /dev/null
+ENV{DEVTYPE}=="iio_device", GROUP="input", MODE="0660", SECLABEL{smack}="_"
+ENV{DEVTYPE}=="iio_device", ACTION=="add", RUN+="/bin/chown sensor:input %S/%p/buffer/length %S/%p/buffer/enable"
+ENV{DEVTYPE}=="iio_device", ACTION=="add", RUN+="/bin/chsmack -a * %S/%p/buffer/length %S/%p/buffer/enable"
+SUBSYSTEM!="input", GOTO="sensor_rules_end"
+ENV{ID_INPUT_TOUCHPAD}=="1", GOTO="sensor_rules_end"
+ENV{ID_INPUT_TOUCHSCREEN}=="1", GOTO="sensor_rules_end"
+ENV{ID_INPUT_KEY}=="1", GOTO="sensor_rules_end"
+ENV{ID_INPUT_KEYPAD}=="1", GOTO="sensor_rules_end"
+ENV{ID_INPUT_KEYBOARD}=="1", GOTO="sensor_rules_end"
+ENV{ID_INPUT_MOUSE}=="1", GOTO="sensor_rules_end"
+ENV{ID_INPUT_JOYSTICK}=="1", GOTO="sensor_rules_end"
+
+SUBSYSTEM=="input", ACTION=="add", RUN+="/bin/chown sensor:input %S/%p/enable %S/%p/poll_delay"
+SUBSYSTEM=="input", ACTION=="add", RUN+="/bin/chsmack -a * %S/%p/enable %S/%p/poll_delay"
+
+LABEL="sensor_rules_end"
--- /dev/null
+SUBSYSTEMS=="sensors", DEVPATH=="*ssp_sensor*", \
+RUN+="/bin/sh -c '/bin/chown sensor:sensor %S/%p/enable %S/%p/set_cal_data %S/%p/*_poll_delay'"
+
+SUBSYSTEMS=="sensors", DEVPATH=="*ssp_sensor*", \
+RUN+="/bin/sh -c '/bin/chsmack -a \* %S/%p/enable %S/%p/set_cal_data %S/%p/*_poll_delay'"
+
+SUBSYSTEMS=="misc", DEVPATH=="/devices/virtual/misc/ssp_sensorhub", \
+ENV{DEVNAME}=="/dev/ssp_sensorhub", GROUP="input", MODE="0660", SECLABEL{smack}="*"
+
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+Name: sensor-hal-n4
+Summary: Note4 Sensor HAL
+Version: 1.0.3
+Release: 0
+Group: Service/Sensor
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source1: 99-sensor.rules
+Source2: 99-sensorhub.rules
+
+%if "%{?profile}" == "mobile"
+ExcludeArch: %{arm} %ix86 x86_64
+%else
+ExcludeArch: %{arm} aarch64 %ix86 x86_64
+%endif
+
+BuildRequires: cmake
+BuildRequires: pkgconfig(dlog)
+BuildRequires: sensor-hal-devel
+
+%description
+Note4 Sensor HAL
+
+%prep
+%setup -q
+
+%build
+export CXXFLAGS+=" -Wextra -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings -Wswitch-default"
+export CXXFLAGS+=" -Wnon-virtual-dtor -Wno-c++0x-compat -Wno-unused-parameter -Wno-empty-body"
+export CXXFLAGS+=" -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-strict-aliasing"
+export CXXFLAGS+=" -fno-unroll-loops -fsigned-char -fstrict-overflow"
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+mkdir -p %{buildroot}/usr/lib/udev/rules.d
+
+install -m 0644 %SOURCE1 %{buildroot}/usr/lib/udev/rules.d
+install -m 0644 %SOURCE2 %{buildroot}/usr/lib/udev/rules.d
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%manifest packaging/%{name}.manifest
+/usr/lib/udev/rules.d/99-sensor.rules
+/usr/lib/udev/rules.d/99-sensorhub.rules
+/usr/lib/sensor/*.so
+%{_datadir}/license/sensor-hal-n4
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#include <macro.h>
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+
+#include "accel_device.h"
+
+#define MODEL_NAME "ICM20610"
+#define VENDOR "Invensense"
+#define RESOLUTION 16
+#define RAW_DATA_UNIT 0.119
+#define MIN_INTERVAL 1
+#define MAX_BATCH_COUNT 0
+
+#define SENSOR_NAME "SENSOR_ACCELEROMETER"
+#define SENSOR_TYPE_ACCEL "ACCEL"
+
+#define INPUT_NAME "accelerometer_sensor"
+#define ACCEL_SENSORHUB_POLL_NODE_NAME "accel_poll_delay"
+
+#define GRAVITY 9.80665
+#define G_TO_MG 1000
+#define RAW_DATA_TO_G_UNIT(X) (((float)(X))/((float)G_TO_MG))
+#define RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(X) (GRAVITY * (RAW_DATA_TO_G_UNIT(X)))
+
+#define MIN_RANGE(RES) (-((1 << (RES))/2))
+#define MAX_RANGE(RES) (((1 << (RES))/2)-1)
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_ACCELEROMETER,
+ event_type: (SENSOR_DEVICE_ACCELEROMETER << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: MIN_RANGE(RESOLUTION) * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(RAW_DATA_UNIT),
+ max_range: MAX_RANGE(RESOLUTION) * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(RAW_DATA_UNIT),
+ resolution: RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(RAW_DATA_UNIT),
+ min_interval: MIN_INTERVAL,
+ max_batch_count: MAX_BATCH_COUNT,
+ wakeup_supported: false
+};
+
+accel_device::accel_device()
+: m_node_handle(-1)
+, m_x(-1)
+, m_y(-1)
+, m_z(-1)
+, m_polling_interval(1000)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = ACCEL_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name);
+ query.sensor_type = SENSOR_TYPE_ACCEL;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = "accel_enable";
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+ m_interval_node = info.interval_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "accel handle open fail for accel processor");
+ throw ENXIO;
+ }
+
+ if (m_method == INPUT_EVENT_METHOD) {
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+
+ update_value = [=]() {
+ return this->update_value_input_event();
+ };
+ } else {
+ if (!info.buffer_length_node_path.empty())
+ util::set_node_value(info.buffer_length_node_path, 600);
+
+ if (!info.buffer_enable_node_path.empty())
+ util::set_node_value(info.buffer_enable_node_path, 1);
+
+ update_value = [=]() {
+ return this->update_value_iio();
+ };
+ }
+
+ _I("accel_device is created!");
+}
+
+accel_device::~accel_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("accel_device is destroyed!");
+}
+
+int accel_device::get_poll_fd(void)
+{
+ return m_node_handle;
+}
+
+int accel_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool accel_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_ACCELEROMETER_ENABLE_BIT);
+ set_interval(id, m_polling_interval);
+
+ m_fired_time = 0;
+ _I("Enable accelerometer sensor");
+ return true;
+}
+
+bool accel_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_ACCELEROMETER_ENABLE_BIT);
+
+ _I("Disable accelerometer sensor");
+ return true;
+}
+
+bool accel_device::set_interval(uint32_t id, unsigned long val)
+{
+ unsigned long long polling_interval_ns;
+
+ polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
+
+ if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
+ _E("Failed to set polling resource: %s", m_interval_node.c_str());
+ return false;
+ }
+
+ _I("Interval is changed from %dms to %dms", m_polling_interval, val);
+ m_polling_interval = val;
+ return true;
+}
+
+bool accel_device::update_value_input_event(void)
+{
+ int accel_raw[3] = {0,};
+ bool x,y,z;
+ int read_input_cnt = 0;
+ const int INPUT_MAX_BEFORE_SYN = 10;
+ unsigned long long fired_time = 0;
+ bool syn = false;
+
+ x = y = z = false;
+
+ struct input_event accel_input;
+ _D("accel event detection!");
+
+ while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
+ int len = read(m_node_handle, &accel_input, sizeof(accel_input));
+ if (len != sizeof(accel_input)) {
+ _E("accel_file read fail, read_len = %d",len);
+ return false;
+ }
+
+ ++read_input_cnt;
+
+ if (accel_input.type == EV_REL) {
+ switch (accel_input.code) {
+ case REL_X:
+ accel_raw[0] = (int)accel_input.value;
+ x = true;
+ break;
+ case REL_Y:
+ accel_raw[1] = (int)accel_input.value;
+ y = true;
+ break;
+ case REL_Z:
+ accel_raw[2] = (int)accel_input.value;
+ z = true;
+ break;
+ default:
+ _E("accel_input event[type = %d, code = %d] is unknown.", accel_input.type, accel_input.code);
+ return false;
+ break;
+ }
+ } else if (accel_input.type == EV_SYN) {
+ syn = true;
+ fired_time = util::get_timestamp(&accel_input.time);
+ } else {
+ _E("accel_input event[type = %d, code = %d] is unknown.", accel_input.type, accel_input.code);
+ return false;
+ }
+ }
+
+ if (syn == false) {
+ _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
+ return false;
+ }
+
+ if (x)
+ m_x = accel_raw[0];
+ if (y)
+ m_y = accel_raw[1];
+ if (z)
+ m_z = accel_raw[2];
+
+ m_fired_time = fired_time;
+
+ _D("m_x = %d, m_y = %d, m_z = %d, time = %lluus", m_x, m_y, m_z, m_fired_time);
+
+ return true;
+}
+
+bool accel_device::update_value_iio(void)
+{
+ struct {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ int64_t timestamp;
+ } __attribute__((packed)) data;
+
+ struct pollfd pfd;
+
+ pfd.fd = m_node_handle;
+ pfd.events = POLLIN | POLLERR;
+ pfd.revents = 0;
+
+ int ret = poll(&pfd, 1, -1);
+
+ if (ret == -1) {
+ _ERRNO(errno, _E, "Failed to poll from m_node_handle:%d", m_node_handle);
+ return false;
+ } else if (!ret) {
+ _E("poll timeout m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (pfd.revents & POLLERR) {
+ _E("poll exception occurred! m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (!(pfd.revents & POLLIN)) {
+ _E("poll nothing to read! m_node_handle:%d, pfd.revents = %d", m_node_handle, pfd.revents);
+ return false;
+ }
+
+ int len = read(m_node_handle, &data, sizeof(data));
+
+ if (len != sizeof(data)) {
+ _E("Failed to read data, m_node_handle:%d read_len:%d", m_node_handle, len);
+ return false;
+ }
+
+ m_x = data.x;
+ m_y = data.y;
+ m_z = data.z;
+ m_fired_time = NSEC_TO_MSEC(data.timestamp);
+
+ _D("m_x = %d, m_y = %d, m_z = %d, time = %lluus", m_x, m_y, m_z, m_fired_time);
+
+ return true;
+}
+
+int accel_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ _D("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int accel_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 3;
+ sensor_data->values[0] = m_x;
+ sensor_data->values[1] = m_y;
+ sensor_data->values[2] = m_z;
+
+ raw_to_base(sensor_data);
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
+
+void accel_device::raw_to_base(sensor_data_t *data)
+{
+ data->values[0] = RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(data->values[0] * RAW_DATA_UNIT);
+ data->values[1] = RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(data->values[1] * RAW_DATA_UNIT);
+ data->values[2] = RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(data->values[2] * RAW_DATA_UNIT);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _ACCEL_DEVICE_H_
+#define _ACCEL_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class accel_device : public sensor_device {
+public:
+ accel_device();
+ virtual ~accel_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ int m_x;
+ int m_y;
+ int m_z;
+ unsigned long m_polling_interval;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_data_node;
+ std::string m_enable_node;
+ std::string m_interval_node;
+
+ std::function<bool (void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_input_event(void);
+ bool update_value_iio(void);
+
+ void raw_to_base(sensor_data_t *data);
+};
+#endif /* _ACCEL_DEVICE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <sensor/sensor_hal.h>
+#include <sensor_log.h>
+#include <vector>
+
+#include "accel/accel_device.h"
+#include "gyro/gyro_device.h"
+#include "gyro_uncal/gyro_uncal_device.h"
+#include "geomag/geomag_device.h"
+#include "pressure/pressure_device.h"
+#include "light/light_device.h"
+#include "proxi/proxi_device.h"
+#include "ultraviolet/uv_device.h"
+
+static std::vector<sensor_device_t> devs;
+
+template<typename _sensor>
+void create_sensor(const char *name)
+{
+ sensor_device *instance = NULL;
+ try {
+ instance = new _sensor;
+ } catch (std::exception &e) {
+ ERR("Failed to create %s sensor device, exception: %s", name, e.what());
+ return;
+ } catch (int err) {
+ _ERRNO(err, _E, "Failed to create %s sensor device", name);
+ return;
+ }
+
+ devs.push_back(instance);
+}
+
+extern "C" int create(sensor_device_t **devices)
+{
+ create_sensor<accel_device>("Accelerometer");
+ create_sensor<gyro_device>("Gyroscope");
+ create_sensor<gyro_uncal_device>("Gyroscope Uncal");
+ create_sensor<geomag_device>("Magnetometer");
+ create_sensor<pressure_device>("Pressure");
+ create_sensor<light_device>("Light");
+ create_sensor<proxi_device>("Proximity");
+ create_sensor<uv_device>("Ultraviolet");
+
+ *devices = &devs[0];
+ return devs.size();
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#include <macro.h>
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+
+#include "geomag_device.h"
+
+#define MODEL_NAME "YAS532"
+#define VENDOR "YAMAHA"
+#define RESOLUTION 16
+#define RAW_DATA_UNIT 0.1
+#define MIN_INTERVAL 10
+#define MAX_BATCH_COUNT 0
+
+#define SENSOR_NAME "SENSOR_GEOMAGNETIC"
+#define SENSOR_TYPE_MAGNETIC "MAGNETIC"
+
+#define INPUT_NAME "geomagnetic_sensor"
+#define GEOMAG_SENSORHUB_POLL_NODE_NAME "mag_poll_delay"
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_GEOMAGNETIC,
+ event_type: (SENSOR_DEVICE_GEOMAGNETIC << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: -1200,
+ max_range: 1200,
+ resolution: RAW_DATA_UNIT,
+ min_interval: 10,
+ max_batch_count: 0,
+ wakeup_supported: false
+};
+
+geomag_device::geomag_device()
+: m_node_handle(-1)
+, m_x(-1)
+, m_y(-1)
+, m_z(-1)
+, m_hdst(0)
+, m_polling_interval(1000)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = GEOMAG_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name);
+ query.sensor_type = SENSOR_TYPE_MAGNETIC;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = "geomagnetic_enable";
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+ m_interval_node = info.interval_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "Failed to open magnetic sensor");
+ throw ENXIO;
+ }
+
+ if (m_method == INPUT_EVENT_METHOD) {
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+
+ update_value = [=]() {
+ return this->update_value_input_event();
+ };
+ } else {
+ if (!info.buffer_length_node_path.empty())
+ util::set_node_value(info.buffer_length_node_path, 480);
+
+ if (!info.buffer_enable_node_path.empty())
+ util::set_node_value(info.buffer_enable_node_path, 1);
+
+ update_value = [=]() {
+ return this->update_value_iio();
+ };
+ }
+
+ _I("geomag_device is created!");
+}
+
+geomag_device::~geomag_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("geomag_sensor is destroyed!");
+}
+
+int geomag_device::get_poll_fd(void)
+{
+ return m_node_handle;
+}
+
+int geomag_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool geomag_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_GEOMAGNETIC_ENABLE_BIT);
+ set_interval(id, m_polling_interval);
+
+ m_fired_time = 0;
+ _I("Enable geomagnetic sensor");
+ return true;
+}
+
+bool geomag_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_GEOMAGNETIC_ENABLE_BIT);
+
+ _I("Disable geomagnetic sensor");
+ return true;
+}
+
+bool geomag_device::set_interval(uint32_t id, unsigned long val)
+{
+ unsigned long long polling_interval_ns;
+
+ polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
+
+ if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
+ ERR("Failed to set polling resource: %s\n", m_interval_node.c_str());
+ return false;
+ }
+
+ _I("Interval is changed from %dms to %dms", m_polling_interval, val);
+ m_polling_interval = val;
+ return true;
+}
+
+bool geomag_device::update_value_input_event(void)
+{
+ int geo_raw[4] = {0, };
+ bool x, y, z, hdst;
+ int read_input_cnt = 0;
+ const int INPUT_MAX_BEFORE_SYN = 10;
+ unsigned long long fired_time = 0;
+ bool syn = false;
+
+ x = y = z = hdst = false;
+
+ struct input_event geo_input;
+ _D("geo event detection!");
+
+ while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
+ int len = read(m_node_handle, &geo_input, sizeof(geo_input));
+ if (len != sizeof(geo_input)) {
+ _E("geo_file read fail, read_len = %d\n", len);
+ return false;
+ }
+
+ ++read_input_cnt;
+
+ if (geo_input.type == EV_REL) {
+ switch (geo_input.code) {
+ case REL_RX:
+ geo_raw[0] = (int)geo_input.value;
+ x = true;
+ break;
+ case REL_RY:
+ geo_raw[1] = (int)geo_input.value;
+ y = true;
+ break;
+ case REL_RZ:
+ geo_raw[2] = (int)geo_input.value;
+ z = true;
+ break;
+ case REL_HWHEEL:
+ geo_raw[3] = (int)geo_input.value;
+ hdst = true;
+ break;
+ default:
+ _E("geo_input event[type = %d, code = %d] is unknown.", geo_input.type, geo_input.code);
+ return false;
+ break;
+ }
+ } else if (geo_input.type == EV_SYN) {
+ syn = true;
+ fired_time = util::get_timestamp(&geo_input.time);
+ } else {
+ _E("geo_input event[type = %d, code = %d] is unknown.", geo_input.type, geo_input.code);
+ return false;
+ }
+ }
+
+ if (syn == false) {
+ _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
+ return false;
+ }
+
+ if (x)
+ m_x = geo_raw[0];
+ if (y)
+ m_y = geo_raw[1];
+ if (z)
+ m_z = geo_raw[2];
+ if (hdst)
+ m_hdst = geo_raw[3] - 1; /* accuracy bias: -1 */
+
+ m_fired_time = fired_time;
+
+ _D("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);
+
+ return true;
+}
+
+
+bool geomag_device::update_value_iio(void)
+{
+ struct {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ int8_t hdst;
+ int64_t timestamp;
+ } __attribute__((packed)) data;
+
+ struct pollfd pfd;
+
+ pfd.fd = m_node_handle;
+ pfd.events = POLLIN | POLLERR;
+ pfd.revents = 0;
+
+ int ret = poll(&pfd, 1, -1);
+
+ if (ret == -1) {
+ _ERRNO(errno, _E, "Failed to poll from m_node_handle:%d", m_node_handle);
+ return false;
+ } else if (!ret) {
+ _E("poll timeout m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (pfd.revents & POLLERR) {
+ _E("poll exception occurred! m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (!(pfd.revents & POLLIN)) {
+ _E("poll nothing to read! m_node_handle:%d, pfd.revents = %d", m_node_handle, pfd.revents);
+ return false;
+ }
+
+ int len = read(m_node_handle, &data, sizeof(data));
+
+ if (len != sizeof(data)) {
+ _E("Failed to read data, m_node_handle:%d read_len:%d", m_node_handle, len);
+ return false;
+ }
+
+ m_x = data.x;
+ m_y = data.y;
+ m_z = data.z;
+ m_hdst = data.hdst - 1;
+ m_fired_time = NSEC_TO_MSEC(data.timestamp);
+
+ _D("m_x = %d, m_y = %d, m_z = %d, time = %lluus", m_x, m_y, m_z, m_fired_time);
+
+ return true;
+}
+
+int geomag_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ _D("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int geomag_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = (m_hdst == 1)? 0 : m_hdst;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 4;
+ sensor_data->values[0] = m_x;
+ sensor_data->values[1] = m_y;
+ sensor_data->values[2] = m_z;
+ sensor_data->values[3] = (m_hdst == 1)? 0 : m_hdst;
+
+ raw_to_base(sensor_data);
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
+
+void geomag_device::raw_to_base(sensor_data_t *data)
+{
+ data->values[0] = data->values[0] * RAW_DATA_UNIT;
+ data->values[1] = data->values[1] * RAW_DATA_UNIT;
+ data->values[2] = data->values[2] * RAW_DATA_UNIT;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _GEOMAG_DEVICE_H_
+#define _GEOMAG_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class geomag_device : public sensor_device {
+public:
+ geomag_device();
+ virtual ~geomag_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ int m_x;
+ int m_y;
+ int m_z;
+ int m_hdst;
+ unsigned long m_polling_interval;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_data_node;
+ std::string m_enable_node;
+ std::string m_interval_node;
+
+ std::function<bool(void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_input_event(void);
+ bool update_value_iio(void);
+
+ void raw_to_base(sensor_data_t *data);
+};
+#endif /*_GEOMAG_DEVICE_H_*/
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#include <macro.h>
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+
+#include "gyro_device.h"
+
+#define MODEL_NAME "ICM20610"
+#define VENDOR "Invensense"
+#define RESOLUTION 16
+#define RAW_DATA_UNIT 61.04
+#define MIN_INTERVAL 5
+#define MAX_BATCH_COUNT 30
+
+#define SENSOR_NAME "SENSOR_GYROSCOPE"
+#define SENSOR_TYPE_GYRO "GYRO"
+
+#define INPUT_NAME "gyro_sensor"
+#define GYRO_SENSORHUB_POLL_NODE_NAME "gyro_poll_delay"
+
+#define DPS_TO_MDPS 1000
+#define RAW_DATA_TO_DPS_UNIT(X) ((float)(X)/((float)DPS_TO_MDPS))
+#define MIN_RANGE(RES) (-((1 << (RES))/2))
+#define MAX_RANGE(RES) (((1 << (RES))/2)-1)
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_GYROSCOPE,
+ event_type: (SENSOR_DEVICE_GYROSCOPE << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: MIN_RANGE(RESOLUTION) * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT),
+ max_range: MAX_RANGE(RESOLUTION) * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT),
+ resolution: RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT),
+ min_interval: MIN_INTERVAL,
+ max_batch_count: MAX_BATCH_COUNT,
+ wakeup_supported: false
+};
+
+gyro_device::gyro_device()
+: m_node_handle(-1)
+, m_x(-1)
+, m_y(-1)
+, m_z(-1)
+, m_polling_interval(1000)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = GYRO_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name);
+ query.sensor_type = SENSOR_TYPE_GYRO;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = "gyro_enable";
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+ m_interval_node = info.interval_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "Failed to open gyro handle");
+ throw ENXIO;
+ }
+
+ if (m_method == INPUT_EVENT_METHOD) {
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+
+ update_value = [=]() {
+ return this->update_value_input_event();
+ };
+ } else {
+ if (!info.buffer_length_node_path.empty())
+ util::set_node_value(info.buffer_length_node_path, 600);
+
+ if (!info.buffer_enable_node_path.empty())
+ util::set_node_value(info.buffer_enable_node_path, 1);
+
+ update_value = [=]() {
+ return this->update_value_iio();
+ };
+ }
+
+ _I("gyro_device is created!");
+}
+
+gyro_device::~gyro_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("gyro_device is destroyed!");
+}
+
+int gyro_device::get_poll_fd(void)
+{
+ return m_node_handle;
+}
+
+int gyro_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool gyro_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_GYROSCOPE_ENABLE_BIT);
+ set_interval(id, m_polling_interval);
+
+ m_fired_time = 0;
+ _I("Enable gyroscope sensor");
+ return true;
+}
+
+bool gyro_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_GYROSCOPE_ENABLE_BIT);
+
+ _I("Disable gyroscope sensor");
+ return true;
+}
+
+bool gyro_device::set_interval(uint32_t id, unsigned long val)
+{
+ unsigned long long polling_interval_ns;
+
+ polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
+
+ if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
+ _E("Failed to set polling resource: %s", m_interval_node.c_str());
+ return false;
+ }
+
+ _I("Interval is changed from %dms to %dms", m_polling_interval, val);
+ m_polling_interval = val;
+ return true;
+}
+
+bool gyro_device::update_value_input_event(void)
+{
+ int gyro_raw[3] = {0,};
+ bool x,y,z;
+ int read_input_cnt = 0;
+ const int INPUT_MAX_BEFORE_SYN = 10;
+ unsigned long long fired_time = 0;
+ bool syn = false;
+
+ x = y = z = false;
+
+ struct input_event gyro_input;
+ _D("gyro event detection!");
+
+ while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
+ int len = read(m_node_handle, &gyro_input, sizeof(gyro_input));
+ if (len != sizeof(gyro_input)) {
+ _E("gyro_file read fail, read_len = %d", len);
+ return false;
+ }
+
+ ++read_input_cnt;
+
+ if (gyro_input.type == EV_REL) {
+ switch (gyro_input.code) {
+ case REL_RX:
+ gyro_raw[0] = (int)gyro_input.value;
+ x = true;
+ break;
+ case REL_RY:
+ gyro_raw[1] = (int)gyro_input.value;
+ y = true;
+ break;
+ case REL_RZ:
+ gyro_raw[2] = (int)gyro_input.value;
+ z = true;
+ break;
+ default:
+ _E("gyro_input event[type = %d, code = %d] is unknown.", gyro_input.type, gyro_input.code);
+ return false;
+ break;
+ }
+ } else if (gyro_input.type == EV_SYN) {
+ syn = true;
+ fired_time = util::get_timestamp(&gyro_input.time);
+ } else {
+ _E("gyro_input event[type = %d, code = %d] is unknown.", gyro_input.type, gyro_input.code);
+ return false;
+ }
+ }
+
+ if (syn == false) {
+ _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
+ return false;
+ }
+
+ if (x)
+ m_x = gyro_raw[0];
+ if (y)
+ m_y = gyro_raw[1];
+ if (z)
+ m_z = gyro_raw[2];
+
+ m_fired_time = fired_time;
+
+ _D("m_x = %d, m_y = %d, m_z = %d, time = %lluus", m_x, m_y, m_z, m_fired_time);
+
+ return true;
+}
+
+bool gyro_device::update_value_iio(void)
+{
+ struct {
+ int32_t x;
+ int32_t y;
+ int32_t z;
+ int64_t timestamp;
+ } __attribute__((packed)) data;
+
+ struct pollfd pfd;
+
+ pfd.fd = m_node_handle;
+ pfd.events = POLLIN | POLLERR;
+ pfd.revents = 0;
+
+ int ret = poll(&pfd, 1, -1);
+
+ if (ret == -1) {
+ _ERRNO(errno, _E, "Failed to poll from m_node_handle:%d", m_node_handle);
+ return false;
+ } else if (!ret) {
+ _E("poll timeout m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (pfd.revents & POLLERR) {
+ _E("poll exception occurred! m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (!(pfd.revents & POLLIN)) {
+ _E("poll nothing to read! m_node_handle:%d, pfd.revents = %d", m_node_handle, pfd.revents);
+ return false;
+ }
+
+ int len = read(m_node_handle, &data, sizeof(data));
+
+ if (len != sizeof(data)) {
+ _E("Failed to read data, m_node_handle:%d read_len:%d", m_node_handle, len);
+ return false;
+ }
+
+ m_x = data.x;
+ m_y = data.y;
+ m_z = data.z;
+ m_fired_time = NSEC_TO_MSEC(data.timestamp);
+
+ _D("m_x = %d, m_y = %d, m_z = %d, time = %lluus", m_x, m_y, m_z, m_fired_time);
+
+ return true;
+}
+
+int gyro_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ _D("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int gyro_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 3;
+ sensor_data->values[0] = m_x;
+ sensor_data->values[1] = m_y;
+ sensor_data->values[2] = m_z;
+
+ raw_to_base(sensor_data);
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
+
+void gyro_device::raw_to_base(sensor_data_t *data)
+{
+ data->values[0] = data->values[0] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+ data->values[1] = data->values[1] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+ data->values[2] = data->values[2] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _GYRO_DEVICE_H_
+#define _GYRO_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class gyro_device : public sensor_device {
+public:
+ gyro_device();
+ virtual ~gyro_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ int m_x;
+ int m_y;
+ int m_z;
+ unsigned long m_polling_interval;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_data_node;
+ std::string m_enable_node;
+ std::string m_interval_node;
+
+ std::function<bool (void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_input_event(void);
+ bool update_value_iio(void);
+
+ void raw_to_base(sensor_data_t *data);
+};
+#endif /* _GYRO_DEVICE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+
+#include "gyro_uncal_device.h"
+
+#define MODEL_NAME "BMI168"
+#define VENDOR "Boach"
+#define RESOLUTION 16
+#define RAW_DATA_UNIT 61.04
+#define MIN_INTERVAL 1
+#define MAX_BATCH_COUNT 0
+
+#define SENSOR_NAME "SENSOR_GYROSCOPE_UNCALIBRATED"
+#define SENSOR_TYPE_GYRO_UNCAL "GYRO"
+
+#define INPUT_NAME "uncal_gyro_sensor"
+#define GYRO_UNCAL_SENSORHUB_POLL_NODE_NAME "uncal_gyro_poll_delay"
+
+#define DPS_TO_MDPS 1000
+#define RAW_DATA_TO_DPS_UNIT(X) ((float)(X)/((float)DPS_TO_MDPS))
+#define MIN_RANGE(RES) (-((1 << (RES))/2))
+#define MAX_RANGE(RES) (((1 << (RES))/2)-1)
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_GYROSCOPE_UNCAL,
+ event_type: (SENSOR_DEVICE_GYROSCOPE_UNCAL << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: MIN_RANGE(RESOLUTION) * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT),
+ max_range: MAX_RANGE(RESOLUTION) * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT),
+ resolution: RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT),
+ min_interval: MIN_INTERVAL,
+ max_batch_count: MAX_BATCH_COUNT,
+ wakeup_supported: false
+};
+
+gyro_uncal_device::gyro_uncal_device()
+: m_node_handle(-1)
+, m_x(-1)
+, m_y(-1)
+, m_z(-1)
+, m_x_offset(-1)
+, m_y_offset(-1)
+, m_z_offset(-1)
+, m_polling_interval(1000)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = GYRO_UNCAL_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name);
+ query.sensor_type = SENSOR_TYPE_GYRO_UNCAL;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = "uncal_gyro_enable";
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+ m_interval_node = info.interval_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "gyro_uncal handle open fail for gyro_uncal device");
+ throw ENXIO;
+ }
+
+ if (m_method == INPUT_EVENT_METHOD) {
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+
+ update_value = [=]() {
+ return this->update_value_input_event();
+ };
+ }
+
+ _I("gyro_uncal_device is created!");
+}
+
+gyro_uncal_device::~gyro_uncal_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("gyro_uncal_device is destroyed!");
+}
+
+int gyro_uncal_device::get_poll_fd(void)
+{
+ return m_node_handle;
+}
+
+int gyro_uncal_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool gyro_uncal_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_GYRO_UNCALIB_ENABLE_BIT);
+ set_interval(id, m_polling_interval);
+
+ m_fired_time = 0;
+ _I("Enable gyroscope uncalibration sensor");
+ return true;
+}
+
+bool gyro_uncal_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_GYRO_UNCALIB_ENABLE_BIT);
+
+ _I("Disable gyroscope uncalibration sensor");
+ return true;
+}
+
+bool gyro_uncal_device::set_interval(uint32_t id, unsigned long val)
+{
+ unsigned long long polling_interval_ns;
+
+ polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
+
+ if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
+ _E("Failed to set polling resource: %s", m_interval_node.c_str());
+ return false;
+ }
+
+ _I("Interval is changed from %dms to %dms", m_polling_interval, val);
+ m_polling_interval = val;
+ return true;
+}
+
+bool gyro_uncal_device::update_value_input_event(void)
+{
+ int gyro_uncal_raw[6] = {0,};
+ bool x,y,z,x_offset,y_offset,z_offset;
+ int read_input_cnt = 0;
+ const int INPUT_MAX_BEFORE_SYN = 10;
+ unsigned long long fired_time = 0;
+ bool syn = false;
+
+ x = y = z = x_offset = y_offset = z_offset = false;
+
+ struct input_event gyro_uncal_input;
+ _D("uncal gyro event detection!");
+
+ while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
+ int len = read(m_node_handle, &gyro_uncal_input, sizeof(gyro_uncal_input));
+ if (len != sizeof(gyro_uncal_input)) {
+ _E("gyro_file read fail, read_len = %d",len);
+ return false;
+ }
+
+ ++read_input_cnt;
+
+ if (gyro_uncal_input.type == EV_REL) {
+ switch (gyro_uncal_input.code) {
+ case REL_RX:
+ gyro_uncal_raw[0] = (int)gyro_uncal_input.value;
+ x = true;
+ break;
+ case REL_RY:
+ gyro_uncal_raw[1] = (int)gyro_uncal_input.value;
+ y = true;
+ break;
+ case REL_RZ:
+ gyro_uncal_raw[2] = (int)gyro_uncal_input.value;
+ z = true;
+ break;
+ case REL_HWHEEL:
+ gyro_uncal_raw[3] = (int)gyro_uncal_input.value;
+ x_offset = true;
+ break;
+ case REL_DIAL:
+ gyro_uncal_raw[4] = (int)gyro_uncal_input.value;
+ y_offset = true;
+ break;
+ case REL_WHEEL:
+ gyro_uncal_raw[5] = (int)gyro_uncal_input.value;
+ z_offset= true;
+ break;
+ default:
+ _E("gyro_uncal_input event[type = %d, code = %d] is unknown.", gyro_uncal_input.type, gyro_uncal_input.code);
+ return false;
+ break;
+ }
+ } else if (gyro_uncal_input.type == EV_SYN) {
+ syn = true;
+ fired_time = util::get_timestamp(&gyro_uncal_input.time);
+ } else {
+ _E("gyro_uncal_input event[type = %d, code = %d] is unknown.", gyro_uncal_input.type, gyro_uncal_input.code);
+ return false;
+ }
+ }
+
+ if (syn == false) {
+ _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
+ return false;
+ }
+
+ if (x)
+ m_x = gyro_uncal_raw[0];
+ if (y)
+ m_y = gyro_uncal_raw[1];
+ if (z)
+ m_z = gyro_uncal_raw[2];
+ if (x_offset)
+ m_x_offset= gyro_uncal_raw[3];
+ if (y_offset)
+ m_y_offset= gyro_uncal_raw[4];
+ if (z_offset)
+ m_z_offset= gyro_uncal_raw[5];
+
+ m_fired_time = fired_time;
+
+ _D("m_x = %d, m_y = %d, m_z = %d, m_x_offset = %d, m_y_offset = %d, m_z_offset = %d, time = %lluus", m_x, m_y, m_z, m_x_offset, m_y_offset, m_z_offset, m_fired_time);
+
+ return true;
+}
+
+int gyro_uncal_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ _D("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int gyro_uncal_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 6;
+ sensor_data->values[0] = m_x;
+ sensor_data->values[1] = m_y;
+ sensor_data->values[2] = m_z;
+ sensor_data->values[2] = m_x_offset;
+ sensor_data->values[2] = m_y_offset;
+ sensor_data->values[2] = m_z_offset;
+
+ raw_to_base(sensor_data);
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
+
+void gyro_uncal_device::raw_to_base(sensor_data_t *data)
+{
+ data->values[0] = data->values[0] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+ data->values[1] = data->values[1] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+ data->values[2] = data->values[2] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+ data->values[3] = data->values[3] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+ data->values[4] = data->values[4] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+ data->values[5] = data->values[5] * RAW_DATA_TO_DPS_UNIT(RAW_DATA_UNIT);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _GYRO_UNCAL_DEVICE_H_
+#define _GYRO_UNCAL_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class gyro_uncal_device : public sensor_device {
+public:
+ gyro_uncal_device();
+ virtual ~gyro_uncal_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ int m_x;
+ int m_y;
+ int m_z;
+ int m_x_offset;
+ int m_y_offset;
+ int m_z_offset;
+ unsigned long m_polling_interval;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_data_node;
+ std::string m_enable_node;
+ std::string m_interval_node;
+
+ std::function<bool (void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_input_event(void);
+
+ void raw_to_base(sensor_data_t *data);
+};
+#endif /* _GYRO_UNCAL_DEVICE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <math.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#include <macro.h>
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+
+#include "light_device.h"
+
+#define MODEL_NAME "TMG399x"
+#define VENDOR "AMS"
+#define MIN_RANGE 0
+#define MAX_RANGE 60000
+#define RESOLUTION 1
+#define RAW_DATA_UNIT 1
+#define MIN_INTERVAL 200
+#define MAX_BATCH_COUNT 0
+
+#define SENSOR_NAME "SENSOR_LIGHT"
+#define SENSOR_TYPE_LIGHT "LIGHT"
+
+#define INPUT_NAME "light_sensor"
+#define LIGHT_SENSORHUB_POLL_NODE_NAME "light_poll_delay"
+
+#define BIAS 1
+#define D_Factor 1190
+#define R_Coef 360
+#define G_Coef 1000
+#define B_Coef 0
+#define CT_Coef (3343)
+#define CT_Offset (1596)
+#define INTEGRATION_CYCLE 278
+#define MAX_LUX_VALUE 150000
+#define MAX_ALS_VALUE 0xFFFF
+#define GAB (0.15)
+#define min_t(a,b) (((a) < (b)) ? (a) : (b))
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_LIGHT,
+ event_type: (SENSOR_DEVICE_LIGHT << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: MIN_RANGE,
+ max_range: MAX_RANGE,
+ resolution: RAW_DATA_UNIT,
+ min_interval: MIN_INTERVAL,
+ max_batch_count: MAX_BATCH_COUNT,
+ wakeup_supported: false
+};
+
+light_device::light_device()
+: m_node_handle(-1)
+, m_lux(-1)
+, m_polling_interval(1000)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = LIGHT_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = true;
+ query.sensor_type = SENSOR_TYPE_LIGHT;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = "light_enable";
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+ m_interval_node = info.interval_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "light handle open fail for light device");
+ throw ENXIO;
+ }
+
+ if (m_method != INPUT_EVENT_METHOD)
+ throw ENXIO;
+
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+
+ update_value = [=]() {
+ return this->update_value_lux();
+ };
+
+ _I("light_device is created!");
+}
+
+light_device::~light_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("light_device is destroyed!");
+}
+
+int light_device::get_poll_fd()
+{
+ return m_node_handle;
+}
+
+int light_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool light_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_LIGHT_ENABLE_BIT);
+ set_interval(id, m_polling_interval);
+
+ m_fired_time = 0;
+ _I("Enable light sensor");
+ return true;
+}
+
+bool light_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_LIGHT_ENABLE_BIT);
+
+ _I("Disable light sensor");
+ return true;
+}
+
+bool light_device::set_interval(uint32_t id, unsigned long val)
+{
+ unsigned long long polling_interval_ns;
+
+ polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
+
+ if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
+ _E("Failed to set polling resource: %s", m_interval_node.c_str());
+ return false;
+ }
+
+ _I("Interval is changed from %dms to %dms", m_polling_interval, val);
+ m_polling_interval = val;
+ return true;
+}
+
+bool light_device::update_value_lux(void)
+{
+ size_t raw_red = 0, raw_green = 0, raw_blue = 0, raw_white = 0;
+ size_t raw_ir_cmp = 0, raw_amb_pga = 0;
+ int read_input_cnt = 0;
+ const int INPUT_MAX_BEFORE_SYN = 10;
+ unsigned long long fired_time = 0;
+ bool syn = false;
+
+ struct input_event light_event;
+ _D("light event detection!");
+
+ while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
+ int len = read(m_node_handle, &light_event, sizeof(light_event));
+ if (len != sizeof(light_event)) {
+ _E("light_file read fail, read_len = %d\n",len);
+ return false;
+ }
+
+ ++read_input_cnt;
+
+ if (light_event.type == EV_REL) {
+ switch (light_event.code) {
+ case REL_HWHEEL:
+ raw_red = light_event.value - 1;
+ break;
+ case REL_DIAL:
+ raw_green = light_event.value - 1;
+ break;
+ case REL_WHEEL:
+ raw_blue = light_event.value - 1;
+ break;
+ case REL_MISC:
+ raw_white = light_event.value - 1;
+ break;
+ case REL_RY:
+ raw_ir_cmp = light_event.value - 1;
+ break;
+ case REL_RZ:
+ raw_amb_pga = light_event.value - 1;
+ break;
+ default:
+ _E("light_event event[type = %d, code = %d] is unknown.", light_event.type, light_event.code);
+ return false;
+ }
+ } else if (light_event.type == EV_SYN) {
+ syn = true;
+ fired_time = util::get_timestamp(&light_event.time);
+ } else {
+ _E("light_event event[type = %d, code = %d] is unknown.", light_event.type, light_event.code);
+ return false;
+ }
+ }
+
+ if (syn == false) {
+ _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
+ return false;
+ }
+
+ compute_lux_tmg399x(raw_red, raw_green, raw_blue, raw_white, raw_ir_cmp, raw_amb_pga);
+ m_fired_time = fired_time;
+
+ _D("update_value_lux, lux : %d", m_lux);
+
+ return true;
+}
+
+int light_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ _D("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int light_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 2;
+ sensor_data->values[0] = m_lux;
+ sensor_data->values[1] = m_cct;
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
+
+void 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)
+{
+ const int luxgain[4] = {1, 4, 16, 64};
+ size_t rp1, gp1, bp1, cp1;
+ int64_t lux = 0, calculated_lux = 0;
+ size_t cct, cpl, gain;
+ int ir;
+ int sat;
+
+ sat = min_t(MAX_ALS_VALUE, ((256 - a_time) << 10));
+ sat = sat * 7 / 10;
+
+ if (a_gain == 0 && (int)clear >= sat) {
+ lux = MAX_LUX_VALUE;
+ cct = 5800;
+ double logvalue = log10(lux);
+ calculated_lux = (int)pow(10, (logvalue + GAB));
+
+ m_lux = (float)calculated_lux;
+ m_cct = (float)cct;
+ _D("Saturation!!!"
+ "RED : %d, GREEN : %d, BLUE : %d, CLEAR : %d,"
+ "Lux = %f, CCT = %f, sat = %d",
+ red, green, blue, clear, calculated_lux, m_cct, sat);
+ return;
+ }
+
+ ir = red + green + blue - clear + 1;
+
+ if (ir < 0)
+ ir = 0;
+ else
+ ir >>= 1;
+
+ gain = luxgain[a_gain];
+
+ /* calculate cpl */
+ cpl = 256 - a_time;
+ cpl *= INTEGRATION_CYCLE;
+ cpl *= 10;
+ cpl *= gain;
+
+ if (!cpl)
+ cpl = 1;
+
+ /* remove ir from counts*/
+ rp1 = red - ir;
+ gp1 = green - ir;
+ bp1 = blue - ir;
+ cp1 = clear - ir;
+
+ if ((int)red > ir)
+ lux += R_Coef * rp1;
+ _D("lux step1 = %lld\n", lux);
+ if ((int)green > ir)
+ lux += G_Coef * gp1;
+ _D("lux step2 = %lld\n", lux);
+ if ((int)blue > ir)
+ lux -= B_Coef * bp1;
+ _D("lux step3 = %lld\n", lux);
+
+ if (lux < 0)
+ lux = 0;
+
+ lux *= D_Factor;
+ lux /= cpl;
+ _D("lux_step4 = %lld, cpl = %d\n", lux, cpl);
+
+ if (lux < 0)
+ lux = 0;
+
+ if (rp1 < 1)
+ rp1 = 1;
+
+ cct = ((CT_Coef * bp1) / rp1) + CT_Offset;
+
+ if (lux < 6) {
+ calculated_lux = lux;
+ } else if (lux < 31) {
+ double logvalue = log10(lux);
+ calculated_lux = (int)pow(10, (logvalue + GAB));
+ } else if (lux < 60) {
+ calculated_lux = (int64_t)log2(pow(lux - 30, 8)) + 46;
+ } else if (lux < 130) {
+ calculated_lux = (int64_t)log2(pow(lux - 59, 10)) + 120;
+ } else if (lux < 240) {
+ calculated_lux = (int64_t)log2(pow(lux - 129, 20)) + 200;
+ } else if (lux < 360) {
+ calculated_lux = (int64_t)log2(pow(lux - 239, 16)) + 400;
+ } else if (lux < 570) {
+ calculated_lux = (int64_t)log2(pow(lux - 359, 27)) + 600;
+ } else if (lux < 790) {
+ calculated_lux = (int64_t)log2(pow(lux - 569, 28)) + 900;
+ } else if (lux < 1140) {
+ calculated_lux = (int64_t)log2(pow(lux - 789, 37)) + 1300;
+ } else if (lux < 1620) {
+ calculated_lux = (int64_t)log2(pow(lux - 1139, 55)) + 1800;
+ } else if (lux < 2370) {
+ calculated_lux = (int64_t)log2(pow(lux - 1619, 99)) + 2400;
+ } else if (lux < 3550) {
+ calculated_lux = (int64_t)log2(pow(lux - 2369, 100)) + 4000;
+ } else if (lux < 6600) {
+ calculated_lux = (int64_t)((log2(pow(lux - 3549, 50)) + 6000) * pow(lux - 3549, 0.0435));
+ } else {
+ double logvalue = log10(lux);
+ calculated_lux = (int)pow(10, (logvalue + GAB));
+ }
+
+ m_lux = (float)calculated_lux;
+ m_cct = (float)cct;
+
+ if (lux == 0) {
+ _E("RED : %d, GREEN : %d, BLUE : %d, CLEAR : %d,"
+ " CALCULATED LUX : %f, CCT : %f"
+ " a_time = %d, gain = %d, ir=%d,"
+ " rp1=%d, gp1=%d, bp1=%d, cp1=%d, cpl=%d\n",
+ red, green, blue, clear,
+ m_lux, m_cct,
+ a_time, gain, ir,
+ rp1, gp1, bp1, cp1, cpl);
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _LIGHT_DEVICE_H_
+#define _LIGHT_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class light_device : public sensor_device {
+public:
+ light_device();
+ virtual ~light_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ float m_lux;
+ float m_cct;
+ unsigned long m_polling_interval;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_enable_node;
+ std::string m_data_node;
+ std::string m_interval_node;
+
+ std::function<bool (void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_lux(void);
+
+ void compute_lux_tmg399x(size_t red, size_t green, size_t blue, size_t clear, size_t a_time, size_t a_gain);
+};
+#endif /* _LIGHT_DEVICE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MACRO_H__
+#define __MACRO_H__
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#define NSEC_TO_MSEC(x) ((x) / 1000)
+
+#endif /* __MACRO_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+#include <math.h>
+
+#include <macro.h>
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+#include "pressure_device.h"
+
+#define SEA_LEVEL_RESOLUTION 0.01
+#define SEA_LEVEL_PRESSURE 101325.0
+#define SEA_LEVEL_EPSILON 0.00001
+
+#define MODEL_NAME "BMP180"
+#define VENDOR "BOSCH"
+#define RESOLUTION 1
+#define RAW_DATA_UNIT 0.01
+#define MIN_INTERVAL 180
+#define MIN_RANGE 260
+#define MAX_RANGE 1260
+#define TEMPERATURE_RESOLUTION 0.002083
+#define TEMPERATURE_OFFSET 42.5
+#define MAX_BATCH_COUNT 50
+
+#define SENSOR_NAME "SENSOR_PRESSURE"
+#define SENSOR_TYPE_PRESSURE "PRESSURE"
+
+#define INPUT_NAME "pressure_sensor"
+#define PRESSURE_SENSORHUB_POLL_NODE_NAME "pressure_poll_delay"
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_PRESSURE,
+ event_type: (SENSOR_DEVICE_PRESSURE << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: MIN_RANGE,
+ max_range: MAX_RANGE,
+ resolution: RAW_DATA_UNIT,
+ min_interval: MIN_INTERVAL,
+ max_batch_count: MAX_BATCH_COUNT,
+ wakeup_supported: false
+};
+
+pressure_device::pressure_device()
+: m_node_handle(-1)
+, m_pressure(0)
+, m_temperature(0)
+, m_sea_level_pressure(SEA_LEVEL_PRESSURE)
+, m_polling_interval(1000)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = PRESSURE_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name);
+ query.sensor_type = SENSOR_TYPE_PRESSURE;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = "pressure_enable";
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+ m_interval_node = info.interval_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "pressure handle open fail for pressure sensor");
+ throw ENXIO;
+ }
+
+ if (m_method == INPUT_EVENT_METHOD) {
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+
+ update_value = [=]() {
+ return this->update_value_input_event();
+ };
+ } else {
+ if (!info.buffer_length_node_path.empty())
+ util::set_node_value(info.buffer_length_node_path, 480);
+
+ if (!info.buffer_enable_node_path.empty())
+ util::set_node_value(info.buffer_enable_node_path, 1);
+
+ update_value = [=]() {
+ return this->update_value_iio();
+ };
+ }
+
+ _I("pressure_device is created!");
+}
+
+pressure_device::~pressure_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("pressure_device is destroyed!");
+}
+
+int pressure_device::get_poll_fd(void)
+{
+ return m_node_handle;
+}
+
+int pressure_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool pressure_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_PRESSURE_ENABLE_BIT);
+ set_interval(id, m_polling_interval);
+
+ m_fired_time = 0;
+ _I("Enable pressure sensor");
+ return true;
+}
+
+bool pressure_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_PRESSURE_ENABLE_BIT);
+
+ _I("Disable pressure sensor");
+ return true;
+}
+
+bool pressure_device::set_interval(uint32_t id, unsigned long val)
+{
+ unsigned long long polling_interval_ns;
+
+ polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
+
+ if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
+ _E("Failed to set polling resource: %s", m_interval_node.c_str());
+ return false;
+ }
+
+ _I("Interval is changed from %dms to %dms", m_polling_interval, val);
+ m_polling_interval = val;
+ return true;
+}
+
+bool pressure_device::update_value_input_event(void)
+{
+ int pressure_raw[3] = {0,};
+ bool pressure = false;
+ bool sea_level = false;
+ bool temperature = false;
+ int read_input_cnt = 0;
+ const int INPUT_MAX_BEFORE_SYN = 10;
+ unsigned long long fired_time = 0;
+ bool syn = false;
+
+ struct input_event pressure_event;
+ _D("pressure event detection!");
+
+ while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
+ int len = read(m_node_handle, &pressure_event, sizeof(pressure_event));
+ if (len != sizeof(pressure_event)) {
+ _E("pressure_file read fail, read_len = %d\n",len);
+ return false;
+ }
+
+ ++read_input_cnt;
+
+ if (pressure_event.type == EV_REL) {
+ switch (pressure_event.code) {
+ case REL_HWHEEL:
+ pressure_raw[0] = (int)pressure_event.value;
+ pressure = true;
+ break;
+ case REL_DIAL:
+ pressure_raw[1] = (int)pressure_event.value;
+ sea_level = true;
+ break;
+ case REL_WHEEL:
+ pressure_raw[2] = (int)pressure_event.value;
+ temperature = true;
+ break;
+ default:
+ _E("pressure_event event[type = %d, code = %d] is unknown.", pressure_event.type, pressure_event.code);
+ return false;
+ break;
+ }
+ } else if (pressure_event.type == EV_SYN) {
+ syn = true;
+ fired_time = util::get_timestamp(&pressure_event.time);
+ } else {
+ _E("pressure_event event[type = %d, code = %d] is unknown.", pressure_event.type, pressure_event.code);
+ return false;
+ }
+ }
+
+ if (syn == false) {
+ _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
+ return false;
+ }
+
+ if (pressure)
+ m_pressure = pressure_raw[0];
+ if (sea_level)
+ m_sea_level_pressure = pressure_raw[1];
+ if (temperature)
+ m_temperature = pressure_raw[2];
+
+ m_fired_time = fired_time;
+
+ _D("m_pressure = %d, sea_level = %d, temperature = %d, time = %lluus", m_pressure, m_sea_level_pressure, m_temperature, m_fired_time);
+
+ return true;
+}
+
+bool pressure_device::update_value_iio(void)
+{
+ struct {
+ int32_t pressure;
+ int32_t temperature;
+ int32_t sea_level_pressure;
+ int64_t timestamp;
+ } __attribute__((packed)) data;
+
+ struct pollfd pfd;
+
+ pfd.fd = m_node_handle;
+ pfd.events = POLLIN | POLLERR;
+ pfd.revents = 0;
+
+ int ret = poll(&pfd, 1, -1);
+
+ if (ret == -1) {
+ _ERRNO(errno, _E, "Failed to poll from m_node_handle:%d", m_node_handle);
+ return false;
+ } else if (!ret) {
+ _E("poll timeout m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (pfd.revents & POLLERR) {
+ _E("poll exception occurred! m_node_handle:%d", m_node_handle);
+ return false;
+ }
+
+ if (!(pfd.revents & POLLIN)) {
+ _E("poll nothing to read! m_node_handle:%d, pfd.revents = %d", m_node_handle, pfd.revents);
+ return false;
+ }
+
+ int len = read(m_node_handle, &data, sizeof(data));
+
+ if (len != sizeof(data)) {
+ _E("Failed to read data, m_node_handle:%d read_len:%d", m_node_handle, len);
+ return false;
+ }
+
+ m_pressure = data.pressure;
+ m_temperature = data.temperature;
+ m_sea_level_pressure = (float)data.sea_level_pressure;
+ m_fired_time = NSEC_TO_MSEC(data.timestamp);
+
+ _I("m_pressure = %d, m_temperature = %d, m_sea_level_pressure = %f, time = %lluus", m_pressure, m_temperature, m_sea_level_pressure, m_fired_time);
+
+ return true;
+}
+
+int pressure_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ _D("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int pressure_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 3;
+ sensor_data->values[0] = m_pressure;
+ sensor_data->values[1] = (float)m_sea_level_pressure;
+ sensor_data->values[2] = m_temperature;
+
+ raw_to_base(sensor_data);
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
+
+void pressure_device::raw_to_base(sensor_data_t *data)
+{
+ data->values[0] = data->values[0] * RAW_DATA_UNIT;
+ m_sea_level_pressure = data->values[1] * SEA_LEVEL_RESOLUTION;
+ data->values[1] = pressure_to_altitude(data->values[0]);
+ data->values[2] = data->values[2] * TEMPERATURE_RESOLUTION + TEMPERATURE_OFFSET;
+}
+
+float pressure_device::pressure_to_altitude(float pressure)
+{
+ float sea_level_pressure = m_sea_level_pressure;
+
+ if (sea_level_pressure < SEA_LEVEL_EPSILON && sea_level_pressure > -SEA_LEVEL_EPSILON)
+ sea_level_pressure = SEA_LEVEL_PRESSURE * SEA_LEVEL_RESOLUTION;
+
+ return 44330.0f * (1.0f - pow(pressure/sea_level_pressure, 1.0f/5.255f));
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _PRESSURE_DEVICE_H_
+#define _PRESSURE_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class pressure_device : public sensor_device {
+public:
+ pressure_device();
+ virtual ~pressure_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ int m_pressure;
+ int m_temperature;
+ float m_sea_level_pressure;
+ unsigned long m_polling_interval;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_data_node;
+ std::string m_enable_node;
+ std::string m_interval_node;
+
+ std::function<bool (void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_input_event(void);
+ bool update_value_iio(void);
+
+ void raw_to_base(sensor_data_t *data);
+ float pressure_to_altitude(float pressure);
+};
+#endif /*_PRESSURE_DEVICE_H_*/
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#include <macro.h>
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+
+#include "proxi_device.h"
+
+#define MODEL_NAME "TMG399x"
+#define VENDOR "AMS"
+#define MIN_RANGE 0
+#define MAX_RANGE 5
+#define RESOLUTION 1
+#define RAW_DATA_UNIT 1
+#define MIN_INTERVAL 0
+#define MAX_BATCH_COUNT 0
+
+#define SENSOR_NAME "SENSOR_PROXIMITY"
+#define SENSOR_TYPE_PROXI "PROXI"
+
+#define INPUT_NAME "proximity_sensor"
+#define PROXI_SENSORHUB_POLL_NODE_NAME "prox_poll_delay"
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_PROXIMITY,
+ event_type: (SENSOR_DEVICE_PROXIMITY << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: MIN_RANGE,
+ max_range: MAX_RANGE,
+ resolution: RESOLUTION,
+ min_interval: MIN_INTERVAL,
+ max_batch_count: MAX_BATCH_COUNT,
+ wakeup_supported: false
+};
+
+proxi_device::proxi_device()
+: m_node_handle(-1)
+, m_state(PROXIMITY_NODE_STATE_FAR)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = PROXI_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = true;
+ query.sensor_type = SENSOR_TYPE_PROXI;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = "proximity_enable";
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "Failed to open proximity sensor handle");
+ throw ENXIO;
+ }
+
+ if (m_method != INPUT_EVENT_METHOD)
+ throw ENXIO;
+
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+
+ update_value = [=]() {
+ return this->update_value_input_event();
+ };
+
+ _I("Proxi_sensor_hal is created!");
+}
+
+proxi_device::~proxi_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("Proxi_sensor_hal is destroyed!");
+}
+
+int proxi_device::get_poll_fd(void)
+{
+ return m_node_handle;
+}
+
+int proxi_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool proxi_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_PROXIMITY_ENABLE_BIT);
+
+ m_fired_time = 0;
+ INFO("Enable proxi sensor");
+ return true;
+}
+
+bool proxi_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_PROXIMITY_ENABLE_BIT);
+
+ INFO("Disable proxi sensor");
+ return true;
+}
+
+bool proxi_device::set_interval(uint32_t id, unsigned long val)
+{
+ return false;
+}
+
+bool proxi_device::update_value_input_event(void)
+{
+ struct input_event proxi_event;
+ _I("proxi event detection!");
+
+ int len = read(m_node_handle, &proxi_event, sizeof(proxi_event));
+
+ if (len == -1) {
+ _ERRNO(errno, _E, "Failed to read from m_node_handle");
+ return false;
+ }
+
+ _D("read event, len : %d , type : %x , code : %x , value : %x", len, proxi_event.type, proxi_event.code, proxi_event.value);
+ if ((proxi_event.type != EV_ABS) || (proxi_event.code != ABS_DISTANCE))
+ return false;
+
+ if (proxi_event.value != PROXIMITY_NODE_STATE_FAR && proxi_event.value != PROXIMITY_NODE_STATE_NEAR) {
+ _E("PROXIMITY_STATE Unknown: %d", proxi_event.value);
+ return false;
+ }
+
+ m_state = proxi_event.value;
+ m_fired_time = util::get_timestamp(&proxi_event.time);
+
+ return true;
+}
+
+int proxi_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ DBG("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int proxi_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 1;
+ sensor_data->values[0] = m_state * 5;
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _PROXI_DEVICE_H_
+#define _PROXI_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class proxi_device : public sensor_device {
+public:
+ enum proxi_node_state_event_t {
+ PROXIMITY_NODE_STATE_NEAR = 0,
+ PROXIMITY_NODE_STATE_FAR = 1,
+ PROXIMITY_NODE_STATE_UNKNOWN = 2,
+ };
+
+ proxi_device();
+ virtual ~proxi_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ unsigned int m_state;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_data_node;
+ std::string m_enable_node;
+
+ std::string m_model_id;
+ std::string m_vendor;
+ std::string m_chip_name;
+
+ std::function<bool(void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_input_event(void);
+};
+#endif /* _PROXI_DEVICE_H_ */
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _SENSOR_COMMON_H_
+#define _SENSOR_COMMON_H_
+
+#define SENSOR_EVENT_SHIFT 16
+#define RAW_DATA_EVENT 0x0001
+
+#define UNKNOWN_NAME "UNKNOWN"
+
+enum sensorhub_enable_bit {
+ SENSORHUB_ACCELEROMETER_ENABLE_BIT = 0,
+ SENSORHUB_GYROSCOPE_ENABLE_BIT,
+ SENSORHUB_GEOMAGNETIC_UNCALIB_ENABLE_BIT,
+ SENSORHUB_GEOMAGNETIC_RAW_ENABLE_BIT,
+ SENSORHUB_GEOMAGNETIC_ENABLE_BIT,
+ SENSORHUB_PRESSURE_ENABLE_BIT,
+ SENSORHUB_GESTURE_ENABLE_BIT,
+ SENSORHUB_PROXIMITY_ENABLE_BIT,
+ SENSORHUB_TEMPERATURE_HUMIDITY_ENABLE_BIT,
+ SENSORHUB_LIGHT_ENABLE_BIT,
+ SENSORHUB_PROXIMITY_RAW_ENABLE_BIT,
+ SENSORHUB_ORIENTATION_ENABLE_BIT,
+ SENSORHUB_STEP_DETECTOR_ENABLE_BIT = 12,
+ SENSORHUB_SIG_MOTION_ENABLE_BIT,
+ SENSORHUB_GYRO_UNCALIB_ENABLE_BIT,
+ SENSORHUB_GAME_ROTATION_VECTOR_ENABLE_BIT = 15,
+ SENSORHUB_ROTATION_VECTOR_ENABLE_BIT,
+ SENSORHUB_STEP_COUNTER_ENABLE_BIT,
+ SENSORHUB_HRM_RAW_ENABLE_BIT,
+ SENSORHUB_HRM_RAW_FAC_ENABLE_BIT,
+ SENSORHUB_HRM_LIB_ENABLE_BIT,
+ SENSORHUB_TILT_MOTION,
+ SENSORHUB_UV_SENSOR,
+ SENSORHUB_PIR_ENABLE_BIT,
+ SENSORHUB_PIR_RAW_ENABLE_BIT,
+ SENSORHUB_GSR_ENABLE_BIT = 25,
+ SENSORHUB_ENABLE_BIT_MAX,
+};
+
+#endif /* _SENSOR_COMMON_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _SENSOR_LOG_H_
+#define _SENSOR_LOG_H_
+
+#include <dlog.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX 256
+#endif
+
+#ifdef LOG_TAG
+ #undef LOG_TAG
+#endif
+#define LOG_TAG "SENSOR"
+
+#define LOG_DUMP(fp, fmt, arg...) do { if (fp) fprintf(fp, fmt, ##arg); else _E(fmt, ##arg); } while(0)
+
+#ifdef _DEBUG
+#define DBG SLOGD
+#else
+#define DBG(...) do{} while(0)
+#endif
+
+#define ERR SLOGE
+#define WARN SLOGW
+#define INFO SLOGI
+#define _E ERR
+#define _W WARN
+#define _I INFO
+#define _D DBG
+
+#define _ERRNO(errno, tag, fmt, arg...) do { \
+ char buf[1024]; \
+ char *error = strerror_r(errno, buf, 1024); \
+ if (!error) { \
+ _E("Failed to strerror_r()"); \
+ break; \
+ } \
+ tag(fmt" (%s[%d])", ##arg, error, errno); \
+ } while (0)
+
+#ifdef _DEBUG
+#define warn_if(expr, fmt, arg...) do { \
+ if(expr) { \
+ _D("(%s) -> " fmt, #expr, ##arg); \
+ } \
+ } while (0)
+#define ret_if(expr) do { \
+ if(expr) { \
+ _D("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return; \
+ } \
+ } while (0)
+#define retv_if(expr, val) do { \
+ if(expr) { \
+ _D("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return (val); \
+ } \
+ } while (0)
+#define retm_if(expr, fmt, arg...) do { \
+ if(expr) { \
+ _E(fmt, ##arg); \
+ _D("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return; \
+ } \
+ } while (0)
+#define retvm_if(expr, val, fmt, arg...) do { \
+ if(expr) { \
+ _E(fmt, ##arg); \
+ _D("(%s) -> %s() return", #expr, __FUNCTION__); \
+ return (val); \
+ } \
+ } while (0)
+
+#else
+#define warn_if(expr, fmt, arg...) do { \
+ if(expr) { \
+ _E(fmt, ##arg); \
+ } \
+ } while (0)
+#define ret_if(expr) do { \
+ if(expr) { \
+ return; \
+ } \
+ } while (0)
+#define retv_if(expr, val) do { \
+ if(expr) { \
+ return (val); \
+ } \
+ } while (0)
+#define retm_if(expr, fmt, arg...) do { \
+ if(expr) { \
+ _E(fmt, ##arg); \
+ return; \
+ } \
+ } while (0)
+#define retvm_if(expr, val, fmt, arg...) do { \
+ if(expr) { \
+ _E(fmt, ##arg); \
+ return (val); \
+ } \
+ } while (0)
+
+#endif
+
+#endif /* _SENSOR_LOG_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#include <util.h>
+#include <sensor_common.h>
+#include <sensor_log.h>
+
+#include "uv_device.h"
+
+#define MODEL_NAME "MAX86902_UV"
+#define VENDOR "MAXIM"
+#define RESOLUTION 1
+#define RAW_DATA_UNIT 1
+#define MIN_INTERVAL 10
+#define MAX_BATCH_COUNT 0
+
+#define SENSOR_NAME "ULTRAVIOLET_SENSOR"
+#define SENSOR_TYPE_ULTRAVIOLET "ULTRAVIOLET"
+
+#define INPUT_NAME "uv_sensor"
+#define UV_SENSORHUB_POLL_NODE_NAME "uv_poll_dealy"
+#define IIO_ENABLE_NAME "uv_enable"
+
+#define BIAS 1
+
+static sensor_info_t sensor_info = {
+ id: 0x1,
+ name: SENSOR_NAME,
+ type: SENSOR_DEVICE_ULTRAVIOLET,
+ event_type: (SENSOR_DEVICE_ULTRAVIOLET << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT,
+ model_name: MODEL_NAME,
+ vendor: VENDOR,
+ min_range: 0,
+ max_range: 65535,
+ resolution: 0,
+ min_interval: 0,
+ max_batch_count: 0,
+ wakeup_supported: false
+};
+
+uv_device::uv_device()
+: m_node_handle(-1)
+, m_ultraviolet(0)
+, m_polling_interval(1000)
+, m_fired_time(0)
+, m_sensorhub_controlled(false)
+{
+ const std::string sensorhub_interval_node_name = UV_SENSORHUB_POLL_NODE_NAME;
+
+ node_info_query query;
+ node_info info;
+
+ query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name);
+ query.sensor_type = SENSOR_TYPE_ULTRAVIOLET;
+ query.key = INPUT_NAME;
+ query.iio_enable_node_name = IIO_ENABLE_NAME;
+ query.sensorhub_interval_node_name = sensorhub_interval_node_name;
+
+ if (!util::get_node_info(query, info)) {
+ _E("Failed to get node info");
+ throw ENXIO;
+ }
+
+ util::show_node_info(info);
+
+ m_method = info.method;
+ m_data_node = info.data_node_path;
+ m_enable_node = info.enable_node_path;
+ m_interval_node = info.interval_node_path;
+
+ m_node_handle = open(m_data_node.c_str(), O_RDONLY);
+
+ if (m_node_handle < 0) {
+ _ERRNO(errno, _E, "Failed to open uv handle");
+ throw ENXIO;
+ }
+
+ if (m_method == INPUT_EVENT_METHOD) {
+ if (!util::set_monotonic_clock(m_node_handle))
+ throw ENXIO;
+ }
+
+ update_value = [=]() {
+ return this->update_value_input_event();
+ };
+
+ _I("uv_sensor is created!");
+}
+
+uv_device::~uv_device()
+{
+ close(m_node_handle);
+ m_node_handle = -1;
+
+ _I("uv_sensor is destroyed!");
+}
+
+int uv_device::get_poll_fd()
+{
+ return m_node_handle;
+}
+
+int uv_device::get_sensors(const sensor_info_t **sensors)
+{
+ *sensors = &sensor_info;
+
+ return 1;
+}
+
+bool uv_device::enable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_UV_SENSOR);
+ set_interval(id, m_polling_interval);
+
+ m_fired_time = 0;
+ _I("Enable uverometer sensor");
+ return true;
+}
+
+bool uv_device::disable(uint32_t id)
+{
+ util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_UV_SENSOR);
+
+ _I("Disable uverometer sensor");
+ return true;
+}
+
+bool uv_device::set_interval(uint32_t id, unsigned long val)
+{
+ unsigned long long polling_interval_ns;
+
+ polling_interval_ns = ((unsigned long long)(val) * 1000llu * 1000llu);
+
+ if (!util::set_node_value(m_interval_node, polling_interval_ns)) {
+ _E("Failed to set polling resource: %s", m_interval_node.c_str());
+ return false;
+ }
+
+ _I("Interval is changed from %dms to %dms", m_polling_interval, val);
+ m_polling_interval = val;
+ return true;
+}
+
+bool uv_device::update_value_input_event(void)
+{
+ int ultraviolet_raw = -1;
+ bool ultraviolet = false;
+ int read_input_cnt = 0;
+ const int INPUT_MAX_BEFORE_SYN = 10;
+ unsigned long long fired_time = 0;
+ bool syn = false;
+
+ struct input_event ultraviolet_event;
+ _D("ultraviolet event detection!");
+
+ while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) {
+ int len = read(m_node_handle, &ultraviolet_event, sizeof(ultraviolet_event));
+ if (len != sizeof(ultraviolet_event)) {
+ _E("ultraviolet file read fail, read_len = %d\n",len);
+ return false;
+ }
+
+ ++read_input_cnt;
+
+ if (ultraviolet_event.type == EV_REL && ultraviolet_event.code == REL_MISC) {
+ ultraviolet_raw = (int)ultraviolet_event.value - BIAS;
+ ultraviolet = true;
+ } else if (ultraviolet_event.type == EV_SYN) {
+ syn = true;
+ fired_time = util::get_timestamp(&ultraviolet_event.time);
+ } else {
+ _E("ultraviolet event[type = %d, code = %d] is unknown.", ultraviolet_event.type, ultraviolet_event.code);
+ return false;
+ }
+ }
+
+ if (syn == false) {
+ _E("EV_SYN didn't come until %d inputs had come", read_input_cnt);
+ return false;
+ }
+
+ if (ultraviolet)
+ m_ultraviolet = ultraviolet_raw;
+
+ m_fired_time = fired_time;
+
+ _D("m_ultraviolet = %d, time = %lluus", m_ultraviolet, m_fired_time);
+
+ return true;
+}
+
+int uv_device::read_fd(uint32_t **ids)
+{
+ if (!update_value()) {
+ _D("Failed to update value");
+ return false;
+ }
+
+ event_ids.clear();
+ event_ids.push_back(sensor_info.id);
+
+ *ids = &event_ids[0];
+
+ return event_ids.size();
+}
+
+int uv_device::get_data(uint32_t id, sensor_data_t **data, int *length)
+{
+ sensor_data_t *sensor_data;
+ sensor_data = (sensor_data_t *)malloc(sizeof(sensor_data_t));
+ retvm_if(!sensor_data, -ENOMEM, "Memory allocation failed");
+
+ sensor_data->accuracy = SENSOR_ACCURACY_GOOD;
+ sensor_data->timestamp = m_fired_time;
+ sensor_data->value_count = 1;
+ sensor_data->values[0] = m_ultraviolet;
+
+ raw_to_base(sensor_data);
+
+ *data = sensor_data;
+ *length = sizeof(sensor_data_t);
+
+ return 0;
+}
+
+void uv_device::raw_to_base(sensor_data_t *data)
+{
+ data->values[0] = data->values[0] * RAW_DATA_UNIT;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _UV_DEVICE_H_
+#define _UV_DEVICE_H_
+
+#include <sensor/sensor_hal.h>
+#include <string>
+#include <vector>
+#include <functional>
+
+class uv_device : public sensor_device {
+public:
+ uv_device();
+ virtual ~uv_device();
+
+ int get_poll_fd(void);
+ int get_sensors(const sensor_info_t **sensors);
+
+ bool enable(uint32_t id);
+ bool disable(uint32_t id);
+
+ bool set_interval(uint32_t id, unsigned long val);
+
+ int read_fd(uint32_t **ids);
+ int get_data(uint32_t id, sensor_data_t **data, int *length);
+
+private:
+ int m_node_handle;
+ int m_ultraviolet;
+ unsigned long m_polling_interval;
+ unsigned long long m_fired_time;
+ bool m_sensorhub_controlled;
+
+ int m_method;
+ std::string m_data_node;
+ std::string m_enable_node;
+ std::string m_interval_node;
+
+ std::function<bool (void)> update_value;
+
+ std::vector<uint32_t> event_ids;
+
+ bool update_value_input_event(void);
+
+ void raw_to_base(sensor_data_t *data);
+};
+#endif /* _UV_DEVICE_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <linux/input.h>
+#include <util.h>
+#include <sensor_log.h>
+#include <fstream>
+
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+using std::string;
+
+#define PREFIX_EVENT "event"
+
+static bool get_event_num(const string &input_path, string &event_num)
+{
+ const string event_prefix = PREFIX_EVENT;
+ DIR *dir = NULL;
+ struct dirent dir_entry;
+ struct dirent *result = NULL;
+ std::string node_name;
+ int error;
+ bool find = false;
+
+ dir = opendir(input_path.c_str());
+ if (!dir) {
+ ERR("Failed to open dir: %s", input_path.c_str());
+ return false;
+ }
+
+ int prefix_size = event_prefix.size();
+
+ while (true) {
+ error = readdir_r(dir, &dir_entry, &result);
+
+ if (error != 0)
+ continue;
+
+ if (result == NULL)
+ break;
+
+ node_name = std::string(dir_entry.d_name);
+
+ if (node_name.compare(0, prefix_size, event_prefix) != 0)
+ continue;
+
+ event_num = node_name.substr(prefix_size, node_name.size() - prefix_size);
+ find = true;
+ break;
+ }
+
+ closedir(dir);
+
+ return find;
+}
+
+static bool get_iio_node_info(const string& enable_node_name, const string& device_num, node_info &info)
+{
+ const string base_dir = string("/sys/bus/iio/devices/iio:device") + device_num + string("/");
+
+ info.data_node_path = string("/dev/iio:device") + device_num;
+ info.enable_node_path = base_dir + enable_node_name;
+ info.interval_node_path = base_dir + string("sampling_frequency");
+ info.buffer_enable_node_path = base_dir + string("buffer/enable");
+ info.buffer_length_node_path = base_dir + string("buffer/length");
+ info.trigger_node_path = base_dir + string("trigger/current_trigger");
+
+ return true;
+}
+
+static bool get_sensorhub_iio_node_info(const string &interval_node_name, const string& device_num, node_info &info)
+{
+ const string base_dir = string("/sys/bus/iio/devices/iio:device") + device_num + string("/");
+ const string hub_dir = "/sys/class/sensors/ssp_sensor/";
+
+ info.data_node_path = string("/dev/iio:device") + device_num;
+ info.enable_node_path = hub_dir + string("enable");
+ info.interval_node_path = hub_dir + interval_node_name;
+ info.buffer_enable_node_path = base_dir + string("buffer/enable");
+ info.buffer_length_node_path = base_dir + string("buffer/length");
+ return true;
+}
+
+static bool get_input_event_node_info(const string& device_num, node_info &info)
+{
+ string base_dir;
+ string event_num;
+
+ base_dir = string("/sys/class/input/input") + device_num + string("/");
+
+ if (!get_event_num(base_dir, event_num))
+ return false;
+
+ info.data_node_path = string("/dev/input/event") + event_num;
+
+ info.enable_node_path = base_dir + string("enable");
+ info.interval_node_path = base_dir + string("poll_delay");
+ return true;
+}
+
+static bool get_sensorhub_input_event_node_info(const string &interval_node_name, const string& device_num, node_info &info)
+{
+ const string base_dir = "/sys/class/sensors/ssp_sensor/";
+ string event_num;
+
+ string input_dir = string("/sys/class/input/input") + device_num + string("/");
+
+ if (!get_event_num(input_dir, event_num))
+ return false;
+
+ info.data_node_path = string("/dev/input/event") + event_num;
+ info.enable_node_path = base_dir + string("enable");
+ info.interval_node_path = base_dir + interval_node_name;
+ return true;
+}
+
+static bool get_node_value(const string &node_path, int &value)
+{
+ ifstream node(node_path, ifstream::binary);
+
+ if (!node)
+ return false;
+
+ node >> value;
+
+ return true;
+}
+
+static bool get_input_method(const string &key, int &method, string &device_num)
+{
+ input_method_info input_info[2] = {
+ {INPUT_EVENT_METHOD, "/sys/class/input/", "input"},
+ {IIO_METHOD, "/sys/bus/iio/devices/", "iio:device"}
+ };
+
+ const int input_info_len = sizeof(input_info)/sizeof(input_info[0]);
+ size_t prefix_size;
+ std::string name_node, name;
+ std::string d_name;
+ DIR *dir = NULL;
+ struct dirent dir_entry;
+ struct dirent *result = NULL;
+ int error;
+ bool find = false;
+
+ for (int i = 0; i < input_info_len; ++i) {
+
+ prefix_size = input_info[i].prefix.size();
+
+ dir = opendir(input_info[i].dir_path.c_str());
+ if (!dir) {
+ ERR("Failed to open dir: %s", input_info[i].dir_path.c_str());
+ return false;
+ }
+
+ find = false;
+
+ while (true) {
+ error = readdir_r(dir, &dir_entry, &result);
+
+ if (error != 0)
+ continue;
+
+ if (result == NULL)
+ break;
+
+ d_name = std::string(dir_entry.d_name);
+
+ if (d_name.compare(0, prefix_size, input_info[i].prefix) != 0)
+ continue;
+
+ name_node = input_info[i].dir_path + d_name + string("/name");
+
+ ifstream infile(name_node.c_str());
+ if (!infile)
+ continue;
+
+ infile >> name;
+
+ if (name != key)
+ continue;
+
+ device_num = d_name.substr(prefix_size, d_name.size() - prefix_size);
+ find = true;
+ method = input_info[i].method;
+ break;
+ }
+
+ closedir(dir);
+
+ if (find)
+ break;
+ }
+
+ return find;
+}
+
+bool util::set_monotonic_clock(int fd)
+{
+#ifdef EVIOCSCLOCKID
+ int clockId = CLOCK_MONOTONIC;
+ if (ioctl(fd, EVIOCSCLOCKID, &clockId) != 0) {
+ _E("Fail to set monotonic timestamp for fd[%d]", fd);
+ return false;
+ }
+#endif
+ return true;
+}
+
+bool util::set_enable_node(const string &node_path, bool sensorhub_controlled, bool enable, int enable_bit)
+{
+ int prev_status, status;
+
+ if (!get_node_value(node_path, prev_status)) {
+ ERR("Failed to get node: %s", node_path.c_str());
+ return false;
+ }
+
+ int _enable_bit = sensorhub_controlled ? enable_bit : 0;
+
+ if (enable)
+ status = prev_status | (1 << _enable_bit);
+ else
+ status = prev_status & (~(1 << _enable_bit));
+
+ if (!set_node_value(node_path, status)) {
+ ERR("Failed to set node: %s", node_path.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+unsigned long long util::get_timestamp(void)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return ((unsigned long long)(t.tv_sec)*1000000000LL + t.tv_nsec) / 1000;
+}
+
+unsigned long long util::get_timestamp(timeval *t)
+{
+ if (!t) {
+ ERR("t is NULL");
+ return 0;
+ }
+
+ return ((unsigned long long)(t->tv_sec)*1000000LL +t->tv_usec);
+}
+
+bool util::is_sensorhub_controlled(const string &key)
+{
+ string key_node = string("/sys/class/sensors/ssp_sensor/") + key;
+
+ if (access(key_node.c_str(), F_OK) == 0)
+ return true;
+
+ return false;
+}
+
+bool util::get_node_info(const node_info_query &query, node_info &info)
+{
+ int method;
+ string device_num;
+
+ if (!get_input_method(query.key, method, device_num)) {
+ ERR("Failed to get input method for %s", query.key.c_str());
+ return false;
+ }
+
+ info.method = method;
+
+ if (method == IIO_METHOD) {
+ if (query.sensorhub_controlled)
+ return get_sensorhub_iio_node_info(query.sensorhub_interval_node_name, device_num, info);
+ else
+ return get_iio_node_info(query.iio_enable_node_name, device_num, info);
+ } else {
+ if (query.sensorhub_controlled)
+ return get_sensorhub_input_event_node_info(query.sensorhub_interval_node_name, device_num, info);
+ else
+ return get_input_event_node_info(device_num, info);
+ }
+}
+
+void util::show_node_info(node_info &info)
+{
+ if (info.data_node_path.size())
+ INFO("Data node: %s", info.data_node_path.c_str());
+ if (info.enable_node_path.size())
+ INFO("Enable node: %s", info.enable_node_path.c_str());
+ if (info.interval_node_path.size())
+ INFO("Interval node: %s", info.interval_node_path.c_str());
+ if (info.buffer_enable_node_path.size())
+ INFO("Buffer enable node: %s", info.buffer_enable_node_path.c_str());
+ if (info.buffer_length_node_path.size())
+ INFO("Buffer length node: %s", info.buffer_length_node_path.c_str());
+ if (info.trigger_node_path.size())
+ INFO("Trigger node: %s", info.trigger_node_path.c_str());
+}
+
+bool util::set_node_value(const string &node_path, int value)
+{
+ ofstream node(node_path, ofstream::binary);
+
+ if (!node)
+ return false;
+
+ node << value;
+
+ return true;
+}
+
+bool util::set_node_value(const string &node_path, unsigned long long value)
+{
+ ofstream node(node_path, ofstream::binary);
+
+ if (!node)
+ return false;
+
+ node << value;
+
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _SENSOR_UTIL_H_
+#define _SENSOR_UTIL_H_
+
+#include <sys/time.h>
+#include <string>
+
+typedef struct {
+ int method;
+ std::string data_node_path;
+ std::string enable_node_path;
+ std::string interval_node_path;
+ std::string buffer_enable_node_path;
+ std::string buffer_length_node_path;
+ std::string trigger_node_path;
+} node_info;
+
+typedef struct {
+ bool sensorhub_controlled;
+ std::string sensor_type;
+ std::string key;
+ std::string iio_enable_node_name;
+ std::string sensorhub_interval_node_name;
+} node_info_query;
+
+enum input_method {
+ IIO_METHOD = 0,
+ INPUT_EVENT_METHOD = 1,
+};
+
+typedef struct {
+ int method;
+ std::string dir_path;
+ std::string prefix;
+} input_method_info;
+
+namespace util {
+ bool set_monotonic_clock(int fd);
+
+ bool set_enable_node(const std::string &node_path, bool sensorhub_controlled, bool enable, int enable_bit = 0);
+
+ unsigned long long get_timestamp(void);
+ unsigned long long get_timestamp(timeval *t);
+
+ bool is_sensorhub_controlled(const std::string &key);
+ bool get_node_info(const node_info_query &query, node_info &info);
+ void show_node_info(node_info &info);
+ bool set_node_value(const std::string &node_path, int value);
+ bool set_node_value(const std::string &node_path, unsigned long long value);
+}
+#endif /*_SENSOR_UTIL_H_*/