From 0c4a33155691c0e4b8ca563945110c0916153660 Mon Sep 17 00:00:00 2001 From: Tai Kuo Date: Mon, 20 Feb 2023 15:05:46 +0800 Subject: [PATCH] [DO NOT MERGE] device/lynx: Change to use common vibrator HAL Use common vibrator hal in hardware/google/pixel instead of device/google/lynx. This will use the common vibrator hal from now on to support the adaptive haptics feature. Bug: 198239103 Bug: 269762222 Test: Verified on device Change-Id: Ia90fe77222fbce0c54ecf3fc5439fea5cda5c892 --- conf/init.lynx.rc | 7 - device-lynx.mk | 9 +- vibrator/Android.bp | 52 - vibrator/OWNERS | 4 - vibrator/common/Android.bp | 37 - vibrator/common/HardwareBase.cpp | 136 -- vibrator/common/HardwareBase.h | 221 --- vibrator/common/utils.h | 173 -- vibrator/cs40l26/Android.bp | 107 -- vibrator/cs40l26/CapoDetector.cpp | 215 --- vibrator/cs40l26/Hardware.h | 362 ----- vibrator/cs40l26/TEST_MAPPING | 10 - vibrator/cs40l26/Vibrator.cpp | 1441 ----------------- vibrator/cs40l26/Vibrator.h | 235 --- ...e.vibrator-service.cs40l26-private-lynx.rc | 47 - ....vibrator-service.cs40l26-private-lynx.xml | 7 - vibrator/cs40l26/device.mk | 6 - vibrator/cs40l26/inc/CapoDetector.h | 107 -- vibrator/cs40l26/proto/capo.proto | 148 -- vibrator/cs40l26/service.cpp | 55 - vibrator/cs40l26/tests/Android.bp | 35 - vibrator/cs40l26/tests/mocks.h | 85 - vibrator/cs40l26/tests/test-hwapi.cpp | 288 ---- vibrator/cs40l26/tests/test-hwcal.cpp | 386 ----- vibrator/cs40l26/tests/test-vibrator.cpp | 692 -------- vibrator/cs40l26/tests/types.h | 33 - vibrator/cs40l26/tests/utils.h | 46 - 27 files changed, 2 insertions(+), 4942 deletions(-) delete mode 100644 vibrator/Android.bp delete mode 100644 vibrator/OWNERS delete mode 100644 vibrator/common/Android.bp delete mode 100644 vibrator/common/HardwareBase.cpp delete mode 100644 vibrator/common/HardwareBase.h delete mode 100644 vibrator/common/utils.h delete mode 100644 vibrator/cs40l26/Android.bp delete mode 100644 vibrator/cs40l26/CapoDetector.cpp delete mode 100644 vibrator/cs40l26/Hardware.h delete mode 100644 vibrator/cs40l26/TEST_MAPPING delete mode 100644 vibrator/cs40l26/Vibrator.cpp delete mode 100644 vibrator/cs40l26/Vibrator.h delete mode 100644 vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.rc delete mode 100644 vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.xml delete mode 100644 vibrator/cs40l26/device.mk delete mode 100644 vibrator/cs40l26/inc/CapoDetector.h delete mode 100644 vibrator/cs40l26/proto/capo.proto delete mode 100644 vibrator/cs40l26/service.cpp delete mode 100644 vibrator/cs40l26/tests/Android.bp delete mode 100644 vibrator/cs40l26/tests/mocks.h delete mode 100644 vibrator/cs40l26/tests/test-hwapi.cpp delete mode 100644 vibrator/cs40l26/tests/test-hwcal.cpp delete mode 100644 vibrator/cs40l26/tests/test-vibrator.cpp delete mode 100644 vibrator/cs40l26/tests/types.h delete mode 100644 vibrator/cs40l26/tests/utils.h diff --git a/conf/init.lynx.rc b/conf/init.lynx.rc index ad61381..c5fbb19 100644 --- a/conf/init.lynx.rc +++ b/conf/init.lynx.rc @@ -116,10 +116,3 @@ on override-sf-uclamp # it should be written by the system init. on property:ro.boot.hardware.sku=G82U8 setprop audio.camerasound.force true - -# Route vibrator.adaptive_haptics.enabled to persist -on property:vibrator.adaptive_haptics.enabled=0 - setprop persist.vendor.vibrator.hal.context.enable false - -on property:vibrator.adaptive_haptics.enabled=1 - setprop persist.vendor.vibrator.hal.context.enable true diff --git a/device-lynx.mk b/device-lynx.mk index 8047df6..4da9417 100644 --- a/device-lynx.mk +++ b/device-lynx.mk @@ -28,7 +28,7 @@ DEVICE_PACKAGE_OVERLAYS += device/google/lynx/lynx/overlay include device/google/lynx/audio/lynx/audio-tables.mk include device/google/gs201/device-shipping-common.mk -include device/google/lynx/vibrator/cs40l26/device.mk +include hardware/google/pixel/vibrator/cs40l26/device.mk # go/lyric-soong-variables $(call soong_config_set,lyric,camera_hardware,lynx) @@ -154,12 +154,7 @@ endif PRODUCT_VENDOR_PROPERTIES += \ ro.vendor.vibrator.hal.supported_primitives=243 \ ro.vendor.vibrator.hal.f0.comp.enabled=1 \ - ro.vendor.vibrator.hal.redc.comp.enabled=0 \ - persist.vendor.vibrator.hal.context.enable=false \ - persist.vendor.vibrator.hal.context.scale=40 \ - persist.vendor.vibrator.hal.context.fade=true \ - persist.vendor.vibrator.hal.context.cooldowntime=1600 \ - persist.vendor.vibrator.hal.context.settlingtime=5000 + ro.vendor.vibrator.hal.redc.comp.enabled=0 # Trusty liboemcrypto.so PRODUCT_SOONG_NAMESPACES += vendor/google_devices/lynx/prebuilts diff --git a/vibrator/Android.bp b/vibrator/Android.bp deleted file mode 100644 index c6da071..0000000 --- a/vibrator/Android.bp +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// 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. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_defaults { - name: "PixelVibratorDefaultsPrivateLynx", - relative_install_path: "hw", - static_libs: [ - "PixelVibratorCommonPrivateLynx", - ], - shared_libs: [ - "libbase", - "libbinder_ndk", - "libcutils", - "libhardware", - "liblog", - "libutils", - ], -} - -cc_defaults { - name: "PixelVibratorBinaryDefaultsPrivateLynx", - defaults: ["PixelVibratorDefaultsPrivateLynx"], - shared_libs: [ - "android.hardware.vibrator-V2-ndk", - ], -} - -cc_defaults { - name: "PixelVibratorTestDefaultsPrivateLynx", - defaults: ["PixelVibratorDefaultsPrivateLynx"], - static_libs: [ - "android.hardware.vibrator-V2-ndk", - ], - test_suites: ["device-tests"], - require_root: true, -} diff --git a/vibrator/OWNERS b/vibrator/OWNERS deleted file mode 100644 index 899224c..0000000 --- a/vibrator/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -chasewu@google.com -michaelwr@google.com -taikuo@google.com -chrispaulo@google.com diff --git a/vibrator/common/Android.bp b/vibrator/common/Android.bp deleted file mode 100644 index b2a6d48..0000000 --- a/vibrator/common/Android.bp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// 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. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_library { - name: "PixelVibratorCommonPrivateLynx", - srcs: [ - "HardwareBase.cpp", - ], - shared_libs: [ - "libbase", - "libcutils", - "liblog", - "libutils", - ], - cflags: [ - "-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)", - "-DLOG_TAG=\"android.hardware.vibrator@1.x-common\"", - ], - export_include_dirs: ["."], - vendor_available: true, -} diff --git a/vibrator/common/HardwareBase.cpp b/vibrator/common/HardwareBase.cpp deleted file mode 100644 index 8e07e99..0000000 --- a/vibrator/common/HardwareBase.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * 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 "HardwareBase.h" - -#include -#include - -#include -#include - -#include "utils.h" - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -HwApiBase::HwApiBase() { - mPathPrefix = std::getenv("HWAPI_PATH_PREFIX") ?: ""; - if (mPathPrefix.empty()) { - ALOGE("Failed get HWAPI path prefix!"); - } -} - -void HwApiBase::saveName(const std::string &name, const std::ios *stream) { - mNames[stream] = name; -} - -bool HwApiBase::has(const std::ios &stream) { - return !!stream; -} - -void HwApiBase::debug(int fd) { - dprintf(fd, "Kernel:\n"); - - for (auto &entry : utils::pathsFromEnv("HWAPI_DEBUG_PATHS", mPathPrefix)) { - auto &path = entry.first; - auto &stream = entry.second; - std::string line; - - dprintf(fd, " %s:\n", path.c_str()); - while (std::getline(stream, line)) { - dprintf(fd, " %s\n", line.c_str()); - } - } - - mRecordsMutex.lock(); - dprintf(fd, " Records:\n"); - for (auto &r : mRecords) { - if (r == nullptr) { - continue; - } - dprintf(fd, " %s\n", r->toString(mNames).c_str()); - } - mRecordsMutex.unlock(); -} - -HwCalBase::HwCalBase() { - std::ifstream calfile; - auto propertyPrefix = std::getenv("PROPERTY_PREFIX"); - - if (propertyPrefix != NULL) { - mPropertyPrefix = std::string(propertyPrefix); - } else { - ALOGE("Failed get property prefix!"); - } - - utils::fileFromEnv("CALIBRATION_FILEPATH", &calfile); - - for (std::string line; std::getline(calfile, line);) { - if (line.empty() || line[0] == '#') { - continue; - } - std::istringstream is_line(line); - std::string key, value; - if (std::getline(is_line, key, ':') && std::getline(is_line, value)) { - mCalData[utils::trim(key)] = utils::trim(value); - } - } -} - -void HwCalBase::debug(int fd) { - std::ifstream stream; - std::string path; - std::string line; - struct context { - HwCalBase *obj; - int fd; - } context{this, fd}; - - dprintf(fd, "Properties:\n"); - - property_list( - [](const char *key, const char *value, void *cookie) { - struct context *context = static_cast(cookie); - HwCalBase *obj = context->obj; - int fd = context->fd; - const std::string expect{obj->mPropertyPrefix}; - const std::string actual{key, std::min(strlen(key), expect.size())}; - if (actual == expect) { - dprintf(fd, " %s:\n", key); - dprintf(fd, " %s\n", value); - } - }, - &context); - - dprintf(fd, "\n"); - - dprintf(fd, "Persist:\n"); - - utils::fileFromEnv("CALIBRATION_FILEPATH", &stream, &path); - - dprintf(fd, " %s:\n", path.c_str()); - while (std::getline(stream, line)) { - dprintf(fd, " %s\n", line.c_str()); - } -} - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/common/HardwareBase.h b/vibrator/common/HardwareBase.h deleted file mode 100644 index 5b07040..0000000 --- a/vibrator/common/HardwareBase.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * 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. - */ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "utils.h" - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -using ::android::base::unique_fd; - -class HwApiBase { - private: - using NamesMap = std::map; - - class RecordInterface { - public: - virtual std::string toString(const NamesMap &names) = 0; - virtual ~RecordInterface() {} - }; - template - class Record : public RecordInterface { - public: - Record(const char *func, const T &value, const std::ios *stream) - : mFunc(func), mValue(value), mStream(stream) {} - std::string toString(const NamesMap &names) override; - - private: - const char *mFunc; - const T mValue; - const std::ios *mStream; - }; - using Records = std::list>; - - static constexpr uint32_t RECORDS_SIZE = 32; - - public: - HwApiBase(); - void debug(int fd); - - protected: - void saveName(const std::string &name, const std::ios *stream); - template - void open(const std::string &name, T *stream); - bool has(const std::ios &stream); - template - bool get(T *value, std::istream *stream); - template - bool set(const T &value, std::ostream *stream); - template - bool poll(const T &value, std::istream *stream, const int32_t timeout = -1); - template - void record(const char *func, const T &value, const std::ios *stream); - - private: - std::string mPathPrefix; - NamesMap mNames; - Records mRecords{RECORDS_SIZE}; - std::mutex mRecordsMutex; - std::mutex mIoMutex; -}; - -#define HWAPI_RECORD(args...) HwApiBase::record(__FUNCTION__, ##args) - -template -void HwApiBase::open(const std::string &name, T *stream) { - saveName(name, stream); - utils::openNoCreate(mPathPrefix + name, stream); -} - -template -bool HwApiBase::get(T *value, std::istream *stream) { - ATRACE_NAME("HwApi::get"); - std::scoped_lock ioLock{mIoMutex}; - bool ret; - stream->seekg(0); - *stream >> *value; - if (!(ret = !!*stream)) { - ALOGE("Failed to read %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno)); - } - stream->clear(); - HWAPI_RECORD(*value, stream); - return ret; -} - -template -bool HwApiBase::set(const T &value, std::ostream *stream) { - ATRACE_NAME("HwApi::set"); - using utils::operator<<; - std::scoped_lock ioLock{mIoMutex}; - bool ret; - *stream << value << std::endl; - if (!(ret = !!*stream)) { - ALOGE("Failed to write %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno)); - stream->clear(); - } - HWAPI_RECORD(value, stream); - return ret; -} - -template -bool HwApiBase::poll(const T &value, std::istream *stream, const int32_t timeoutMs) { - ATRACE_NAME("HwApi::poll"); - auto path = mPathPrefix + mNames[stream]; - unique_fd fileFd{::open(path.c_str(), O_RDONLY)}; - unique_fd epollFd{epoll_create(1)}; - epoll_event event = { - .events = EPOLLPRI | EPOLLET, - }; - T actual; - bool ret; - int epollRet; - - if (timeoutMs < -1) { - ALOGE("Invalid polling timeout!"); - return false; - } - - if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fileFd, &event)) { - ALOGE("Failed to poll %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno)); - return false; - } - - while ((ret = get(&actual, stream)) && (actual != value)) { - epollRet = epoll_wait(epollFd, &event, 1, timeoutMs); - if (epollRet <= 0) { - ALOGE("Polling error or timeout! (%d)", epollRet); - return false; - } - } - - HWAPI_RECORD(value, stream); - return ret; -} - -template -void HwApiBase::record(const char *func, const T &value, const std::ios *stream) { - std::lock_guard lock(mRecordsMutex); - mRecords.emplace_back(std::make_unique>(func, value, stream)); - mRecords.pop_front(); -} - -template -std::string HwApiBase::Record::toString(const NamesMap &names) { - using utils::operator<<; - std::stringstream ret; - - ret << mFunc << " '" << names.at(mStream) << "' = '" << mValue << "'"; - - return ret.str(); -} - -class HwCalBase { - public: - HwCalBase(); - void debug(int fd); - - protected: - template - bool getProperty(const char *key, T *value, const T defval); - template - bool getPersist(const char *key, T *value); - - private: - std::string mPropertyPrefix; - std::map mCalData; -}; - -template -bool HwCalBase::getProperty(const char *key, T *outval, const T defval) { - ATRACE_NAME("HwCal::getProperty"); - *outval = utils::getProperty(mPropertyPrefix + key, defval); - return true; -} - -template -bool HwCalBase::getPersist(const char *key, T *value) { - ATRACE_NAME("HwCal::getPersist"); - auto it = mCalData.find(key); - if (it == mCalData.end()) { - ALOGE("Missing %s config!", key); - return false; - } - std::stringstream stream{it->second}; - utils::unpack(stream, value); - if (!stream || !stream.eof()) { - ALOGE("Invalid %s config!", key); - return false; - } - return true; -} - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/common/utils.h b/vibrator/common/utils.h deleted file mode 100644 index 188554d..0000000 --- a/vibrator/common/utils.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * 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. - */ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { -namespace utils { - -template -class Is_Iterable { - private: - template - static std::true_type test(typename U::iterator *u); - - template - static std::false_type test(U *u); - - public: - static const bool value = decltype(test(0))::value; -}; - -template -using Enable_If_Iterable = std::enable_if_t::value == B>; - -template -using Enable_If_Signed = std::enable_if_t, U>; - -template -using Enable_If_Unsigned = std::enable_if_t, U>; - -// override for default behavior of printing as a character -inline std::ostream &operator<<(std::ostream &stream, const int8_t value) { - return stream << +value; -} -// override for default behavior of printing as a character -inline std::ostream &operator<<(std::ostream &stream, const uint8_t value) { - return stream << +value; -} - -template -inline auto toUnderlying(const T value) { - return static_cast>(value); -} - -template -inline Enable_If_Iterable unpack(std::istream &stream, T *value) { - for (auto &entry : *value) { - stream >> entry; - } -} - -template -inline Enable_If_Iterable unpack(std::istream &stream, T *value) { - stream >> *value; -} - -template <> -inline void unpack(std::istream &stream, std::string *value) { - *value = std::string(std::istreambuf_iterator(stream), {}); - stream.setstate(std::istream::eofbit); -} - -template -inline Enable_If_Signed getProperty(const std::string &key, const T def) { - if (std::is_floating_point_v) { - float result; - std::string value = ::android::base::GetProperty(key, ""); - if (!value.empty() && ::android::base::ParseFloat(value, &result)) { - return result; - } - return def; - } else { - return ::android::base::GetIntProperty(key, def); - } -} - -template -inline Enable_If_Unsigned getProperty(const std::string &key, const T def) { - return ::android::base::GetUintProperty(key, def); -} - -template <> -inline bool getProperty(const std::string &key, const bool def) { - return ::android::base::GetBoolProperty(key, def); -} - -template -static void openNoCreate(const std::string &file, T *outStream) { - auto mode = std::is_base_of_v ? std::ios_base::out : std::ios_base::in; - - // Force 'in' mode to prevent file creation - outStream->open(file, mode | std::ios_base::in); - if (!*outStream) { - ALOGE("Failed to open %s (%d): %s", file.c_str(), errno, strerror(errno)); - } -} - -template -static void fileFromEnv(const char *env, T *outStream, std::string *outName = nullptr) { - auto file = std::getenv(env); - - if (file == nullptr) { - ALOGE("Failed get env %s", env); - return; - } - - if (outName != nullptr) { - *outName = std::string(file); - } - - openNoCreate(file, outStream); -} - -static ATTRIBUTE_UNUSED auto pathsFromEnv(const char *env, const std::string &prefix = "") { - std::map ret; - auto value = std::getenv(env); - - if (value == nullptr) { - return ret; - } - - std::istringstream paths{value}; - std::string path; - - while (paths >> path) { - ret[path].open(prefix + path); - } - - return ret; -} - -static ATTRIBUTE_UNUSED std::string trim(const std::string &str, - const std::string &whitespace = " \t") { - const auto str_begin = str.find_first_not_of(whitespace); - if (str_begin == std::string::npos) { - return ""; - } - - const auto str_end = str.find_last_not_of(whitespace); - const auto str_range = str_end - str_begin + 1; - - return str.substr(str_begin, str_range); -} - -} // namespace utils -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/Android.bp b/vibrator/cs40l26/Android.bp deleted file mode 100644 index f60189d..0000000 --- a/vibrator/cs40l26/Android.bp +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// 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. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_defaults { - name: "android.hardware.vibrator-defaults.cs40l26-private-lynx", - cflags: [ - "-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)", - "-DLOG_TAG=\"android.hardware.vibrator-cs40l26\"", - ], - shared_libs: [ - "libbinder", - ], -} - -cc_defaults { - name: "VibratorHalCs40l26BinaryDefaultsPrivateLynx", - defaults: [ - "PixelVibratorBinaryDefaultsPrivateLynx", - "android.hardware.vibrator-defaults.cs40l26-private-lynx", - ], - include_dirs: [ - "external/tinyalsa/include", - ], - shared_libs: [ - "libcutils", - "libtinyalsa", - ], -} - -cc_defaults { - name: "VibratorHalCs40l26TestDefaultsPrivateLynx", - defaults: [ - "PixelVibratorTestDefaultsPrivateLynx", - "android.hardware.vibrator-defaults.cs40l26-private-lynx", - ], - static_libs: [ - "libtinyalsa", - ], - shared_libs: ["android.hardware.vibrator-impl.cs40l26-private-lynx"], -} - -cc_library_shared { - name: "libvibecapo_proto_lynx", - vendor_available: true, - owner: "google", - srcs: [ - "proto/capo.proto", - ], - shared_libs: [ - "libprotobuf-cpp-full", - ], - export_include_dirs: [ - "inc", - ], - proto: { - type: "lite", - export_proto_headers: true, - }, -} - -cc_library_shared { - name: "android.hardware.vibrator-impl.cs40l26-private-lynx", - defaults: ["VibratorHalCs40l26BinaryDefaultsPrivateLynx"], - srcs: [ - "Vibrator.cpp", - "CapoDetector.cpp", - ], - static_libs: [ - "chre_client", - ], - shared_libs: [ - "libvibecapo_proto_lynx", - "libprotobuf-cpp-full", - ], - export_include_dirs: [ - ".", - "inc", - ], - vendor_available: true, - visibility: [":__subpackages__"], -} - -cc_binary { - name: "android.hardware.vibrator-service.cs40l26-private-lynx", - defaults: ["VibratorHalCs40l26BinaryDefaultsPrivateLynx"], - init_rc: ["android.hardware.vibrator-service.cs40l26-private-lynx.rc"], - vintf_fragments: ["android.hardware.vibrator-service.cs40l26-private-lynx.xml"], - srcs: ["service.cpp"], - shared_libs: ["android.hardware.vibrator-impl.cs40l26-private-lynx"], - proprietary: true, -} diff --git a/vibrator/cs40l26/CapoDetector.cpp b/vibrator/cs40l26/CapoDetector.cpp deleted file mode 100644 index 0fc4d4b..0000000 --- a/vibrator/cs40l26/CapoDetector.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2022 Google LLC. All Rights Reserved. - * - * 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 "CapoDetector.h" -#include -#include -#include - -#include - -#ifdef LOG_TAG -#undef LOG_TAG -#define LOG_TAG "CapoDetector" -#endif - -namespace android { -namespace chre { - -namespace { // anonymous namespace for file-local definitions - -/** - * Called when onConnected() to send NanoappList request. - */ -void requestNanoappList(SocketClient &client) { - flatbuffers::FlatBufferBuilder builder; - HostProtocolHost::encodeNanoappListRequest(builder); - if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) { - ALOGE("Failed to send NanoappList request"); - } -} - -} // namespace - -/** - * Called when initializing connection with CHRE socket. - */ -sp CapoDetector::start() { - sp listener = new CapoDetector(); - if (!listener->connectInBackground(kChreSocketName, listener)) { - ALOGE("Couldn't connect to CHRE socket"); - return nullptr; - } - ALOGI("%s connect to CHRE socket.", __func__); - - return listener; -} - -/** - * Called when the socket is successfully (re-)connected. - * Reset the position and try to send NanoappList request. - */ -void CapoDetector::onConnected() { - flatbuffers::FlatBufferBuilder builder; - - // Reset the last position type. - last_position_type_ = capo::PositionType::UNKNOWN; - requestNanoappList(*this); -} - -/** - * Called when we have failed to (re-)connect the socket after many attempts - * and are giving up. - */ -void CapoDetector::onConnectionAborted() { - ALOGE("%s, Capo Aborting Connection!", __func__); -} - -/** - * Invoked when the socket is disconnected, and this connection loss was not - * the result of an explicit call to disconnect(). - * Reset the position while disconnecting. - */ - -void CapoDetector::onDisconnected() { - last_position_type_ = capo::PositionType::UNKNOWN; -} - -/** - * Decode unix socket msgs to CHRE messages, and call the appropriate - * callback depending on the CHRE message. - */ -void CapoDetector::onMessageReceived(const void *data, size_t length) { - if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) { - ALOGE("Failed to decode message"); - } -} - -/** - * Listen for messages from capo nanoapp and handle the message. - */ -void CapoDetector::handleNanoappMessage(const fbs::NanoappMessageT &message) { - ALOGI("%s, Id %" PRIu64 ", type %d, size %d", __func__, message.app_id, message.message_type, - static_cast(message.message.size())); - // Exclude the message with unmatched nanoapp id. - if (message.app_id != kCapoNanoappId) - return; - - // Handle the message with message_type. - switch (message.message_type) { - case capo::MessageType::ACK_NOTIFICATION: { - capo::AckNotification gd; - gd.set_notification_type(static_cast(message.message[1])); - ALOGD("%s, get notification event from capo nanoapp, type %d", __func__, - gd.notification_type()); - break; - } - case capo::MessageType::POSITION_DETECTED: { - capo::PositionDetected gd; - gd.set_position_type(static_cast(message.message[1])); - ALOGD("%s, get position event from capo nanoapp, type %d", __func__, - gd.position_type()); - - // Callback to function while getting carried position event. - if (callback_func_ != nullptr) { - last_position_type_ = gd.position_type(); - ALOGD("%s, sent position type %d to callback function", __func__, - last_position_type_); - callback_func_(last_position_type_); - } - break; - } - default: - ALOGE("%s, get invalid message, type: %" PRIu32 ", from capo nanoapp.", __func__, - message.message_type); - break; - } -} - -/** - * Handle the response of a NanoappList request. - * Ensure that capo nanoapp is running. - */ -void CapoDetector::handleNanoappListResponse(const fbs::NanoappListResponseT &response) { - for (const std::unique_ptr &nanoapp : response.nanoapps) { - if (nanoapp->app_id == kCapoNanoappId) { - if (nanoapp->enabled) - enable(); - else - ALOGE("Capo nanoapp not enabled"); - return; - } - } - ALOGE("Capo nanoapp not found"); -} - -/** - * Send enabling message to the nanoapp. - */ -void CapoDetector::enable() { - // Create CHRE message with serialized message - flatbuffers::FlatBufferBuilder builder, config_builder, force_builder; - - auto config_data = std::make_unique(); - auto msg = std::make_unique(); - - config_data->set_still_time_threshold_nanosecond(mCapoDetectorMDParameters.still_time_threshold_ns); - config_data->set_window_width_nanosecond(mCapoDetectorMDParameters.window_width_ns); - config_data->set_motion_confidence_threshold(mCapoDetectorMDParameters.motion_confidence_threshold); - config_data->set_still_confidence_threshold(mCapoDetectorMDParameters.still_confidence_threshold); - config_data->set_var_threshold(mCapoDetectorMDParameters.var_threshold); - config_data->set_var_threshold_delta(mCapoDetectorMDParameters.var_threshold_delta); - - msg->set_allocated_config_data(config_data.release()); - - auto pb_size = msg->ByteSizeLong(); - auto pb_data = std::make_unique(pb_size); - - if (!msg->SerializeToArray(pb_data.get(), pb_size)) { - ALOGE("Failed to serialize message."); - } - - ALOGI("Configuring CapoDetector"); - // Configure the detector from host-side - android::chre::HostProtocolHost::encodeNanoappMessage( - config_builder, getNanoppAppId(), capo::MessageType::CONFIGURE_DETECTOR, getHostEndPoint(), - pb_data.get(), pb_size); - ALOGI("Sending capo config message to Nanoapp, %" PRIu32 " bytes", config_builder.GetSize()); - if (!sendMessage(config_builder.GetBufferPointer(), config_builder.GetSize())) { - ALOGE("Failed to send config event for capo nanoapp"); - } - - ALOGI("Enabling CapoDetector"); - android::chre::HostProtocolHost::encodeNanoappMessage( - builder, getNanoppAppId(), capo::MessageType::ENABLE_DETECTOR, getHostEndPoint(), - /*messageData*/ nullptr, /*messageDataLenbuffer*/ 0); - ALOGI("Sending enable message to Nanoapp, %" PRIu32 " bytes", builder.GetSize()); - if (!sendMessage(builder.GetBufferPointer(), builder.GetSize())) { - ALOGE("Failed to send enable event for capo nanoapp"); - } - - ALOGI("Forcing CapoDetector to update state"); - // Force an updated state upon connection - android::chre::HostProtocolHost::encodeNanoappMessage( - force_builder, getNanoppAppId(), capo::MessageType::FORCE_UPDATE, getHostEndPoint(), - /*messageData*/ nullptr, /*messageDataLenbuffer*/ 0); - ALOGI("Sending force-update message to Nanoapp, %" PRIu32 " bytes", force_builder.GetSize()); - if (!sendMessage(force_builder.GetBufferPointer(), force_builder.GetSize())) { - ALOGE("Failed to send force-update event for capo nanoapp"); - } -} - -} // namespace chre -} // namespace android diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h deleted file mode 100644 index be97594..0000000 --- a/vibrator/cs40l26/Hardware.h +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * 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. - */ -#pragma once - -#include - -#include "HardwareBase.h" -#include "Vibrator.h" - -#define PROC_SND_PCM "/proc/asound/pcm" -#define HAPTIC_PCM_DEVICE_SYMBOL "haptic nohost playback" - -static struct pcm_config haptic_nohost_config = { - .channels = 1, - .rate = 48000, - .period_size = 80, - .period_count = 2, - .format = PCM_FORMAT_S16_LE, -}; - -enum WaveformIndex : uint16_t { - /* Physical waveform */ - WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0, - WAVEFORM_RESERVED_INDEX_1 = 1, - WAVEFORM_CLICK_INDEX = 2, - WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3, - WAVEFORM_THUD_INDEX = 4, - WAVEFORM_SPIN_INDEX = 5, - WAVEFORM_QUICK_RISE_INDEX = 6, - WAVEFORM_SLOW_RISE_INDEX = 7, - WAVEFORM_QUICK_FALL_INDEX = 8, - WAVEFORM_LIGHT_TICK_INDEX = 9, - WAVEFORM_LOW_TICK_INDEX = 10, - WAVEFORM_RESERVED_MFG_1, - WAVEFORM_RESERVED_MFG_2, - WAVEFORM_RESERVED_MFG_3, - WAVEFORM_MAX_PHYSICAL_INDEX, - /* OWT waveform */ - WAVEFORM_COMPOSE = WAVEFORM_MAX_PHYSICAL_INDEX, - WAVEFORM_PWLE, - /* - * Refer to , the WAVEFORM_MAX_INDEX must not exceed 96. - * #define FF_GAIN 0x60 // 96 in decimal - * #define FF_MAX_EFFECTS FF_GAIN - */ - WAVEFORM_MAX_INDEX, -}; - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -class HwApi : public Vibrator::HwApi, private HwApiBase { - public: - HwApi() { - open("calibration/f0_stored", &mF0); - open("default/f0_offset", &mF0Offset); - open("calibration/redc_stored", &mRedc); - open("calibration/q_stored", &mQ); - open("default/vibe_state", &mVibeState); - open("default/num_waves", &mEffectCount); - open("default/owt_free_space", &mOwtFreeSpace); - open("default/f0_comp_enable", &mF0CompEnable); - open("default/redc_comp_enable", &mRedcCompEnable); - open("default/delay_before_stop_playback_us", &mMinOnOffInterval); - } - - bool setF0(std::string value) override { return set(value, &mF0); } - bool setF0Offset(uint32_t value) override { return set(value, &mF0Offset); } - bool setRedc(std::string value) override { return set(value, &mRedc); } - bool setQ(std::string value) override { return set(value, &mQ); } - bool getEffectCount(uint32_t *value) override { return get(value, &mEffectCount); } - bool pollVibeState(uint32_t value, int32_t timeoutMs) override { - return poll(value, &mVibeState, timeoutMs); - } - bool hasOwtFreeSpace() override { return has(mOwtFreeSpace); } - bool getOwtFreeSpace(uint32_t *value) override { return get(value, &mOwtFreeSpace); } - bool setF0CompEnable(bool value) override { return set(value, &mF0CompEnable); } - bool setRedcCompEnable(bool value) override { return set(value, &mRedcCompEnable); } - bool setMinOnOffInterval(uint32_t value) override { return set(value, &mMinOnOffInterval); } - uint32_t getContextScale() override { - return utils::getProperty("persist.vendor.vibrator.hal.context.scale", 100); - } - bool getContextEnable() override { - return utils::getProperty("persist.vendor.vibrator.hal.context.enable", false); - } - uint32_t getContextSettlingTime() override { - return utils::getProperty("persist.vendor.vibrator.hal.context.settlingtime", 3000); - } - uint32_t getContextCooldownTime() override { - return utils::getProperty("persist.vendor.vibrator.hal.context.cooldowntime", 1000); - } - bool getContextFadeEnable() override { - return utils::getProperty("persist.vendor.vibrator.hal.context.fade", false); - } - - // TODO(b/234338136): Need to add the force feedback HW API test cases - bool setFFGain(int fd, uint16_t value) override { - struct input_event gain = { - .type = EV_FF, - .code = FF_GAIN, - .value = value, - }; - if (write(fd, (const void *)&gain, sizeof(gain)) != sizeof(gain)) { - return false; - } - return true; - } - bool setFFEffect(int fd, struct ff_effect *effect, uint16_t timeoutMs) override { - if (((*effect).replay.length != timeoutMs) || (ioctl(fd, EVIOCSFF, effect) < 0)) { - ALOGE("setFFEffect fail"); - return false; - } else { - return true; - } - } - bool setFFPlay(int fd, int8_t index, bool value) override { - struct input_event play = { - .type = EV_FF, - .code = static_cast(index), - .value = value, - }; - if (write(fd, (const void *)&play, sizeof(play)) != sizeof(play)) { - return false; - } else { - return true; - } - } - bool getHapticAlsaDevice(int *card, int *device) override { - std::string line; - std::ifstream myfile(PROC_SND_PCM); - if (myfile.is_open()) { - while (getline(myfile, line)) { - if (line.find(HAPTIC_PCM_DEVICE_SYMBOL) != std::string::npos) { - std::stringstream ss(line); - std::string currentToken; - std::getline(ss, currentToken, ':'); - sscanf(currentToken.c_str(), "%d-%d", card, device); - return true; - } - } - myfile.close(); - } else { - ALOGE("Failed to read file: %s", PROC_SND_PCM); - } - return false; - } - bool setHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) override { - int ret = 0; - - if (enable) { - *haptic_pcm = pcm_open(card, device, PCM_OUT, &haptic_nohost_config); - if (!pcm_is_ready(*haptic_pcm)) { - ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm)); - goto fail; - } - - ret = pcm_prepare(*haptic_pcm); - if (ret < 0) { - ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm)); - goto fail; - } - - ret = pcm_start(*haptic_pcm); - if (ret < 0) { - ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm)); - goto fail; - } - - return true; - } else { - if (*haptic_pcm) { - pcm_close(*haptic_pcm); - *haptic_pcm = NULL; - } - return true; - } - - fail: - pcm_close(*haptic_pcm); - *haptic_pcm = NULL; - return false; - } - bool uploadOwtEffect(int fd, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect, - uint32_t *outEffectIndex, int *status) override { - (*effect).u.periodic.custom_len = numBytes / sizeof(uint16_t); - delete[] ((*effect).u.periodic.custom_data); - (*effect).u.periodic.custom_data = new int16_t[(*effect).u.periodic.custom_len]{0x0000}; - if ((*effect).u.periodic.custom_data == nullptr) { - ALOGE("Failed to allocate memory for custom data\n"); - *status = EX_NULL_POINTER; - return false; - } - memcpy((*effect).u.periodic.custom_data, owtData, numBytes); - - if ((*effect).id != -1) { - ALOGE("(*effect).id != -1"); - } - - /* Create a new OWT waveform to update the PWLE or composite effect. */ - (*effect).id = -1; - if (ioctl(fd, EVIOCSFF, effect) < 0) { - ALOGE("Failed to upload effect %d (%d): %s", *outEffectIndex, errno, strerror(errno)); - delete[] ((*effect).u.periodic.custom_data); - *status = EX_ILLEGAL_STATE; - return false; - } - - if ((*effect).id >= FF_MAX_EFFECTS || (*effect).id < 0) { - ALOGE("Invalid waveform index after upload OWT effect: %d", (*effect).id); - *status = EX_ILLEGAL_ARGUMENT; - return false; - } - *outEffectIndex = (*effect).id; - *status = 0; - return true; - } - bool eraseOwtEffect(int fd, int8_t effectIndex, std::vector *effect) override { - uint32_t effectCountBefore, effectCountAfter, i, successFlush = 0; - - if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) { - ALOGE("Invalid waveform index for OWT erase: %d", effectIndex); - return false; - } - - if (effectIndex < WAVEFORM_MAX_INDEX) { - /* Normal situation. Only erase the effect which we just played. */ - if (ioctl(fd, EVIOCRMFF, effectIndex) < 0) { - ALOGE("Failed to erase effect %d (%d): %s", effectIndex, errno, strerror(errno)); - } - for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) { - if ((*effect)[i].id == effectIndex) { - (*effect)[i].id = -1; - break; - } - } - } else { - /* Flush all non-prestored effects of ff-core and driver. */ - getEffectCount(&effectCountBefore); - for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < FF_MAX_EFFECTS; i++) { - if (ioctl(fd, EVIOCRMFF, i) >= 0) { - successFlush++; - } - } - getEffectCount(&effectCountAfter); - ALOGW("Flushed effects: ff: %d; driver: %d -> %d; success: %d", effectIndex, - effectCountBefore, effectCountAfter, successFlush); - /* Reset all OWT effect index of HAL. */ - for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) { - (*effect)[i].id = -1; - } - } - return true; - } - - void debug(int fd) override { HwApiBase::debug(fd); } - - private: - std::ofstream mF0; - std::ofstream mF0Offset; - std::ofstream mRedc; - std::ofstream mQ; - std::ifstream mEffectCount; - std::ifstream mVibeState; - std::ifstream mOwtFreeSpace; - std::ofstream mF0CompEnable; - std::ofstream mRedcCompEnable; - std::ofstream mMinOnOffInterval; -}; - -class HwCal : public Vibrator::HwCal, private HwCalBase { - private: - static constexpr char VERSION[] = "version"; - static constexpr char F0_CONFIG[] = "f0_measured"; - static constexpr char REDC_CONFIG[] = "redc_measured"; - static constexpr char Q_CONFIG[] = "q_measured"; - static constexpr char TICK_VOLTAGES_CONFIG[] = "v_tick"; - static constexpr char CLICK_VOLTAGES_CONFIG[] = "v_click"; - static constexpr char LONG_VOLTAGES_CONFIG[] = "v_long"; - - static constexpr uint32_t VERSION_DEFAULT = 2; - static constexpr int32_t DEFAULT_FREQUENCY_SHIFT = 0; - static constexpr std::array V_TICK_DEFAULT = {1, 100}; - static constexpr std::array V_CLICK_DEFAULT = {1, 100}; - static constexpr std::array V_LONG_DEFAULT = {1, 100}; - - public: - HwCal() {} - - bool getVersion(uint32_t *value) override { - if (getPersist(VERSION, value)) { - return true; - } - *value = VERSION_DEFAULT; - return true; - } - bool getLongFrequencyShift(int32_t *value) override { - return getProperty("long.frequency.shift", value, DEFAULT_FREQUENCY_SHIFT); - } - bool getF0(std::string *value) override { return getPersist(F0_CONFIG, value); } - bool getRedc(std::string *value) override { return getPersist(REDC_CONFIG, value); } - bool getQ(std::string *value) override { return getPersist(Q_CONFIG, value); } - bool getTickVolLevels(std::array *value) override { - if (getPersist(TICK_VOLTAGES_CONFIG, value)) { - return true; - } - *value = V_TICK_DEFAULT; - return true; - } - bool getClickVolLevels(std::array *value) override { - if (getPersist(CLICK_VOLTAGES_CONFIG, value)) { - return true; - } - *value = V_CLICK_DEFAULT; - return true; - } - bool getLongVolLevels(std::array *value) override { - if (getPersist(LONG_VOLTAGES_CONFIG, value)) { - return true; - } - *value = V_LONG_DEFAULT; - return true; - } - bool isChirpEnabled() override { - bool value; - getProperty("chirp.enabled", &value, false); - return value; - } - bool getSupportedPrimitives(uint32_t *value) override { - return getProperty("supported_primitives", value, (uint32_t)0); - } - bool isF0CompEnabled() override { - bool value; - getProperty("f0.comp.enabled", &value, true); - return value; - } - bool isRedcCompEnabled() override { - bool value; - getProperty("redc.comp.enabled", &value, true); - return value; - } - void debug(int fd) override { HwCalBase::debug(fd); } -}; - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/TEST_MAPPING b/vibrator/cs40l26/TEST_MAPPING deleted file mode 100644 index 1d8ff7a..0000000 --- a/vibrator/cs40l26/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "VibratorHalCs40l26TestSuite", - "keywords": [ - "nextgen" - ] - } - ] -} diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp deleted file mode 100644 index 21a1682..0000000 --- a/vibrator/cs40l26/Vibrator.cpp +++ /dev/null @@ -1,1441 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * 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 "Vibrator.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "CapoDetector.h" - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) -#endif - -#ifdef LOG_TAG -#undef LOG_TAG -#define LOG_TAG "Vibrator" -#endif - -using CapoDetector = android::chre::CapoDetector; - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { -static constexpr uint8_t FF_CUSTOM_DATA_LEN = 2; -static constexpr uint16_t FF_CUSTOM_DATA_LEN_MAX_COMP = 2044; // (COMPOSE_SIZE_MAX + 1) * 8 + 4 -static constexpr uint16_t FF_CUSTOM_DATA_LEN_MAX_PWLE = 2302; - -static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100; - -static constexpr uint32_t WAVEFORM_LONG_VIBRATION_THRESHOLD_MS = 50; - -static constexpr uint8_t VOLTAGE_SCALE_MAX = 100; - -static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby -static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; // SVC initialization time -static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling -static constexpr uint32_t MAX_TIME_MS = UINT16_MAX; - -static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100); -static constexpr auto POLLING_TIMEOUT = 20; -static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000; - -/* nsections is 8 bits. Need to preserve 1 section for the first delay before the first effect. */ -static constexpr int32_t COMPOSE_SIZE_MAX = 254; -static constexpr int32_t COMPOSE_PWLE_SIZE_MAX_DEFAULT = 127; - -// Measured resonant frequency, f0_measured, is represented by Q10.14 fixed -// point format on cs40l26 devices. The expression to calculate f0 is: -// f0 = f0_measured / 2^Q14_BIT_SHIFT -// See the LRA Calibration Support documentation for more details. -static constexpr int32_t Q14_BIT_SHIFT = 14; - -// Measured Q factor, q_measured, is represented by Q8.16 fixed -// point format on cs40l26 devices. The expression to calculate q is: -// q = q_measured / 2^Q16_BIT_SHIFT -// See the LRA Calibration Support documentation for more details. -static constexpr int32_t Q16_BIT_SHIFT = 16; - -static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383; - -static constexpr uint32_t WT_LEN_CALCD = 0x00800000; -static constexpr uint8_t PWLE_CHIRP_BIT = 0x8; // Dynamic/static frequency and voltage -static constexpr uint8_t PWLE_BRAKE_BIT = 0x4; -static constexpr uint8_t PWLE_AMP_REG_BIT = 0x2; - -static constexpr float PWLE_LEVEL_MIN = 0.0; -static constexpr float PWLE_LEVEL_MAX = 1.0; -static constexpr float CS40L26_PWLE_LEVEL_MIX = -1.0; -static constexpr float CS40L26_PWLE_LEVEL_MAX = 0.9995118; -static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.00; -static constexpr float PWLE_FREQUENCY_MIN_HZ = 1.00; -static constexpr float PWLE_FREQUENCY_MAX_HZ = 1000.00; -static constexpr float PWLE_BW_MAP_SIZE = - 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ); - -#ifndef DISABLE_ADAPTIVE_HAPTICS_FEATURE -static constexpr bool mAdaptiveHapticsEnable = true; -#else -static constexpr bool mAdaptiveHapticsEnable = false; -#endif /* DISABLE_ADAPTIVE_HAPTICS_FEATURE */ - -static sp vibeContextListener; -uint8_t mCapoDeviceState = 0; -uint32_t mLastFaceUpEvent = 0; -uint32_t mLastEffectPlayedTime = 0; -float mLastPlayedScale = 0; - -static uint32_t getCurrentTimeInMs(void) { - return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); -} - -static void capoEventCallback(uint8_t eventId) { - ALOGD("Vibrator %s, From: 0x%x To: 0x%x", __func__, mCapoDeviceState, (uint32_t)eventId); - // Record the last moment we were in FACE_UP state - if (mCapoDeviceState == capo::PositionType::ON_TABLE_FACE_UP || - eventId == capo::PositionType::ON_TABLE_FACE_UP) { - mLastFaceUpEvent = getCurrentTimeInMs(); - } - mCapoDeviceState = eventId; -} - -static uint8_t getDeviceState(void) { - return mCapoDeviceState; -} - -enum WaveformBankID : uint8_t { - RAM_WVFRM_BANK, - ROM_WVFRM_BANK, - OWT_WVFRM_BANK, -}; - -enum WaveformIndex : uint16_t { - /* Physical waveform */ - WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0, - WAVEFORM_RESERVED_INDEX_1 = 1, - WAVEFORM_CLICK_INDEX = 2, - WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3, - WAVEFORM_THUD_INDEX = 4, - WAVEFORM_SPIN_INDEX = 5, - WAVEFORM_QUICK_RISE_INDEX = 6, - WAVEFORM_SLOW_RISE_INDEX = 7, - WAVEFORM_QUICK_FALL_INDEX = 8, - WAVEFORM_LIGHT_TICK_INDEX = 9, - WAVEFORM_LOW_TICK_INDEX = 10, - WAVEFORM_RESERVED_MFG_1, - WAVEFORM_RESERVED_MFG_2, - WAVEFORM_RESERVED_MFG_3, - WAVEFORM_MAX_PHYSICAL_INDEX, - /* OWT waveform */ - WAVEFORM_COMPOSE = WAVEFORM_MAX_PHYSICAL_INDEX, - WAVEFORM_PWLE, - /* - * Refer to , the WAVEFORM_MAX_INDEX must not exceed 96. - * #define FF_GAIN 0x60 // 96 in decimal - * #define FF_MAX_EFFECTS FF_GAIN - */ - WAVEFORM_MAX_INDEX, -}; - -std::vector defaultSupportedPrimitives = { - ndk::enum_range().begin(), ndk::enum_range().end()}; - -enum vibe_state { - VIBE_STATE_STOPPED = 0, - VIBE_STATE_HAPTIC, - VIBE_STATE_ASP, -}; - -std::mutex mActiveId_mutex; // protects mActiveId - -static int min(int x, int y) { - return x < y ? x : y; -} - -static int floatToUint16(float input, uint16_t *output, float scale, float min, float max) { - if (input < min || input > max) - return -ERANGE; - - *output = roundf(input * scale); - return 0; -} - -struct dspmem_chunk { - uint8_t *head; - uint8_t *current; - uint8_t *max; - int bytes; - - uint32_t cache; - int cachebits; -}; - -static dspmem_chunk *dspmem_chunk_create(void *data, int size) { - auto ch = new dspmem_chunk{ - .head = reinterpret_cast(data), - .current = reinterpret_cast(data), - .max = reinterpret_cast(data) + size, - }; - - return ch; -} - -static bool dspmem_chunk_end(struct dspmem_chunk *ch) { - return ch->current == ch->max; -} - -static int dspmem_chunk_bytes(struct dspmem_chunk *ch) { - return ch->bytes; -} - -static int dspmem_chunk_write(struct dspmem_chunk *ch, int nbits, uint32_t val) { - int nwrite, i; - - nwrite = min(24 - ch->cachebits, nbits); - ch->cache <<= nwrite; - ch->cache |= val >> (nbits - nwrite); - ch->cachebits += nwrite; - nbits -= nwrite; - - if (ch->cachebits == 24) { - if (dspmem_chunk_end(ch)) - return -ENOSPC; - - ch->cache &= 0xFFFFFF; - for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= 8) - *ch->current++ = (ch->cache & 0xFF000000) >> 24; - - ch->bytes += sizeof(ch->cache); - ch->cachebits = 0; - } - - if (nbits) - return dspmem_chunk_write(ch, nbits, val); - - return 0; -} - -static int dspmem_chunk_flush(struct dspmem_chunk *ch) { - if (!ch->cachebits) - return 0; - - return dspmem_chunk_write(ch, 24 - ch->cachebits, 0); -} - -Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) - : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)), mAsyncHandle(std::async([] {})) { - int32_t longFrequencyShift; - std::string caldata{8, '0'}; - uint32_t calVer; - - const char *inputEventName = std::getenv("INPUT_EVENT_NAME"); - const char *inputEventPathName = std::getenv("INPUT_EVENT_PATH"); - if ((strstr(inputEventName, "cs40l26") != nullptr) || - (strstr(inputEventName, "cs40l26_dual_input") != nullptr)) { - glob_t inputEventPaths; - int fd = -1; - int ret; - uint32_t val = 0; - char str[20] = {0x00}; - for (uint8_t retry = 0; retry < 10; retry++) { - ret = glob(inputEventPathName, 0, nullptr, &inputEventPaths); - if (ret) { - ALOGE("Fail to get input event paths (%d): %s", errno, strerror(errno)); - } else { - for (int i = 0; i < inputEventPaths.gl_pathc; i++) { - fd = TEMP_FAILURE_RETRY(open(inputEventPaths.gl_pathv[i], O_RDWR)); - if (fd > 0) { - if (ioctl(fd, EVIOCGBIT(0, sizeof(val)), &val) > 0 && - (val & (1 << EV_FF)) && ioctl(fd, EVIOCGNAME(sizeof(str)), &str) > 0 && - strstr(str, inputEventName) != nullptr) { - mInputFd.reset(fd); - ALOGI("Control %s through %s", inputEventName, - inputEventPaths.gl_pathv[i]); - break; - } - close(fd); - } - } - } - - if (ret == 0) { - globfree(&inputEventPaths); - } - if (mInputFd.ok()) { - break; - } - - sleep(1); - ALOGW("Retry #%d to search in %zu input devices.", retry, inputEventPaths.gl_pathc); - } - - if (!mInputFd.ok()) { - ALOGE("Fail to get an input event with name %s", inputEventName); - } - } else { - ALOGE("The input name %s is not cs40l26_input or cs40l26_dual_input", inputEventName); - } - - mFfEffects.resize(WAVEFORM_MAX_INDEX); - mEffectDurations.resize(WAVEFORM_MAX_INDEX); - mEffectDurations = { - 1000, 100, 30, 1000, 300, 130, 150, 500, 100, 15, 20, 1000, 1000, 1000, - }; /* 11+3 waveforms. The duration must < UINT16_MAX */ - - uint8_t effectIndex; - for (effectIndex = 0; effectIndex < WAVEFORM_MAX_INDEX; effectIndex++) { - if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) { - /* Initialize physical waveforms. */ - mFfEffects[effectIndex] = { - .type = FF_PERIODIC, - .id = -1, - .replay.length = static_cast(mEffectDurations[effectIndex]), - .u.periodic.waveform = FF_CUSTOM, - .u.periodic.custom_data = new int16_t[2]{RAM_WVFRM_BANK, effectIndex}, - .u.periodic.custom_len = FF_CUSTOM_DATA_LEN, - }; - // Bypass the waveform update due to different input name - if ((strstr(inputEventName, "cs40l26") != nullptr) || - (strstr(inputEventName, "cs40l26_dual_input") != nullptr)) { - if (!mHwApi->setFFEffect( - mInputFd, &mFfEffects[effectIndex], - static_cast(mFfEffects[effectIndex].replay.length))) { - ALOGE("Failed upload effect %d (%d): %s", effectIndex, errno, strerror(errno)); - } - } - if (mFfEffects[effectIndex].id != effectIndex) { - ALOGW("Unexpected effect index: %d -> %d", effectIndex, mFfEffects[effectIndex].id); - } - } else { - /* Initiate placeholders for OWT effects. */ - mFfEffects[effectIndex] = { - .type = FF_PERIODIC, - .id = -1, - .replay.length = 0, - .u.periodic.waveform = FF_CUSTOM, - .u.periodic.custom_data = nullptr, - .u.periodic.custom_len = 0, - }; - } - } - - if (mHwCal->getF0(&caldata)) { - mHwApi->setF0(caldata); - } - if (mHwCal->getRedc(&caldata)) { - mHwApi->setRedc(caldata); - } - if (mHwCal->getQ(&caldata)) { - mHwApi->setQ(caldata); - } - - mHwCal->getLongFrequencyShift(&longFrequencyShift); - if (longFrequencyShift > 0) { - mF0Offset = longFrequencyShift * std::pow(2, 14); - } else if (longFrequencyShift < 0) { - mF0Offset = std::pow(2, 24) - std::abs(longFrequencyShift) * std::pow(2, 14); - } else { - mF0Offset = 0; - } - - mHwCal->getVersion(&calVer); - if (calVer == 2) { - mHwCal->getTickVolLevels(&mTickEffectVol); - mHwCal->getClickVolLevels(&mClickEffectVol); - mHwCal->getLongVolLevels(&mLongEffectVol); - } else { - ALOGD("Unsupported calibration version: %u!", calVer); - } - - mHwApi->setF0CompEnable(mHwCal->isF0CompEnabled()); - mHwApi->setRedcCompEnable(mHwCal->isRedcCompEnabled()); - - mIsUnderExternalControl = false; - - mIsChirpEnabled = mHwCal->isChirpEnabled(); - - mHwCal->getSupportedPrimitives(&mSupportedPrimitivesBits); - if (mSupportedPrimitivesBits > 0) { - for (auto e : defaultSupportedPrimitives) { - if (mSupportedPrimitivesBits & (1 << uint32_t(e))) { - mSupportedPrimitives.emplace_back(e); - } - } - } else { - for (auto e : defaultSupportedPrimitives) { - mSupportedPrimitivesBits |= (1 << uint32_t(e)); - } - mSupportedPrimitives = defaultSupportedPrimitives; - } - - mHwApi->setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US); - - if (mAdaptiveHapticsEnable) { - vibeContextListener = CapoDetector::start(); - if (vibeContextListener == nullptr) { - ALOGE("%s, CapoDetector failed to start", __func__); - } else { - ALOGD("%s, CapoDetector started successfully! NanoAppID: 0x%x", __func__, - (uint32_t)vibeContextListener->getNanoppAppId()); - vibeContextListener->setCallback(capoEventCallback); - ALOGD("%s, CapoDetector Set Callback function from vibe", __func__); - } - } -} - -ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) { - ATRACE_NAME("Vibrator::getCapabilities"); - - int32_t ret = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK | - IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY | - IVibrator::CAP_GET_Q_FACTOR; - if (hasHapticAlsaDevice()) { - ret |= IVibrator::CAP_EXTERNAL_CONTROL; - } else { - ALOGE("No haptics ALSA device"); - } - if (mHwApi->hasOwtFreeSpace()) { - ret |= IVibrator::CAP_COMPOSE_EFFECTS; - if (mIsChirpEnabled) { - ret |= IVibrator::CAP_FREQUENCY_CONTROL | IVibrator::CAP_COMPOSE_PWLE_EFFECTS; - } - } - *_aidl_return = ret; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::off() { - ATRACE_NAME("Vibrator::off"); - bool ret{true}; - const std::scoped_lock lock(mActiveId_mutex); - - if (mActiveId >= 0) { - /* Stop the active effect. */ - if (!mHwApi->setFFPlay(mInputFd, mActiveId, false)) { - ALOGE("Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno)); - ret = false; - } - - if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && - (!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { - ALOGE("Failed to clean up the composed effect %d", mActiveId); - ret = false; - } - } else { - ALOGV("Vibrator is already off"); - } - - mActiveId = -1; - setGlobalAmplitude(false); - if (mF0Offset) { - mHwApi->setF0Offset(0); - } - - if (ret) { - return ndk::ScopedAStatus::ok(); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } -} - -ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, - const std::shared_ptr &callback) { - ATRACE_NAME("Vibrator::on"); - if (timeoutMs > MAX_TIME_MS) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - const uint16_t index = (timeoutMs < WAVEFORM_LONG_VIBRATION_THRESHOLD_MS) - ? WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX - : WAVEFORM_LONG_VIBRATION_EFFECT_INDEX; - if (MAX_COLD_START_LATENCY_MS <= MAX_TIME_MS - timeoutMs) { - timeoutMs += MAX_COLD_START_LATENCY_MS; - } - setGlobalAmplitude(true); - if (mF0Offset) { - mHwApi->setF0Offset(mF0Offset); - } - return on(timeoutMs, index, nullptr /*ignored*/, callback); -} - -ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, - const std::shared_ptr &callback, - int32_t *_aidl_return) { - ATRACE_NAME("Vibrator::perform"); - return performEffect(effect, strength, callback, _aidl_return); -} - -ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector *_aidl_return) { - *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK, - Effect::DOUBLE_CLICK}; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { - ATRACE_NAME("Vibrator::setAmplitude"); - if (amplitude <= 0.0f || amplitude > 1.0f) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - mLongEffectScale = amplitude; - if (!isUnderExternalControl()) { - return setGlobalAmplitude(true); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } -} - -ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) { - ATRACE_NAME("Vibrator::setExternalControl"); - setGlobalAmplitude(enabled); - - if (mHasHapticAlsaDevice || mConfigHapticAlsaDeviceDone || hasHapticAlsaDevice()) { - if (!mHwApi->setHapticPcmAmp(&mHapticPcm, enabled, mCard, mDevice)) { - ALOGE("Failed to %s haptic pcm device: %d", (enabled ? "enable" : "disable"), mDevice); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - } else { - ALOGE("No haptics ALSA device"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - mIsUnderExternalControl = enabled; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t *maxDelayMs) { - ATRACE_NAME("Vibrator::getCompositionDelayMax"); - *maxDelayMs = COMPOSE_DELAY_MAX_MS; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t *maxSize) { - ATRACE_NAME("Vibrator::getCompositionSizeMax"); - *maxSize = COMPOSE_SIZE_MAX; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector *supported) { - *supported = mSupportedPrimitives; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, - int32_t *durationMs) { - ndk::ScopedAStatus status; - uint32_t effectIndex; - if (primitive != CompositePrimitive::NOOP) { - status = getPrimitiveDetails(primitive, &effectIndex); - if (!status.isOk()) { - return status; - } - - *durationMs = mEffectDurations[effectIndex]; - } else { - *durationMs = 0; - } - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::compose(const std::vector &composite, - const std::shared_ptr &callback) { - ATRACE_NAME("Vibrator::compose"); - uint16_t size; - uint16_t nextEffectDelay; - - auto ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_COMP]{0x00}, - FF_CUSTOM_DATA_LEN_MAX_COMP); - - if (composite.size() > COMPOSE_SIZE_MAX || composite.empty()) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - /* Check if there is a wait before the first effect. */ - nextEffectDelay = composite.front().delayMs; - if (nextEffectDelay > COMPOSE_DELAY_MAX_MS || nextEffectDelay < 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } else if (nextEffectDelay > 0) { - size = composite.size() + 1; - } else { - size = composite.size(); - } - - dspmem_chunk_write(ch, 8, 0); /* Padding */ - dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & size)); /* nsections */ - dspmem_chunk_write(ch, 8, 0); /* repeat */ - uint8_t header_count = dspmem_chunk_bytes(ch); - - /* Insert 1 section for a wait before the first effect. */ - if (nextEffectDelay) { - dspmem_chunk_write(ch, 32, 0); /* amplitude, index, repeat & flags */ - dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */ - } - - for (uint32_t i_curr = 0, i_next = 1; i_curr < composite.size(); i_curr++, i_next++) { - auto &e_curr = composite[i_curr]; - uint32_t effectIndex = 0; - uint32_t effectVolLevel = 0; - if (e_curr.scale < 0.0f || e_curr.scale > 1.0f) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - if (e_curr.primitive != CompositePrimitive::NOOP) { - ndk::ScopedAStatus status; - status = getPrimitiveDetails(e_curr.primitive, &effectIndex); - if (!status.isOk()) { - return status; - } - effectVolLevel = intensityToVolLevel(e_curr.scale, effectIndex); - } - - /* Fetch the next composite effect delay and fill into the current section */ - nextEffectDelay = 0; - if (i_next < composite.size()) { - auto &e_next = composite[i_next]; - int32_t delay = e_next.delayMs; - - if (delay > COMPOSE_DELAY_MAX_MS || delay < 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - nextEffectDelay = delay; - } - - if (effectIndex == 0 && nextEffectDelay == 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & effectVolLevel)); /* amplitude */ - dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & effectIndex)); /* index */ - dspmem_chunk_write(ch, 8, 0); /* repeat */ - dspmem_chunk_write(ch, 8, 0); /* flags */ - dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */ - } - dspmem_chunk_flush(ch); - if (header_count == dspmem_chunk_bytes(ch)) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } else { - return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch, - callback); - } -} - -ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem_chunk *ch, - const std::shared_ptr &callback) { - ndk::ScopedAStatus status = ndk::ScopedAStatus::ok(); - - if (effectIndex >= FF_MAX_EFFECTS) { - ALOGE("Invalid waveform index %d", effectIndex); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) { - ALOGE("Previous vibration pending: prev: %d, curr: %d", mActiveId, effectIndex); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - if (ch) { - /* Upload OWT effect. */ - if (ch->head == nullptr) { - ALOGE("Invalid OWT bank"); - delete ch; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - bool isPwle = (*reinterpret_cast(ch->head) != 0x0000); - effectIndex = isPwle ? WAVEFORM_PWLE : WAVEFORM_COMPOSE; - - uint32_t freeBytes; - mHwApi->getOwtFreeSpace(&freeBytes); - if (dspmem_chunk_bytes(ch) > freeBytes) { - ALOGE("Invalid OWT length: Effect %d: %d > %d!", effectIndex, dspmem_chunk_bytes(ch), - freeBytes); - delete ch; - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - int errorStatus; - if (!mHwApi->uploadOwtEffect(mInputFd, ch->head, dspmem_chunk_bytes(ch), - &mFfEffects[effectIndex], &effectIndex, &errorStatus)) { - delete ch; - ALOGE("Invalid uploadOwtEffect"); - return ndk::ScopedAStatus::fromExceptionCode(errorStatus); - } - delete ch; - - } else if (effectIndex == WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX || - effectIndex == WAVEFORM_LONG_VIBRATION_EFFECT_INDEX) { - /* Update duration for long/short vibration. */ - mFfEffects[effectIndex].replay.length = static_cast(timeoutMs); - if (!mHwApi->setFFEffect(mInputFd, &mFfEffects[effectIndex], - static_cast(timeoutMs))) { - ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - } - - const std::scoped_lock lock(mActiveId_mutex); - mActiveId = effectIndex; - /* Play the event now. */ - if (!mHwApi->setFFPlay(mInputFd, effectIndex, true)) { - ALOGE("Failed to play effect %d (%d): %s", effectIndex, errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback); - return ndk::ScopedAStatus::ok(); -} - -uint16_t Vibrator::amplitudeToScale(float amplitude, float maximum, bool scalable) { - float ratio = 100; /* Unit: % */ - - if (maximum != 0) - ratio = amplitude / maximum * 100; - - if (maximum == 0 || ratio > 100) - ratio = 100; - - if (scalable && mContextEnable & mAdaptiveHapticsEnable) { - uint32_t now = getCurrentTimeInMs(); - uint32_t last_played = mLastEffectPlayedTime; - float context_scale = 1.0; - bool device_face_up = getDeviceState() == capo::PositionType::ON_TABLE_FACE_UP; - float pre_scaled_ratio = ratio; - mLastEffectPlayedTime = now; - - ALOGD("Vibrator Now: %u, Last: %u, ScaleTime: %u, Since? %d", now, mLastFaceUpEvent, mScaleTime, (now < mLastFaceUpEvent + mScaleTime)); - /* If the device is face-up or within the fade scaling range, find new scaling factor */ - if (device_face_up || now < mLastFaceUpEvent + mScaleTime) { - /* Device is face-up, so we will scale it down. Start with highest scaling factor */ - context_scale = mScalingFactor <= 100 ? static_cast(mScalingFactor)/100 : 1.0; - if (mFadeEnable && mScaleTime > 0 && (context_scale < 1.0) && (now < mLastFaceUpEvent + mScaleTime) && !device_face_up) { - float fade_scale = static_cast(now - mLastFaceUpEvent)/static_cast(mScaleTime); - context_scale += ((1.0 - context_scale)*fade_scale); - ALOGD("Vibrator fade scale applied: %f", fade_scale); - } - ratio *= context_scale; - ALOGD("Vibrator adjusting for face-up: pre: %f, post: %f", - std::round(pre_scaled_ratio), std::round(ratio)); - } - - /* If we haven't played an effect within the cooldown time, save the scaling factor */ - if ((now - last_played) > mScaleCooldown) { - ALOGD("Vibrator updating lastplayed scale, old: %f, new: %f", mLastPlayedScale, context_scale); - mLastPlayedScale = context_scale; - } - else { - /* Override the scale to match previously played scale */ - ratio = mLastPlayedScale * pre_scaled_ratio; - ALOGD("Vibrator repeating last scale: %f, new ratio: %f, duration since last: %u", mLastPlayedScale, ratio, (now - last_played)); - } - } - - return std::round(ratio); -} - -void Vibrator::updateContext() { - mContextEnable = mHwApi->getContextEnable(); - mFadeEnable = mHwApi->getContextFadeEnable(); - mScalingFactor = mHwApi->getContextScale(); - mScaleTime = mHwApi->getContextSettlingTime(); - mScaleCooldown = mHwApi->getContextCooldownTime(); -} - -ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum, bool scalable) { - uint16_t scale; - - if (mAdaptiveHapticsEnable && scalable) { - updateContext(); - } - - scale = amplitudeToScale(amplitude, maximum, scalable); - - if (!mHwApi->setFFGain(mInputFd, scale)) { - ALOGE("Failed to set the gain to %u (%d): %s", scale, errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) { - uint8_t amplitude = set ? roundf(mLongEffectScale * mLongEffectVol[1]) : VOLTAGE_SCALE_MAX; - if (!set) { - mLongEffectScale = 1.0; // Reset the scale for the later new effect. - } - return setEffectAmplitude(amplitude, VOLTAGE_SCALE_MAX, true); -} - -ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector * /*_aidl_return*/) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); -} - -ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t /*id*/, Effect /*effect*/, - EffectStrength /*strength*/) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); -} -ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); -} - -ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) { - std::string caldata{8, '0'}; - if (!mHwCal->getF0(&caldata)) { - ALOGE("Failed to get resonant frequency (%d): %s", errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - *resonantFreqHz = static_cast(std::stoul(caldata, nullptr, 16)) / (1 << Q14_BIT_SHIFT); - - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) { - std::string caldata{8, '0'}; - if (!mHwCal->getQ(&caldata)) { - ALOGE("Failed to get q factor (%d): %s", errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - *qFactor = static_cast(std::stoul(caldata, nullptr, 16)) / (1 << Q16_BIT_SHIFT); - - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) { - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { - *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ; - return ndk::ScopedAStatus::ok(); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } -} - -ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) { - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { - *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ; - return ndk::ScopedAStatus::ok(); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } -} - -ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector *_aidl_return) { - // TODO(b/170919640): complete implementation - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { - std::vector bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, 1.0); - *_aidl_return = bandwidthAmplitudeMap; - return ndk::ScopedAStatus::ok(); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } -} - -ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) { - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { - *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS; - return ndk::ScopedAStatus::ok(); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } -} - -ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) { - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { - *maxSize = COMPOSE_PWLE_SIZE_MAX_DEFAULT; - return ndk::ScopedAStatus::ok(); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } -} - -ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector *supported) { - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { - *supported = { - Braking::NONE, - }; - return ndk::ScopedAStatus::ok(); - } else { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } -} - -static void resetPreviousEndAmplitudeEndFrequency(float *prevEndAmplitude, - float *prevEndFrequency) { - const float reset = -1.0; - *prevEndAmplitude = reset; - *prevEndFrequency = reset; -} - -static void incrementIndex(int *index) { - *index += 1; -} - -static void constructPwleSegment(dspmem_chunk *ch, uint16_t delay, uint16_t amplitude, - uint16_t frequency, uint8_t flags, uint32_t vbemfTarget = 0) { - dspmem_chunk_write(ch, 16, delay); - dspmem_chunk_write(ch, 12, amplitude); - dspmem_chunk_write(ch, 12, frequency); - /* feature flags to control the chirp, CLAB braking, back EMF amplitude regulation */ - dspmem_chunk_write(ch, 8, (flags | 1) << 4); - if (flags & PWLE_AMP_REG_BIT) { - dspmem_chunk_write(ch, 24, vbemfTarget); /* target back EMF voltage */ - } -} - -static int constructActiveSegment(dspmem_chunk *ch, int duration, float amplitude, float frequency, - bool chirp) { - uint16_t delay = 0; - uint16_t amp = 0; - uint16_t freq = 0; - uint8_t flags = 0x0; - if ((floatToUint16(duration, &delay, 4, 0.0f, COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) < 0) || - (floatToUint16(amplitude, &, 2048, CS40L26_PWLE_LEVEL_MIX, CS40L26_PWLE_LEVEL_MAX) < - 0) || - (floatToUint16(frequency, &freq, 4, PWLE_FREQUENCY_MIN_HZ, PWLE_FREQUENCY_MAX_HZ) < 0)) { - ALOGE("Invalid argument: %d, %f, %f", duration, amplitude, frequency); - return -ERANGE; - } - if (chirp) { - flags |= PWLE_CHIRP_BIT; - } - constructPwleSegment(ch, delay, amp, freq, flags, 0 /*ignored*/); - return 0; -} - -static int constructBrakingSegment(dspmem_chunk *ch, int duration, Braking brakingType) { - uint16_t delay = 0; - uint16_t freq = 0; - uint8_t flags = 0x00; - if (floatToUint16(duration, &delay, 4, 0.0f, COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) < 0) { - ALOGE("Invalid argument: %d", duration); - return -ERANGE; - } - floatToUint16(PWLE_FREQUENCY_MIN_HZ, &freq, 4, PWLE_FREQUENCY_MIN_HZ, PWLE_FREQUENCY_MAX_HZ); - if (static_cast::type>(brakingType)) { - flags |= PWLE_BRAKE_BIT; - } - - constructPwleSegment(ch, delay, 0 /*ignored*/, freq, flags, 0 /*ignored*/); - return 0; -} - -static void updateWLength(dspmem_chunk *ch, uint32_t totalDuration) { - totalDuration *= 8; /* Unit: 0.125 ms (since wlength played @ 8kHz). */ - totalDuration |= WT_LEN_CALCD; /* Bit 23 is for WT_LEN_CALCD; Bit 22 is for WT_INDEFINITE. */ - *(ch->head + 0) = (totalDuration >> 24) & 0xFF; - *(ch->head + 1) = (totalDuration >> 16) & 0xFF; - *(ch->head + 2) = (totalDuration >> 8) & 0xFF; - *(ch->head + 3) = totalDuration & 0xFF; -} - -static void updateNSection(dspmem_chunk *ch, int segmentIdx) { - *(ch->head + 7) |= (0xF0 & segmentIdx) >> 4; /* Bit 4 to 7 */ - *(ch->head + 9) |= (0x0F & segmentIdx) << 4; /* Bit 3 to 0 */ -} - -ndk::ScopedAStatus Vibrator::composePwle(const std::vector &composite, - const std::shared_ptr &callback) { - ATRACE_NAME("Vibrator::composePwle"); - int32_t capabilities; - - Vibrator::getCapabilities(&capabilities); - if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) == 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - - if (composite.empty() || composite.size() > COMPOSE_PWLE_SIZE_MAX_DEFAULT) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - std::vector supported; - Vibrator::getSupportedBraking(&supported); - bool isClabSupported = - std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end(); - - int segmentIdx = 0; - uint32_t totalDuration = 0; - float prevEndAmplitude; - float prevEndFrequency; - resetPreviousEndAmplitudeEndFrequency(&prevEndAmplitude, &prevEndFrequency); - auto ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_PWLE]{0x00}, - FF_CUSTOM_DATA_LEN_MAX_PWLE); - bool chirp = false; - - dspmem_chunk_write(ch, 24, 0x000000); /* Waveform length placeholder */ - dspmem_chunk_write(ch, 8, 0); /* Repeat */ - dspmem_chunk_write(ch, 12, 0); /* Wait time between repeats */ - dspmem_chunk_write(ch, 8, 0x00); /* nsections placeholder */ - - for (auto &e : composite) { - switch (e.getTag()) { - case PrimitivePwle::active: { - auto active = e.get(); - if (active.duration < 0 || - active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - if (active.startAmplitude < PWLE_LEVEL_MIN || - active.startAmplitude > PWLE_LEVEL_MAX || - active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - if (active.startAmplitude > CS40L26_PWLE_LEVEL_MAX) { - active.startAmplitude = CS40L26_PWLE_LEVEL_MAX; - } - if (active.endAmplitude > CS40L26_PWLE_LEVEL_MAX) { - active.endAmplitude = CS40L26_PWLE_LEVEL_MAX; - } - - if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ || - active.startFrequency > PWLE_FREQUENCY_MAX_HZ || - active.endFrequency < PWLE_FREQUENCY_MIN_HZ || - active.endFrequency > PWLE_FREQUENCY_MAX_HZ) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - if (!((active.startAmplitude == prevEndAmplitude) && - (active.startFrequency == prevEndFrequency))) { - if (constructActiveSegment(ch, 0, active.startAmplitude, active.startFrequency, - false) < 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - incrementIndex(&segmentIdx); - } - - if (active.startFrequency != active.endFrequency) { - chirp = true; - } - if (constructActiveSegment(ch, active.duration, active.endAmplitude, - active.endFrequency, chirp) < 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - incrementIndex(&segmentIdx); - - prevEndAmplitude = active.endAmplitude; - prevEndFrequency = active.endFrequency; - totalDuration += active.duration; - chirp = false; - break; - } - case PrimitivePwle::braking: { - auto braking = e.get(); - if (braking.braking > Braking::CLAB) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } else if (!isClabSupported && (braking.braking == Braking::CLAB)) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - if (constructBrakingSegment(ch, 0, braking.braking) < 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - incrementIndex(&segmentIdx); - - if (constructBrakingSegment(ch, braking.duration, braking.braking) < 0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - incrementIndex(&segmentIdx); - - resetPreviousEndAmplitudeEndFrequency(&prevEndAmplitude, &prevEndFrequency); - totalDuration += braking.duration; - break; - } - } - - if (segmentIdx > COMPOSE_PWLE_SIZE_MAX_DEFAULT) { - ALOGE("Too many PrimitivePwle section!"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - } - dspmem_chunk_flush(ch); - - /* Update wlength */ - totalDuration += MAX_COLD_START_LATENCY_MS; - if (totalDuration > 0x7FFFF) { - ALOGE("Total duration is too long (%d)!", totalDuration); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - updateWLength(ch, totalDuration); - - /* Update nsections */ - updateNSection(ch, segmentIdx); - - return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch, - callback); -} - -bool Vibrator::isUnderExternalControl() { - return mIsUnderExternalControl; -} - -binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { - if (fd < 0) { - ALOGE("Called debug() with invalid fd."); - return STATUS_OK; - } - - (void)args; - (void)numArgs; - - dprintf(fd, "AIDL:\n"); - - dprintf(fd, " F0 Offset: %" PRIu32 "\n", mF0Offset); - - dprintf(fd, " Voltage Levels:\n"); - dprintf(fd, " Tick Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mTickEffectVol[0], - mTickEffectVol[1]); - dprintf(fd, " Click Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mClickEffectVol[0], - mClickEffectVol[1]); - dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mLongEffectVol[0], - mLongEffectVol[1]); - - dprintf(fd, " FF effect:\n"); - dprintf(fd, " Physical waveform:\n"); - dprintf(fd, "\tId\tIndex\tt ->\tt'\n"); - for (uint8_t effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) { - dprintf(fd, "\t%d\t%d\t%d\t%d\n", mFfEffects[effectId].id, - mFfEffects[effectId].u.periodic.custom_data[1], mEffectDurations[effectId], - mFfEffects[effectId].replay.length); - } - dprintf(fd, " OWT waveform:\n"); - dprintf(fd, "\tId\tBytes\tData\n"); - for (uint8_t effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; - effectId++) { - uint32_t numBytes = mFfEffects[effectId].u.periodic.custom_len * 2; - std::stringstream ss; - ss << " "; - for (int i = 0; i < numBytes; i++) { - ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex - << (uint16_t)(*( - reinterpret_cast(mFfEffects[effectId].u.periodic.custom_data) + - i)) - << " "; - } - dprintf(fd, "\t%d\t%d\t{%s}\n", mFfEffects[effectId].id, numBytes, ss.str().c_str()); - } - - dprintf(fd, "\n"); - dprintf(fd, "\n"); - - mHwApi->debug(fd); - - dprintf(fd, "\n"); - - mHwCal->debug(fd); - - dprintf(fd, "Capo Info\n"); - if (vibeContextListener) { - dprintf(fd, "Capo ID: 0x%x\n", (uint32_t)(vibeContextListener->getNanoppAppId())); - dprintf(fd, "Capo State: %d DetectedState: %d\n", vibeContextListener->getCarriedPosition(), - getDeviceState()); - } else { - dprintf(fd, "Capo ID: 0x%x\n", (uint32_t)(0xdeadbeef)); - dprintf(fd, "Capo State: %d DetectedState: %d\n", (uint32_t)0x454545, getDeviceState()); - } - - fsync(fd); - return STATUS_OK; -} - -bool Vibrator::hasHapticAlsaDevice() { - // We need to call findHapticAlsaDevice once only. Calling in the - // constructor is too early in the boot process and the pcm file contents - // are empty. Hence we make the call here once only right before we need to. - if (!mConfigHapticAlsaDeviceDone) { - if (mHwApi->getHapticAlsaDevice(&mCard, &mDevice)) { - mHasHapticAlsaDevice = true; - mConfigHapticAlsaDeviceDone = true; - } else { - ALOGE("Haptic ALSA device not supported"); - } - } else { - ALOGD("Haptic ALSA device configuration done."); - } - return mHasHapticAlsaDevice; -} - -ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength strength, - uint32_t *outEffectIndex, uint32_t *outTimeMs, - uint32_t *outVolLevel) { - uint32_t effectIndex; - uint32_t timeMs; - float intensity; - uint32_t volLevel; - switch (strength) { - case EffectStrength::LIGHT: - intensity = 0.5f; - break; - case EffectStrength::MEDIUM: - intensity = 0.7f; - break; - case EffectStrength::STRONG: - intensity = 1.0f; - break; - default: - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - - switch (effect) { - case Effect::TEXTURE_TICK: - effectIndex = WAVEFORM_LIGHT_TICK_INDEX; - intensity *= 0.5f; - break; - case Effect::TICK: - effectIndex = WAVEFORM_CLICK_INDEX; - intensity *= 0.5f; - break; - case Effect::CLICK: - effectIndex = WAVEFORM_CLICK_INDEX; - intensity *= 0.7f; - break; - case Effect::HEAVY_CLICK: - effectIndex = WAVEFORM_CLICK_INDEX; - intensity *= 1.0f; - break; - default: - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - - volLevel = intensityToVolLevel(intensity, effectIndex); - timeMs = mEffectDurations[effectIndex] + MAX_COLD_START_LATENCY_MS; - - *outEffectIndex = effectIndex; - *outTimeMs = timeMs; - *outVolLevel = volLevel; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength, - uint32_t *outTimeMs, dspmem_chunk *outCh) { - ndk::ScopedAStatus status; - uint32_t timeMs = 0; - uint32_t thisEffectIndex; - uint32_t thisTimeMs; - uint32_t thisVolLevel; - switch (effect) { - case Effect::DOUBLE_CLICK: - dspmem_chunk_write(outCh, 8, 0); /* Padding */ - dspmem_chunk_write(outCh, 8, 2); /* nsections */ - dspmem_chunk_write(outCh, 8, 0); /* repeat */ - - status = getSimpleDetails(Effect::CLICK, strength, &thisEffectIndex, &thisTimeMs, - &thisVolLevel); - if (!status.isOk()) { - return status; - } - timeMs += thisTimeMs; - - dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisVolLevel)); /* amplitude */ - dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisEffectIndex)); /* index */ - dspmem_chunk_write(outCh, 8, 0); /* repeat */ - dspmem_chunk_write(outCh, 8, 0); /* flags */ - dspmem_chunk_write(outCh, 16, - (uint16_t)(0xFFFF & WAVEFORM_DOUBLE_CLICK_SILENCE_MS)); /* delay */ - - timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS; - - status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisEffectIndex, &thisTimeMs, - &thisVolLevel); - if (!status.isOk()) { - return status; - } - timeMs += thisTimeMs; - - dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisVolLevel)); /* amplitude */ - dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisEffectIndex)); /* index */ - dspmem_chunk_write(outCh, 8, 0); /* repeat */ - dspmem_chunk_write(outCh, 8, 0); /* flags */ - dspmem_chunk_write(outCh, 16, 0); /* delay */ - dspmem_chunk_flush(outCh); - - break; - default: - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - - *outTimeMs = timeMs; - - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive, - uint32_t *outEffectIndex) { - uint32_t effectIndex; - uint32_t primitiveBit = 1 << int32_t(primitive); - if ((primitiveBit & mSupportedPrimitivesBits) == 0x0) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - - switch (primitive) { - case CompositePrimitive::NOOP: - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - case CompositePrimitive::CLICK: - effectIndex = WAVEFORM_CLICK_INDEX; - break; - case CompositePrimitive::THUD: - effectIndex = WAVEFORM_THUD_INDEX; - break; - case CompositePrimitive::SPIN: - effectIndex = WAVEFORM_SPIN_INDEX; - break; - case CompositePrimitive::QUICK_RISE: - effectIndex = WAVEFORM_QUICK_RISE_INDEX; - break; - case CompositePrimitive::SLOW_RISE: - effectIndex = WAVEFORM_SLOW_RISE_INDEX; - break; - case CompositePrimitive::QUICK_FALL: - effectIndex = WAVEFORM_QUICK_FALL_INDEX; - break; - case CompositePrimitive::LIGHT_TICK: - effectIndex = WAVEFORM_LIGHT_TICK_INDEX; - break; - case CompositePrimitive::LOW_TICK: - effectIndex = WAVEFORM_LOW_TICK_INDEX; - break; - default: - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - - *outEffectIndex = effectIndex; - - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strength, - const std::shared_ptr &callback, - int32_t *outTimeMs) { - ndk::ScopedAStatus status; - uint32_t effectIndex; - uint32_t timeMs = 0; - uint32_t volLevel; - dspmem_chunk *ch = nullptr; - switch (effect) { - case Effect::TEXTURE_TICK: - // fall-through - case Effect::TICK: - // fall-through - case Effect::CLICK: - // fall-through - case Effect::HEAVY_CLICK: - status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel); - break; - case Effect::DOUBLE_CLICK: - ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_COMP]{0x00}, - FF_CUSTOM_DATA_LEN_MAX_COMP); - status = getCompoundDetails(effect, strength, &timeMs, ch); - volLevel = VOLTAGE_SCALE_MAX; - break; - default: - status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - break; - } - if (!status.isOk()) { - goto exit; - } - - status = performEffect(effectIndex, volLevel, ch, callback); - -exit: - *outTimeMs = timeMs; - return status; -} - -ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel, - dspmem_chunk *ch, - const std::shared_ptr &callback) { - setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX, false); - - return on(MAX_TIME_MS, effectIndex, ch, callback); -} - -void Vibrator::waitForComplete(std::shared_ptr &&callback) { - if (!mHwApi->pollVibeState(VIBE_STATE_HAPTIC, POLLING_TIMEOUT)) { - ALOGW("Failed to get state \"Haptic\""); - } - mHwApi->pollVibeState(VIBE_STATE_STOPPED); - - const std::scoped_lock lock(mActiveId_mutex); - if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && - (!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { - ALOGE("Failed to clean up the composed effect %d", mActiveId); - } - mActiveId = -1; - - if (callback) { - auto ret = callback->onComplete(); - if (!ret.isOk()) { - ALOGE("Failed completion callback: %d", ret.getExceptionCode()); - } - } -} - -uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) { - uint32_t volLevel; - auto calc = [](float intst, std::array v) -> uint32_t { - return std::lround(intst * (v[1] - v[0])) + v[0]; - }; - - switch (effectIndex) { - case WAVEFORM_LIGHT_TICK_INDEX: - volLevel = calc(intensity, mTickEffectVol); - break; - case WAVEFORM_QUICK_RISE_INDEX: - // fall-through - case WAVEFORM_QUICK_FALL_INDEX: - volLevel = calc(intensity, mLongEffectVol); - break; - case WAVEFORM_CLICK_INDEX: - // fall-through - case WAVEFORM_THUD_INDEX: - // fall-through - case WAVEFORM_SPIN_INDEX: - // fall-through - case WAVEFORM_SLOW_RISE_INDEX: - // fall-through - default: - volLevel = calc(intensity, mClickEffectVol); - break; - } - return volLevel; -} - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/Vibrator.h b/vibrator/cs40l26/Vibrator.h deleted file mode 100644 index 7c9e99c..0000000 --- a/vibrator/cs40l26/Vibrator.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * 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. - */ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -class Vibrator : public BnVibrator { - public: - // APIs for interfacing with the kernel driver. - class HwApi { - public: - virtual ~HwApi() = default; - // Stores the LRA resonant frequency to be used for PWLE playback - // and click compensation. - virtual bool setF0(std::string value) = 0; - // Stores the frequency offset for long vibrations. - virtual bool setF0Offset(uint32_t value) = 0; - // Stores the LRA series resistance to be used for click - // compensation. - virtual bool setRedc(std::string value) = 0; - // Stores the LRA Q factor to be used for Q-dependent waveform - // selection. - virtual bool setQ(std::string value) = 0; - // Reports the number of effect waveforms loaded in firmware. - virtual bool getEffectCount(uint32_t *value) = 0; - // Blocks until timeout or vibrator reaches desired state - // (2 = ASP enabled, 1 = haptic enabled, 0 = disabled). - virtual bool pollVibeState(uint32_t value, int32_t timeoutMs = -1) = 0; - // Reports whether getOwtFreeSpace() is supported. - virtual bool hasOwtFreeSpace() = 0; - // Reports the available OWT bytes. - virtual bool getOwtFreeSpace(uint32_t *value) = 0; - // Enables/Disables F0 compensation enable status - virtual bool setF0CompEnable(bool value) = 0; - // Enables/Disables Redc compensation enable status - virtual bool setRedcCompEnable(bool value) = 0; - // Stores the minumun delay time between playback and stop effects. - virtual bool setMinOnOffInterval(uint32_t value) = 0; - // Gets the scaling factor for contextual haptic events. - virtual uint32_t getContextScale() = 0; - // Gets the enable status for contextual haptic events. - virtual bool getContextEnable() = 0; - // Gets the settling time for contextual haptic events. - // This will allow the device to stay face up for the duration given, - // even if InMotion events were detected. - virtual uint32_t getContextSettlingTime() = 0; - // Gets the cooldown time for contextual haptic events. - // This is used to avoid changing the scale of close playback events. - virtual uint32_t getContextCooldownTime() = 0; - // Checks the enable status for contextual haptics fade feature. When enabled - // this feature will cause the scaling factor to fade back up to max over - // the setting time set, instead of instantaneously changing it back to max. - virtual bool getContextFadeEnable() = 0; - // Indicates the number of 0.125-dB steps of attenuation to apply to - // waveforms triggered in response to vibration calls from the - // Android vibrator HAL. - virtual bool setFFGain(int fd, uint16_t value) = 0; - // Create/modify custom effects for all physical waveforms. - virtual bool setFFEffect(int fd, struct ff_effect *effect, uint16_t timeoutMs) = 0; - // Activates/deactivates the effect index after setFFGain() and setFFEffect(). - virtual bool setFFPlay(int fd, int8_t index, bool value) = 0; - // Get the Alsa device for the audio coupled haptics effect - virtual bool getHapticAlsaDevice(int *card, int *device) = 0; - // Set haptics PCM amplifier before triggering audio haptics feature - virtual bool setHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, - int device) = 0; - // Set OWT waveform for compose or compose PWLE request - virtual bool uploadOwtEffect(int fd, uint8_t *owtData, uint32_t numBytes, - struct ff_effect *effect, uint32_t *outEffectIndex, - int *status) = 0; - // Erase OWT waveform - virtual bool eraseOwtEffect(int fd, int8_t effectIndex, std::vector *effect) = 0; - // Emit diagnostic information to the given file. - virtual void debug(int fd) = 0; - }; - - // APIs for obtaining calibration/configuration data from persistent memory. - class HwCal { - public: - virtual ~HwCal() = default; - // Obtain the calibration version - virtual bool getVersion(uint32_t *value) = 0; - // Obtains the LRA resonant frequency to be used for PWLE playback - // and click compensation. - virtual bool getF0(std::string *value) = 0; - // Obtains the LRA series resistance to be used for click - // compensation. - virtual bool getRedc(std::string *value) = 0; - // Obtains the LRA Q factor to be used for Q-dependent waveform - // selection. - virtual bool getQ(std::string *value) = 0; - // Obtains frequency shift for long vibrations. - virtual bool getLongFrequencyShift(int32_t *value) = 0; - // Obtains the v0/v1(min/max) voltage levels to be applied for - // tick/click/long in units of 1%. - virtual bool getTickVolLevels(std::array *value) = 0; - virtual bool getClickVolLevels(std::array *value) = 0; - virtual bool getLongVolLevels(std::array *value) = 0; - // Checks if the chirp feature is enabled. - virtual bool isChirpEnabled() = 0; - // Obtains the supported primitive effects. - virtual bool getSupportedPrimitives(uint32_t *value) = 0; - // Checks if the f0 compensation feature needs to be enabled. - virtual bool isF0CompEnabled() = 0; - // Checks if the redc compensation feature needs to be enabled. - virtual bool isRedcCompEnabled() = 0; - // Emit diagnostic information to the given file. - virtual void debug(int fd) = 0; - }; - - public: - Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal); - - ndk::ScopedAStatus getCapabilities(int32_t *_aidl_return) override; - ndk::ScopedAStatus off() override; - ndk::ScopedAStatus on(int32_t timeoutMs, - const std::shared_ptr &callback) override; - ndk::ScopedAStatus perform(Effect effect, EffectStrength strength, - const std::shared_ptr &callback, - int32_t *_aidl_return) override; - ndk::ScopedAStatus getSupportedEffects(std::vector *_aidl_return) override; - ndk::ScopedAStatus setAmplitude(float amplitude) override; - ndk::ScopedAStatus setExternalControl(bool enabled) override; - ndk::ScopedAStatus getCompositionDelayMax(int32_t *maxDelayMs); - ndk::ScopedAStatus getCompositionSizeMax(int32_t *maxSize); - ndk::ScopedAStatus getSupportedPrimitives(std::vector *supported) override; - ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive, - int32_t *durationMs) override; - ndk::ScopedAStatus compose(const std::vector &composite, - const std::shared_ptr &callback) override; - ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector *_aidl_return) override; - ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override; - ndk::ScopedAStatus alwaysOnDisable(int32_t id) override; - ndk::ScopedAStatus getResonantFrequency(float *resonantFreqHz) override; - ndk::ScopedAStatus getQFactor(float *qFactor) override; - ndk::ScopedAStatus getFrequencyResolution(float *freqResolutionHz) override; - ndk::ScopedAStatus getFrequencyMinimum(float *freqMinimumHz) override; - ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector *_aidl_return) override; - ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t *durationMs) override; - ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t *maxSize) override; - ndk::ScopedAStatus getSupportedBraking(std::vector *supported) override; - ndk::ScopedAStatus composePwle(const std::vector &composite, - const std::shared_ptr &callback) override; - - binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; - - private: - ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, struct dspmem_chunk *ch, - const std::shared_ptr &callback); - // set 'amplitude' based on an arbitrary scale determined by 'maximum' - ndk::ScopedAStatus setEffectAmplitude(float amplitude, float maximum, bool scalable); - ndk::ScopedAStatus setGlobalAmplitude(bool set); - // 'simple' effects are those precompiled and loaded into the controller - ndk::ScopedAStatus getSimpleDetails(Effect effect, EffectStrength strength, - uint32_t *outEffectIndex, uint32_t *outTimeMs, - uint32_t *outVolLevel); - // 'compound' effects are those composed by stringing multiple 'simple' effects - ndk::ScopedAStatus getCompoundDetails(Effect effect, EffectStrength strength, - uint32_t *outTimeMs, struct dspmem_chunk *outCh); - ndk::ScopedAStatus getPrimitiveDetails(CompositePrimitive primitive, uint32_t *outEffectIndex); - ndk::ScopedAStatus performEffect(Effect effect, EffectStrength strength, - const std::shared_ptr &callback, - int32_t *outTimeMs); - ndk::ScopedAStatus performEffect(uint32_t effectIndex, uint32_t volLevel, - struct dspmem_chunk *ch, - const std::shared_ptr &callback); - ndk::ScopedAStatus setPwle(const std::string &pwleQueue); - bool isUnderExternalControl(); - void waitForComplete(std::shared_ptr &&callback); - uint32_t intensityToVolLevel(float intensity, uint32_t effectIndex); - bool findHapticAlsaDevice(int *card, int *device); - bool hasHapticAlsaDevice(); - bool enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device); - uint16_t amplitudeToScale(float amplitude, float maximum, bool scalable); - void updateContext(); - - std::unique_ptr mHwApi; - std::unique_ptr mHwCal; - uint32_t mF0Offset; - std::array mTickEffectVol; - std::array mClickEffectVol; - std::array mLongEffectVol; - std::vector mFfEffects; - std::vector mEffectDurations; - std::future mAsyncHandle; - ::android::base::unique_fd mInputFd; - int8_t mActiveId{-1}; - struct pcm *mHapticPcm; - int mCard; - int mDevice; - bool mHasHapticAlsaDevice{false}; - bool mIsUnderExternalControl; - float mLongEffectScale = 1.0; - bool mIsChirpEnabled; - uint32_t mScaleTime; - bool mFadeEnable; - uint32_t mScalingFactor; - uint32_t mScaleCooldown; - bool mContextEnable; - uint32_t mSupportedPrimitivesBits = 0x0; - std::vector mSupportedPrimitives; - bool mConfigHapticAlsaDeviceDone{false}; -}; - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.rc deleted file mode 100644 index 6986d1a..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.rc +++ /dev/null @@ -1,47 +0,0 @@ -on property:vendor.all.modules.ready=1 - wait /sys/bus/i2c/devices/i2c-cs40l26a/calibration/redc_cal_time_ms - - mkdir /mnt/vendor/persist/haptics 0770 system system - chmod 770 /mnt/vendor/persist/haptics - chmod 440 /mnt/vendor/persist/haptics/cs40l26.cal - chown system system /mnt/vendor/persist/haptics - chown system system /mnt/vendor/persist/haptics/cs40l26.cal - - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/calibration/f0_stored - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/calibration/q_stored - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/calibration/redc_stored - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/vibe_state - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/num_waves - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/f0_offset - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/owt_free_space - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/f0_comp_enable - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/redc_comp_enable - chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/delay_before_stop_playback_us - - enable vendor.vibrator.cs40l26 - -service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-private-lynx - class hal - user system - group system input context_hub - - setenv INPUT_EVENT_NAME cs40l26_input - setenv INPUT_EVENT_PATH /dev/input/event* - setenv PROPERTY_PREFIX ro.vendor.vibrator.hal. - setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l26.cal - - setenv HWAPI_PATH_PREFIX /sys/bus/i2c/devices/i2c-cs40l26a/ - setenv HWAPI_DEBUG_PATHS " - calibration/f0_stored - calibration/redc_stored - calibration/q_stored - default/vibe_state - default/num_waves - default/f0_offset - default/owt_free_space - default/f0_comp_enable - default/redc_comp_enable - default/delay_before_stop_playback_us - " - - disabled diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.xml b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.xml deleted file mode 100644 index 4db8f8c..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private-lynx.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - android.hardware.vibrator - 2 - IVibrator/default - - diff --git a/vibrator/cs40l26/device.mk b/vibrator/cs40l26/device.mk deleted file mode 100644 index 68860ef..0000000 --- a/vibrator/cs40l26/device.mk +++ /dev/null @@ -1,6 +0,0 @@ -PRODUCT_PACKAGES += \ - android.hardware.vibrator-service.cs40l26-private-lynx - -BOARD_SEPOLICY_DIRS += \ - hardware/google/pixel-sepolicy/vibrator/common \ - hardware/google/pixel-sepolicy/vibrator/cs40l26 diff --git a/vibrator/cs40l26/inc/CapoDetector.h b/vibrator/cs40l26/inc/CapoDetector.h deleted file mode 100644 index 4b898ef..0000000 --- a/vibrator/cs40l26/inc/CapoDetector.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2022 Google LLC. All Rights Reserved. - * - * 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 "proto/capo.pb.h" - -using android::sp; -using android::chre::HostProtocolHost; -using android::chre::IChreMessageHandlers; -using android::chre::SocketClient; - -// following convention of CHRE code. -namespace fbs = ::chre::fbs; - -namespace android { -namespace chre { - -#define NS_FROM_MS(x) ((x)*1000000) - -struct CapoMDParams { - uint64_t still_time_threshold_ns; - uint32_t window_width_ns; - float motion_confidence_threshold; - float still_confidence_threshold; - float var_threshold; - float var_threshold_delta; -}; - -class CapoDetector : public android::chre::SocketClient::ICallbacks, - public android::chre::IChreMessageHandlers, - public android::chre::SocketClient { - public: - // Typedef declaration for callback function. - typedef std::function cb_fn_t; - - // Called when initializing connection with CHRE socket. - static android::sp start(); - // Called when the socket is successfully (re-)connected. - // Reset the position and try to send NanoappList request. - void onConnected() override; - // Called when we have failed to (re-)connect the socket after many attempts - // and are giving up. - void onConnectionAborted() override; - // Invoked when the socket is disconnected, and this connection loss - // was not the result of an explicit call to disconnect(). - // Reset the position while disconnecting. - void onDisconnected() override; - // Decode unix socket msgs to CHRE messages, and call the appropriate - // callback depending on the CHRE message. - void onMessageReceived(const void *data, size_t length) override; - // Listen for messages from capo nanoapp and handle the message. - void handleNanoappMessage(const ::chre::fbs::NanoappMessageT &message) override; - // Handle the response of a NanoappList request. - // Ensure that capo nanoapp is running. - void handleNanoappListResponse(const ::chre::fbs::NanoappListResponseT &response) override; - // Send enabling message to the nanoapp. - void enable(); - - // Get last carried position type. - uint8_t getCarriedPosition() { return last_position_type_; } - // Get the host endpoint. - uint16_t getHostEndPoint() { return kHostEndpoint; } - // Get the capo nanoapp ID. - uint64_t getNanoppAppId() { return kCapoNanoappId; } - // Set up callback_func_ if needed. - void setCallback(cb_fn_t cb) { callback_func_ = cb; } - - private: - // Nanoapp ID of capo, ref: go/nanoapp-id-tracker. - static constexpr uint64_t kCapoNanoappId = 0x476f6f676c001020ULL; - // String of socket name for connecting chre. - static constexpr char kChreSocketName[] = "chre"; - // The host endpoint we use when sending message. - // Set with 0x9020 based on 0x8000 AND capo_app_id(1020). - // Ref: go/host-endpoint-id-tracker. - static constexpr uint16_t kHostEndpoint = 0x9020; - // Using for hal layer callback function. - cb_fn_t callback_func_ = nullptr; - // Last carried position received from the nano app - capo::PositionType last_position_type_ = capo::PositionType::UNKNOWN; - // Motion detector parameters for host-driven capo config - const struct CapoMDParams mCapoDetectorMDParameters { - .still_time_threshold_ns = NS_FROM_MS(500), - .window_width_ns = NS_FROM_MS(100), - .motion_confidence_threshold = 0.98f, - .still_confidence_threshold = 0.99f, - .var_threshold = 0.0125f, - .var_threshold_delta = 0.0125f, - }; -}; - -} // namespace chre -} // namespace android diff --git a/vibrator/cs40l26/proto/capo.proto b/vibrator/cs40l26/proto/capo.proto deleted file mode 100644 index 00b3186..0000000 --- a/vibrator/cs40l26/proto/capo.proto +++ /dev/null @@ -1,148 +0,0 @@ -syntax = "proto3"; - -package capo; - -// The message types used in capo nanoapp. Some of them are H2C -// (Host-To-CHRE) and others are C2H (CHRE-To-Host). One message type must be -// either H2C or C2H. Each message type can choose to have payload or not. -enum MessageType { - // Explicitly prevents 0 from being used as a valid message type. - // Doing so protects from obscure bugs caused by default-initialized values. - INVALID = 0; - - // Detector configuration related message start from 100. - // Signal for host to acknowledge the notification. - // It contains AckNotification payload. - ACK_NOTIFICATION = 100; - - // Signal to enable the carried position detector for device. No payload. - ENABLE_DETECTOR = 101; - - // Signal to disable the carried position detector for device. No payload. - DISABLE_DETECTOR = 102; - - // Signal to request most recent carried position detector state. No payload. - REQUEST_UPDATE = 103; - - // Signal to force carried position detector to refresh state. No payload. - FORCE_UPDATE = 104; - - // Configure the detector with desired parameters. ConfigureDetector payload. - CONFIGURE_DETECTOR = 105; - - // Position Detection related message start from 200. - // Signal while carried position of device detected. - // It contains PositionDetected payload. - POSITION_DETECTED = 200; -} - -// Notification Type. -enum NotificationType { - // Explicitly prevents 0 from being used as a valid notification type. - // Doing so protects from obscure bugs caused by default-initialized values. - INVALID_NOTIFICATION = 0; - - // Notification of enabling the carried position detector for device. - ENABLE_NOTIFICATION = 1; - - // Notification of disabling the carried position detector for device. - DISABLE_NOTIFICATION = 2; - - // Notification of request update from the carried position detector. - REQUEST_UPDATE_NOTIFICATION = 3; - - // Notification of force update from the carried position detector. - FORCE_UPDATE_NOTIFICATION = 4; - - // Notification of configure message. - CONFIGURE_NOTIFICATION = 5; -} - -// This message type used for host to acknowledge the notification. -message AckNotification { - // Sent a notification type for host to acknowledge. - NotificationType notification_type = 1; -} - -// Position type. -enum PositionType { - // Explicitly prevents 0 from being used as a valid carried position type. - // Doing so protects from obscure bugs caused by default-initialized values. - UNKNOWN = 0; - - // Carried position while device is in motion. - IN_MOTION = 1; - - // Carried position while device is on table and faces up. - ON_TABLE_FACE_UP = 2; - - // Carried position while device is on table and faces down. - ON_TABLE_FACE_DOWN = 3; - - // Carried position while device is stationary in unknown orientation. - STATIONARY_UNKNOWN = 4; -} - -// This message type used to notify host a position was a detected. -message PositionDetected { - // Sent a position type that is defined in PositionTypes. - PositionType position_type = 1; -} - -// Predefined configurations for detector. -enum ConfigPresetType { - // Explicitly prevents 0 from being used as a valid type. - // Doing so protects from obscure bugs caused by default-initialized values. - CONFIG_PRESET_UNSPECIFIED = 0; - - // Default preset. - CONFIG_PRESET_DEFAULT = 1; - - // Preset for sticky-stationary behavior. - CONFIG_PRESET_STICKY_STATIONARY = 2; -} - -message ConfigureDetector { - // Ref: cs/location/lbs/contexthub/nanoapps/motiondetector/motion_detector.h - message ConfigData { - // These algo parameters are exposed to enable tuning via server flags. - // The amount of time that the algorithm's computed stillness confidence - // must exceed still_confidence_threshold before entering the stationary - // state. Increasing this value will make the algorithm take longer to - // transition from the in motion state to the stationary state. - uint64 still_time_threshold_nanosecond = 1; - - // The amount of time in which the variance should be averaged. Increasing - // this value will effectively smooth the input data, making the algorithm - // less likely to transition between states. - uint32 window_width_nanosecond = 2; - - // The required confidence that the device is in motion before entering the - // motion state. Valid range is [0.0, 1.0], where 1.0 indicates that the - // algorithm must be 100% certain that the device is moving before entering - // the motion state. If the Instant Motion sensor is triggered, this value - // is ignored and the algorithm is immediately transitioned into the in - // motion state. - float motion_confidence_threshold = 3; - - // The required confidence that the device is stationary before entering the - // stationary state. Valid range is [0.0, 1.0], where 1.0 indicates that the - // algorithm must be 100% certain that the device is stationary before - // entering the stationary state. - float still_confidence_threshold = 4; - - // The variance threshold for the StillnessDetector algorithm. Increasing - // this value causes the algorithm to be less likely to detect motion. - float var_threshold = 5; - - // The variance threshold delta for the StillnessDetector algorithm about - // which the stationary confidence is calculated. Valid range is - // [0.0, var_threshold]. - float var_threshold_delta = 6; - } - - oneof type { - ConfigPresetType preset_type = 1; - ConfigData config_data = 2; - } -} diff --git a/vibrator/cs40l26/service.cpp b/vibrator/cs40l26/service.cpp deleted file mode 100644 index 27173d9..0000000 --- a/vibrator/cs40l26/service.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * 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 "Hardware.h" -#include "Vibrator.h" - -using ::aidl::android::hardware::vibrator::HwApi; -using ::aidl::android::hardware::vibrator::HwCal; -using ::aidl::android::hardware::vibrator::Vibrator; -using ::android::defaultServiceManager; -using ::android::ProcessState; -using ::android::sp; -using ::android::String16; - -#if !defined(VIBRATOR_NAME) -#define VIBRATOR_NAME "default" -#endif - -int main() { - auto svc = ndk::SharedRefBase::make(std::make_unique(), - std::make_unique()); - const auto svcName = std::string() + svc->descriptor + "/" + VIBRATOR_NAME; - - ProcessState::initWithDriver("/dev/vndbinder"); - - auto svcBinder = svc->asBinder(); - binder_status_t status = AServiceManager_addService(svcBinder.get(), svcName.c_str()); - LOG_ALWAYS_FATAL_IF(status != STATUS_OK); - - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); - - ABinderProcess_setThreadPoolMaxThreadCount(0); - ABinderProcess_joinThreadPool(); - - return EXIT_FAILURE; // should not reach -} diff --git a/vibrator/cs40l26/tests/Android.bp b/vibrator/cs40l26/tests/Android.bp deleted file mode 100644 index c53ec23..0000000 --- a/vibrator/cs40l26/tests/Android.bp +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// 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. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_test { - name: "VibratorHalCs40l26TestSuitePrivateLynx", - defaults: ["VibratorHalCs40l26TestDefaultsPrivateLynx"], - srcs: [ - "test-hwcal.cpp", - "test-hwapi.cpp", - "test-vibrator.cpp", - ], - static_libs: [ - "libc++fs", - "libgmock", - ], - shared_libs: [ - "libbase", - ], -} diff --git a/vibrator/cs40l26/tests/mocks.h b/vibrator/cs40l26/tests/mocks.h deleted file mode 100644 index 5ba0270..0000000 --- a/vibrator/cs40l26/tests/mocks.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * 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 ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H -#define ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H - -#include - -#include "Vibrator.h" - -class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi { - public: - MOCK_METHOD0(destructor, void()); - MOCK_METHOD1(setF0, bool(std::string value)); - MOCK_METHOD1(setF0Offset, bool(uint32_t value)); - MOCK_METHOD1(setRedc, bool(std::string value)); - MOCK_METHOD1(setQ, bool(std::string value)); - MOCK_METHOD1(getEffectCount, bool(uint32_t *value)); - MOCK_METHOD2(pollVibeState, bool(uint32_t value, int32_t timeoutMs)); - MOCK_METHOD0(hasOwtFreeSpace, bool()); - MOCK_METHOD1(getOwtFreeSpace, bool(uint32_t *value)); - MOCK_METHOD1(setF0CompEnable, bool(bool value)); - MOCK_METHOD1(setRedcCompEnable, bool(bool value)); - MOCK_METHOD1(setMinOnOffInterval, bool(uint32_t value)); - MOCK_METHOD0(getContextScale, uint32_t()); - MOCK_METHOD0(getContextEnable, bool()); - MOCK_METHOD0(getContextSettlingTime, uint32_t()); - MOCK_METHOD0(getContextCooldownTime, uint32_t()); - MOCK_METHOD0(getContextFadeEnable, bool()); - MOCK_METHOD2(setFFGain, bool(int fd, uint16_t value)); - MOCK_METHOD3(setFFEffect, bool(int fd, struct ff_effect *effect, uint16_t timeoutMs)); - MOCK_METHOD3(setFFPlay, bool(int fd, int8_t index, bool value)); - MOCK_METHOD2(getHapticAlsaDevice, bool(int *card, int *device)); - MOCK_METHOD4(setHapticPcmAmp, bool(struct pcm **haptic_pcm, bool enable, int card, int device)); - MOCK_METHOD6(uploadOwtEffect, - bool(int fd, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect, - uint32_t *outEffectIndex, int *status)); - MOCK_METHOD3(eraseOwtEffect, bool(int fd, int8_t effectIndex, std::vector *effect)); - MOCK_METHOD1(debug, void(int fd)); - - ~MockApi() override { destructor(); }; -}; - -class MockCal : public ::aidl::android::hardware::vibrator::Vibrator::HwCal { - public: - MOCK_METHOD0(destructor, void()); - MOCK_METHOD1(getVersion, bool(uint32_t *value)); - MOCK_METHOD1(getF0, bool(std::string &value)); - MOCK_METHOD1(getRedc, bool(std::string &value)); - MOCK_METHOD1(getQ, bool(std::string &value)); - MOCK_METHOD1(getLongFrequencyShift, bool(int32_t *value)); - MOCK_METHOD1(getTickVolLevels, bool(std::array *value)); - MOCK_METHOD1(getClickVolLevels, bool(std::array *value)); - MOCK_METHOD1(getLongVolLevels, bool(std::array *value)); - MOCK_METHOD0(isChirpEnabled, bool()); - MOCK_METHOD1(getSupportedPrimitives, bool(uint32_t *value)); - MOCK_METHOD0(isF0CompEnabled, bool()); - MOCK_METHOD0(isRedcCompEnabled, bool()); - MOCK_METHOD1(debug, void(int fd)); - - ~MockCal() override { destructor(); }; - // b/132668253: Workaround gMock Compilation Issue - bool getF0(std::string *value) { return getF0(*value); } - bool getRedc(std::string *value) { return getRedc(*value); } - bool getQ(std::string *value) { return getQ(*value); } -}; - -class MockVibratorCallback : public aidl::android::hardware::vibrator::BnVibratorCallback { - public: - MOCK_METHOD(ndk::ScopedAStatus, onComplete, ()); -}; - -#endif // ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H diff --git a/vibrator/cs40l26/tests/test-hwapi.cpp b/vibrator/cs40l26/tests/test-hwapi.cpp deleted file mode 100644 index cc4d465..0000000 --- a/vibrator/cs40l26/tests/test-hwapi.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * 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 "Hardware.h" - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -using ::testing::Test; -using ::testing::TestParamInfo; -using ::testing::ValuesIn; -using ::testing::WithParamInterface; - -class HwApiTest : public Test { - private: - static constexpr const char *FILE_NAMES[]{ - "calibration/f0_stored", - "default/f0_offset", - "calibration/redc_stored", - "calibration/q_stored", - "default/f0_comp_enable", - "default/redc_comp_enable", - "default/owt_free_space", - "default/num_waves", - "default/delay_before_stop_playback_us", - }; - - public: - void SetUp() override { - std::string prefix; - for (auto n : FILE_NAMES) { - auto name = std::filesystem::path(n); - auto path = std::filesystem::path(mFilesDir.path) / name; - fs_mkdirs(path.c_str(), S_IRWXU); - std::ofstream touch{path}; - mFileMap[name] = path; - } - prefix = std::filesystem::path(mFilesDir.path) / ""; - setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true); - mHwApi = std::make_unique(); - - for (auto n : FILE_NAMES) { - auto name = std::filesystem::path(n); - auto path = std::filesystem::path(mEmptyDir.path) / name; - } - prefix = std::filesystem::path(mEmptyDir.path) / ""; - setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true); - mNoApi = std::make_unique(); - } - - void TearDown() override { verifyContents(); } - - static auto ParamNameFixup(std::string str) { - std::replace(str.begin(), str.end(), '/', '_'); - return str; - } - - protected: - // Set expected file content for a test. - template - void expectContent(const std::string &name, const T &value) { - mExpectedContent[name] << value << std::endl; - } - - // Set actual file content for an input test. - template - void updateContent(const std::string &name, const T &value) { - std::ofstream(mFileMap[name]) << value << std::endl; - } - - template - void expectAndUpdateContent(const std::string &name, const T &value) { - expectContent(name, value); - updateContent(name, value); - } - - // Compare all file contents against expected contents. - void verifyContents() { - for (auto &a : mFileMap) { - std::ifstream file{a.second}; - std::string expect = mExpectedContent[a.first].str(); - std::string actual = std::string(std::istreambuf_iterator(file), - std::istreambuf_iterator()); - EXPECT_EQ(expect, actual) << a.first; - } - } - - protected: - std::unique_ptr mHwApi; - std::unique_ptr mNoApi; - std::map mFileMap; - TemporaryDir mFilesDir; - TemporaryDir mEmptyDir; - std::map mExpectedContent; -}; - -template -class HwApiTypedTest : public HwApiTest, - public WithParamInterface>> { - public: - static auto PrintParam(const TestParamInfo &info) { - return ParamNameFixup(std::get<0>(info.param)); - } - static auto MakeParam(std::string name, std::function func) { - return std::make_tuple(name, func); - } -}; - -using HasTest = HwApiTypedTest; - -TEST_P(HasTest, success_returnsTrue) { - auto param = GetParam(); - auto func = std::get<1>(param); - - EXPECT_TRUE(func(*mHwApi)); -} - -TEST_P(HasTest, success_returnsFalse) { - auto param = GetParam(); - auto func = std::get<1>(param); - - EXPECT_FALSE(func(*mNoApi)); -} - -INSTANTIATE_TEST_CASE_P(HwApiTests, HasTest, - ValuesIn({ - HasTest::MakeParam("default/owt_free_space", - &Vibrator::HwApi::hasOwtFreeSpace), - }), - HasTest::PrintParam); - -using GetUint32Test = HwApiTypedTest; - -TEST_P(GetUint32Test, success) { - auto param = GetParam(); - auto name = std::get<0>(param); - auto func = std::get<1>(param); - uint32_t expect = std::rand(); - uint32_t actual = ~expect; - - expectAndUpdateContent(name, expect); - - EXPECT_TRUE(func(*mHwApi, &actual)); - EXPECT_EQ(expect, actual); -} - -TEST_P(GetUint32Test, failure) { - auto param = GetParam(); - auto func = std::get<1>(param); - uint32_t value; - - EXPECT_FALSE(func(*mNoApi, &value)); -} - -INSTANTIATE_TEST_CASE_P(HwApiTests, GetUint32Test, - ValuesIn({ - GetUint32Test::MakeParam("default/num_waves", - &Vibrator::HwApi::getEffectCount), - GetUint32Test::MakeParam("default/owt_free_space", - &Vibrator::HwApi::getOwtFreeSpace), - }), - GetUint32Test::PrintParam); - -using SetBoolTest = HwApiTypedTest; - -TEST_P(SetBoolTest, success_returnsTrue) { - auto param = GetParam(); - auto name = std::get<0>(param); - auto func = std::get<1>(param); - - expectContent(name, "1"); - - EXPECT_TRUE(func(*mHwApi, true)); -} - -TEST_P(SetBoolTest, success_returnsFalse) { - auto param = GetParam(); - auto name = std::get<0>(param); - auto func = std::get<1>(param); - - expectContent(name, "0"); - - EXPECT_TRUE(func(*mHwApi, false)); -} - -TEST_P(SetBoolTest, failure) { - auto param = GetParam(); - auto func = std::get<1>(param); - - EXPECT_FALSE(func(*mNoApi, true)); - EXPECT_FALSE(func(*mNoApi, false)); -} - -INSTANTIATE_TEST_CASE_P(HwApiTests, SetBoolTest, - ValuesIn({ - SetBoolTest::MakeParam("default/f0_comp_enable", - &Vibrator::HwApi::setF0CompEnable), - SetBoolTest::MakeParam("default/redc_comp_enable", - &Vibrator::HwApi::setRedcCompEnable), - }), - SetBoolTest::PrintParam); - -using SetUint32Test = HwApiTypedTest; - -TEST_P(SetUint32Test, success) { - auto param = GetParam(); - auto name = std::get<0>(param); - auto func = std::get<1>(param); - uint32_t value = std::rand(); - - expectContent(name, value); - - EXPECT_TRUE(func(*mHwApi, value)); -} - -TEST_P(SetUint32Test, failure) { - auto param = GetParam(); - auto func = std::get<1>(param); - uint32_t value = std::rand(); - - EXPECT_FALSE(func(*mNoApi, value)); -} - -INSTANTIATE_TEST_CASE_P(HwApiTests, SetUint32Test, - ValuesIn({ - SetUint32Test::MakeParam("default/f0_offset", - &Vibrator::HwApi::setF0Offset), - SetUint32Test::MakeParam("default/delay_before_stop_playback_us", - &Vibrator::HwApi::setMinOnOffInterval), - }), - SetUint32Test::PrintParam); - -using SetStringTest = HwApiTypedTest; - -TEST_P(SetStringTest, success) { - auto param = GetParam(); - auto name = std::get<0>(param); - auto func = std::get<1>(param); - std::string value = TemporaryFile().path; - - expectContent(name, value); - - EXPECT_TRUE(func(*mHwApi, value)); -} - -TEST_P(SetStringTest, failure) { - auto param = GetParam(); - auto func = std::get<1>(param); - std::string value = TemporaryFile().path; - - EXPECT_FALSE(func(*mNoApi, value)); -} - -INSTANTIATE_TEST_CASE_P( - HwApiTests, SetStringTest, - ValuesIn({ - SetStringTest::MakeParam("calibration/f0_stored", &Vibrator::HwApi::setF0), - SetStringTest::MakeParam("calibration/redc_stored", &Vibrator::HwApi::setRedc), - SetStringTest::MakeParam("calibration/q_stored", &Vibrator::HwApi::setQ), - }), - SetStringTest::PrintParam); - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/tests/test-hwcal.cpp b/vibrator/cs40l26/tests/test-hwcal.cpp deleted file mode 100644 index e482b6c..0000000 --- a/vibrator/cs40l26/tests/test-hwcal.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * 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 "Hardware.h" - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -using ::testing::Test; - -class HwCalTest : public Test { - protected: - static constexpr std::array V_TICK_DEFAULT = {1, 100}; - static constexpr std::array V_CLICK_DEFAULT = {1, 100}; - static constexpr std::array V_LONG_DEFAULT = {1, 100}; - - public: - void SetUp() override { setenv("CALIBRATION_FILEPATH", mCalFile.path, true); } - - private: - template - static void pack(std::ostream &stream, const T &value, std::string lpad, std::string rpad) { - stream << lpad << value << rpad; - } - - template ::size_type N> - static void pack(std::ostream &stream, const std::array &value, std::string lpad, - std::string rpad) { - for (auto &entry : value) { - pack(stream, entry, lpad, rpad); - } - } - - protected: - void createHwCal() { mHwCal = std::make_unique(); } - - template - void write(const std::string key, const T &value, std::string lpad = " ", - std::string rpad = "") { - std::ofstream calfile{mCalFile.path, std::ios_base::app}; - calfile << key << ":"; - pack(calfile, value, lpad, rpad); - calfile << std::endl; - } - - void unlink() { ::unlink(mCalFile.path); } - - protected: - std::unique_ptr mHwCal; - TemporaryFile mCalFile; -}; - -TEST_F(HwCalTest, f0_measured) { - uint32_t randInput = std::rand(); - std::string expect = std::to_string(randInput); - std::string actual = std::to_string(~randInput); - - write("f0_measured", expect); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getF0(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, f0_missing) { - std::string actual; - - createHwCal(); - - EXPECT_FALSE(mHwCal->getF0(&actual)); -} - -TEST_F(HwCalTest, redc_measured) { - uint32_t randInput = std::rand(); - std::string expect = std::to_string(randInput); - std::string actual = std::to_string(~randInput); - - write("redc_measured", expect); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getRedc(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, redc_missing) { - std::string actual; - - createHwCal(); - - EXPECT_FALSE(mHwCal->getRedc(&actual)); -} - -TEST_F(HwCalTest, q_measured) { - uint32_t randInput = std::rand(); - std::string expect = std::to_string(randInput); - std::string actual = std::to_string(~randInput); - - write("q_measured", expect); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getQ(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, q_missing) { - std::string actual; - - createHwCal(); - - EXPECT_FALSE(mHwCal->getQ(&actual)); -} - -TEST_F(HwCalTest, v_levels) { - std::array expect; - std::array actual; - - // voltage for tick effects - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - - write("v_tick", expect); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getTickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - // voltage for click effects - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - - write("v_click", expect); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getClickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - // voltage for long effects - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - - write("v_long", expect); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getLongVolLevels(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, v_missing) { - std::array expect = V_TICK_DEFAULT; - std::array actual; - - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; }); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getTickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_CLICK_DEFAULT; - - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; }); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getClickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_LONG_DEFAULT; - - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; }); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getLongVolLevels(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, v_short) { - std::array expect = V_TICK_DEFAULT; - std::array actual; - - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; }); - - write("v_tick", std::array()); - write("v_click", std::array()); - write("v_long", std::array()); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getTickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_CLICK_DEFAULT; - EXPECT_TRUE(mHwCal->getClickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_LONG_DEFAULT; - EXPECT_TRUE(mHwCal->getLongVolLevels(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, v_long) { - std::array expect = V_TICK_DEFAULT; - std::array actual; - - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; }); - - write("v_tick", std::array()); - write("v_click", std::array()); - write("v_long", std::array()); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getTickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_CLICK_DEFAULT; - EXPECT_TRUE(mHwCal->getClickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_LONG_DEFAULT; - EXPECT_TRUE(mHwCal->getLongVolLevels(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, v_nofile) { - std::array expect = V_TICK_DEFAULT; - std::array actual; - - std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; }); - - write("v_tick", actual); - write("v_click", actual); - write("v_long", actual); - unlink(); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getTickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_CLICK_DEFAULT; - EXPECT_TRUE(mHwCal->getClickVolLevels(&actual)); - EXPECT_EQ(expect, actual); - - expect = V_LONG_DEFAULT; - EXPECT_TRUE(mHwCal->getLongVolLevels(&actual)); - EXPECT_EQ(expect, actual); -} - -TEST_F(HwCalTest, multiple) { - uint32_t randInput = std::rand(); - std::string f0Expect = std::to_string(randInput); - std::string f0Actual = std::to_string(~randInput); - randInput = std::rand(); - std::string redcExpect = std::to_string(randInput); - std::string redcActual = std::to_string(~randInput); - randInput = std::rand(); - std::string qExpect = std::to_string(randInput); - std::string qActual = std::to_string(~randInput); - std::array volTickExpect, volClickExpect, volLongExpect; - std::array volActual; - - std::transform(volTickExpect.begin(), volTickExpect.end(), volActual.begin(), [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - - write("f0_measured", f0Expect); - write("redc_measured", redcExpect); - write("q_measured", qExpect); - write("v_tick", volTickExpect); - std::transform(volClickExpect.begin(), volClickExpect.end(), volActual.begin(), - [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - write("v_click", volClickExpect); - std::transform(volLongExpect.begin(), volLongExpect.end(), volActual.begin(), [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - write("v_long", volLongExpect); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getF0(&f0Actual)); - EXPECT_EQ(f0Expect, f0Actual); - EXPECT_TRUE(mHwCal->getRedc(&redcActual)); - EXPECT_EQ(redcExpect, redcActual); - EXPECT_TRUE(mHwCal->getQ(&qActual)); - EXPECT_EQ(qExpect, qActual); - EXPECT_TRUE(mHwCal->getTickVolLevels(&volActual)); - EXPECT_EQ(volTickExpect, volActual); - EXPECT_TRUE(mHwCal->getClickVolLevels(&volActual)); - EXPECT_EQ(volClickExpect, volActual); - EXPECT_TRUE(mHwCal->getLongVolLevels(&volActual)); - EXPECT_EQ(volLongExpect, volActual); -} - -TEST_F(HwCalTest, trimming) { - uint32_t randInput = std::rand(); - std::string f0Expect = std::to_string(randInput); - std::string f0Actual = std::to_string(~randInput); - randInput = std::rand(); - std::string redcExpect = std::to_string(randInput); - std::string redcActual = std::to_string(randInput); - randInput = std::rand(); - std::string qExpect = std::to_string(randInput); - std::string qActual = std::to_string(randInput); - std::array volTickExpect, volClickExpect, volLongExpect; - std::array volActual; - - std::transform(volTickExpect.begin(), volTickExpect.end(), volActual.begin(), [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - - write("f0_measured", f0Expect, " \t", "\t "); - write("redc_measured", redcExpect, " \t", "\t "); - write("q_measured", qExpect, " \t", "\t "); - write("v_tick", volTickExpect, " \t", "\t "); - std::transform(volClickExpect.begin(), volClickExpect.end(), volActual.begin(), - [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - write("v_click", volClickExpect, " \t", "\t "); - std::transform(volLongExpect.begin(), volLongExpect.end(), volActual.begin(), [](uint32_t &e) { - e = std::rand(); - return ~e; - }); - write("v_long", volLongExpect, " \t", "\t "); - - createHwCal(); - - EXPECT_TRUE(mHwCal->getF0(&f0Actual)); - EXPECT_EQ(f0Expect, f0Actual); - EXPECT_TRUE(mHwCal->getRedc(&redcActual)); - EXPECT_EQ(redcExpect, redcActual); - EXPECT_TRUE(mHwCal->getQ(&qActual)); - EXPECT_EQ(qExpect, qActual); - EXPECT_TRUE(mHwCal->getTickVolLevels(&volActual)); - EXPECT_EQ(volTickExpect, volActual); - EXPECT_TRUE(mHwCal->getClickVolLevels(&volActual)); - EXPECT_EQ(volClickExpect, volActual); - EXPECT_TRUE(mHwCal->getLongVolLevels(&volActual)); - EXPECT_EQ(volLongExpect, volActual); -} - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/tests/test-vibrator.cpp b/vibrator/cs40l26/tests/test-vibrator.cpp deleted file mode 100644 index 603ef5e..0000000 --- a/vibrator/cs40l26/tests/test-vibrator.cpp +++ /dev/null @@ -1,692 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * 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 "Vibrator.h" -#include "mocks.h" -#include "types.h" -#include "utils.h" - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::Assign; -using ::testing::AtLeast; -using ::testing::AtMost; -using ::testing::Combine; -using ::testing::DoAll; -using ::testing::DoDefault; -using ::testing::Exactly; -using ::testing::Expectation; -using ::testing::ExpectationSet; -using ::testing::Ge; -using ::testing::Mock; -using ::testing::MockFunction; -using ::testing::Range; -using ::testing::Return; -using ::testing::Sequence; -using ::testing::SetArgPointee; -using ::testing::SetArgReferee; -using ::testing::Test; -using ::testing::TestParamInfo; -using ::testing::ValuesIn; -using ::testing::WithParamInterface; - -// Forward Declarations - -static EffectQueue Queue(const QueueEffect &effect); -static EffectQueue Queue(const QueueDelay &delay); -template -static EffectQueue Queue(const T &first, const U &second, Args... rest); - -static EffectLevel Level(float intensity, float levelLow, float levelHigh); -static EffectScale Scale(float intensity, float levelLow, float levelHigh); - -// Constants With Arbitrary Values - -static constexpr uint32_t CAL_VERSION = 2; -static constexpr std::array V_TICK_DEFAULT = {1, 100}; -static constexpr std::array V_CLICK_DEFAULT{1, 100}; -static constexpr std::array V_LONG_DEFAULT{1, 100}; -static constexpr std::array EFFECT_DURATIONS{ - 0, 100, 30, 1000, 300, 130, 150, 500, 100, 15, 20, 1000, 1000, 1000}; - -// Constants With Prescribed Values - -static const std::map EFFECT_INDEX{ - {Effect::CLICK, 2}, - {Effect::TICK, 2}, - {Effect::HEAVY_CLICK, 2}, - {Effect::TEXTURE_TICK, 9}, -}; -static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; -static constexpr uint8_t VOLTAGE_SCALE_MAX = 100; -static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby -static constexpr auto POLLING_TIMEOUT = 20; -enum WaveformIndex : uint16_t { - /* Physical waveform */ - WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0, - WAVEFORM_RESERVED_INDEX_1 = 1, - WAVEFORM_CLICK_INDEX = 2, - WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3, - WAVEFORM_THUD_INDEX = 4, - WAVEFORM_SPIN_INDEX = 5, - WAVEFORM_QUICK_RISE_INDEX = 6, - WAVEFORM_SLOW_RISE_INDEX = 7, - WAVEFORM_QUICK_FALL_INDEX = 8, - WAVEFORM_LIGHT_TICK_INDEX = 9, - WAVEFORM_LOW_TICK_INDEX = 10, - WAVEFORM_RESERVED_MFG_1, - WAVEFORM_RESERVED_MFG_2, - WAVEFORM_RESERVED_MFG_3, - WAVEFORM_MAX_PHYSICAL_INDEX, - /* OWT waveform */ - WAVEFORM_COMPOSE = WAVEFORM_MAX_PHYSICAL_INDEX, - WAVEFORM_PWLE, - /* - * Refer to , the WAVEFORM_MAX_INDEX must not exceed 96. - * #define FF_GAIN 0x60 // 96 in decimal - * #define FF_MAX_EFFECTS FF_GAIN - */ - WAVEFORM_MAX_INDEX, -}; - -static const EffectScale ON_GLOBAL_SCALE{levelToScale(V_LONG_DEFAULT[1])}; -static const EffectIndex ON_EFFECT_INDEX{0}; - -static const std::map EFFECT_SCALE{ - {{Effect::TICK, EffectStrength::LIGHT}, - Scale(0.5f * 0.5f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::TICK, EffectStrength::MEDIUM}, - Scale(0.5f * 0.7f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::TICK, EffectStrength::STRONG}, - Scale(0.5f * 1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::CLICK, EffectStrength::LIGHT}, - Scale(0.7f * 0.5f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::CLICK, EffectStrength::MEDIUM}, - Scale(0.7f * 0.7f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::CLICK, EffectStrength::STRONG}, - Scale(0.7f * 1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::HEAVY_CLICK, EffectStrength::LIGHT}, - Scale(1.0f * 0.5f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::HEAVY_CLICK, EffectStrength::MEDIUM}, - Scale(1.0f * 0.7f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::HEAVY_CLICK, EffectStrength::STRONG}, - Scale(1.0f * 1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - {{Effect::TEXTURE_TICK, EffectStrength::LIGHT}, - Scale(0.5f * 0.5f, V_TICK_DEFAULT[0], V_TICK_DEFAULT[1])}, - {{Effect::TEXTURE_TICK, EffectStrength::MEDIUM}, - Scale(0.5f * 0.7f, V_TICK_DEFAULT[0], V_TICK_DEFAULT[1])}, - {{Effect::TEXTURE_TICK, EffectStrength::STRONG}, - Scale(0.5f * 1.0f, V_TICK_DEFAULT[0], V_TICK_DEFAULT[1])}, -}; - -static const std::map EFFECT_QUEUE{ - {{Effect::DOUBLE_CLICK, EffectStrength::LIGHT}, - Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), - Level(0.7f * 0.5f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - 100, - QueueEffect{EFFECT_INDEX.at(Effect::CLICK), - Level(1.0f * 0.5f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])})}, - {{Effect::DOUBLE_CLICK, EffectStrength::MEDIUM}, - Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), - Level(0.7f * 0.7f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - 100, - QueueEffect{EFFECT_INDEX.at(Effect::CLICK), - Level(1.0f * 0.7f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])})}, - {{Effect::DOUBLE_CLICK, EffectStrength::STRONG}, - Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), - Level(0.7f * 1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])}, - 100, - QueueEffect{EFFECT_INDEX.at(Effect::CLICK), - Level(1.0f * 1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])})}, -}; - -EffectQueue Queue(const QueueEffect &effect) { - auto index = std::get<0>(effect); - auto level = std::get<1>(effect); - auto string = std::to_string(index) + "." + std::to_string(level); - auto duration = EFFECT_DURATIONS[index]; - return {string, duration}; -} - -EffectQueue Queue(const QueueDelay &delay) { - auto string = std::to_string(delay); - return {string, delay}; -} - -template -EffectQueue Queue(const T &first, const U &second, Args... rest) { - auto head = Queue(first); - auto tail = Queue(second, rest...); - auto string = std::get<0>(head) + "," + std::get<0>(tail); - auto duration = std::get<1>(head) + std::get<1>(tail); - return {string, duration}; -} - -static EffectLevel Level(float intensity, float levelLow, float levelHigh) { - return std::lround(intensity * (levelHigh - levelLow)) + levelLow; -} - -static EffectScale Scale(float intensity, float levelLow, float levelHigh) { - return levelToScale(Level(intensity, levelLow, levelHigh)); -} - -class VibratorTest : public Test { - public: - void SetUp() override { - setenv("INPUT_EVENT_NAME", "CS40L26TestSuite", true); - std::unique_ptr mockapi; - std::unique_ptr mockcal; - - createMock(&mockapi, &mockcal); - createVibrator(std::move(mockapi), std::move(mockcal)); - } - - void TearDown() override { deleteVibrator(); } - - protected: - void createMock(std::unique_ptr *mockapi, std::unique_ptr *mockcal) { - *mockapi = std::make_unique(); - *mockcal = std::make_unique(); - - mMockApi = mockapi->get(); - mMockCal = mockcal->get(); - - ON_CALL(*mMockApi, destructor()).WillByDefault(Assign(&mMockApi, nullptr)); - - ON_CALL(*mMockApi, setFFGain(_, _)).WillByDefault(Return(true)); - ON_CALL(*mMockApi, setFFEffect(_, _, _)).WillByDefault(Return(true)); - ON_CALL(*mMockApi, setFFPlay(_, _, _)).WillByDefault(Return(true)); - ON_CALL(*mMockApi, pollVibeState(_, _)).WillByDefault(Return(true)); - ON_CALL(*mMockApi, uploadOwtEffect(_, _, _, _, _, _)).WillByDefault(Return(true)); - ON_CALL(*mMockApi, eraseOwtEffect(_, _, _)).WillByDefault(Return(true)); - - ON_CALL(*mMockApi, getOwtFreeSpace(_)) - .WillByDefault(DoAll(SetArgPointee<0>(11504), Return(true))); - - ON_CALL(*mMockCal, destructor()).WillByDefault(Assign(&mMockCal, nullptr)); - - ON_CALL(*mMockCal, getVersion(_)) - .WillByDefault(DoAll(SetArgPointee<0>(CAL_VERSION), Return(true))); - - ON_CALL(*mMockCal, getTickVolLevels(_)) - .WillByDefault(DoAll(SetArgPointee<0>(V_TICK_DEFAULT), Return(true))); - ON_CALL(*mMockCal, getClickVolLevels(_)) - .WillByDefault(DoAll(SetArgPointee<0>(V_CLICK_DEFAULT), Return(true))); - ON_CALL(*mMockCal, getLongVolLevels(_)) - .WillByDefault(DoAll(SetArgPointee<0>(V_LONG_DEFAULT), Return(true))); - - relaxMock(false); - } - - void createVibrator(std::unique_ptr mockapi, std::unique_ptr mockcal, - bool relaxed = true) { - if (relaxed) { - relaxMock(true); - } - mVibrator = ndk::SharedRefBase::make(std::move(mockapi), std::move(mockcal)); - if (relaxed) { - relaxMock(false); - } - } - - void deleteVibrator(bool relaxed = true) { - if (relaxed) { - relaxMock(true); - } - mVibrator.reset(); - } - - private: - void relaxMock(bool relax) { - auto times = relax ? AnyNumber() : Exactly(0); - - Mock::VerifyAndClearExpectations(mMockApi); - Mock::VerifyAndClearExpectations(mMockCal); - - EXPECT_CALL(*mMockApi, destructor()).Times(times); - EXPECT_CALL(*mMockApi, setF0(_)).Times(times); - EXPECT_CALL(*mMockApi, setF0Offset(_)).Times(times); - EXPECT_CALL(*mMockApi, setRedc(_)).Times(times); - EXPECT_CALL(*mMockApi, setQ(_)).Times(times); - EXPECT_CALL(*mMockApi, hasOwtFreeSpace()).Times(times); - EXPECT_CALL(*mMockApi, getOwtFreeSpace(_)).Times(times); - EXPECT_CALL(*mMockApi, setF0CompEnable(_)).Times(times); - EXPECT_CALL(*mMockApi, setRedcCompEnable(_)).Times(times); - EXPECT_CALL(*mMockApi, pollVibeState(_, _)).Times(times); - EXPECT_CALL(*mMockApi, setFFGain(_, _)).Times(times); - EXPECT_CALL(*mMockApi, setFFEffect(_, _, _)).Times(times); - EXPECT_CALL(*mMockApi, setFFPlay(_, _, _)).Times(times); - EXPECT_CALL(*mMockApi, setMinOnOffInterval(_)).Times(times); - EXPECT_CALL(*mMockApi, getContextScale()).Times(times); - EXPECT_CALL(*mMockApi, getContextEnable()).Times(times); - EXPECT_CALL(*mMockApi, getContextSettlingTime()).Times(times); - EXPECT_CALL(*mMockApi, getContextCooldownTime()).Times(times); - EXPECT_CALL(*mMockApi, getContextFadeEnable()).Times(times); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).Times(times); - EXPECT_CALL(*mMockApi, setHapticPcmAmp(_, _, _, _)).Times(times); - - EXPECT_CALL(*mMockApi, debug(_)).Times(times); - - EXPECT_CALL(*mMockCal, destructor()).Times(times); - EXPECT_CALL(*mMockCal, getF0(_)).Times(times); - EXPECT_CALL(*mMockCal, getRedc(_)).Times(times); - EXPECT_CALL(*mMockCal, getQ(_)).Times(times); - EXPECT_CALL(*mMockCal, getTickVolLevels(_)).Times(times); - EXPECT_CALL(*mMockCal, getClickVolLevels(_)).Times(times); - EXPECT_CALL(*mMockCal, getLongVolLevels(_)).Times(times); - EXPECT_CALL(*mMockCal, isChirpEnabled()).Times(times); - EXPECT_CALL(*mMockCal, getLongFrequencyShift(_)).Times(times); - EXPECT_CALL(*mMockCal, isF0CompEnabled()).Times(times); - EXPECT_CALL(*mMockCal, isRedcCompEnabled()).Times(times); - EXPECT_CALL(*mMockCal, debug(_)).Times(times); - } - - protected: - MockApi *mMockApi; - MockCal *mMockCal; - std::shared_ptr mVibrator; - uint32_t mEffectIndex; -}; - -TEST_F(VibratorTest, Constructor) { - std::unique_ptr mockapi; - std::unique_ptr mockcal; - std::string f0Val = std::to_string(std::rand()); - std::string redcVal = std::to_string(std::rand()); - std::string qVal = std::to_string(std::rand()); - uint32_t calVer; - uint32_t supportedPrimitivesBits = 0x0; - Expectation volGet; - Sequence f0Seq, redcSeq, qSeq, supportedPrimitivesSeq; - - EXPECT_CALL(*mMockApi, destructor()).WillOnce(DoDefault()); - EXPECT_CALL(*mMockCal, destructor()).WillOnce(DoDefault()); - - deleteVibrator(false); - - createMock(&mockapi, &mockcal); - - EXPECT_CALL(*mMockCal, getF0(_)) - .InSequence(f0Seq) - .WillOnce(DoAll(SetArgReferee<0>(f0Val), Return(true))); - EXPECT_CALL(*mMockApi, setF0(f0Val)).InSequence(f0Seq).WillOnce(Return(true)); - - EXPECT_CALL(*mMockCal, getRedc(_)) - .InSequence(redcSeq) - .WillOnce(DoAll(SetArgReferee<0>(redcVal), Return(true))); - EXPECT_CALL(*mMockApi, setRedc(redcVal)).InSequence(redcSeq).WillOnce(Return(true)); - - EXPECT_CALL(*mMockCal, getQ(_)) - .InSequence(qSeq) - .WillOnce(DoAll(SetArgReferee<0>(qVal), Return(true))); - EXPECT_CALL(*mMockApi, setQ(qVal)).InSequence(qSeq).WillOnce(Return(true)); - - EXPECT_CALL(*mMockCal, getLongFrequencyShift(_)).WillOnce(Return(true)); - - mMockCal->getVersion(&calVer); - if (calVer == 2) { - volGet = EXPECT_CALL(*mMockCal, getTickVolLevels(_)).WillOnce(DoDefault()); - volGet = EXPECT_CALL(*mMockCal, getClickVolLevels(_)).WillOnce(DoDefault()); - volGet = EXPECT_CALL(*mMockCal, getLongVolLevels(_)).WillOnce(DoDefault()); - } - - EXPECT_CALL(*mMockCal, isF0CompEnabled()).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, setF0CompEnable(true)).WillOnce(Return(true)); - EXPECT_CALL(*mMockCal, isRedcCompEnabled()).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, setRedcCompEnable(true)).WillOnce(Return(true)); - - EXPECT_CALL(*mMockCal, isChirpEnabled()).WillOnce(Return(true)); - EXPECT_CALL(*mMockCal, getSupportedPrimitives(_)) - .InSequence(supportedPrimitivesSeq) - .WillOnce(DoAll(SetArgPointee<0>(supportedPrimitivesBits), Return(true))); - - EXPECT_CALL(*mMockApi, setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US)).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, getContextScale()).WillOnce(Return(0)); - EXPECT_CALL(*mMockApi, getContextEnable()).WillOnce(Return(false)); - EXPECT_CALL(*mMockApi, getContextSettlingTime()).WillOnce(Return(0)); - EXPECT_CALL(*mMockApi, getContextCooldownTime()).WillOnce(Return(0)); - EXPECT_CALL(*mMockApi, getContextFadeEnable()).WillOnce(Return(false)); - createVibrator(std::move(mockapi), std::move(mockcal), false); -} - -TEST_F(VibratorTest, on) { - Sequence s1, s2; - uint16_t duration = std::rand() + 1; - - EXPECT_CALL(*mMockApi, setFFGain(_, ON_GLOBAL_SCALE)).InSequence(s1).WillOnce(DoDefault()); - EXPECT_CALL(*mMockApi, setFFEffect(_, _, duration + MAX_COLD_START_LATENCY_MS)) - .InSequence(s2) - .WillOnce(DoDefault()); - EXPECT_CALL(*mMockApi, setFFPlay(_, ON_EFFECT_INDEX, true)) - .InSequence(s1, s2) - .WillOnce(DoDefault()); - EXPECT_TRUE(mVibrator->on(duration, nullptr).isOk()); -} - -TEST_F(VibratorTest, off) { - Sequence s1; - EXPECT_CALL(*mMockApi, setFFGain(_, ON_GLOBAL_SCALE)).InSequence(s1).WillOnce(DoDefault()); - EXPECT_TRUE(mVibrator->off().isOk()); -} - -TEST_F(VibratorTest, supportsAmplitudeControl_supported) { - int32_t capabilities; - EXPECT_CALL(*mMockApi, hasOwtFreeSpace()).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).WillOnce(Return(true)); - - EXPECT_TRUE(mVibrator->getCapabilities(&capabilities).isOk()); - EXPECT_GT(capabilities & IVibrator::CAP_AMPLITUDE_CONTROL, 0); -} - -TEST_F(VibratorTest, supportsExternalAmplitudeControl_unsupported) { - int32_t capabilities; - EXPECT_CALL(*mMockApi, hasOwtFreeSpace()).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).WillOnce(Return(true)); - - EXPECT_TRUE(mVibrator->getCapabilities(&capabilities).isOk()); - EXPECT_EQ(capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL, 0); -} - -TEST_F(VibratorTest, setAmplitude_supported) { - EffectAmplitude amplitude = static_cast(std::rand()) / RAND_MAX ?: 1.0f; - - EXPECT_CALL(*mMockApi, setFFGain(_, amplitudeToScale(amplitude))).WillOnce(Return(true)); - - EXPECT_TRUE(mVibrator->setAmplitude(amplitude).isOk()); -} - -TEST_F(VibratorTest, supportsExternalControl_supported) { - int32_t capabilities; - EXPECT_CALL(*mMockApi, hasOwtFreeSpace()).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).WillOnce(Return(true)); - - EXPECT_TRUE(mVibrator->getCapabilities(&capabilities).isOk()); - EXPECT_GT(capabilities & IVibrator::CAP_EXTERNAL_CONTROL, 0); -} - -TEST_F(VibratorTest, supportsExternalControl_unsupported) { - int32_t capabilities; - EXPECT_CALL(*mMockApi, hasOwtFreeSpace()).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).WillOnce(Return(false)); - - EXPECT_TRUE(mVibrator->getCapabilities(&capabilities).isOk()); - EXPECT_EQ(capabilities & IVibrator::CAP_EXTERNAL_CONTROL, 0); -} - -TEST_F(VibratorTest, setExternalControl_enable) { - Sequence s1, s2; - EXPECT_CALL(*mMockApi, setFFGain(_, ON_GLOBAL_SCALE)).InSequence(s1).WillOnce(DoDefault()); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).InSequence(s2).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, setHapticPcmAmp(_, true, _, _)) - .InSequence(s1, s2) - .WillOnce(Return(true)); - - EXPECT_TRUE(mVibrator->setExternalControl(true).isOk()); -} - -TEST_F(VibratorTest, setExternalControl_disable) { - Sequence s1, s2, s3, s4; - - // The default mIsUnderExternalControl is false, so it needs to turn on the External Control - // to make mIsUnderExternalControl become true. - EXPECT_CALL(*mMockApi, setFFGain(_, ON_GLOBAL_SCALE)) - .InSequence(s1) - .InSequence(s1) - .WillOnce(DoDefault()); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).InSequence(s2).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, setHapticPcmAmp(_, true, _, _)).InSequence(s3).WillOnce(Return(true)); - - EXPECT_TRUE(mVibrator->setExternalControl(true).isOk()); - - EXPECT_CALL(*mMockApi, setFFGain(_, levelToScale(VOLTAGE_SCALE_MAX))) - .InSequence(s4) - .WillOnce(DoDefault()); - EXPECT_CALL(*mMockApi, setHapticPcmAmp(_, false, _, _)) - .InSequence(s1, s2, s3, s4) - .WillOnce(Return(true)); - - EXPECT_TRUE(mVibrator->setExternalControl(false).isOk()); -} - -class EffectsTest : public VibratorTest, public WithParamInterface { - public: - static auto PrintParam(const TestParamInfo &info) { - auto param = info.param; - auto effect = std::get<0>(param); - auto strength = std::get<1>(param); - return toString(effect) + "_" + toString(strength); - } -}; - -TEST_P(EffectsTest, perform) { - auto param = GetParam(); - auto effect = std::get<0>(param); - auto strength = std::get<1>(param); - auto scale = EFFECT_SCALE.find(param); - auto queue = EFFECT_QUEUE.find(param); - EffectDuration duration; - auto callback = ndk::SharedRefBase::make(); - std::promise promise; - std::future future{promise.get_future()}; - auto complete = [&promise] { - promise.set_value(); - return ndk::ScopedAStatus::ok(); - }; - bool composeEffect; - - ExpectationSet eSetup; - Expectation eActivate, ePollHaptics, ePollStop, eEraseDone; - - if (scale != EFFECT_SCALE.end()) { - EffectIndex index = EFFECT_INDEX.at(effect); - duration = EFFECT_DURATIONS[index]; - - eSetup += EXPECT_CALL(*mMockApi, setFFGain(_, levelToScale(scale->second))) - .WillOnce(DoDefault()); - eActivate = EXPECT_CALL(*mMockApi, setFFPlay(_, index, true)) - .After(eSetup) - .WillOnce(DoDefault()); - } else if (queue != EFFECT_QUEUE.end()) { - duration = std::get<1>(queue->second); - eSetup += EXPECT_CALL(*mMockApi, setFFGain(_, ON_GLOBAL_SCALE)) - .After(eSetup) - .WillOnce(DoDefault()); - eSetup += EXPECT_CALL(*mMockApi, getOwtFreeSpace(_)).WillOnce(DoDefault()); - eSetup += EXPECT_CALL(*mMockApi, uploadOwtEffect(_, _, _, _, _, _)) - .After(eSetup) - .WillOnce(DoDefault()); - eActivate = EXPECT_CALL(*mMockApi, setFFPlay(_, WAVEFORM_COMPOSE, true)) - .After(eSetup) - .WillOnce(DoDefault()); - composeEffect = true; - } else { - duration = 0; - } - - if (duration) { - ePollHaptics = EXPECT_CALL(*mMockApi, pollVibeState(1, POLLING_TIMEOUT)) - .After(eActivate) - .WillOnce(DoDefault()); - ePollStop = EXPECT_CALL(*mMockApi, pollVibeState(0, -1)) - .After(ePollHaptics) - .WillOnce(DoDefault()); - if (composeEffect) { - eEraseDone = EXPECT_CALL(*mMockApi, eraseOwtEffect(_, _, _)) - .After(ePollStop) - .WillOnce(DoDefault()); - EXPECT_CALL(*callback, onComplete()).After(eEraseDone).WillOnce(complete); - } else { - EXPECT_CALL(*callback, onComplete()).After(ePollStop).WillOnce(complete); - } - } - - int32_t lengthMs; - ndk::ScopedAStatus status = mVibrator->perform(effect, strength, callback, &lengthMs); - if (status.isOk()) { - EXPECT_LE(duration, lengthMs); - } else { - EXPECT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode()); - EXPECT_EQ(0, lengthMs); - } - - if (duration) { - EXPECT_EQ(future.wait_for(std::chrono::milliseconds(100)), std::future_status::ready); - } -} - -const std::vector kEffects{ndk::enum_range().begin(), - ndk::enum_range().end()}; -const std::vector kEffectStrengths{ndk::enum_range().begin(), - ndk::enum_range().end()}; - -INSTANTIATE_TEST_CASE_P(VibratorTests, EffectsTest, - Combine(ValuesIn(kEffects.begin(), kEffects.end()), - ValuesIn(kEffectStrengths.begin(), kEffectStrengths.end())), - EffectsTest::PrintParam); - -struct PrimitiveParam { - CompositePrimitive primitive; - EffectIndex index; -}; - -class PrimitiveTest : public VibratorTest, public WithParamInterface { - public: - static auto PrintParam(const TestParamInfo &info) { - return toString(info.param.primitive); - } -}; - -const std::vector kPrimitiveParams = { - {CompositePrimitive::CLICK, 2}, {CompositePrimitive::THUD, 4}, - {CompositePrimitive::SPIN, 5}, {CompositePrimitive::QUICK_RISE, 6}, - {CompositePrimitive::SLOW_RISE, 7}, {CompositePrimitive::QUICK_FALL, 8}, - {CompositePrimitive::LIGHT_TICK, 9}, {CompositePrimitive::LOW_TICK, 10}, -}; - -TEST_P(PrimitiveTest, getPrimitiveDuration) { - auto param = GetParam(); - auto primitive = param.primitive; - auto index = param.index; - int32_t duration; - - EXPECT_EQ(EX_NONE, mVibrator->getPrimitiveDuration(primitive, &duration).getExceptionCode()); - EXPECT_EQ(EFFECT_DURATIONS[index], duration); -} - -INSTANTIATE_TEST_CASE_P(VibratorTests, PrimitiveTest, - ValuesIn(kPrimitiveParams.begin(), kPrimitiveParams.end()), - PrimitiveTest::PrintParam); - -struct ComposeParam { - std::string name; - std::vector composite; - EffectQueue queue; -}; - -class ComposeTest : public VibratorTest, public WithParamInterface { - public: - static auto PrintParam(const TestParamInfo &info) { return info.param.name; } -}; - -TEST_P(ComposeTest, compose) { - auto param = GetParam(); - auto composite = param.composite; - auto queue = std::get<0>(param.queue); - ExpectationSet eSetup; - Expectation eActivate, ePollHaptics, ePollStop, eEraseDone; - auto callback = ndk::SharedRefBase::make(); - std::promise promise; - std::future future{promise.get_future()}; - auto complete = [&promise] { - promise.set_value(); - return ndk::ScopedAStatus::ok(); - }; - - eSetup += EXPECT_CALL(*mMockApi, setFFGain(_, ON_GLOBAL_SCALE)) - .After(eSetup) - .WillOnce(DoDefault()); - eSetup += EXPECT_CALL(*mMockApi, getOwtFreeSpace(_)).WillOnce(DoDefault()); - eSetup += EXPECT_CALL(*mMockApi, uploadOwtEffect(_, _, _, _, _, _)) - .After(eSetup) - .WillOnce(DoDefault()); - eActivate = EXPECT_CALL(*mMockApi, setFFPlay(_, WAVEFORM_COMPOSE, true)) - .After(eSetup) - .WillOnce(DoDefault()); - - ePollHaptics = EXPECT_CALL(*mMockApi, pollVibeState(1, POLLING_TIMEOUT)) - .After(eActivate) - .WillOnce(DoDefault()); - ePollStop = - EXPECT_CALL(*mMockApi, pollVibeState(0, -1)).After(ePollHaptics).WillOnce(DoDefault()); - eEraseDone = - EXPECT_CALL(*mMockApi, eraseOwtEffect(_, _, _)).After(ePollStop).WillOnce(DoDefault()); - EXPECT_CALL(*callback, onComplete()).After(eEraseDone).WillOnce(complete); - - EXPECT_EQ(EX_NONE, mVibrator->compose(composite, callback).getExceptionCode()); - - EXPECT_EQ(future.wait_for(std::chrono::milliseconds(100)), std::future_status::ready); -} - -const std::vector kComposeParams = { - {"click", - {{0, CompositePrimitive::CLICK, 1.0f}}, - Queue(QueueEffect(2, Level(1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])), 0)}, - {"thud", - {{1, CompositePrimitive::THUD, 0.8f}}, - Queue(1, QueueEffect(4, Level(0.8f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])), 0)}, - {"spin", - {{2, CompositePrimitive::SPIN, 0.6f}}, - Queue(2, QueueEffect(5, Level(0.6f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])), 0)}, - {"quick_rise", - {{3, CompositePrimitive::QUICK_RISE, 0.4f}}, - Queue(3, QueueEffect(6, Level(0.4f, V_LONG_DEFAULT[0], V_LONG_DEFAULT[1])), 0)}, - {"slow_rise", - {{4, CompositePrimitive::SLOW_RISE, 0.0f}}, - Queue(4, QueueEffect(7, Level(0.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])), 0)}, - {"quick_fall", - {{5, CompositePrimitive::QUICK_FALL, 1.0f}}, - Queue(5, QueueEffect(8, Level(1.0f, V_LONG_DEFAULT[0], V_LONG_DEFAULT[1])), 0)}, - {"pop", - {{6, CompositePrimitive::SLOW_RISE, 1.0f}, {50, CompositePrimitive::THUD, 1.0f}}, - Queue(6, QueueEffect(7, Level(1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])), 50, - QueueEffect(4, Level(1.0f, V_CLICK_DEFAULT[0], V_CLICK_DEFAULT[1])), 0)}, - {"snap", - {{7, CompositePrimitive::QUICK_RISE, 1.0f}, {0, CompositePrimitive::QUICK_FALL, 1.0f}}, - Queue(7, QueueEffect(6, Level(1.0f, V_LONG_DEFAULT[0], V_LONG_DEFAULT[1])), - QueueEffect(8, Level(1.0f, V_LONG_DEFAULT[0], V_LONG_DEFAULT[1])), 0)}, -}; - -INSTANTIATE_TEST_CASE_P(VibratorTests, ComposeTest, - ValuesIn(kComposeParams.begin(), kComposeParams.end()), - ComposeTest::PrintParam); -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/tests/types.h b/vibrator/cs40l26/tests/types.h deleted file mode 100644 index e05c648..0000000 --- a/vibrator/cs40l26/tests/types.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * 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 ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H -#define ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H - -#include - -using EffectIndex = uint16_t; -using EffectLevel = uint32_t; -using EffectAmplitude = float; -using EffectScale = uint16_t; -using EffectDuration = uint32_t; -using EffectQueue = std::tuple; -using EffectTuple = std::tuple<::aidl::android::hardware::vibrator::Effect, - ::aidl::android::hardware::vibrator::EffectStrength>; - -using QueueEffect = std::tuple; -using QueueDelay = uint32_t; - -#endif // ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H diff --git a/vibrator/cs40l26/tests/utils.h b/vibrator/cs40l26/tests/utils.h deleted file mode 100644 index e7f6055..0000000 --- a/vibrator/cs40l26/tests/utils.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * 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 ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H -#define ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H - -#include - -#include "types.h" - -static inline EffectScale toScale(float amplitude, float maximum) { - float ratio = 100; /* Unit: % */ - if (maximum != 0) - ratio = amplitude / maximum * 100; - - if (maximum == 0 || ratio > 100) - ratio = 100; - - return std::round(ratio); -} - -static inline EffectScale levelToScale(EffectLevel level) { - return toScale(level, 100); -} - -static inline EffectScale amplitudeToScale(EffectAmplitude amplitude) { - return toScale(amplitude, 1.0f); -} - -static inline uint32_t msToCycles(EffectDuration ms) { - return ms * 48; -} - -#endif // ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H