From 04cf04fab5d6b09dcc4da25d16bd10326d64a9b7 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Wed, 14 Apr 2021 14:30:48 +0200 Subject: [PATCH] sm8250-common: vibrator: Implement OOS style effects for LED vibrator This change implements the following effects: - Effect::CLICK - Effect::DOUBLE_CLICK - Effect::TICK - Effect::HEAVY_CLICK Effect write streams were dumped using following strace command: - strace -fp `pidof vendor.oneplus.hardware.lmvibrator@1.0-service` -e openat,write Also, these effects can easily be tested with following test app: - https://github.com/luk1337/VibeTest Change-Id: Ie65caa0c65dc81bb35a7bcc56870649e895ced3f --- vibrator/Vibrator.cpp | 101 ++++++++++++++++++++++++++++++------ vibrator/include/Vibrator.h | 1 - 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/vibrator/Vibrator.cpp b/vibrator/Vibrator.cpp index 8ec2701..063523a 100644 --- a/vibrator/Vibrator.cpp +++ b/vibrator/Vibrator.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,53 @@ namespace vibrator { static const char LED_DEVICE[] = "/sys/class/leds/vibrator"; +static std::map>> LED_EFFECTS{ + { Effect::CLICK, { + { "/sys/class/leds/vibrator/ignore_store", "0" }, + { "/sys/class/leds/vibrator/duration", "10" }, + { "/sys/class/leds/vibrator/vmax", "0x1f" }, + { "/sys/class/leds/vibrator/gain", "0x80" }, + { "/sys/class/leds/vibrator/seq", "0x00 0x03" }, + { "/sys/class/leds/vibrator/loop", "0x00 0x00" }, + { "/sys/class/leds/vibrator/brightness", "1" }, + }}, + { Effect::DOUBLE_CLICK, { + { "/sys/class/leds/vibrator/ignore_store", "0" }, + { "/sys/class/leds/vibrator/duration", "30" }, + { "/sys/class/leds/vibrator/vmax", "0x1f" }, + { "/sys/class/leds/vibrator/gain", "0x80" }, + { "/sys/class/leds/vibrator/seq", "0x00 0x03" }, + { "/sys/class/leds/vibrator/loop", "0x00 0x00" }, + { "/sys/class/leds/vibrator/brightness", "1" }, + { "SLEEP", "150" }, + { "/sys/class/leds/vibrator/ignore_store", "0" }, + { "/sys/class/leds/vibrator/duration", "30" }, + { "/sys/class/leds/vibrator/vmax", "0x1f" }, + { "/sys/class/leds/vibrator/gain", "0x80" }, + { "/sys/class/leds/vibrator/seq", "0x00 0x03" }, + { "/sys/class/leds/vibrator/loop", "0x00 0x00" }, + { "/sys/class/leds/vibrator/brightness", "1" }, + }}, + { Effect::TICK, { + { "/sys/class/leds/vibrator/ignore_store", "0" }, + { "/sys/class/leds/vibrator/duration", "30" }, + { "/sys/class/leds/vibrator/vmax", "0x1f" }, + { "/sys/class/leds/vibrator/gain", "0x80" }, + { "/sys/class/leds/vibrator/seq", "0x00 0x03" }, + { "/sys/class/leds/vibrator/loop", "0x00 0x00" }, + { "/sys/class/leds/vibrator/brightness", "1" }, + }}, + { Effect::HEAVY_CLICK, { + { "/sys/class/leds/vibrator/ignore_store", "0" }, + { "/sys/class/leds/vibrator/duration", "10" }, + { "/sys/class/leds/vibrator/vmax", "0x1f" }, + { "/sys/class/leds/vibrator/gain", "0x80" }, + { "/sys/class/leds/vibrator/seq", "0x00 0x03" }, + { "/sys/class/leds/vibrator/loop", "0x00 0x00" }, + { "/sys/class/leds/vibrator/brightness", "1" }, + }} +}; + InputFFDevice::InputFFDevice() { DIR *dp; @@ -439,21 +487,41 @@ ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength es, const std long playLengthMs; int ret; - if (ledVib.mDetected) - return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); - ALOGD("Vibrator perform effect %d", effect); - if (effect < Effect::CLICK || - effect > Effect::HEAVY_CLICK) - return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + if (ledVib.mDetected) { + if (const auto it = LED_EFFECTS.find(effect); it != LED_EFFECTS.end()) { + for (const auto &[path, value] : it->second) { + if (path == "SLEEP") { + usleep(atoi(value.c_str()) * 1000); + } else { + ledVib.write_value(path.c_str(), value.c_str()); + } + } - if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && es != EffectStrength::STRONG) - return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + // Restore gain from persist prop + char gain[PROPERTY_VALUE_MAX]{}; + property_get("persist.vendor.vib.gain", gain, "0x55"); + ledVib.write_value("/sys/class/leds/vibrator/gain", gain); - ret = ff.playEffect((static_cast(effect)), es, &playLengthMs); - if (ret != 0) - return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC)); + // Return magic value for play length so that we won't end up calling on() / off() + playLengthMs = 150; + } else { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + } else { + if (effect < Effect::CLICK || + effect > Effect::HEAVY_CLICK) + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + + if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && + es != EffectStrength::STRONG) + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + + ret = ff.playEffect((static_cast(effect)), es, &playLengthMs); + if (ret != 0) + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC)); + } if (callback != nullptr) { std::thread([=] { @@ -469,11 +537,12 @@ ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength es, const std } ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector* _aidl_return) { - if (ledVib.mDetected) - return ndk::ScopedAStatus::ok(); - - *_aidl_return = {Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD, - Effect::POP, Effect::HEAVY_CLICK}; + if (ledVib.mDetected) { + *_aidl_return = {Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::HEAVY_CLICK}; + } else { + *_aidl_return = {Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD, + Effect::POP, Effect::HEAVY_CLICK}; + } return ndk::ScopedAStatus::ok(); } diff --git a/vibrator/include/Vibrator.h b/vibrator/include/Vibrator.h index e0694ca..826261b 100644 --- a/vibrator/include/Vibrator.h +++ b/vibrator/include/Vibrator.h @@ -60,7 +60,6 @@ public: int on(int32_t timeoutMs); int off(); bool mDetected; -private: int write_value(const char *file, const char *value); };