pax_global_header00006660000000000000000000000064140241503340014506gustar00rootroot0000000000000052 comment=d7a36de882b3f8818d485b0ec94f3fa5fe1152dd hfd-service-0.1.0/000077500000000000000000000000001402415033400137035ustar00rootroot00000000000000hfd-service-0.1.0/.gitignore000066400000000000000000000006101402415033400156700ustar00rootroot00000000000000 # Created by https://www.gitignore.io/api/cmake # Edit at https://www.gitignore.io/?templates=cmake ### CMake ### CMakeLists.txt.user CMakeCache.txt CMakeFiles CMakeScripts Testing Makefile cmake_install.cmake install_manifest.txt compile_commands.json CTestTestfile.cmake _deps ### CMake Patch ### # External projects *-prefix/ # End of https://www.gitignore.io/api/cmake build build-* hfd-service-0.1.0/CMakeLists.txt000066400000000000000000000021551402415033400164460ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0) project(hfd-service) set(CMAKE_CXX_STANDARD 14) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) include(FindPkgConfig) include(GNUInstallDirs) pkg_check_modules(UDEV REQUIRED libudev) option(ENABLE_LIBHYBRIS "Enable libhybris support" ON) if (ENABLE_LIBHYBRIS) pkg_check_modules(ANDROID_HEADERS android-headers) pkg_check_modules(ANDROID_HARDWARE libhardware) if(ANDROID_HEADERS_FOUND AND ANDROID_HARDWARE_FOUND) message(STATUS "Bulding with libhybris support") set(HAVE_LIBHYBRIS true) else() message(WARNING "Bulding without libhybris support, missing required dependencies!") endif() else() message(STATUS "Bulding without libhybris support") endif() find_package(Qt5Core REQUIRED) find_package(Qt5DBus REQUIRED) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") add_subdirectory(src) add_subdirectory(tools) add_subdirectory(qt) # Dbus file install(FILES data/hfd-service.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/init ) # Dbus policy install(FILES data/com.lomiri.hfd.conf DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/dbus-1/system.d ) hfd-service-0.1.0/Jenkinsfile000066400000000000000000000057171402415033400161010ustar00rootroot00000000000000String stashFileList = '*.gz,*.bz2,*.xz,*.deb,*.ddeb,*.dsc,*.changes,*.buildinfo,lintian.txt' String archiveFileList = '*.gz,*.bz2,*.xz,*.deb,*.ddeb,*.dsc,*.changes,*.buildinfo' pipeline { agent any stages { stage('Build source') { steps { sh '/usr/bin/build-source.sh' stash(name: 'source', includes: stashFileList) cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) } } stage('Build binary - armhf') { steps { parallel( "Build binary - armhf": { node(label: 'arm64') { cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) unstash 'source' sh '''export architecture="armhf" build-binary.sh''' stash(includes: stashFileList, name: 'build-armhf') cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) } }, "Build binary - arm64": { node(label: 'arm64') { cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) unstash 'source' sh '''export architecture="arm64" build-binary.sh''' stash(includes: stashFileList, name: 'build-arm64') cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) } }, "Build binary - amd64": { node(label: 'amd64') { cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) unstash 'source' sh '''export architecture="amd64" build-binary.sh''' stash(includes: stashFileList, name: 'build-amd64') cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) } } ) } } stage('Results') { steps { cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) unstash 'build-armhf' unstash 'build-arm64' unstash 'build-amd64' archiveArtifacts(artifacts: archiveFileList, fingerprint: true, onlyIfSuccessful: true) sh '''/usr/bin/build-repo.sh''' } } stage('Cleanup') { steps { cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true) } } } } hfd-service-0.1.0/Readme.md000066400000000000000000000011071402415033400154210ustar00rootroot00000000000000# hfd-service **H**uman **f**eedback **d**evice **service** is a dbus activated service that manages human feedback devices sutch as leds and vibrators on mobile devices. This replaces usensord and unity8's own led/light handeler ## Why? We have a need for a more modular system running service now that we have different devices handeling implementations differently. Secondly we could not use unity8's own led handeler as this only runs in userspace and we wont have access to sysfs devices from there in a secure maner. We can use a dbus service protected with apparmor. hfd-service-0.1.0/data/000077500000000000000000000000001402415033400146145ustar00rootroot00000000000000hfd-service-0.1.0/data/com.lomiri.hfd.conf000066400000000000000000000007371402415033400203020ustar00rootroot00000000000000 hfd-service-0.1.0/data/com.lomiri.hfd.xml000066400000000000000000000016011402415033400201440ustar00rootroot00000000000000 hfd-service-0.1.0/data/hfd-service.conf000066400000000000000000000006731402415033400176700ustar00rootroot00000000000000description "hfd service for feedback support" start on started dbus stop on stopped dbus pre-start script # If we're running on Android-based device, we want to wait until the # Android container is up. if [ -e /system/build.prop ]; then while ! initctl status lxc-android-config| \ grep -q ' start/running,\| start/post-start,'; do sleep 0.1 done fi end script exec hfd-service hfd-service-0.1.0/debian/000077500000000000000000000000001402415033400151255ustar00rootroot00000000000000hfd-service-0.1.0/debian/changelog000066400000000000000000000002141402415033400167740ustar00rootroot00000000000000hfd-service (0.1.0) xenial; urgency=medium * initial release -- Marius Gripsgard Sat, 21 Mar 2020 02:06:32 +0100 hfd-service-0.1.0/debian/compat000066400000000000000000000000021402415033400163230ustar00rootroot000000000000009 hfd-service-0.1.0/debian/control000066400000000000000000000026211402415033400165310ustar00rootroot00000000000000Source: hfd-service Section: admin Priority: optional Build-Depends: cmake (>= 2.8.10), debhelper (>= 9), pkg-config, libandroid-properties-dev, libhardware-dev, android-headers, libudev-dev, qtbase5-dev, qtfeedback5-dev, cmake-extras, qtdeclarative5-dev Maintainer: Marius Gripsgard Standards-Version: 3.9.5 Homepage: https://github.com/ubports/deviceinfo Package: hfd-service Section: libs Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, Description: Library to detect and configure devices Library to detect and configure devices Package: libqt5feedback5-hfd Section: libs Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, hfd-service, Description: Library to detect and configure devices Library to detect and configure devices Package: qml-module-hfd Section: libs Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, hfd-service, Description: Library to detect and configure devices Library to detect and configure devices Package: hfd-service-tools Section: admin Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, hfd-service, Description: Tools to detect and configure devices Tools to detect and configure devices hfd-service-0.1.0/debian/copyright000066400000000000000000000020561402415033400170630ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: deviceinfo Upstream-Contact: Marius Gripsgard Source: https://github.com/ubports/deviceinfo Files: * Copyright: 2019 UBports foundation, Marius Gripsgard License: GPL-3 License: GPL-3 This program is free software: you can redistribute it and/or modify it under the terms of the the GNU General Public License version 3, as published by the Free Software Foundation. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR PURPOSE. See the applicable version of the GNU Lesser General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . . On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-3' hfd-service-0.1.0/debian/hfd-service-tools.install000066400000000000000000000000341402415033400220470ustar00rootroot00000000000000usr/bin/hfd-service-tools-* hfd-service-0.1.0/debian/hfd-service.install000066400000000000000000000001261402415033400207130ustar00rootroot00000000000000usr/bin/hfd-service etc/init/hfd-service.conf etc/dbus-1/system.d/com.lomiri.hfd.conf hfd-service-0.1.0/debian/libqt5feedback5-hfd.install000066400000000000000000000000651402415033400222070ustar00rootroot00000000000000/usr/lib/*/qt5/plugins/feedback/libqtfeedback_hfd.so hfd-service-0.1.0/debian/qml-module-hfd.install000066400000000000000000000000311402415033400213220ustar00rootroot00000000000000/usr/lib/*/qt5/qml/Hfd/* hfd-service-0.1.0/debian/rules000077500000000000000000000001141402415033400162010ustar00rootroot00000000000000#!/usr/bin/make -f %: dh $@ --parallel --buildsystem cmake --fail-missing hfd-service-0.1.0/qt/000077500000000000000000000000001402415033400143275ustar00rootroot00000000000000hfd-service-0.1.0/qt/CMakeLists.txt000066400000000000000000000000701402415033400170640ustar00rootroot00000000000000add_subdirectory(feedback-plugin) add_subdirectory(qml) hfd-service-0.1.0/qt/demo/000077500000000000000000000000001402415033400152535ustar00rootroot00000000000000hfd-service-0.1.0/qt/demo/feedback.qml000066400000000000000000000016371402415033400175210ustar00rootroot00000000000000import QtQuick 2.7 import Ubuntu.Components 1.3 import QtFeedback 5.0 MainView { id: root objectName: 'mainView' applicationName: "app" automaticOrientation: true width: units.gu(45) height: units.gu(75) Page { anchors.fill: parent header: PageHeader { id: header title: i18n.tr("led test") } Column { anchors { top: header.bottom left: parent.left right: parent.right bottom: parent.bottom } Button { text: "feedback" onClicked: haptic.start(); } } HapticsEffect { id: haptic attackIntensity: 0.0 attackTime: 50 intensity: 1.0 duration: 100 fadeTime: 50 fadeIntensity: 0.0 } } } hfd-service-0.1.0/qt/demo/leds.qml000066400000000000000000000012041402415033400167120ustar00rootroot00000000000000import QtQuick 2.7 import Ubuntu.Components 1.3 import Hfd 0.1 MainView { id: root objectName: 'mainView' applicationName: "app" automaticOrientation: true width: units.gu(45) height: units.gu(75) Page { anchors.fill: parent header: PageHeader { id: header title: i18n.tr("led test") } Column { anchors.fill: parent Button { text: "on" onClicked: Leds.state = Leds.state == 0 ? 1 : 0 } Label { text: "state: " + Leds.state } } } } hfd-service-0.1.0/qt/feedback-plugin/000077500000000000000000000000001402415033400173475ustar00rootroot00000000000000hfd-service-0.1.0/qt/feedback-plugin/CMakeLists.txt000066400000000000000000000017001402415033400221050ustar00rootroot00000000000000find_package(PkgConfig) find_package(Qt5Core REQUIRED) find_package(Qt5DBus REQUIRED) find_package(Qt5Feedback REQUIRED) qt5_add_resources(FEEDBACK_RESOURCES feedback.qrc) set(QTFEEDBACK_HFD_SRC hfd_feedback.h hfd_feedback.cpp ) qt5_add_dbus_interface(QTFEEDBACK_HFD_SRC ${CMAKE_SOURCE_DIR}/data/com.lomiri.hfd.xml hfdInterface ) add_library( qtfeedback_hfd SHARED ${QTFEEDBACK_HFD_SRC} ${FEEDBACK_RESOURCES} ) # Ideally, we would read the plugin installation location from cmake # but this does not work currently. set(PLUGIN_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/qt5/plugins/feedback") # get_target_property(PLUGIN_LOCATION Qt5::Feedback PLUGIN_LOCATION) message(STATUS "Installing Qt5 feedback plugin to: ${PLUGIN_INSTALL_LOCATION}") target_link_libraries( qtfeedback_hfd ${CMAKE_THREAD_LIBS_INIT} Qt5::Core Qt5::DBus Qt5::Feedback ) install( TARGETS qtfeedback_hfd LIBRARY DESTINATION ${PLUGIN_INSTALL_LOCATION}) hfd-service-0.1.0/qt/feedback-plugin/feedback.json000066400000000000000000000000601402415033400217620ustar00rootroot00000000000000{ "Interfaces": ["QFeedbackHapticsInterface"] } hfd-service-0.1.0/qt/feedback-plugin/feedback.qrc000066400000000000000000000001411402415033400215760ustar00rootroot00000000000000 feedback.json hfd-service-0.1.0/qt/feedback-plugin/hfd_feedback.cpp000066400000000000000000000127771402415033400224360ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "hfd_feedback.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hfdInterface.h" hfd::Feedback::Feedback() : QObject(), enabled(false), state(QFeedbackEffect::Stopped) { m_interface = std::make_shared("com.lomiri.hfd", "/com/lomiri/hfd", QDBusConnection::systemBus(), this); actuatorList << createFeedbackActuator(this, 42); } hfd::Feedback::~Feedback() { } QFeedbackInterface::PluginPriority hfd::Feedback::pluginPriority() { return PluginHighPriority; } QList hfd::Feedback::actuators() { return actuatorList; } void hfd::Feedback::setActuatorProperty(const QFeedbackActuator&, ActuatorProperty prop, const QVariant &value) { switch (prop) { case Enabled: enabled = value.toBool(); break; default: break; } } QVariant hfd::Feedback::actuatorProperty(const QFeedbackActuator &actuator, ActuatorProperty prop) { QVariant result; switch (prop) { case Name: result = QString::fromLocal8Bit("Hfd Vibrator"); break; case State: result = actuator.isValid() ? QFeedbackActuator::Ready : QFeedbackActuator::Unknown; break; case Enabled: result = enabled; break; } return result; } bool hfd::Feedback::isActuatorCapabilitySupported(const QFeedbackActuator &, QFeedbackActuator::Capability cap) { bool result = false; switch(cap) { case QFeedbackActuator::Envelope: result = true; break; case QFeedbackActuator::Period: result = false; break; } return result; } void hfd::Feedback::updateEffectProperty(const QFeedbackHapticsEffect *, EffectProperty) { } void hfd::Feedback::hapticsVibrateReply(QDBusPendingCallWatcher *watcher, int period, int repeat) { QDBusPendingReply<> reply = *watcher; if (reply.isError()) { qWarning() << "Failed to vibrate with pattern:" << reply.error().message(); state = QFeedbackEffect::Stopped; } else { if ((repeat == QFeedbackEffect::Infinite) || (--repeat > 0)) QTimer::singleShot(period*2, [=]() { vibrate(period, repeat); }); else state = QFeedbackEffect::Stopped; } watcher->deleteLater(); } void hfd::Feedback::vibrate(int period, int repeat) { if (!(period && repeat)) state = QFeedbackEffect::Stopped; if (state != QFeedbackEffect::Running) { // Maybe stopped/paused before this async call. return; } QDBusInterface iface("com.lomiri.hfd", "/com/lomiri/hfd", "com.lomiri.hfd.Vibrator"); QDBusPendingCall call = m_interface->vibrate(period); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, &QDBusPendingCallWatcher::finished, [=](){ hapticsVibrateReply(watcher, period, repeat); }); } void hfd::Feedback::startVibration(const QFeedbackHapticsEffect *effect) { int duration = effect->duration(); if (duration == 0) duration = 150; int period = effect->period(); int repeat; if ((duration == QFeedbackEffect::Infinite) || (duration < 0)) { // If duration is set to QFeedbackEffect::Infinite or a negative // value, we repeat this effect forever until stopped. The // effective period should have been set to a positive value or // 150ms by default. duration = QFeedbackEffect::Infinite; repeat = QFeedbackEffect::Infinite; if (period <= 0) period = 150; } else if (period <= 0) { // If duration is set to a positive value and period is invalid, // then use duration as period. repeat = 1; period = duration; } else { // Otherwise, repeat this effect as many times as the duration // may cover the effect period. repeat = (duration + period - 1) / period; } vibrate(period, repeat); } void hfd::Feedback::setEffectState(const QFeedbackHapticsEffect *effect, QFeedbackEffect::State state) { this->state = state; switch (state) { case QFeedbackEffect::Stopped: break; case QFeedbackEffect::Paused: break; case QFeedbackEffect::Running: QTimer::singleShot(0, [=]() { startVibration(effect); }); break; case QFeedbackEffect::Loading: break; } } QFeedbackEffect::State hfd::Feedback::effectState(const QFeedbackHapticsEffect *) { return state; } hfd-service-0.1.0/qt/feedback-plugin/hfd_feedback.h000066400000000000000000000042301402415033400220640ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include #include #include #include class QDBusPendingCallWatcher; class ComLomiriHfdVibratorInterface; namespace hfd { class Feedback : public QObject, public QFeedbackHapticsInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtFeedbackPlugin" FILE "feedback.json") Q_INTERFACES(QFeedbackHapticsInterface) public: Feedback(); virtual ~Feedback(); // From QFeedbackHapticsInterface virtual PluginPriority pluginPriority(); QList actuators(); QFeedbackEffect::State effectState(const QFeedbackHapticsEffect *); void setEffectState (const QFeedbackHapticsEffect* effect, QFeedbackEffect::State state); bool isActuatorCapabilitySupported(const QFeedbackActuator &, QFeedbackActuator::Capability); void setActuatorProperty(const QFeedbackActuator &, ActuatorProperty, const QVariant &); QVariant actuatorProperty(const QFeedbackActuator &, ActuatorProperty); void updateEffectProperty(const QFeedbackHapticsEffect* effect, EffectProperty property); private: std::shared_ptr m_interface; QList actuatorList; void hapticsVibrateReply(QDBusPendingCallWatcher *watcher, int period, int repeat); void vibrate(int period, int repeat); void startVibration(const QFeedbackHapticsEffect *effect); bool enabled; QFeedbackEffect::State state; }; } hfd-service-0.1.0/qt/qml/000077500000000000000000000000001402415033400151205ustar00rootroot00000000000000hfd-service-0.1.0/qt/qml/CMakeLists.txt000066400000000000000000000006341402415033400176630ustar00rootroot00000000000000find_package(QmlPlugins) find_package(Qt5Gui REQUIRED) set(HFD_QML_SRC plugin.cpp leds.cpp ) qt5_add_dbus_interface(HFD_QML_SRC ${CMAKE_SOURCE_DIR}/data/com.lomiri.hfd.xml hfdInterface ) add_library(hfd-qml MODULE ${HFD_QML_SRC} ) target_link_libraries(hfd-qml hfd-core Qt5::Core Qt5::Gui Qt5::DBus ) add_qmlplugin( Hfd 1.0 Hfd TARGET_PREFIX Hfd TARGETS hfd-qml ) hfd-service-0.1.0/qt/qml/leds.cpp000066400000000000000000000044051402415033400165560ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "leds.h" #include #include "hfdInterface.h" Leds::Leds(QObject* parent) : QObject(parent), m_color("blue"), m_state(Leds::Off), m_onMs(1000), m_offMs(3000) { m_interface = std::make_shared("com.lomiri.hfd", "/com/lomiri/hfd", QDBusConnection::systemBus(), this); } void Leds::setState(Leds::State newState) { if (m_state != newState) { // Make sure all values are up-to-date before setting state on if (newState == State::On) { m_interface->setColor(m_color.rgba()); m_interface->setOnMs(m_onMs); m_interface->setOffMs(m_offMs); } m_interface->setState(newState); m_state = newState; Q_EMIT stateChanged(m_state); } } Leds::State Leds::state() const { return m_state; } void Leds::setColor(const QColor &color) { if (m_color != color) { m_interface->setColor(color.rgba()); m_color = color; Q_EMIT colorChanged(m_color); } } QColor Leds::color() const { return m_color; } int Leds::onMillisec() const { return m_onMs; } void Leds::setOnMillisec(int onMs) { if (m_onMs != onMs) { m_interface->setOnMs(onMs); m_onMs = onMs; Q_EMIT onMillisecChanged(m_onMs); } } int Leds::offMillisec() const { return m_offMs; } void Leds::setOffMillisec(int offMs) { if (m_offMs != offMs) { m_interface->setOffMs(offMs); m_offMs = offMs; Q_EMIT offMillisecChanged(m_offMs); } } hfd-service-0.1.0/qt/qml/leds.h000066400000000000000000000036261402415033400162270ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include #include #include class ComLomiriHfdLedsInterface; class Leds: public QObject { Q_OBJECT Q_PROPERTY(State state READ state WRITE setState NOTIFY stateChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(int onMillisec READ onMillisec WRITE setOnMillisec NOTIFY onMillisecChanged) Q_PROPERTY(int offMillisec READ offMillisec WRITE setOffMillisec NOTIFY offMillisecChanged) public: enum State { Off = 0, On = 1, }; Q_ENUM(State) explicit Leds(QObject *parent = 0); void setState(State newState); State state() const; void setColor(const QColor &color); QColor color() const; int onMillisec() const; void setOnMillisec(int onMs); int offMillisec() const; void setOffMillisec(int offMs); Q_SIGNALS: void stateChanged(State newState); void colorChanged(const QColor &color); void onMillisecChanged(int onMs); void offMillisecChanged(int offMs); private: std::shared_ptr m_interface; QColor m_color; State m_state; int m_onMs; int m_offMs; void turnOff(); void turnOn(); }; hfd-service-0.1.0/qt/qml/plugin.cpp000066400000000000000000000020731402415033400171240ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "plugin.h" #include "leds.h" #include static QObject *leds_provider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return new Leds(); } void HfdPlugin::registerTypes(const char *uri) { Q_ASSERT(uri == QLatin1String("Hfd")); qmlRegisterSingletonType(uri, 0, 1, "Leds", leds_provider); } hfd-service-0.1.0/qt/qml/plugin.h000066400000000000000000000017171402415033400165750ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include #include class HfdPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: void registerTypes(const char *uri) override; }; hfd-service-0.1.0/qt/qml/qmldir000066400000000000000000000000601402415033400163270ustar00rootroot00000000000000module Hfd plugin hfd-qml typeinfo hfd.qmltypes hfd-service-0.1.0/src/000077500000000000000000000000001402415033400144725ustar00rootroot00000000000000hfd-service-0.1.0/src/CMakeLists.txt000066400000000000000000000016361402415033400172400ustar00rootroot00000000000000add_subdirectory(udev) if (HAVE_LIBHYBRIS) include_directories( ${ANDROID_HEADERS_INCLUDE_DIRS} ) set(LIBHYBRIS_SRC leds-hybris.cpp ) set(LIBHYBRIS_LIBRARIES ${ANDROID_HARDWARE_LIBRARIES} ) add_definitions(-DHAVE_LIBHYBRIS) endif() add_library(hfd-core STATIC leds.cpp leds-sysfs.cpp vibrator.cpp vibrator-ff.cpp vibrator-sysfs.cpp vibrator-legacy.cpp ${LIBHYBRIS_SRC} ) target_link_libraries(hfd-core udev-cpp ${LIBHYBRIS_LIBRARIES} ) set(SERVICE_SRC service.cpp dbusAdaptor.h ) qt5_add_dbus_adaptor(SERVICE_SRC ${CMAKE_SOURCE_DIR}/data/com.lomiri.hfd.xml ${CMAKE_CURRENT_SOURCE_DIR}/dbusAdaptor.h DbusAdaptor ) add_executable(hfd-service ${SERVICE_SRC} ) target_link_libraries(hfd-service hfd-core Qt5::Core Qt5::DBus ) install(TARGETS hfd-service RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) hfd-service-0.1.0/src/common.h000066400000000000000000000014171402415033400161360ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once namespace hfd { enum State { Off, On }; } hfd-service-0.1.0/src/dbusAdaptor.h000066400000000000000000000022351402415033400171150ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include class DbusAdaptor : public QObject { Q_OBJECT public: DbusAdaptor(QObject *parent = 0) : QObject(parent) {}; public Q_SLOTS: virtual void vibrate() = 0; virtual void vibrate(int durationMs) = 0; virtual void rumble(int durationMs, int repeat) = 0; virtual void setState(int state) = 0; virtual void setColor(unsigned int color) = 0; virtual void setOnMs(int ms) = 0; virtual void setOffMs(int ms) = 0; }; hfd-service-0.1.0/src/leds-hybris.cpp000066400000000000000000000061621402415033400174300ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "leds-hybris.h" #include #include extern "C" { #include #include #include } // legacy hybris support namespace hfd { light_device_t* getLightDevice() { int err; hw_module_t* module; light_device_t* lightDevice; err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { hw_device_t* device; err = module->methods->open(module, LIGHT_ID_NOTIFICATIONS, &device); if (err == 0 && device) { lightDevice = (light_device_t*)device; return lightDevice; } else { std::cout << "Failed to access notification lights" << std::endl; } } else { std::cout << "Failed to initialize lights hardware." << std::endl; } return nullptr; } bool LedsHybris::usable() { light_device_t* lightDevice = getLightDevice(); const bool loaded = (lightDevice != nullptr); if (lightDevice) { hw_device_t* device = (hw_device_t*) lightDevice; device->close(device); } return loaded; } LedsHybris::LedsHybris() : Leds() { if (m_lightDevice) { return; } m_lightDevice = getLightDevice(); if (m_lightDevice) turnOff(); // Get up to date configure(); } LedsHybris::~LedsHybris() { if (m_lightDevice) { hw_device_t* device = (hw_device_t*) m_lightDevice; device->close(device); } } void LedsHybris::configure() { if (m_state == State::On) turnOn(); else turnOff(); } void LedsHybris::turnOn() { // pulse light_state_t state; memset(&state, 0, sizeof(light_state_t)); state.color = m_color; state.flashMode = LIGHT_FLASH_TIMED; state.flashOnMS = m_onMs; state.flashOffMS = m_offMs; state.brightnessMode = BRIGHTNESS_MODE_USER; if (!m_lightDevice) return; if (m_lightDevice->set_light(m_lightDevice, &state) != 0) { std::cout << "Failed to turn the light off"; } } void LedsHybris::turnOff() { light_state_t state; memset(&state, 0, sizeof(light_state_t)); state.color = 0x00000000; state.flashMode = LIGHT_FLASH_NONE; state.flashOnMS = 0; state.flashOffMS = 0; state.brightnessMode = 0; if (!m_lightDevice) return; if (m_lightDevice->set_light(m_lightDevice, &state) != 0) { std::cout << "Failed to turn the light off"; } } } hfd-service-0.1.0/src/leds-hybris.h000066400000000000000000000017611402415033400170750ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "leds.h" struct light_device_t; namespace hfd { class LedsHybris : public Leds { public: LedsHybris(); ~LedsHybris(); static bool usable(); protected: void configure() override; private: void turnOn(); void turnOff(); light_device_t* m_lightDevice = nullptr; }; } hfd-service-0.1.0/src/leds-sysfs.cpp000066400000000000000000000102001402415033400172630ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "leds-sysfs.h" #include "utils.h" #include #include #include static bool has_timer_trigger(Udev::UdevDevice const& dev) { std::string trigger_value; try { // get_sysattr() always gives the full list of available values. trigger_value = dev.get_sysattr("trigger"); } catch (std::runtime_error const&) { return false; } /* * Word "timer" maybe at the start or the end, in the middle surrounded by * spaces, or surrounded by '[' and ']'. */ static std::regex timer_re("(^|[[ ])timer([] ]|$)", std::regex_constants::extended); return std::regex_search(trigger_value, timer_re); } namespace hfd { bool LedsSysfs::usable() { if (access("/sys/class/leds", F_OK ) == -1) return false; Udev::Udev udev; Udev::UdevEnumerate enumerator = udev.enumerate_new(); enumerator.add_match_sysattr("subsystem","leds"); enumerator.scan_devices(); bool red, green, blue = false; for (auto dev : enumerator.enumerate_devices()) { auto splitted = utils::split(dev.get_sysname(), ':'); for (auto color : splitted) { std::cout << "got: " << color << std::endl; if (color == "red") red = has_timer_trigger(dev); if (color == "green") green = has_timer_trigger(dev); if (color == "blue") blue = has_timer_trigger(dev); } } return (red && green && blue); } LedsSysfs::LedsSysfs(): Leds() { Udev::Udev udev; Udev::UdevEnumerate enumerator = udev.enumerate_new(); enumerator.add_match_sysattr("subsystem","leds"); enumerator.scan_devices(); for (auto dev : enumerator.enumerate_devices()) { auto splitted = utils::split(dev.get_sysname(), ':'); for (auto color : splitted) { std::cout << "got: " << color << std::endl; if (color == "red") m_rgbDevices[Colors::RED] = dev; if (color == "green") m_rgbDevices[Colors::GREEN] = dev; if (color == "blue") m_rgbDevices[Colors::BLUE] = dev; } } for (auto dev : m_rgbDevices) { dev.second.set_sysattr("trigger", "timer"); } m_timer = true; // Get up to date configure(); } // Over simplyfied led controlls! void LedsSysfs::configure() { if (m_state == State::On) { std::cout << "red: " << std::to_string(rgba::Red(m_color)) << std::endl; std::cout << "green: " << std::to_string(rgba::Green(m_color)) << std::endl; std::cout << "blue: " << std::to_string(rgba::Blue(m_color)) << std::endl; setDelay(); setLed(Colors::RED, rgba::Red(m_color)); setLed(Colors::GREEN, rgba::Green(m_color)); setLed(Colors::BLUE, rgba::Blue(m_color)); } else { m_rgbDevices[Colors::RED].set_sysattr("brightness", "0"); m_rgbDevices[Colors::GREEN].set_sysattr("brightness", "0"); m_rgbDevices[Colors::BLUE].set_sysattr("brightness", "0"); } } void LedsSysfs::setDelay() { if (m_timer) { for (auto dev : m_rgbDevices) { dev.second.set_sysattr("trigger", "timer"); dev.second.set_sysattr("delay_on", std::to_string(m_onMs)); dev.second.set_sysattr("delay_off", std::to_string(m_offMs)); } } } void LedsSysfs::setLed(Colors color, int value) { m_rgbDevices[color].set_sysattr("brightness", std::to_string(value)); } } hfd-service-0.1.0/src/leds-sysfs.h000066400000000000000000000021561402415033400167430ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include "leds.h" #include #include "udev/udev-cpp.h" namespace hfd { class LedsSysfs : public Leds { public: LedsSysfs(); static bool usable(); protected: void configure() override; private: enum Colors { RED = 0, GREEN = 1, BLUE = 2 }; void setDelay(); void setLed(Colors color, int value); std::map m_rgbDevices; }; } hfd-service-0.1.0/src/leds.cpp000066400000000000000000000055271402415033400161360ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "leds.h" #include "leds-sysfs.h" #ifdef HAVE_LIBHYBRIS #include "leds-hybris.h" #endif #include namespace hfd { class LedsDummy : public Leds { public: LedsDummy() = default; protected: void configure() override { if (m_state == State::On) { std::cout << "LedsDummy on, color: " << m_color << std::endl; } else { std::cout << "LedsDummy off" << std::endl; } }; }; std::shared_ptr Leds::create() { #ifdef HAVE_LIBHYBRIS if (LedsHybris::usable()) { std::cout << "Using hybris leds" << std::endl; return std::make_shared(); } else #endif if (LedsSysfs::usable()) { std::cout << "Using sysfs leds" << std::endl; return std::make_shared(); } std::cout << "Using dummy leds" << std::endl; return std::make_shared(); } std::shared_ptr Leds::create(std::string type) { if (type == "sysfs") { std::cout << "Using sysfs leds" << std::endl; return std::make_shared(); } #ifdef HAVE_LIBHYBRIS else if (type == "hybris") { std::cout << "Using hybris leds" << std::endl; return std::make_shared(); } #endif std::cout << "Using dummy leds" << std::endl; return std::make_shared(); } Leds::Leds() : m_color(0x00ff0080), m_state(State::Off), m_onMs(1000), m_offMs(3000) { } void Leds::setState(State newState) { m_state = newState; configure(); } State Leds::state() const { return m_state; } void Leds::setColor(const Rgba &color) { if (m_color != color) { m_color = color; if (m_state == State::On) configure(); } } Rgba Leds::color() const { return m_color; } int Leds::onMs() const { return m_onMs; } void Leds::setOnMs(int onMs) { if (m_onMs != onMs) { m_onMs = onMs; if (m_state == State::On) configure(); } } int Leds::offMs() const { return m_offMs; } void Leds::setOffMs(int offMs) { if (m_offMs != offMs) { m_offMs = offMs; if (m_state == State::On) configure(); } } } hfd-service-0.1.0/src/leds.h000066400000000000000000000025171402415033400155770ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include "common.h" #include "rgba.h" #include namespace hfd { class Leds { public: Leds(); void turnOn(const Rgba &color, int onMs, int offMs); void setState(State state); State state() const; void setColor(const Rgba &color); Rgba color() const; int onMs() const; void setOnMs(int onMs); int offMs() const; void setOffMs(int offMs); static std::shared_ptr create(); static std::shared_ptr create(std::string type); protected: virtual void configure() = 0; Rgba m_color; State m_state; int m_onMs; int m_offMs; bool m_timer = false; }; } hfd-service-0.1.0/src/repeatThread.h000066400000000000000000000040761402415033400172620ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include #include #include #include #include namespace hfd { class RepeatThread { public: RepeatThread(std::function func, int sleep, int times) : m_func(func) , m_times(times) , m_sleepMs(sleep) , m_thread(&RepeatThread::runner, this) {}; ~RepeatThread() { abort(); }; inline void abort() { { std::lock_guard lock(m_mutex); m_break = true; m_cv.notify_all(); } m_thread.join(); }; private: inline void runner() { for (auto i = 0; i <= m_times; i++) { { std::unique_lock lock(m_mutex); auto timeout = std::chrono::steady_clock::now() + m_sleepMs; bool is_stopped = m_cv.wait_until(lock, timeout, [&]() { return m_break; }); if (is_stopped) break; } // Call m_func() without the lock; we don't support canceling // in the middle. m_func(); } }; std::mutex m_mutex; std::condition_variable m_cv; bool m_break = false; int m_times; std::chrono::milliseconds m_sleepMs; std::function m_func; std::thread m_thread; }; } hfd-service-0.1.0/src/rgba.h000066400000000000000000000017711402415033400155640ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once typedef unsigned int Rgba; namespace hfd { namespace rgba { inline int Red(Rgba rgb) { return ((rgb >> 16) & 0xff); } inline int Green(Rgba rgb) { return ((rgb >> 8) & 0xff); } inline int Blue(Rgba rgb) { return (rgb & 0xff); } inline int Alpha(Rgba rgb) { return rgb >> 24; } } } hfd-service-0.1.0/src/service.cpp000066400000000000000000000060471402415033400166450ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "dbusAdaptor.h" #include "vibrator.h" #include "leds.h" #include "utils.h" #include "hfdadaptor.h" #include #include #include class DbusAdaptorService : public DbusAdaptor { Q_OBJECT public: DbusAdaptorService(std::shared_ptr vibrator, std::shared_ptr leds) : DbusAdaptor() , m_vibrator(vibrator) , m_leds(leds) {} public Q_SLOTS: void vibrate() override { m_vibrator->vibrate(); }; void vibrate(int durationMs) override {m_vibrator->vibrate(durationMs); }; void rumble(int durationMs, int repeat) override { m_vibrator->rumble(durationMs, repeat); }; void setState(int state) override { m_leds->setState(hfd::utils::toState(state)); }; void setColor(unsigned int color) override { m_leds->setColor(color); } void setOnMs(int ms) override { m_leds->setOnMs(ms); }; void setOffMs(int ms) override { m_leds->setOffMs(ms); }; private: std::shared_ptr m_vibrator; std::shared_ptr m_leds; }; #include "service.moc" int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); // Environment variables to switch between implementations const char* vibrator_impl_env = getenv("HFD_VIBRATOR_IMPL"); const char* leds_impl_env = getenv("HFD_LEDS_IMPL"); std::cout << "Starting vibrator impl" << std::endl; std::shared_ptr vibrator; if (vibrator_impl_env) vibrator = hfd::Vibrator::create(vibrator_impl_env); else vibrator = hfd::Vibrator::create(); std::cout << "Starting leds impl" << std::endl; std::shared_ptr leds; if (leds_impl_env) leds = hfd::Leds::create(leds_impl_env); else leds = hfd::Leds::create(); std::cout << "done" << std::endl; auto dbusAdaptor = new DbusAdaptorService(vibrator, leds); new VibratorAdaptor(dbusAdaptor); new LedsAdaptor(dbusAdaptor); QDBusConnection connection = QDBusConnection::systemBus(); connection.registerObject("/com/lomiri/hfd", dbusAdaptor); connection.registerService("com.lomiri.hfd"); if (connection.lastError().isValid()) { std::cout << "Not connected to DBus!!!" << std::endl; qWarning() << connection.lastError(); return 1; } std::cout << "Started dbus conn" << std::endl; return app.exec(); } hfd-service-0.1.0/src/udev/000077500000000000000000000000001402415033400154355ustar00rootroot00000000000000hfd-service-0.1.0/src/udev/CMakeLists.txt000066400000000000000000000002431402415033400201740ustar00rootroot00000000000000 add_library(udev-cpp STATIC udev.cpp udevDevice.cpp udevEnumerate.cpp udevMonitor.cpp ) target_link_libraries(udev-cpp ${UDEV_LIBRARIES} ) hfd-service-0.1.0/src/udev/udev-cpp.h000066400000000000000000000114501402415033400173320ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include #include #include #include namespace Udev { using UdevHandle = struct udev; using UdevMonitorHandle = struct udev_monitor; using UdevDeviceHandle = struct udev_device; using UdevEnumerateHandle = struct udev_enumerate; class UdevMonitor; class UdevDevice; class UdevEnumerate; /** * Class representing a udev context */ class Udev { public: /** * Acquire new udev context */ explicit Udev(); Udev(const Udev& other); Udev(Udev&& other); Udev& operator=(const Udev& other); Udev& operator=(Udev&& other); ~Udev(); /** * Create new udev monitor for netlink described by @name. * @param name Name can be "udev" or "kernel" (default is "udev") * @return A {@link UdevMonitor} instance */ UdevMonitor monitor_new_from_netlink(const char *name = "udev"); UdevDevice device_from_syspath(std::string) const; /** * Create new udev enumerator * @return A {@link UdevEnumerator} instance which can be used to enumerate devices known to udev */ UdevEnumerate enumerate_new(); private: UdevHandle *handle; }; /** * Class that encapsulates monitoring functionality provided by Udev */ class UdevMonitor { public: UdevMonitor(UdevMonitorHandle *monitor); UdevMonitor(const UdevMonitor &other); UdevMonitor(UdevMonitor &&other); UdevMonitor& operator=(const UdevMonitor &monitor); UdevMonitor& operator=(UdevMonitor &&monitor); ~UdevMonitor(); void enable_receiving() const; int get_fd() const; UdevDevice receive_device() const; private: UdevMonitorHandle *handle; }; /** * Class that encapsulated enumeration functionality provided by Udev */ class UdevEnumerate { public: UdevEnumerate(UdevEnumerateHandle *enumerate); UdevEnumerate(const UdevEnumerate &other); UdevEnumerate(UdevEnumerate &&other); UdevEnumerate &operator=(const UdevEnumerate &other); UdevEnumerate &operator=(UdevEnumerate &&other); ~UdevEnumerate(); void add_match_subsystem(const std::string subsystem) const; void add_nomatch_subsystem(const std::string subsystem) const; void add_match_sysattr(const std::string sysattr, const std::string value = "") const; void add_nomatch_sysattr(const std::string sysattr, const std::string value = "") const; void add_match_property(const std::string property, const std::string value) const; void add_match_tag(const std::string tag) const; void add_match_is_initialized() const; void scan_devices() const; void scan_subsystems() const; std::vector enumerate_devices() const; private: UdevEnumerateHandle *handle; }; /** * Class that encapsulates the concept of a device as described by Udev */ class UdevDevice { public: UdevDevice(UdevDeviceHandle *device); UdevDevice(const UdevDevice &); UdevDevice(UdevDevice &&); UdevDevice() = default; UdevDevice& operator=(const UdevDevice &); UdevDevice& operator=(UdevDevice &&); ~UdevDevice(); bool is_initialized() const; bool has_action() const; std::string get_action() const; bool has_devnode() const; std::string get_devnode() const; bool has_devtype() const; std::string get_devtype() const; bool has_subsystem() const; std::string get_subsystem() const; std::string get_devpath() const; std::string get_syspath() const; std::string get_sysname() const; bool has_sysnum() const; std::string get_sysnum() const; bool has_driver() const; std::string get_driver() const; bool has_sysattr(const std::string named) const; std::string get_sysattr(const std::string named) const; void set_sysattr(const std::string named, const std::string value) const; std::vector get_sysattr_keys() const; std::map get_sysattr_map() const; std::vector get_devlinks() const; bool has_property(const std::string named) const; std::string get_property(const std::string named) const; std::map get_properties() const; bool has_tag(const std::string named) const; std::vector get_tags() const; private: UdevDeviceHandle *handle; }; } hfd-service-0.1.0/src/udev/udev.cpp000066400000000000000000000024041402415033400171040ustar00rootroot00000000000000#include #include #include #include #include "udev-cpp.h" namespace Udev { Udev::Udev() : handle(udev_new()) { } Udev::Udev(const Udev &other) : handle(udev_ref(other.handle)) { } Udev::Udev(Udev &&other) : handle(other.handle) { other.handle = nullptr; } Udev& Udev::operator=(const Udev &other) { this->handle = udev_ref(other.handle); return *this; } Udev& Udev::operator=(Udev &&other) { this->handle = other.handle; other.handle = nullptr; return *this; } Udev::~Udev() { if (handle) { udev_unref(handle); } } UdevMonitor Udev::monitor_new_from_netlink(const char *name) { assert(name != nullptr && (std::string(name) == "udev" || std::string(name) == "kernel")); return UdevMonitor(udev_monitor_new_from_netlink(handle, name)); } UdevDevice Udev::device_from_syspath(std::string syspath) const { UdevDeviceHandle *devicep = udev_device_new_from_syspath(handle, syspath.c_str()); if (devicep == NULL) { throw std::runtime_error((std::string("Error while creating UdevDevice from syspath, error is: ") + std::strerror(errno)).c_str()); } return UdevDevice(devicep); } UdevEnumerate Udev::enumerate_new() { return UdevEnumerate(udev_enumerate_new(handle)); } } hfd-service-0.1.0/src/udev/udevDevice.cpp000066400000000000000000000125541402415033400202330ustar00rootroot00000000000000#include #include #include #include "udev-cpp.h" namespace Udev { UdevDevice::UdevDevice(UdevDeviceHandle *device) : handle(device) { } UdevDevice::UdevDevice(const UdevDevice &other) : handle(udev_device_ref(other.handle)) { } UdevDevice::UdevDevice(UdevDevice &&other) : handle(other.handle) { other.handle = nullptr; } UdevDevice& UdevDevice::operator=(const UdevDevice &other) { handle = udev_device_ref(other.handle); return *this; } UdevDevice& UdevDevice::operator=(UdevDevice &&other) { handle = udev_device_ref(other.handle); other.handle = nullptr; return *this; } UdevDevice::~UdevDevice() { if (handle) { udev_device_unref(handle); } } bool UdevDevice::is_initialized() const { return udev_device_get_is_initialized(handle) == 1; } bool UdevDevice::has_action() const { return udev_device_get_action(handle) != nullptr; } std::string UdevDevice::get_action() const { return std::string(udev_device_get_action(handle)); } bool UdevDevice::has_devnode() const { return udev_device_get_devnode(handle) != nullptr; } std::string UdevDevice::get_devnode() const { return udev_device_get_devnode(handle); } bool UdevDevice::has_devtype() const { return udev_device_get_devtype(handle) != nullptr; } std::string UdevDevice::get_devtype() const { return udev_device_get_devtype(handle); } bool UdevDevice::has_subsystem() const { return udev_device_get_subsystem(handle) != nullptr; } std::string UdevDevice::get_subsystem() const { return udev_device_get_subsystem(handle); } std::string UdevDevice::get_devpath() const { return udev_device_get_devpath(handle); } std::string UdevDevice::get_syspath() const { return udev_device_get_syspath(handle); } std::string UdevDevice::get_sysname() const { return udev_device_get_sysname(handle); } bool UdevDevice::has_sysnum() const { return udev_device_get_sysnum(handle) != nullptr; } std::string UdevDevice::get_sysnum() const { return udev_device_get_sysnum(handle); } bool UdevDevice::has_driver() const { return udev_device_get_driver(handle) != nullptr; } std::string UdevDevice::get_driver() const { return udev_device_get_driver(handle); } bool UdevDevice::has_sysattr(const std::string named) const { auto keys = get_sysattr_keys(); return std::find(keys.begin(), keys.end(), named) != keys.end(); } std::string UdevDevice::get_sysattr(const std::string named) const { const char *value = udev_device_get_sysattr_value(handle, named.c_str()); if (value == nullptr) { throw std::runtime_error("systemattr does not exist or could not be retrieved"); } return std::string(value); } void UdevDevice::set_sysattr(const std::string named, const std::string value) const { int ret = udev_device_set_sysattr_value(handle, named.c_str(), (char*)value.c_str()); if (ret < 0) { throw std::runtime_error("systemattr does not exist or could not be set to requested value (check permissions)"); } return; } std::vector UdevDevice::get_sysattr_keys() const { std::vector keys; auto sysattr_list = udev_device_get_sysattr_list_entry(handle); struct udev_list_entry *entry = nullptr; udev_list_entry_foreach(entry, sysattr_list) { keys.emplace_back(udev_list_entry_get_name(entry)); } return keys; } std::map UdevDevice::get_sysattr_map() const { std::map attr; auto sysattr_list = udev_device_get_sysattr_list_entry(handle); struct udev_list_entry *entry = nullptr; udev_list_entry_foreach(entry, sysattr_list) { const char *key = udev_list_entry_get_name(entry); const char *value = udev_device_get_sysattr_value(handle, key); if (entry != nullptr) { if (key != nullptr && value != nullptr) { attr[std::string(udev_list_entry_get_name(entry))] = std::string(value); } } } return attr; } std::vector UdevDevice::get_devlinks() const { std::vector links; struct udev_list_entry *entry = nullptr; udev_list_entry_foreach(entry, udev_device_get_devlinks_list_entry(handle)) { links.emplace_back(udev_list_entry_get_name(entry)); } return links; } bool UdevDevice::has_property(const std::string named) const { return udev_device_get_property_value(handle, named.c_str()) != nullptr; } std::string UdevDevice::get_property(const std::string named) const { return udev_device_get_property_value(handle, named.c_str()); } std::map UdevDevice::get_properties() const { std::map property_map; struct udev_list_entry *entry = nullptr; struct udev_list_entry *properties = udev_device_get_properties_list_entry(handle); udev_list_entry_foreach(entry, properties) { property_map[std::string(udev_list_entry_get_name(entry))] = std::string(udev_list_entry_get_value(entry)); } return property_map; } bool UdevDevice::has_tag(const std::string named) const { return udev_device_has_tag(handle, named.c_str()); } std::vector UdevDevice::get_tags() const { std::vector tags; struct udev_list_entry *entry; struct udev_list_entry *tags_list = udev_device_get_tags_list_entry(handle); udev_list_entry_foreach(entry, tags_list) { tags.emplace_back(udev_list_entry_get_name(entry)); } return tags; } } hfd-service-0.1.0/src/udev/udevEnumerate.cpp000066400000000000000000000047721402415033400207640ustar00rootroot00000000000000#include #include "udev-cpp.h" #include namespace Udev { UdevEnumerate::UdevEnumerate(UdevEnumerateHandle *enumerate) : handle(enumerate) { } UdevEnumerate::UdevEnumerate(const UdevEnumerate &other) : handle(udev_enumerate_ref(other.handle)) { } UdevEnumerate::UdevEnumerate(UdevEnumerate &&other) : handle(other.handle) { other.handle = nullptr; } UdevEnumerate &UdevEnumerate::operator=(const UdevEnumerate &other) { udev_enumerate_ref(other.handle); return *this; } UdevEnumerate &UdevEnumerate::operator=(UdevEnumerate &&other) { handle = other.handle; other.handle = nullptr; return *this; } UdevEnumerate::~UdevEnumerate() { if (handle) { udev_enumerate_unref(handle); } } void UdevEnumerate::add_match_subsystem(const std::string subsystem) const { udev_enumerate_add_match_subsystem(handle, subsystem.c_str()); } void UdevEnumerate::add_nomatch_subsystem(const std::string subsystem) const { udev_enumerate_add_nomatch_subsystem(handle, subsystem.c_str()); } void UdevEnumerate::add_match_sysattr(const std::string sysattr, const std::string value) const { udev_enumerate_add_match_sysattr(handle, sysattr.c_str(), value.length() > 0 ? value.c_str() : nullptr); } void UdevEnumerate::add_nomatch_sysattr(const std::string sysattr, const std::string value) const { udev_enumerate_add_nomatch_sysattr(handle, sysattr.c_str(), value.length() > 0 ? value.c_str() : nullptr); } void UdevEnumerate::add_match_property(const std::string property, const std::string value) const { udev_enumerate_add_match_property(handle, property.c_str(), value.c_str()); } void UdevEnumerate::add_match_tag(const std::string tag) const { udev_enumerate_add_match_tag(handle, tag.c_str()); } void UdevEnumerate::add_match_is_initialized() const { udev_enumerate_add_match_is_initialized(handle); } void UdevEnumerate::scan_devices() const { udev_enumerate_scan_devices(handle); } void UdevEnumerate::scan_subsystems() const { udev_enumerate_scan_subsystems(handle); } std::vector UdevEnumerate::enumerate_devices() const { std::vector devices; struct udev_list_entry *entry = nullptr; struct udev_list_entry *enumeration_list = udev_enumerate_get_list_entry(handle); udev_list_entry_foreach(entry, enumeration_list) { const char *device_path = udev_list_entry_get_name(entry); devices.emplace_back(udev_device_new_from_syspath(udev_enumerate_get_udev(handle), device_path)); } return devices; } } hfd-service-0.1.0/src/udev/udevMonitor.cpp000066400000000000000000000022641402415033400204600ustar00rootroot00000000000000#include #include #include "udev-cpp.h" namespace Udev { UdevMonitor::UdevMonitor(UdevMonitorHandle *monitor) : handle(monitor) { } UdevMonitor::UdevMonitor(const UdevMonitor& other) : handle(udev_monitor_ref(other.handle)) { } UdevMonitor::UdevMonitor(UdevMonitor&& other) : handle(other.handle) { other.handle = nullptr; } UdevMonitor& UdevMonitor::operator=(const UdevMonitor& other) { handle = udev_monitor_ref(other.handle); return *this; } UdevMonitor& UdevMonitor::operator=(UdevMonitor&& other) { handle = other.handle; other.handle = nullptr; return *this; } UdevMonitor::~UdevMonitor() { if (handle) { udev_monitor_unref(handle); } } void UdevMonitor::enable_receiving() const { if (udev_monitor_enable_receiving(handle) != 0) { throw std::runtime_error("Unable to enable receiving of events"); } } int UdevMonitor::get_fd() const { return udev_monitor_get_fd(handle); } UdevDevice UdevMonitor::receive_device() const { auto device = udev_monitor_receive_device(handle); if (device == nullptr) { throw std::runtime_error("Device could not be received"); } return UdevDevice(device); } } hfd-service-0.1.0/src/utils.h000066400000000000000000000024121402415033400160020ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include "leds.h" #include #include namespace hfd { namespace utils { inline std::vector split(std::string strToSplit, char delimeter) { std::stringstream ss(strToSplit); std::string item; std::vector splittedStrings; while (std::getline(ss, item, delimeter)) { splittedStrings.push_back(item); } return splittedStrings; }; inline State toState(int state) { if (state == 1) return State::On; return State::Off; } } } hfd-service-0.1.0/src/vibrator-ff.cpp000066400000000000000000000106231402415033400174210ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Caleb Connolly */ #include "vibrator-ff.h" #include #include #include #include #include #include #include #include /* * This vibrator supports devices using the Kernel Force Feedback API. * Mostly Mainline devices. */ namespace hfd { // For this implementation call the static getFirstFFDevice // And check that it didn't return the empty string. bool VibratorFF::usable() { return VibratorFF::getFirstFFDevice().size() > 0; } // This takes a path to a device like '/dev/input/eventX' // And queries the device to see if it supports FF_RUMBLE bool inputDeviceSupportsFF(std::string devname) { int ret; unsigned char features[1 + FF_MAX/8/sizeof(unsigned char)]; int tempFd = open(devname.c_str(), O_RDWR); int request = EVIOCGBIT(EV_FF, sizeof(features)*sizeof(unsigned char)); bool supported = false; ret = ioctl(tempFd, request, &features); if (testBit(FF_RUMBLE, features)) { supported = true; } else { } ret = close(tempFd); if (ret != 0) { std::cerr << "FF: Failed to close " << tempFd << ": " << ret << std::endl; } return supported; } // Create play and/or stop input events to control // the rumble effect we uploaded in the constructor. void VibratorFF::configure(State state, int durationMs) { int ret; struct input_event play; struct input_event stop; if (state == State::On) { std::cout << "rumbling with magnitude: " << effect.u.rumble.strong_magnitude << " for " << durationMs << "ms" << std::endl; play.type = EV_FF; play.code = effect.id; play.value = 1; write(fd, (const void*) &play, sizeof(play)); usleep(durationMs * 1000); } stop.type = EV_FF; stop.code = effect.id; stop.value = 0; write(fd, (const void*) &stop, sizeof(stop)); } // This finds the first device that supports force feedback // and assumes that it supports rumble, which it may not. // We should also query the device feature flags and be SURE std::string VibratorFF::getFirstFFDevice() { Udev::Udev udev; Udev::UdevEnumerate enumerate = udev.enumerate_new(); enumerate.add_match_subsystem("input"); enumerate.scan_devices(); std::vector devices = enumerate.enumerate_devices(); std::cout << "FF: Found " << devices.size() << " input devices" << std::endl; for(int i = 0; i < devices.size(); i++) { const auto properties = devices.at(i).get_properties(); if (properties.find("DEVNAME") != properties.end()) { std::string temp = devices.at(i).get_properties().at("DEVNAME"); if (inputDeviceSupportsFF(temp)) { std::cout << "Using " << temp << std::endl; return temp; } } } return ""; } // Create a force feedback vibrator VibratorFF::VibratorFF(): Vibrator() { int ret; // Find the first available input device that supports // force feedback, we expect this to succeed as the caller // should have called the static 'usable' method first. devname = VibratorFF::getFirstFFDevice(); std::memset(&effect, 0, sizeof(effect)); // Create a rumble effect effect.type = FF_RUMBLE; effect.id = -1; effect.u.rumble.strong_magnitude = 0x6000; // This should be adjustable effect.u.rumble.weak_magnitude = 0; fd = open(devname.c_str(), O_RDWR); if (fd < 0) { std::cerr << "Can't open force feedback device path: " << devname << std::endl; return; } // Upload the effect to the device, this doesn't cause // it to vibrate, just to store the effect in kernel memory. ret = ioctl(fd, EVIOCSFF, &effect); if (ret < 0) { std::cerr << "Failed to upload rumble effect" << std::endl; return; } } VibratorFF::~VibratorFF() { int ret; if (fd > 0) { // Unload the effect ret = ioctl(fd, EVIOCRMFF, effect.id); if (ret < 0) std::cerr << "Failed to unload effect " << effect.id << std::endl; close(fd); } } } hfd-service-0.1.0/src/vibrator-ff.h000066400000000000000000000032141402415033400170640ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Caleb Connolly */ #pragma once #include #include "vibrator.h" #include "udev/udev-cpp.h" // Borrowed from linuxconsole/utils/bitmaskros.h /* Number of bits for 1 unsigned char */ #define nBitsPerUchar (sizeof(unsigned char) * 8) /* Index=Offset of given bit in 1 unsigned char */ #define bitOffsetInUchar(bit) ((bit)%nBitsPerUchar) /* Index=Offset of the unsigned char associated to the bit * at the given index=offset */ #define ucharIndexForBit(bit) ((bit)/nBitsPerUchar) /* Test the bit with given index=offset in an unsigned char array */ #define testBit(bit, array) ((array[ucharIndexForBit(bit)] >> bitOffsetInUchar(bit)) & 1) namespace hfd { class VibratorFF : public Vibrator { public: VibratorFF(); ~VibratorFF(); static bool usable(); static std::string getFirstFFDevice(); protected: void configure(State state, int durationMs) override; private: struct ff_effect effect; std::string devname; int fd; }; } hfd-service-0.1.0/src/vibrator-legacy.cpp000066400000000000000000000027471402415033400203020ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "vibrator-legacy.h" #include #include // if the kernel support led triggers // we set namespace hfd { bool VibratorLegacy::usable() { return access("/sys/class/timed_output/vibrator", F_OK ) != -1; } VibratorLegacy::VibratorLegacy(): Vibrator() { Udev::Udev udev; m_device = udev.device_from_syspath("/sys/class/timed_output/vibrator"); // Make sure we are off on init configure(State::Off, 0); } VibratorLegacy::~VibratorLegacy() { if (m_thread) { m_thread->join(); } } // Over simplyfied led controlls! void VibratorLegacy::configure(State state, int durationMs) { if (state == State::On) { m_device.set_sysattr("enable", std::to_string(durationMs)); } else { m_device.set_sysattr("enable", "0"); } } } hfd-service-0.1.0/src/vibrator-legacy.h000066400000000000000000000021221402415033400177320ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include "vibrator.h" #include "udev/udev-cpp.h" #include #include namespace hfd { class VibratorLegacy : public Vibrator { public: VibratorLegacy(); ~VibratorLegacy(); static bool usable(); protected: void configure(State state, int durationMs) override; private: Udev::UdevDevice m_device; std::shared_ptr m_thread; }; } hfd-service-0.1.0/src/vibrator-sysfs.cpp000066400000000000000000000064131402415033400201770ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "vibrator-sysfs.h" #include #include #include #include // if the kernel support led triggers // we set namespace hfd { // True if and only if the standard transient trigger is supported. // Some devices implement the transient trigger but don't bother // Actually support it, this function will return a false negative // in that case bool VibratorSysfs::supportTransient() { std::ifstream source_stream("/sys/class/leds/vibrator/trigger"); if (!source_stream) { std::cerr << "Can't read '/sys/class/leds/vibrator/trigger', does the file exist?" << std::endl; return false; } std::string supported_triggers = std::string(std::istreambuf_iterator(source_stream), std::istreambuf_iterator()); bool transientSupported = supported_triggers.find("transient") != std::string::npos; std::cout << "Vibrator supports transient trigger: " << transientSupported << std::endl; return transientSupported; } // Checks that the transient trigger is supported, // or implemented manually by the driver bool VibratorSysfs::usable() { // Need to be able to access the vibrator bool usable = (access("/sys/class/leds/vibrator", F_OK ) != -1); if (!usable) { return false; } // Check if transient is in the list of supported triggers usable = (supportTransient()); // Check if the device supports the transient trigger implicitly. usable |= (access("/sys/class/leds/vibrator/duration", F_OK ) != -1 && access("/sys/class/leds/vibrator/state", F_OK ) != -1 && access("/sys/class/leds/vibrator/activate", F_OK ) != -1); std::cout << "Usable: " << usable << std::endl; return usable; } VibratorSysfs::VibratorSysfs(): Vibrator() { Udev::Udev udev; m_device = udev.device_from_syspath("/sys/class/leds/vibrator"); // If we reached this point but supportTransient() returns false // then the device implements the transient trigger implicitly // so we don't need to enable the transient trigger if (supportTransient()) { m_device.set_sysattr("trigger", "transient"); } // Make sure we are off on init configure(State::Off, 0); } // Over simplyfied led controlls! void VibratorSysfs::configure(State state, int durationMs) { if (state == State::On) { m_device.set_sysattr("state", "1"); m_device.set_sysattr("duration", std::to_string(durationMs)); m_device.set_sysattr("activate", "1"); } else { m_device.set_sysattr("activate", "0"); } } } hfd-service-0.1.0/src/vibrator-sysfs.h000066400000000000000000000020141402415033400176350ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include "vibrator.h" #include "udev/udev-cpp.h" namespace hfd { class VibratorSysfs : public Vibrator { public: VibratorSysfs(); static bool usable(); protected: void configure(State state, int durationMs) override; private: Udev::UdevDevice m_device; static bool supportTransient(); }; } hfd-service-0.1.0/src/vibrator.cpp000066400000000000000000000063121402415033400170300ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include "vibrator.h" #include "vibrator-ff.h" #include "vibrator-sysfs.h" #include "vibrator-legacy.h" #include "repeatThread.h" #include namespace hfd { class VibratorDummy : public Vibrator { public: VibratorDummy() = default; protected: void configure(State state, int durationMs) override { if (state == State::On) { std::cout << "VibratorDummy on, duration: " << durationMs << std::endl; } else { std::cout << "VibratorDummy off" << std::endl; } }; }; std::shared_ptr Vibrator::create() { if (VibratorSysfs::usable()) { std::cout << "Using sysfs vibrator" << std::endl; return std::make_shared(); } else if (VibratorLegacy::usable()) { std::cout << "Using legacy vibrator" << std::endl; return std::make_shared(); } else if (VibratorFF::usable()) { std::cout << "Using force feedback vibrator" << std::endl; return std::make_shared(); } std::cout << "Using dummy vibrator" << std::endl; return std::make_shared(); } std::shared_ptr Vibrator::create(std::string type) { if (type == "ff") { std::cout << "Using force feedback vibrator" << std::endl; return std::make_shared(); } else if (type == "sysfs") { std::cout << "Using sysfs vibrator" << std::endl; return std::make_shared(); } else if (type == "legacy") { std::cout << "Using legacy vibrator" << std::endl; return std::make_shared(); } std::cout << "Using dummy vibrator" << std::endl; return std::make_shared(); } Vibrator::Vibrator() : m_defaultDurationMs(500), m_defaultRepeat(1) { } void Vibrator::vibrate() { vibrate(m_defaultDurationMs); } void Vibrator::vibrate(int durationMs) { configure(State::On, durationMs); } void Vibrator::rumble(int durationMs, int repeat) { m_repeatThread = std::make_shared([=](){ vibrate(durationMs); }, durationMs*2, repeat); } int Vibrator::defaultDurationMs() const { return m_defaultDurationMs; } void Vibrator::setDefaultDurationMs(int durationMs) { if (m_defaultDurationMs != durationMs) { m_defaultDurationMs = durationMs; } } int Vibrator::defaultRepeat() const { return m_defaultRepeat; } void Vibrator::setDefaultRepeat(int repeat) { if (m_defaultRepeat != repeat) { m_defaultRepeat = repeat; } } } hfd-service-0.1.0/src/vibrator.h000066400000000000000000000025451402415033400165010ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #pragma once #include #include "common.h" namespace hfd { class RepeatThread; class Vibrator { public: Vibrator(); void vibrate(); void vibrate(int durationMs); void rumble(int durationMs, int repeat); int defaultDurationMs() const; void setDefaultDurationMs(int durationMs); int defaultRepeat() const; void setDefaultRepeat(int repeat); static std::shared_ptr create(); static std::shared_ptr create(std::string type); protected: virtual void configure(State state, int durationMs) = 0; int m_defaultDurationMs; int m_defaultRepeat; std::shared_ptr m_repeatThread; }; } hfd-service-0.1.0/tools/000077500000000000000000000000001402415033400150435ustar00rootroot00000000000000hfd-service-0.1.0/tools/CMakeLists.txt000066400000000000000000000007041402415033400176040ustar00rootroot00000000000000add_executable(hfd-service-tools-leds hfd_leds.cpp ) add_executable(hfd-service-tools-vibrator hfd_vibrator.cpp ) include_directories("../src") target_link_libraries(hfd-service-tools-leds hfd-core ) target_link_libraries(hfd-service-tools-vibrator hfd-core ) install(TARGETS hfd-service-tools-leds RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS hfd-service-tools-vibrator RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) hfd-service-0.1.0/tools/hfd_cli.cpp000066400000000000000000000004551402415033400171430ustar00rootroot00000000000000void help() { std::cout << "HFD cli tool" << std::endl << " - hdf-service-cli leds [color]" << std::endl << " - hdf-service-cli vibrator [duration] [repeat]" << std::endl; } int main(int argc, char** argv) { if(argc > 1) { } else help(); } hfd-service-0.1.0/tools/hfd_leds.cpp000066400000000000000000000021621402415033400173200ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include #include int main() { auto leds = hfd::Leds::create(); leds->setState(hfd::State::On); sleep(1); leds->setState(hfd::State::Off); leds->setState(hfd::State::On); leds->setColor(0xff0000); sleep(10); leds->setColor(0x00ff00); sleep(10); leds->setColor(0x0000ff); sleep(10); leds->setColor(0xbd5751); sleep(10); leds->setState(hfd::State::Off); } hfd-service-0.1.0/tools/hfd_vibrator.cpp000066400000000000000000000015611402415033400202230ustar00rootroot00000000000000/* * Copyright 2020 UBports foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Marius Gripsgard */ #include #include int main() { auto leds = hfd::Vibrator::create(); leds->vibrate(); sleep(1); leds->rumble(500, 5); sleep(6); }