From cc08745d7270645228a2b5e786d347885a7c7c1c Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 11 May 2016 17:21:00 +0900 Subject: [PATCH] sensor-hal-emul: initial commit for emulator sensor HAL Change-Id: I0786cff7c9c8427ef0c974906b0685b439cd03d1 Signed-off-by: kibak.yoon --- CMakeLists.txt | 161 +++++++ LICENSE.APLv2 | 203 +++++++++ packaging/sensor-hal-emul.manifest | 5 + packaging/sensor-hal-emul.spec | 47 ++ sensor.xml.in | 615 +++++++++++++++++++++++++++ src/accel/accel_device.cpp | 397 +++++++++++++++++ src/accel/accel_device.h | 72 ++++ src/create.cpp | 113 +++++ src/geomag/geomag_device.cpp | 402 +++++++++++++++++ src/geomag/geomag_device.h | 79 ++++ src/gyro/gyro_device.cpp | 387 +++++++++++++++++ src/gyro/gyro_device.h | 71 ++++ src/gyro_uncal/gyro_uncal_device.cpp | 367 ++++++++++++++++ src/gyro_uncal/gyro_uncal_device.h | 76 ++++ src/hrm/hrm_device.cpp | 305 +++++++++++++ src/hrm/hrm_device.h | 71 ++++ src/hrm_raw/hrm_raw_data_reader.cpp | 47 ++ src/hrm_raw/hrm_raw_data_reader.h | 34 ++ src/hrm_raw/hrm_raw_data_reader_standard.cpp | 78 ++++ src/hrm_raw/hrm_raw_data_reader_standard.h | 29 ++ src/hrm_raw/hrm_raw_device.cpp | 308 ++++++++++++++ src/hrm_raw/hrm_raw_device.h | 69 +++ src/light/light_device.cpp | 345 +++++++++++++++ src/light/light_device.h | 66 +++ src/macro.h | 25 ++ src/pressure/pressure_device.cpp | 372 ++++++++++++++++ src/pressure/pressure_device.h | 77 ++++ src/proxi/proxi_device.cpp | 229 ++++++++++ src/proxi/proxi_device.h | 67 +++ src/sensor_common.h | 56 +++ src/sensor_config.cpp | 317 ++++++++++++++ src/sensor_config.h | 103 +++++ src/sensor_log.h | 122 ++++++ src/ultraviolet/uv_device.cpp | 304 +++++++++++++ src/ultraviolet/uv_device.h | 69 +++ src/util.cpp | 395 +++++++++++++++++ src/util.h | 68 +++ 37 files changed, 6551 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE.APLv2 create mode 100644 packaging/sensor-hal-emul.manifest create mode 100644 packaging/sensor-hal-emul.spec create mode 100644 sensor.xml.in create mode 100644 src/accel/accel_device.cpp create mode 100644 src/accel/accel_device.h create mode 100644 src/create.cpp create mode 100644 src/geomag/geomag_device.cpp create mode 100644 src/geomag/geomag_device.h create mode 100644 src/gyro/gyro_device.cpp create mode 100644 src/gyro/gyro_device.h create mode 100644 src/gyro_uncal/gyro_uncal_device.cpp create mode 100644 src/gyro_uncal/gyro_uncal_device.h create mode 100644 src/hrm/hrm_device.cpp create mode 100644 src/hrm/hrm_device.h create mode 100644 src/hrm_raw/hrm_raw_data_reader.cpp create mode 100644 src/hrm_raw/hrm_raw_data_reader.h create mode 100644 src/hrm_raw/hrm_raw_data_reader_standard.cpp create mode 100644 src/hrm_raw/hrm_raw_data_reader_standard.h create mode 100644 src/hrm_raw/hrm_raw_device.cpp create mode 100644 src/hrm_raw/hrm_raw_device.h create mode 100644 src/light/light_device.cpp create mode 100644 src/light/light_device.h create mode 100644 src/macro.h create mode 100644 src/pressure/pressure_device.cpp create mode 100644 src/pressure/pressure_device.h create mode 100644 src/proxi/proxi_device.cpp create mode 100644 src/proxi/proxi_device.h create mode 100644 src/sensor_common.h create mode 100644 src/sensor_config.cpp create mode 100644 src/sensor_config.h create mode 100644 src/sensor_log.h create mode 100644 src/ultraviolet/uv_device.cpp create mode 100644 src/ultraviolet/uv_device.h create mode 100644 src/util.cpp create mode 100644 src/util.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5d31095 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,161 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(sensor-hal-emul CXX) +INCLUDE(GNUInstallDirs) + +SET(ACCEL "ON") +SET(GYRO "ON") +SET(GYRO_UNCAL "OFF") +SET(PROXIMITY "ON") +SET(LIGHT "ON") +SET(GEOMAG "ON") +SET(GEOMAG_UNCAL "OFF") +SET(HRM_RAW "OFF") +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 glib-2.0 gio-2.0 gobject-2.0 vconf libxml-2.0) + +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("${ULTRAVIOLET}" STREQUAL "ON") +FILE(GLOB_RECURSE SRCS ${SRCS} src/ultraviolet/*.cpp) +ADD_DEFINITIONS(-DENABLE_UV) +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}) + +CONFIGURE_FILE(sensor.xml.in sensor.xml @ONLY) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.APLv2 DESTINATION share/license RENAME ${PROJECT_NAME}) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/sensor) +INSTALL(FILES sensor.xml DESTINATION etc) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..6b17abb --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,203 @@ +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. diff --git a/packaging/sensor-hal-emul.manifest b/packaging/sensor-hal-emul.manifest new file mode 100644 index 0000000..75b0fa5 --- /dev/null +++ b/packaging/sensor-hal-emul.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/sensor-hal-emul.spec b/packaging/sensor-hal-emul.spec new file mode 100644 index 0000000..93552a7 --- /dev/null +++ b/packaging/sensor-hal-emul.spec @@ -0,0 +1,47 @@ +Name: sensor-hal-emul +Summary: Emulator Sensor HAL +Version: 1.0.0 +Release: 0 +Group: Service/Sensor +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz + +ExcludeArch: %{arm} aarch64 + +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(libxml-2.0) +BuildRequires: pkgconfig(vconf) +BuildRequires: sensor-hal-devel + +%description +Emulator 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 + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%attr(0644,root,root)/usr/etc/sensor.xml +%manifest packaging/%{name}.manifest +%{_libdir}/sensor/*.so +%{_datadir}/license/sensor-hal-emul diff --git a/sensor.xml.in b/sensor.xml.in new file mode 100644 index 0000000..47230d7 --- /dev/null +++ b/sensor.xml.in @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/accel/accel_device.cpp b/src/accel/accel_device.cpp new file mode 100644 index 0000000..e1229af --- /dev/null +++ b/src/accel/accel_device.cpp @@ -0,0 +1,397 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "accel_device.h" + +#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) + +#define MODEL_NAME "UNKNOWN" +#define VENDOR "UNKNOWN" +#define RESOLUTION 0 +#define RAW_DATA_UNIT 0 +#define MIN_INTERVAL 0 +#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" + +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; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_ACCEL, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + } + + 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; + + if (!config.get(SENSOR_TYPE_ACCEL, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_ACCEL, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + long resolution; + + if (!config.get(SENSOR_TYPE_ACCEL, m_model_id, ELEMENT_RESOLUTION, resolution)) { + _E("[RESOLUTION] is empty"); + throw ENXIO; + } + + m_resolution = (int)resolution; + + _I("m_resolution = %d",m_resolution); + + double raw_data_unit; + + if (!config.get(SENSOR_TYPE_ACCEL, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) { + _E("[RAW_DATA_UNIT] is empty"); + throw ENXIO; + } + + m_raw_data_unit = (float)(raw_data_unit); + _I("m_raw_data_unit = %f", m_raw_data_unit); + + 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, 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("accel_sensor is created!"); +} + +accel_device::~accel_device() +{ + close(m_node_handle); + m_node_handle = -1; + + _I("accel_sensor is destroyed!"); +} + +int accel_device::get_poll_fd() +{ + return m_node_handle; +} + +int accel_device::get_sensors(const sensor_info_t **sensors) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + sensor_info.min_range = MIN_RANGE(m_resolution) * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(m_raw_data_unit); + sensor_info.max_range = MAX_RANGE(m_resolution) * RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(m_raw_data_unit); + sensor_info.resolution = RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(m_raw_data_unit); + sensor_info.min_interval = 1; + sensor_info.max_batch_count = 0; + *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 = 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) +{ + int remains = 1; + 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 --remains; +} + +void accel_device::raw_to_base(sensor_data_t *data) +{ + data->value_count = 3; + data->values[0] = RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(data->values[0] * m_raw_data_unit); + data->values[1] = RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(data->values[1] * m_raw_data_unit); + data->values[2] = RAW_DATA_TO_METRE_PER_SECOND_SQUARED_UNIT(data->values[2] * m_raw_data_unit); +} diff --git a/src/accel/accel_device.h b/src/accel/accel_device.h new file mode 100644 index 0000000..da406d2 --- /dev/null +++ b/src/accel/accel_device.h @@ -0,0 +1,72 @@ +/* + * 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 +#include +#include +#include + +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::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + int m_resolution; + float m_raw_data_unit; + + std::function update_value; + + std::vector 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_ */ diff --git a/src/create.cpp b/src/create.cpp new file mode 100644 index 0000000..db4f176 --- /dev/null +++ b/src/create.cpp @@ -0,0 +1,113 @@ +/* + * 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 +#include +#include + +#ifdef ENABLE_ACCEL +#include "accel/accel_device.h" +#endif +#ifdef ENABLE_GYRO +#include "gyro/gyro_device.h" +#endif +#ifdef ENABLE_GYRO_UNCAL +#include "gyro_uncal/gyro_uncal_device.h" +#endif +#ifdef ENABLE_GEOMAG +#include "geomag/geomag_device.h" +#endif +#ifdef ENABLE_PRESSURE +#include "pressure/pressure_device.h" +#endif +#ifdef ENABLE_UV +#include "ultraviolet/uv_device.h" +#endif +#ifdef ENABLE_LIGHT +#include "light/light_device.h" +#endif +#ifdef ENABLE_PROXIMITY +#include "proxi/proxi_device.h" +#endif +#ifdef ENABLE_HRM_RAW +#include "hrm_raw/hrm_raw_device.h" +#endif +#ifdef ENABLE_HRM +#include "hrm/hrm_device.h" +#endif +#ifdef ENABLE_SENSORHUB +#include "sensorhub/sensorhub.h" +#endif + +static std::vector devs; + +template +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) +{ +#ifdef ENABLE_ACCEL + create_sensor("Accelerometer"); +#endif +#ifdef ENABLE_GYRO + create_sensor("Gyroscope"); +#endif +#ifdef ENABLE_GYRO_UNCAL + create_sensor("Gyroscope Uncal"); +#endif +#ifdef ENABLE_GEOMAG + create_sensor("Geomagnetic"); +#endif +#ifdef ENABLE_PRESSURE + create_sensor("Pressure"); +#endif +#ifdef ENABLE_UV + create_sensor("Ultra Violet"); +#endif +#ifdef ENABLE_LIGHT + create_sensor("Light"); +#endif +#ifdef ENABLE_PROXIMITY + create_sensor("Proximity"); +#endif +#ifdef ENABLE_HRM_RAW + create_sensor("HRM Raw"); +#endif +#ifdef ENABLE_HRM + create_sensor("HRM"); +#endif +#ifdef ENABLE_SENSORHUB + create_sensor("Sensorhub"); +#endif + + *devices = &devs[0]; + return devs.size(); +} diff --git a/src/geomag/geomag_device.cpp b/src/geomag/geomag_device.cpp new file mode 100644 index 0000000..c4a562a --- /dev/null +++ b/src/geomag/geomag_device.cpp @@ -0,0 +1,402 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "geomag_device.h" + +#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: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 0, + resolution: 0, + min_interval: 0, + 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; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_MAGNETIC, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + + } + + 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; + + if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty\n"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty\n"); + throw ENXIO; + } + + _I("m_chip_name = %s\n",m_chip_name.c_str()); + + double min_range; + + if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_MIN_RANGE, min_range)) { + _E("[MIN_RANGE] is empty\n"); + throw ENXIO; + } + + m_min_range = (float)min_range; + _I("m_min_range = %f\n",m_min_range); + + double max_range; + + if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_MAX_RANGE, max_range)) { + _E("[MAX_RANGE] is empty\n"); + throw ENXIO; + } + + m_max_range = (float)max_range; + _I("m_max_range = %f\n",m_max_range); + + double raw_data_unit; + + if (!config.get(SENSOR_TYPE_MAGNETIC, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) { + _E("[RAW_DATA_UNIT] is empty\n"); + throw ENXIO; + } + + m_raw_data_unit = (float)(raw_data_unit); + _I("m_raw_data_unit = %f\n", m_raw_data_unit); + + m_node_handle = open(m_data_node.c_str(), O_RDONLY); + + if (m_node_handle < 0) { + _ERRNO(errno, _E, "geomag handle open fail for geomag 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(); + }; + } 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!\n"); +} + +geomag_device::~geomag_device() +{ + close(m_node_handle); + m_node_handle = -1; + + _I("geomag_sensor is destroyed!\n"); +} + +int geomag_device::get_poll_fd(void) +{ + return m_node_handle; +} + +int geomag_device::get_sensors(const sensor_info_t **sensors) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + sensor_info.min_range = m_min_range; + sensor_info.max_range = m_max_range; + sensor_info.resolution = m_raw_data_unit; + sensor_info.min_interval = 1; + sensor_info.max_batch_count = 0; + *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; + INFO("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); + + INFO("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; + } + + INFO("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; + int16_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 = data.timestamp; + + _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; +} + +int geomag_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 geomag_device::get_data(uint32_t id, sensor_data_t **data, int *length) +{ + int remains = 1; + 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 --remains; +} + +void geomag_device::raw_to_base(sensor_data_t *data) +{ + data->values[0] = data->values[0] * m_raw_data_unit; + data->values[1] = data->values[1] * m_raw_data_unit; + data->values[2] = data->values[2] * m_raw_data_unit; +} diff --git a/src/geomag/geomag_device.h b/src/geomag/geomag_device.h new file mode 100644 index 0000000..70d4d9a --- /dev/null +++ b/src/geomag/geomag_device.h @@ -0,0 +1,79 @@ +/* + * 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 +#include +#include +#include + +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::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + int m_resolution; + float m_min_range; + float m_max_range; + float m_raw_data_unit; + + long a_x; + long a_y; + long a_z; + + std::function update_value; + + std::vector 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_*/ diff --git a/src/gyro/gyro_device.cpp b/src/gyro/gyro_device.cpp new file mode 100644 index 0000000..d8146ab --- /dev/null +++ b/src/gyro/gyro_device.cpp @@ -0,0 +1,387 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "gyro_device.h" + +#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) + +#define SENSOR_NAME "SENSOR_GYROSCOPE" +#define SENSOR_TYPE_GYRO "GYRO" + +#define INPUT_NAME "gyro_sensor" +#define GYRO_SENSORHUB_POLL_NODE_NAME "gyro_poll_delay" + +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: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 0, + resolution: 0, + min_interval: 0, + max_batch_count: 0, + 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; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_GYRO, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + } + + 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; + + if (!config.get(SENSOR_TYPE_GYRO, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_GYRO, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + long resolution; + + if (!config.get(SENSOR_TYPE_GYRO, m_model_id, ELEMENT_RESOLUTION, resolution)) { + _E("[RESOLUTION] is empty"); + throw ENXIO; + } + + m_resolution = (int)resolution; + _I("m_resolution = %d",m_resolution); + + double raw_data_unit; + + if (!config.get(SENSOR_TYPE_GYRO, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) { + _E("[RAW_DATA_UNIT] is empty"); + throw ENXIO; + } + + m_raw_data_unit = (float)(raw_data_unit); + _I("m_raw_data_unit = %f", m_raw_data_unit); + + m_node_handle = open(m_data_node.c_str(), O_RDONLY); + + if (m_node_handle < 0) { + _ERRNO(errno, _E, "gyro handle open fail for gyro 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(); + }; + } 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("RAW_DATA_TO_DPS_UNIT(m_raw_data_unit) = [%f]",RAW_DATA_TO_DPS_UNIT(m_raw_data_unit)); + _I("gyro_sensor is created!"); +} + +gyro_device::~gyro_device() +{ + close(m_node_handle); + m_node_handle = -1; + + _I("gyro_sensor is destroyed!"); +} + +int gyro_device::get_poll_fd(void) +{ + return m_node_handle; +} + +int gyro_device::get_sensors(const sensor_info_t **sensors) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + sensor_info.min_range = MIN_RANGE(m_resolution) * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + sensor_info.max_range = MAX_RANGE(m_resolution) * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + sensor_info.resolution = RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + sensor_info.min_interval = 1; + sensor_info.max_batch_count = 0; + *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 { + 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 = 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) +{ + int remains = 1; + 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 --remains; +} + +void gyro_device::raw_to_base(sensor_data_t *data) +{ + data->value_count = 3; + data->values[0] = data->values[0] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + data->values[1] = data->values[1] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + data->values[2] = data->values[2] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); +} diff --git a/src/gyro/gyro_device.h b/src/gyro/gyro_device.h new file mode 100644 index 0000000..69a5169 --- /dev/null +++ b/src/gyro/gyro_device.h @@ -0,0 +1,71 @@ +/* + * 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 +#include +#include +#include + +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::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + int m_resolution; + float m_raw_data_unit; + + std::function update_value; + + std::vector 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_ */ diff --git a/src/gyro_uncal/gyro_uncal_device.cpp b/src/gyro_uncal/gyro_uncal_device.cpp new file mode 100644 index 0000000..7564714 --- /dev/null +++ b/src/gyro_uncal/gyro_uncal_device.cpp @@ -0,0 +1,367 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "gyro_uncal_device.h" + +#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) + +#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" + +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: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 0, + resolution: 0, + min_interval: 0, + max_batch_count: 0, + 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; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_GYRO_UNCAL, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + } + + 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; + + if (!config.get(SENSOR_TYPE_GYRO_UNCAL, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_GYRO_UNCAL, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + long resolution; + + if (!config.get(SENSOR_TYPE_GYRO_UNCAL, m_model_id, ELEMENT_RESOLUTION, resolution)) { + _E("[RESOLUTION] is empty"); + throw ENXIO; + } + + m_resolution = (int)resolution; + _I("m_resolution = %d",m_resolution); + + double raw_data_unit; + + if (!config.get(SENSOR_TYPE_GYRO_UNCAL, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) { + _E("[RAW_DATA_UNIT] is empty"); + throw ENXIO; + } + + m_raw_data_unit = (float)(raw_data_unit); + _I("m_raw_data_unit = %f",m_raw_data_unit); + + double min_range; + + if (!config.get(SENSOR_TYPE_GYRO_UNCAL, m_model_id, ELEMENT_MIN_RANGE, min_range)) + min_range = MIN_RANGE(m_resolution)* RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + + m_min_range = (float)min_range; + _I("m_min_range = %f",m_min_range); + + double max_range; + + if (!config.get(SENSOR_TYPE_GYRO_UNCAL, m_model_id, ELEMENT_MAX_RANGE, max_range)) + max_range = MAX_RANGE(m_resolution)* RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + + m_max_range = (float)max_range; + _I("m_max_range = %f",m_max_range); + + 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("RAW_DATA_TO_DPS_UNIT(m_raw_data_unit) = [%f]",RAW_DATA_TO_DPS_UNIT(m_raw_data_unit)); + _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) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + sensor_info.min_range = MIN_RANGE(m_resolution) * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + sensor_info.max_range = MAX_RANGE(m_resolution) * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + sensor_info.resolution = RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + sensor_info.min_interval = 1; + sensor_info.max_batch_count = 0; + *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; + INFO("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); + + INFO("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) +{ + int remains = 1; + 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 --remains; +} + +void gyro_uncal_device::raw_to_base(sensor_data_t *data) +{ + data->values[0] = data->values[0] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + data->values[1] = data->values[1] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + data->values[2] = data->values[2] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + data->values[3] = data->values[3] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + data->values[4] = data->values[4] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); + data->values[5] = data->values[5] * RAW_DATA_TO_DPS_UNIT(m_raw_data_unit); +} diff --git a/src/gyro_uncal/gyro_uncal_device.h b/src/gyro_uncal/gyro_uncal_device.h new file mode 100644 index 0000000..66a8a4e --- /dev/null +++ b/src/gyro_uncal/gyro_uncal_device.h @@ -0,0 +1,76 @@ +/* + * 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 +#include +#include +#include + +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::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + int m_resolution; + float m_raw_data_unit; + float m_min_range; + float m_max_range; + + std::function update_value; + + std::vector event_ids; + + bool update_value_input_event(void); + + void raw_to_base(sensor_data_t *data); +}; +#endif /* _GYRO_UNCAL_DEVICE_H_ */ diff --git a/src/hrm/hrm_device.cpp b/src/hrm/hrm_device.cpp new file mode 100644 index 0000000..a04c209 --- /dev/null +++ b/src/hrm/hrm_device.cpp @@ -0,0 +1,305 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "hrm_device.h" + +#define SENSOR_NAME "SENSOR_HRM" +#define SENSOR_TYPE_HRM "HRM" + +#define INPUT_NAME "hrm_lib_sensor" +#define HRM_SENSORHUB_POLL_NODE_NAME "hrm_poll_delay" + +#define DEFAULT_RAW_DATA_UNIT 1 + +static sensor_info_t sensor_info = { + id: 0x1, + name: SENSOR_NAME, + type: SENSOR_DEVICE_HRM, + event_type: (SENSOR_DEVICE_HRM << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT, + model_name: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 1, + resolution: 1, + min_interval: 1, + max_batch_count: 0, + wakeup_supported: false +}; + +hrm_device::hrm_device() +: m_node_handle(-1) +, m_hr(0) +, m_spo2(0) +, m_peek_to_peek(0) +, m_snr(0.0f) +, m_raw_data_unit(DEFAULT_RAW_DATA_UNIT) +, m_polling_interval(1000) +, m_fired_time(0) +, m_interval_supported(false) +, m_sensorhub_controlled(false) +{ + double raw_data_unit = DEFAULT_RAW_DATA_UNIT; + + const std::string sensorhub_interval_node_name = HRM_SENSORHUB_POLL_NODE_NAME; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_HRM, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + } + + query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name); + query.sensor_type = SENSOR_TYPE_HRM; + query.key = INPUT_NAME; + query.iio_enable_node_name = "hrm_lib_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; + + if (access(m_interval_node.c_str(), F_OK) == 0) + m_interval_supported = true; + + if (!config.get(SENSOR_TYPE_HRM, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_HRM, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + if (!config.get(SENSOR_TYPE_HRM, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) { + _I("[RAW_DATA_UNIT] is empty"); + } + + m_raw_data_unit = (float)(raw_data_unit); + _I("m_raw_data_unit = %f", m_raw_data_unit); + + m_node_handle = open(m_data_node.c_str(), O_RDONLY); + + if (m_node_handle < 0) { + _ERRNO(errno, _E, "Failed to open HRM 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("hrm_device is created!"); +} + +hrm_device::~hrm_device() +{ + close(m_node_handle); + m_node_handle = -1; + + _I("hrm_device is destroyed!"); +} + +int hrm_device::get_poll_fd(void) +{ + return m_node_handle; +} + +int hrm_device::get_sensors(const sensor_info_t **sensors) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + *sensors = &sensor_info; + + return 1; +} + +bool hrm_device::enable(uint32_t id) +{ + util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_HRM_LIB_ENABLE_BIT); + if (m_interval_supported) + set_interval(id, m_polling_interval); + + m_fired_time = 0; + _I("Enable HRM sensor"); + return true; +} + +bool hrm_device::disable(uint32_t id) +{ + util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_HRM_LIB_ENABLE_BIT); + + _I("Disable HRM sensor"); + return true; +} + +bool hrm_device::set_interval(uint32_t id, unsigned long val) +{ + unsigned long long polling_interval_ns; + + if (!m_interval_supported) + return true; + + 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 hrm_device::update_value_input_event(void) +{ + const float SNR_SIG_FIGS = 10000.0f; + const int HR_MAX = 300; + int hrm_raw[4] = {0,}; + unsigned long long fired_time = 0; + int read_input_cnt = 0; + const int INPUT_MAX_BEFORE_SYN = 10; + bool syn = false; + + struct input_event hrm_input; + _D("hrm event detection!"); + + while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) { + int len = read(m_node_handle, &hrm_input, sizeof(hrm_input)); + if (len != sizeof(hrm_input)) { + _E("hrm_file read fail, read_len = %d", len); + return false; + } + + ++read_input_cnt; + + if (hrm_input.type == EV_REL) { + switch (hrm_input.code) { + case REL_X: + hrm_raw[0] = (int)hrm_input.value - 1; + break; + case REL_Y: + hrm_raw[1] = (int)hrm_input.value - 1; + break; + case REL_Z: + hrm_raw[2] = (int)hrm_input.value - 1; + break; + default: + _E("hrm_input event[type = %d, code = %d] is unknown.", hrm_input.type, hrm_input.code); + return false; + break; + } + } else if (hrm_input.type == EV_SYN) { + syn = true; + fired_time = util::get_timestamp(&hrm_input.time); + } else { + _E("hrm_input event[type = %d, code = %d] is unknown.", hrm_input.type, hrm_input.code); + return false; + } + } + + if ((hrm_raw[0] * m_raw_data_unit) > HR_MAX) { + _E("Drop abnormal HR: %d", hrm_raw[0]); + return false; + } + + m_hr = hrm_raw[0]; + m_peek_to_peek = hrm_raw[1]; + m_snr = ((float)hrm_raw[2] / SNR_SIG_FIGS); + m_spo2 = 0; + m_fired_time = fired_time; + + return true; +} + +int hrm_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 hrm_device::get_data(uint32_t id, sensor_data_t **data, int *length) +{ + int remains = 1; + 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 = 4; + sensor_data->values[0] = m_hr; + sensor_data->values[1] = m_spo2; + sensor_data->values[2] = m_peek_to_peek; + sensor_data->values[3] = m_snr; + + raw_to_base(sensor_data); + + *data = sensor_data; + *length = sizeof(sensor_data_t); + + return --remains; +} + +void hrm_device::raw_to_base(sensor_data_t *data) +{ + data->values[0] = data->values[0] * m_raw_data_unit; +} diff --git a/src/hrm/hrm_device.h b/src/hrm/hrm_device.h new file mode 100644 index 0000000..324924b --- /dev/null +++ b/src/hrm/hrm_device.h @@ -0,0 +1,71 @@ +/* + * 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 _HRM_DEVICE_H_ +#define _HRM_DEVICE_H_ + +#include +#include +#include +#include + +class hrm_device : public sensor_device { +public: + hrm_device(); + virtual ~hrm_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_hr; + int m_spo2; + int m_peek_to_peek; + float m_snr; + float m_raw_data_unit; + unsigned long m_polling_interval; + unsigned long long m_fired_time; + bool m_interval_supported; + bool m_sensorhub_controlled; + + int m_method; + std::string m_data_node; + std::string m_enable_node; + std::string m_interval_node; + + std::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + std::function update_value; + + std::vector event_ids; + + bool update_value_input_event(void); + + void raw_to_base(sensor_data_t *data); +}; +#endif /*_HRM_DEVICE_H_*/ diff --git a/src/hrm_raw/hrm_raw_data_reader.cpp b/src/hrm_raw/hrm_raw_data_reader.cpp new file mode 100644 index 0000000..3bb0682 --- /dev/null +++ b/src/hrm_raw/hrm_raw_data_reader.cpp @@ -0,0 +1,47 @@ +/* + * 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 +#include "hrm_raw_data_reader.h" + +hrm_raw_data_reader::hrm_raw_data_reader() +{ +} +hrm_raw_data_reader::~hrm_raw_data_reader() +{ +} + +bool hrm_raw_data_reader::open(void) +{ + return true; +} + +bool hrm_raw_data_reader::close(void) +{ + return true; +} + + +bool hrm_raw_data_reader::start(void) +{ + return true; +} + +bool hrm_raw_data_reader::stop(void) +{ + return true; +} diff --git a/src/hrm_raw/hrm_raw_data_reader.h b/src/hrm_raw/hrm_raw_data_reader.h new file mode 100644 index 0000000..d515783 --- /dev/null +++ b/src/hrm_raw/hrm_raw_data_reader.h @@ -0,0 +1,34 @@ +/* + * 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 _HRM_RAW_DATA_READER_H_ +#define _HRM_RAW_DATA_READER_H_ + +#include +#include + +class hrm_raw_data_reader { +public: + hrm_raw_data_reader(); + virtual ~hrm_raw_data_reader(); + + virtual bool open(void); + virtual bool close(void); + virtual bool start(void); + virtual bool stop(void); + virtual bool get_data(int handle, sensor_data_t &data) = 0; +}; +#endif /* _HRM_RAW_DATA_READER_ */ diff --git a/src/hrm_raw/hrm_raw_data_reader_standard.cpp b/src/hrm_raw/hrm_raw_data_reader_standard.cpp new file mode 100644 index 0000000..205579e --- /dev/null +++ b/src/hrm_raw/hrm_raw_data_reader_standard.cpp @@ -0,0 +1,78 @@ +/* + * 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 +#include +#include +#include +#include +#include "hrm_raw_data_reader_standard.h" + +#define INPUT_MAX_BEFORE_SYN 20 +#define INPUT_EVENT_BIAS 1 +#define INPUT_VALUE_COUNT 10 + +hrm_raw_data_reader_standard::hrm_raw_data_reader_standard() +{ +} + +hrm_raw_data_reader_standard::~hrm_raw_data_reader_standard() +{ +} + +bool hrm_raw_data_reader_standard::get_data(int handle, sensor_data_t &data) +{ + bool syn = false; + int read_input_cnt = 0; + int index = 0; + struct input_event hrm_raw_input; + + while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) { + int len = read(handle, &hrm_raw_input, sizeof(hrm_raw_input)); + if (len != sizeof(hrm_raw_input)) { + _E("hrm_raw_file read fail, read_len = %d", len); + return false; + } + + ++read_input_cnt; + + if (hrm_raw_input.type == EV_REL) { + index = hrm_raw_input.code - REL_X; + + /* Check an avaiable value REL_X(0x00) ~ REL_MISC(0x09) */ + if (index >= INPUT_VALUE_COUNT) { + _E("hrm_raw_input event[type = %d, code = %d] is unknown.", hrm_raw_input.type, index); + return false; + } + data.values[index] = (unsigned int)hrm_raw_input.value - INPUT_EVENT_BIAS; + + } else if (hrm_raw_input.type == EV_SYN) { + syn = true; + data.timestamp = util::get_timestamp(&hrm_raw_input.time); + data.value_count = INPUT_VALUE_COUNT; + } else { + _E("hrm_raw_input event[type = %d, code = %d] is unknown.", hrm_raw_input.type, hrm_raw_input.code); + return false; + } + } + + if (!syn) { + _E("EV_SYN didn't come until %d inputs had come", read_input_cnt); + return false; + } + return true; +} diff --git a/src/hrm_raw/hrm_raw_data_reader_standard.h b/src/hrm_raw/hrm_raw_data_reader_standard.h new file mode 100644 index 0000000..caa556a --- /dev/null +++ b/src/hrm_raw/hrm_raw_data_reader_standard.h @@ -0,0 +1,29 @@ +/* + * 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 "hrm_raw_data_reader.h" + +#ifndef _HRM_RAW_DATA_READER_STANDARD_H_ +#define _HRM_RAW_DATA_READER_STANDARD_H_ + +class hrm_raw_data_reader_standard : public hrm_raw_data_reader { +public: + hrm_raw_data_reader_standard(); + ~hrm_raw_data_reader_standard(); + + virtual bool get_data(int handle, sensor_data_t &data); +}; +#endif /* _HRM_RAW_DATA_READER_STANDARD_H_ */ diff --git a/src/hrm_raw/hrm_raw_device.cpp b/src/hrm_raw/hrm_raw_device.cpp new file mode 100644 index 0000000..6f1d47f --- /dev/null +++ b/src/hrm_raw/hrm_raw_device.cpp @@ -0,0 +1,308 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "hrm_raw_data_reader_standard.h" +#include "hrm_raw_device.h" + +#define SENSOR_NAME "SENSOR_HRM_RAW" +#define SENSOR_TYPE_HRM_RAW "HRM_RAW" + +#define INPUT_NAME "hrm_raw_sensor" +#define HRM_SENSORHUB_POLL_NODE_NAME "hrm_poll_delay" + +#define INDEX_HRM_RAW 0x1 +#define INDEX_HRM_LED_GREEN 0x2 + +#define ELEMENT_READER "READER" +#define POLL_1HZ_MS 1000 + +static sensor_info_t sensor_info[] = { + { + id: INDEX_HRM_RAW, + name: SENSOR_NAME, + type: SENSOR_DEVICE_HRM_RAW, + event_type: (SENSOR_DEVICE_HRM_RAW << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT, + model_name: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 1, + resolution: 1, + min_interval: 1, + max_batch_count: 0, + wakeup_supported: false + }, + { + id: INDEX_HRM_LED_GREEN, + name: "HRM LED GREEN SENSOR", + type: SENSOR_DEVICE_HRM_LED_GREEN, + event_type: (SENSOR_DEVICE_HRM_LED_GREEN << SENSOR_EVENT_SHIFT) | RAW_DATA_EVENT, + model_name: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 1, + resolution: 1, + min_interval: 1, + max_batch_count: 0, + wakeup_supported: false + } +}; + +hrm_raw_device::hrm_raw_device() +: m_node_handle(-1) +, m_polling_interval(POLL_1HZ_MS) +, m_raw_interval(POLL_1HZ_MS) +, m_led_green_interval(POLL_1HZ_MS) +, m_interval_supported(false) +, m_sensorhub_controlled(false) +, m_enable(0) +, m_reader(NULL) +{ + const std::string sensorhub_interval_node_name = HRM_SENSORHUB_POLL_NODE_NAME; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_HRM_RAW, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + } + + query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name); + query.sensor_type = SENSOR_TYPE_HRM_RAW; + query.key = INPUT_NAME; + query.iio_enable_node_name = "hrm_raw_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; + + if (access(m_interval_node.c_str(), F_OK) == 0) + m_interval_supported = true; + + if (!config.get(SENSOR_TYPE_HRM_RAW, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_HRM_RAW, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + std::string reader; + + if (!config.get(SENSOR_TYPE_HRM_RAW, m_model_id, ELEMENT_READER, reader)) { + _E("[READER] is empty"); + throw ENXIO; + } + + _I("reader = %s", reader.c_str()); + + m_node_handle = open(m_data_node.c_str(), O_RDONLY); + + if (m_node_handle < 0) { + _ERRNO(errno, _E, "hrm raw handle open fail for hrm raw sensor"); + throw ENXIO; + } + + if (m_method != INPUT_EVENT_METHOD) + throw ENXIO; + + if (!util::set_monotonic_clock(m_node_handle)) + throw ENXIO; + + m_reader = get_reader(reader); + + if (!m_reader) { + _E("Not supported HRM sensor: %s", m_model_id.c_str()); + throw ENXIO; + } + + if (!m_reader->open()) + throw ENXIO; + + _I("hrm_raw_device is created!"); +} + +hrm_raw_device::~hrm_raw_device() +{ + delete m_reader; + close(m_node_handle); + m_node_handle = -1; + + _I("hrm_raw_device is destroyed!"); +} + +int hrm_raw_device::get_poll_fd() +{ + return m_node_handle; +} + +int hrm_raw_device::get_sensors(const sensor_info_t **sensors) +{ + int size = ARRAY_SIZE(sensor_info); + + for (int i = 0; i < size; ++i) { + sensor_info[i].model_name = m_chip_name.c_str(); + sensor_info[i].vendor = m_vendor.c_str(); + } + + *sensors = sensor_info; + + return size; +} + +bool hrm_raw_device::enable(uint32_t id) +{ + ++m_enable; + + if (m_enable > 1) + return true; + + util::set_enable_node(m_enable_node, m_sensorhub_controlled, true, SENSORHUB_HRM_RAW_ENABLE_BIT); + if (m_interval_supported) + set_interval(id, m_polling_interval); + + m_data.timestamp = 0; + + m_reader->start(); + _I("Enable HRM Raw sensor"); + return true; +} + +bool hrm_raw_device::disable(uint32_t id) +{ + --m_enable; + + if (m_enable > 0) + return true; + + util::set_enable_node(m_enable_node, m_sensorhub_controlled, false, SENSORHUB_HRM_RAW_ENABLE_BIT); + + m_reader->stop(); + m_enable = 0; + _I("Disable HRM Raw sensor"); + return true; +} + +bool hrm_raw_device::set_interval(uint32_t id, unsigned long val) +{ + unsigned long interval = 100; + unsigned long long polling_interval_ns; + + if (!m_interval_supported) + return true; + + if (id == INDEX_HRM_LED_GREEN) + interval = (val > m_raw_interval)?m_raw_interval:val; + else + interval = (val > m_led_green_interval)?m_led_green_interval:val; + + polling_interval_ns = ((unsigned long long)(interval) * 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, interval); + m_polling_interval = interval; + + if (id == INDEX_HRM_LED_GREEN) + m_led_green_interval = val; + else + m_raw_interval = val; + + return true; +} + +int hrm_raw_device::read_fd(uint32_t **ids) +{ + if (!m_reader->get_data(m_node_handle, m_data)) { + _D("Failed to update value"); + return false; + } + + int size = ARRAY_SIZE(sensor_info); + + event_ids.clear(); + + for (int i = 0; i < size; ++i) + event_ids.push_back(sensor_info[i].id); + + *ids = &event_ids[0]; + + return event_ids.size(); +} + +int hrm_raw_device::get_data(uint32_t id, sensor_data_t **data, int *length) +{ + int remains = 1; + 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_data.timestamp; + + if (id == INDEX_HRM_LED_GREEN) { + sensor_data->value_count = 1; + sensor_data->values[0] = m_data.values[5]; + } else { + sensor_data->value_count = m_data.value_count; + memcpy(sensor_data->values, m_data.values, m_data.value_count * sizeof(m_data.values[0])); + } + + *data = sensor_data; + *length = sizeof(sensor_data_t); + + return --remains; +} + +hrm_raw_data_reader* hrm_raw_device::get_reader(const std::string& reader) +{ + return new(std::nothrow) hrm_raw_data_reader_standard(); +} diff --git a/src/hrm_raw/hrm_raw_device.h b/src/hrm_raw/hrm_raw_device.h new file mode 100644 index 0000000..6dfa7d3 --- /dev/null +++ b/src/hrm_raw/hrm_raw_device.h @@ -0,0 +1,69 @@ +/* + * 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 _HRM_RAW_DEVICE_H_ +#define _HRM_RAW_DEVICE_H_ + +#include +#include +#include +#include +#include "hrm_raw_data_reader.h" + +class hrm_raw_device : public sensor_device { +public: + hrm_raw_device(); + virtual ~hrm_raw_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; + sensor_data_t m_data; + unsigned long m_polling_interval; + unsigned long m_raw_interval; + unsigned long m_led_green_interval; + + bool m_interval_supported; + bool m_sensorhub_controlled; + int m_enable; + + hrm_raw_data_reader *m_reader; + + int m_method; + std::string m_data_node; + std::string m_enable_node; + std::string m_interval_node; + + std::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + std::vector event_ids; + + hrm_raw_data_reader* get_reader(const std::string& reader); +}; +#endif /* _HRM_RAW_DEVICE_H_ */ diff --git a/src/light/light_device.cpp b/src/light/light_device.cpp new file mode 100644 index 0000000..4a22bab --- /dev/null +++ b/src/light/light_device.cpp @@ -0,0 +1,345 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include "light_device.h" + +#define BIAS 1 + +#define SENSOR_NAME "SENSOR_LIGHT" + +/* ADC value received from Kernel */ +#define MODEL_ID_CAPELLA "CM36686" + +#define SENSOR_TYPE_LIGHT "LIGHT" + +#define INPUT_NAME "light_sensor" +#define LIGHT_SENSORHUB_POLL_NODE_NAME "light_poll_delay" + +const static int light_level[] = {0, 1, 165, 288, 497, 869, 1532, 2692, 4692, 8280, 21428, 65535, 137852}; + +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: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 65536, + resolution: 1, + min_interval: 1, + max_batch_count: 0, + 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; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_LIGHT, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + } + + query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name); + 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; + + if (!config.get(SENSOR_TYPE_LIGHT, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_LIGHT, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + 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) { + if (!util::set_monotonic_clock(m_node_handle)) + throw ENXIO; + + if (m_chip_name == MODEL_ID_CAPELLA) { + update_value = [=]() { + return this->update_value_adc(); + }; + } else { + 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) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + *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); + + INFO("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_adc(void) +{ + int light_raw[2] = {0,}; + int als = -1; + int w = -1; + int lux = -1; + float i_cf = 0.0f; + bool adc, white; + int read_input_cnt = 0; + const int INPUT_MAX_BEFORE_SYN = 10; + unsigned long long fired_time = 0; + bool syn = false; + + adc = white = false; + + struct input_event light_input; + _D("light event detection!"); + + while ((syn == false) && (read_input_cnt < INPUT_MAX_BEFORE_SYN)) { + int len = read(m_node_handle, &light_input, sizeof(light_input)); + if (len != sizeof(light_input)) { + _E("light_file read fail, read_len = %d",len); + return false; + } + + ++read_input_cnt; + + if (light_input.type == EV_REL) { + switch (light_input.code) { + case REL_DIAL: + light_raw[0] = (int)light_input.value - BIAS; + adc = true; + break; + case REL_WHEEL: + light_raw[1] = (int)light_input.value - BIAS; + white = true; + break; + default: + _E("light_input event[type = %d, code = %d] is unknown.", light_input.type, light_input.code); + return false; + break; + } + } else if (light_input.type == EV_SYN) { + syn = true; + fired_time = util::get_timestamp(&light_input.time); + } else { + _E("light_input event[type = %d, code = %d] is unknown.", light_input.type, light_input.code); + return false; + } + } + + if (syn == false) { + _E("EV_SYN didn't come until %d inputs had come", read_input_cnt); + return false; + } + + if (adc && white) { + als = light_raw[0]; + w = (light_raw[1])? light_raw[1] : 1; + i_cf = als / (float) w; + if (i_cf >= 0.33f) { + lux = 0.6985f * pow(als, 0.9943f); + } else { + lux = 0.25f * pow(als, 1.0552f); + } + } + + _D("update_value_lux, lux : %d", lux); + + m_fired_time = fired_time; + m_lux = lux; + + return true; +} + +bool light_device::update_value_lux(void) +{ + int lux = -1; + struct input_event light_event; + _D("light event detection!"); + + int len = read(m_node_handle, &light_event, sizeof(light_event)); + if (len == -1) { + _ERRNO(errno, _E, "Failed to read from m_node_handle"); + return false; + } + + if (light_event.type == EV_ABS && light_event.code == ABS_MISC) { + lux = light_event.value; + } else if (light_event.type == EV_REL && light_event.code == REL_RX) { + lux = light_event.value - BIAS; + } else { + _D("light input event[type = %d, code = %d] is unknown.", light_event.type, light_event.code); + return false; + } + + _D("read event, len : %d, type : %x, code : %x, value : %x", + len, light_event.type, light_event.code, light_event.value); + + _D("update_value_lux, lux : %d", lux); + + m_lux = lux; + m_fired_time = util::get_timestamp(&light_event.time); + + return true; +} + +int light_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 light_device::get_data(uint32_t id, sensor_data_t **data, int *length) +{ + int remains = 1; + 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] = (float)m_lux; + + *data = sensor_data; + *length = sizeof(sensor_data_t); + + return --remains; +} + +int light_device::adc_to_light_level(int adc) +{ + int level_cnt = ARRAY_SIZE(light_level) - 1; + + for (int i = 0; i < level_cnt; ++i) { + if (adc >= light_level[i] && adc < light_level[i + 1]) + return i; + } + + return -1; +} diff --git a/src/light/light_device.h b/src/light/light_device.h new file mode 100644 index 0000000..4a1a71c --- /dev/null +++ b/src/light/light_device.h @@ -0,0 +1,66 @@ +/* + * 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 +#include +#include +#include + +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; + int m_lux; + 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::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + std::function update_value; + + std::vector event_ids; + + bool update_value_adc(void); + bool update_value_lux(void); + int adc_to_light_level(int adc); +}; +#endif /* _LIGHT_DEVICE_H_ */ diff --git a/src/macro.h b/src/macro.h new file mode 100644 index 0000000..132b547 --- /dev/null +++ b/src/macro.h @@ -0,0 +1,25 @@ +/* + * 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)) + +#endif /* __MACRO_H__ */ diff --git a/src/pressure/pressure_device.cpp b/src/pressure/pressure_device.cpp new file mode 100644 index 0000000..c662636 --- /dev/null +++ b/src/pressure/pressure_device.cpp @@ -0,0 +1,372 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "pressure_device.h" + +#define SEA_LEVEL_RESOLUTION 0.01 +#define SEA_LEVEL_PRESSURE 101325.0 +#define SEA_LEVEL_EPSILON 0.00001 + +#define SENSOR_NAME "SENSOR_PRESSURE" +#define SENSOR_TYPE_PRESSURE "PRESSURE" + +#define ELEMENT_TEMPERATURE_RESOLUTION "TEMPERATURE_RESOLUTION" +#define ELEMENT_TEMPERATURE_OFFSET "TEMPERATURE_OFFSET" + +#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: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 0, + resolution: 0, + min_interval: 0, + max_batch_count: 0, + wakeup_supported: false +}; + +pressure_device::pressure_device() +: m_node_handle(-1) +, m_pressure(0) +, m_resolution(0) +, m_temperature(0) +, m_sea_level_pressure(SEA_LEVEL_PRESSURE) +, m_temperature_resolution(0) +, m_temperature_offset(0) +, m_polling_interval(1000) +, m_fired_time(0) +, m_sensorhub_controlled(false) +{ + const std::string sensorhub_interval_node_name = PRESSURE_SENSORHUB_POLL_NODE_NAME; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_PRESSURE, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + + } + + 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; + + if (!config.get(SENSOR_TYPE_PRESSURE, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty\n"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_PRESSURE, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty\n"); + throw ENXIO; + } + + _I("m_chip_name = %s", m_chip_name.c_str()); + + double min_range; + + if (!config.get(SENSOR_TYPE_PRESSURE, m_model_id, ELEMENT_MIN_RANGE, min_range)) { + _E("[MIN_RANGE] is empty\n"); + throw ENXIO; + } + + m_min_range = (float)min_range; + _I("m_min_range = %f\n",m_min_range); + + double max_range; + + if (!config.get(SENSOR_TYPE_PRESSURE, m_model_id, ELEMENT_MAX_RANGE, max_range)) { + _E("[MAX_RANGE] is empty\n"); + throw ENXIO; + } + + m_max_range = (float)max_range; + _I("m_max_range = %f\n",m_max_range); + + double raw_data_unit; + + if (!config.get(SENSOR_TYPE_PRESSURE, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) { + _E("[RAW_DATA_UNIT] is empty\n"); + throw ENXIO; + } + + m_raw_data_unit = (float)(raw_data_unit); + _I("m_raw_data_unit = %f\n", m_raw_data_unit); + + double temperature_resolution; + if (!config.get(SENSOR_TYPE_PRESSURE, m_model_id, ELEMENT_TEMPERATURE_RESOLUTION, temperature_resolution)) { + ERR("[TEMPERATURE_RESOLUTION] is empty\n"); + throw ENXIO; + } + + m_temperature_resolution = (float)temperature_resolution; + INFO("m_temperature_resolution = %f\n", m_temperature_resolution); + + double temperature_offset; + + if (!config.get(SENSOR_TYPE_PRESSURE, m_model_id, ELEMENT_TEMPERATURE_OFFSET, temperature_offset)) { + ERR("[TEMPERATURE_OFFSET] is empty\n"); + throw ENXIO; + } + + m_temperature_offset = (float)temperature_offset; + INFO("m_temperature_offset = %f\n", m_temperature_offset); + + 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(); + }; + } + + _I("pressure_device is created!\n"); +} + +pressure_device::~pressure_device() +{ + close(m_node_handle); + m_node_handle = -1; + + _I("pressure_device is destroyed!\n"); +} + +int pressure_device::get_poll_fd(void) +{ + return m_node_handle; +} + +int pressure_device::get_sensors(const sensor_info_t **sensors) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + sensor_info.min_range = m_min_range; + sensor_info.max_range = m_max_range; + sensor_info.resolution = m_raw_data_unit; + sensor_info.min_interval = 1; + sensor_info.max_batch_count = 0; + *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; + INFO("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); + + INFO("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)) { + ERR("Failed to set polling resource: %s\n", m_interval_node.c_str()); + return false; + } + + INFO("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; +} + +int pressure_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 pressure_device::get_data(uint32_t id, sensor_data_t **data, int *length) +{ + int remains = 1; + 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 --remains; +} + +void pressure_device::raw_to_base(sensor_data_t *data) +{ + data->values[0] = data->values[0] * m_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] * m_temperature_resolution + m_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)); +} + diff --git a/src/pressure/pressure_device.h b/src/pressure/pressure_device.h new file mode 100644 index 0000000..27f08bc --- /dev/null +++ b/src/pressure/pressure_device.h @@ -0,0 +1,77 @@ +/* + * 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 +#include +#include +#include + +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_resolution; + int m_temperature; + float m_sea_level_pressure; + float m_temperature_resolution; + float m_temperature_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::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + float m_min_range; + float m_max_range; + float m_raw_data_unit; + + std::function update_value; + + std::vector 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_*/ diff --git a/src/proxi/proxi_device.cpp b/src/proxi/proxi_device.cpp new file mode 100644 index 0000000..6b46117 --- /dev/null +++ b/src/proxi/proxi_device.cpp @@ -0,0 +1,229 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "proxi_device.h" + +#define MODEL_NAME "UNKNOWN" +#define VENDOR "UNKNOWN" +#define MIN_RANGE 0 +#define MAX_RANGE 5 +#define RESOLUTION 1 +#define MIN_INTERVAL 1 +#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" + +#define RAW_DATA_TO_DISTANCE(x) ((x) * 5) + +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; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_PROXI, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + + } + + query.sensorhub_controlled = m_sensorhub_controlled = util::is_sensorhub_controlled(sensorhub_interval_node_name); + 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; + + if (!config.get(SENSOR_TYPE_PROXI, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_PROXI, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + m_node_handle = open(m_data_node.c_str(), O_RDONLY); + + if (m_node_handle < 0) { + _ERRNO(errno, _E, "proxi handle open fail for proxi 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("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) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + *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::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) +{ + int remains = 1; + 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] = RAW_DATA_TO_DISTANCE(m_state); + + *data = sensor_data; + *length = sizeof(sensor_data_t); + + return --remains; +} diff --git a/src/proxi/proxi_device.h b/src/proxi/proxi_device.h new file mode 100644 index 0000000..93f9e9a --- /dev/null +++ b/src/proxi/proxi_device.h @@ -0,0 +1,67 @@ +/* + * 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 +#include +#include +#include + +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); + + 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 update_value; + + std::vector event_ids; + + bool update_value_input_event(void); +}; + +#endif /* _PROXI_DEVICE_H_ */ diff --git a/src/sensor_common.h b/src/sensor_common.h new file mode 100644 index 0000000..b549c96 --- /dev/null +++ b/src/sensor_common.h @@ -0,0 +1,56 @@ +/* + * 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_ */ diff --git a/src/sensor_config.cpp b/src/sensor_config.cpp new file mode 100644 index 0000000..d8b7c28 --- /dev/null +++ b/src/sensor_config.cpp @@ -0,0 +1,317 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace config; +using std::ifstream; +using std::string; +using std::istringstream; + +#define ROOT_ELEMENT "SENSOR" +#define TEXT_ELEMENT "text" +#define MODEL_ID_ATTR "id" +#define DEFAULT_ATTR "value" + +sensor_config::sensor_config() +{ +} + +sensor_config& sensor_config::get_instance(void) +{ + static bool load_done = false; + static sensor_config inst; + + if (load_done) + return inst; + + inst.load_config(); + inst.get_device_id(); + if (!inst.m_device_id.empty()) + _I("Device ID = %s", inst.m_device_id.c_str()); + else + _E("Failed to get Device ID"); + load_done = true; + + return inst; +} + +bool sensor_config::load_config(const string& config_path) +{ + xmlDocPtr doc; + xmlNodePtr cur; + + _D("sensor_config::load_config(\"%s\") is called!\n",config_path.c_str()); + + doc = xmlParseFile(config_path.c_str()); + + if (doc == NULL) { + _E("There is no %s\n",config_path.c_str()); + return false; + } + + cur = xmlDocGetRootElement(doc); + if(cur == NULL) { + _E("There is no root element in %s\n",config_path.c_str()); + xmlFreeDoc(doc); + return false; + } + + if(xmlStrcmp(cur->name, (const xmlChar *)ROOT_ELEMENT)) { + _E("Wrong type document: there is no [%s] root element in %s\n",ROOT_ELEMENT,config_path.c_str()); + xmlFreeDoc(doc); + return false; + } + + xmlNodePtr model_list_node_ptr; + xmlNodePtr model_node_ptr; + xmlNodePtr element_node_ptr; + xmlAttrPtr attr_ptr; + char* prop = NULL; + + model_list_node_ptr = cur->xmlChildrenNode; + + while (model_list_node_ptr != NULL) { + //skip garbage element, [text] + if (!xmlStrcmp(model_list_node_ptr->name,(const xmlChar *)TEXT_ELEMENT)) { + model_list_node_ptr = model_list_node_ptr->next; + continue; + } + + //insert Model_list to config map + m_sensor_config[(const char*)model_list_node_ptr->name]; + _D("<%s>\n",(const char*)model_list_node_ptr->name); + + model_node_ptr = model_list_node_ptr->xmlChildrenNode; + while (model_node_ptr != NULL){ + //skip garbage element, [text] + if (!xmlStrcmp(model_node_ptr->name,(const xmlChar *)TEXT_ELEMENT)) { + model_node_ptr = model_node_ptr->next; + continue; + } + + + string model_id; + prop = (char*)xmlGetProp(model_node_ptr,(const xmlChar*)MODEL_ID_ATTR); + model_id = prop; + free(prop); + + //insert Model to Model_list + m_sensor_config[(const char*)model_list_node_ptr->name][model_id]; + _D("<%s id=\"%s\">\n",(const char*)model_list_node_ptr->name,model_id.c_str()); + + element_node_ptr = model_node_ptr->xmlChildrenNode; + while (element_node_ptr != NULL) { + //skip garbage element, [text] + if (!xmlStrcmp(element_node_ptr->name,(const xmlChar *)TEXT_ELEMENT)) { + element_node_ptr = element_node_ptr->next; + continue; + } + + //insert Element to Model + m_sensor_config[(const char*)model_list_node_ptr->name][model_id][(const char*)element_node_ptr->name]; + _D("<%s id=\"%s\"><%s>\n",(const char*)model_list_node_ptr->name,model_id.c_str(),(const char*)element_node_ptr->name); + + attr_ptr = element_node_ptr->properties; + while (attr_ptr != NULL) { + + string key,value; + key = (const char*)attr_ptr->name; + prop = (char*)xmlGetProp(element_node_ptr,attr_ptr->name); + value = prop; + free(prop); + + //insert attribute to Element + m_sensor_config[(const char*)model_list_node_ptr->name][model_id][(const char*)element_node_ptr->name][key]=value; + _D("<%s id=\"%s\"><%s \"%s\"=\"%s\">\n",(const char*)model_list_node_ptr->name,model_id.c_str(),(const char*)element_node_ptr->name,key.c_str(),value.c_str()); + attr_ptr = attr_ptr->next; + } + + + element_node_ptr = element_node_ptr->next; + } + + _D("\n"); + model_node_ptr = model_node_ptr->next; + } + + _D("\n"); + model_list_node_ptr = model_list_node_ptr->next; + } + + xmlFreeDoc(doc); + return true; +} + + +bool sensor_config::get(const string& sensor_type,const string& model_id, const string& element, const string& attr, string& value) +{ + auto it_model_list = m_sensor_config.find(sensor_type); + + if (it_model_list == m_sensor_config.end()) { + _E("There is no <%s> element\n",sensor_type.c_str()); + return false; + } + + auto it_model = it_model_list->second.find(model_id); + + if (it_model == it_model_list->second.end()) { + _E("There is no <%s id=\"%s\"> element\n",sensor_type.c_str(),model_id.c_str()); + return false; + } + + auto it_element = it_model->second.find(element); + + if (it_element == it_model->second.end()) { + _D("There is no <%s id=\"%s\"><%s> element\n",sensor_type.c_str(),model_id.c_str(),element.c_str()); + return false; + } + + auto it_attr = it_element->second.find(attr); + + if (it_attr == it_element->second.end()) { + _D("There is no <%s id=\"%s\"><%s \"%s\">\n",sensor_type.c_str(),model_id.c_str(),element.c_str(),attr.c_str()); + return false; + } + + value = it_attr->second; + + return true; +} + +bool sensor_config::get(const string& sensor_type, const string& model_id, const string& element, const string& attr, double& value) +{ + string str_value; + + if (get(sensor_type,model_id,element,attr,str_value) == false) + return false; + + istringstream convert(str_value); + + if ( !(convert >> value)) + value = 0; + + return true; +} + +bool sensor_config::get(const string& sensor_type, const string& model_id, const string& element, const string& attr, long& value) +{ + string str_value; + + if (get(sensor_type,model_id,element,attr,str_value) == false) + return false; + + istringstream convert(str_value); + + if ( !(convert >> value)) + value = 0; + + return true; +} + +bool sensor_config::get(const string& sensor_type, const string& model_id, const string& element, string& value) +{ + if (get(sensor_type, model_id, element, m_device_id, value)) + return true; + + if (get(sensor_type, model_id, element, DEFAULT_ATTR, value)) + return true; + + return false; +} + +bool sensor_config::get(const string& sensor_type, const string& model_id, const string& element, double& value) +{ + if (get(sensor_type, model_id, element, m_device_id, value)) + return true; + + if (get(sensor_type, model_id, element, DEFAULT_ATTR, value)) + return true; + + return false; +} + +bool sensor_config::get(const string& sensor_type, const string& model_id, const string& element, long& value) +{ + if (get(sensor_type, model_id, element, m_device_id, value)) + return true; + + if (get(sensor_type, model_id, element, DEFAULT_ATTR, value)) + return true; + + return false; +} + +bool sensor_config::is_supported(const string& sensor_type,const string& model_id) +{ + auto it_model_list = m_sensor_config.find(sensor_type); + + if (it_model_list == m_sensor_config.end()) + return false; + + auto it_model = it_model_list->second.find(model_id); + + if (it_model == it_model_list->second.end()) + return false; + + return true; +} + +bool sensor_config::get_device_id(void) +{ + const string INFO_INI_PATH = "/etc/info.ini"; + const string START_DELIMETER = "Model="; + const string END_DELIMETER = ";"; + string line; + ifstream in_file; + std::size_t start_pos, end_pos; + bool ret = false; + + in_file.open(INFO_INI_PATH); + + if (!in_file.is_open()) + return false; + + while (!in_file.eof()) { + getline(in_file, line); + start_pos = line.find(START_DELIMETER); + + if (start_pos == std::string::npos) + continue; + + start_pos = start_pos + START_DELIMETER.size(); + end_pos = line.find(END_DELIMETER, start_pos); + + if (end_pos == std::string::npos) + continue; + + m_device_id = line.substr(start_pos, end_pos - start_pos); + ret = true; + break; + } + + in_file.close(); + + return ret; +} diff --git a/src/sensor_config.h b/src/sensor_config.h new file mode 100644 index 0000000..eadc8b9 --- /dev/null +++ b/src/sensor_config.h @@ -0,0 +1,103 @@ +/* + * 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_CONFIG_H_ +#define _SENSOR_CONFIG_H_ + +#include +#include +#include + +#define CONFIG_FILE_PATH "/usr/etc/sensor.xml" + +#define ELEMENT_NAME "NAME" +#define ELEMENT_VENDOR "VENDOR" +#define ELEMENT_RAW_DATA_UNIT "RAW_DATA_UNIT" +#define ELEMENT_RESOLUTION "RESOLUTION" +#define ATTR_VALUE "value" +#define ELEMENT_MIN_RANGE "MIN_RANGE" +#define ELEMENT_MAX_RANGE "MAX_RANGE" + +typedef std::unordered_map Element; +/* +* an Element is a group of attributes +* +* +* "value" -> "LSM330DLC" +* +*/ + +typedef std::unordered_map Model; +/* +* a Model is a group of elements to consist of specific vendor's one sensor configuration +* +* +* +* +* +* -> +* +*/ + +typedef std::unordered_map Model_list; +/* +* a Model_list is a group of Model +* +* +* +* +* +* "lsm330dlc_accel" -> +* +*/ + +typedef std::unordered_map Sensor_config; +/* +* a SensorConfig represents sensors.xml +* +* +* +* +* "ACCEL" -> Model_list +* +*/ + +namespace config { + class sensor_config { + private: + sensor_config(); + sensor_config(sensor_config const&) {}; + sensor_config& operator=(sensor_config const&); + bool load_config(const std::string& config_path = CONFIG_FILE_PATH); + Sensor_config m_sensor_config; + std::string m_device_id; + public: + static sensor_config& get_instance(void); + + bool get(const std::string& sensor_type, const std::string& model_id, const std::string& element, const std::string& attr, std::string& value); + bool get(const std::string& sensor_type, const std::string& model_id, const std::string& element, const std::string& attr, double& value); + bool get(const std::string& sensor_type, const std::string& model_id, const std::string& element, const std::string& attr, long& value); + + bool get(const std::string& sensor_type, const std::string& model_id, const std::string& element, std::string& value); + bool get(const std::string& sensor_type, const std::string& model_id, const std::string& element, double& value); + bool get(const std::string& sensor_type, const std::string& model_id, const std::string& element, long& value); + + bool is_supported(const std::string &sensor_type, const std::string &model_id); + bool get_device_id(void); + }; +} +#endif /* _SENSOR_CONFIG_H_ */ diff --git a/src/sensor_log.h b/src/sensor_log.h new file mode 100644 index 0000000..8e593e2 --- /dev/null +++ b/src/sensor_log.h @@ -0,0 +1,122 @@ +/* + * 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 + +#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_ */ diff --git a/src/ultraviolet/uv_device.cpp b/src/ultraviolet/uv_device.cpp new file mode 100644 index 0000000..eec4f78 --- /dev/null +++ b/src/ultraviolet/uv_device.cpp @@ -0,0 +1,304 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "uv_device.h" + +#define UNKNOWN_NAME "UNKNOWN" +#define SENSOR_NAME "ULTRAVIOLET_SENSOR" + +#define SENSOR_TYPE_ULTRAVIOLET "ULTRAVIOLET" +#define UV_SENSORHUB_POLL_NODE_NAME "uv_poll_dealy" +#define INPUT_NAME "uv_sensor" +#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: UNKNOWN_NAME, + vendor: UNKNOWN_NAME, + min_range: 0, + max_range: 0, + resolution: 0, + min_interval: 0, + max_batch_count: 0, + wakeup_supported: false +}; + +std::vector uv_device::event_ids; + +uv_device::uv_device() +: m_node_handle(-1) +, m_ultraviolet(0) +, m_polling_interval(1000) +, m_fired_time(0) +, m_raw_data_unit(0) +, m_min_range(0) +, m_max_range(0) +, m_sensorhub_controlled(false) +{ + const std::string sensorhub_interval_node_name = UV_SENSORHUB_POLL_NODE_NAME; + config::sensor_config &config = config::sensor_config::get_instance(); + + node_info_query query; + node_info info; + + if (!util::find_model_id(SENSOR_TYPE_ULTRAVIOLET, m_model_id)) { + _E("Failed to find model id"); + throw ENXIO; + } + + 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; + + if (!config.get(SENSOR_TYPE_ULTRAVIOLET, m_model_id, ELEMENT_VENDOR, m_vendor)) { + _E("[VENDOR] is empty"); + throw ENXIO; + } + + _I("m_vendor = %s", m_vendor.c_str()); + + if (!config.get(SENSOR_TYPE_ULTRAVIOLET, m_model_id, ELEMENT_NAME, m_chip_name)) { + _E("[NAME] is empty"); + throw ENXIO; + } + + _I("m_chip_name = %s",m_chip_name.c_str()); + + double min_range; + + if (!config.get(SENSOR_TYPE_ULTRAVIOLET, m_model_id, ELEMENT_MIN_RANGE, min_range)) { + ERR("[MIN_RANGE] is empty\n"); + throw ENXIO; + } + + m_min_range = (float)min_range; + INFO("m_min_range = %f\n",m_min_range); + + double max_range; + + if (!config.get(SENSOR_TYPE_ULTRAVIOLET, m_model_id, ELEMENT_MAX_RANGE, max_range)) { + ERR("[MAX_RANGE] is empty\n"); + throw ENXIO; + } + + m_max_range = (float)max_range; + INFO("m_max_range = %f\n",m_max_range); + + double raw_data_unit; + + if (!config.get(SENSOR_TYPE_ULTRAVIOLET, m_model_id, ELEMENT_RAW_DATA_UNIT, raw_data_unit)) { + _E("[RAW_DATA_UNIT] is empty"); + throw ENXIO; + } + + m_raw_data_unit = (float)(raw_data_unit); + _I("m_raw_data_unit = %f", m_raw_data_unit); + + m_node_handle = open(m_data_node.c_str(), O_RDONLY); + + if (m_node_handle < 0) { + _ERRNO(errno, _E, "uv handle open fail for uv 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(); + }; + + _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) +{ + sensor_info.model_name = m_chip_name.c_str(); + sensor_info.vendor = m_vendor.c_str(); + sensor_info.min_range = m_min_range; + sensor_info.max_range = m_max_range; + sensor_info.resolution = m_raw_data_unit; + sensor_info.min_interval = 1; + sensor_info.max_batch_count = 0; + *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 (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) +{ + int remains = 1; + 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 --remains; +} + +void uv_device::raw_to_base(sensor_data_t *data) +{ + data->values[0] = data->values[0] * m_raw_data_unit; +} diff --git a/src/ultraviolet/uv_device.h b/src/ultraviolet/uv_device.h new file mode 100644 index 0000000..31106d5 --- /dev/null +++ b/src/ultraviolet/uv_device.h @@ -0,0 +1,69 @@ +/* + * 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 +#include +#include +#include + +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; + float m_raw_data_unit; + float m_min_range; + float m_max_range; + bool m_sensorhub_controlled; + + int m_method; + std::string m_data_node; + std::string m_enable_node; + std::string m_interval_node; + + std::string m_model_id; + std::string m_vendor; + std::string m_chip_name; + + std::function update_value; + + static std::vector event_ids; + + bool update_value_input_event(void); + + void raw_to_base(sensor_data_t *data); +}; +#endif /* _UV_DEVICE_H_ */ diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..8b95cdb --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,395 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +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::find_model_id(const string &sensor_type, string &model_id) +{ + std::string dir_path = "/sys/class/sensors/"; + 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; + + dir = opendir(dir_path.c_str()); + if (!dir) { + _D("Failed to open dir: %s", dir_path.c_str()); + return 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 == ".") || (d_name == "..") || (dir_entry.d_ino == 0)) + continue; + + name_node = dir_path + d_name + string("/name"); + + ifstream infile(name_node.c_str()); + + if (!infile) + continue; + + infile >> name; + + if (!config::sensor_config::get_instance().is_supported(sensor_type, name)) + continue; + + model_id = name; + find = true; + break; + } + + closedir(dir); + + return find; +} + +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; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..5c13a85 --- /dev/null +++ b/src/util.h @@ -0,0 +1,68 @@ +/* + * 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 +#include + +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 find_model_id(const std::string &sensor_type, std::string &model_id); + 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_*/ -- 2.7.4