diff --git a/conf/init.comet.rc b/conf/init.comet.rc index 5db789f..b0d45ca 100644 --- a/conf/init.comet.rc +++ b/conf/init.comet.rc @@ -50,3 +50,44 @@ on post-fs-data on post-fs-data chown bluetooth system /proc/bluetooth/timesync +# Haptics +on property:vendor.all.modules.ready=1 + 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/6-0043/calibration/f0_stored + chown system system /sys/bus/i2c/devices/5-0043/calibration/f0_stored + chown system system /sys/bus/i2c/devices/4-0043/calibration/f0_stored + chown system system /sys/bus/i2c/devices/6-0043/calibration/q_stored + chown system system /sys/bus/i2c/devices/5-0043/calibration/q_stored + chown system system /sys/bus/i2c/devices/4-0043/calibration/q_stored + chown system system /sys/bus/i2c/devices/6-0043/calibration/redc_stored + chown system system /sys/bus/i2c/devices/5-0043/calibration/redc_stored + chown system system /sys/bus/i2c/devices/4-0043/calibration/redc_stored + chown system system /sys/bus/i2c/devices/6-0043/default/vibe_state + chown system system /sys/bus/i2c/devices/5-0043/default/vibe_state + chown system system /sys/bus/i2c/devices/4-0043/default/vibe_state + chown system system /sys/bus/i2c/devices/6-0043/default/num_waves + chown system system /sys/bus/i2c/devices/5-0043/default/num_waves + chown system system /sys/bus/i2c/devices/4-0043/default/num_waves + chown system system /sys/bus/i2c/devices/6-0043/default/f0_offset + chown system system /sys/bus/i2c/devices/5-0043/default/f0_offset + chown system system /sys/bus/i2c/devices/4-0043/default/f0_offset + chown system system /sys/bus/i2c/devices/6-0043/default/owt_free_space + chown system system /sys/bus/i2c/devices/5-0043/default/owt_free_space + chown system system /sys/bus/i2c/devices/4-0043/default/owt_free_space + chown system system /sys/bus/i2c/devices/6-0043/default/f0_comp_enable + chown system system /sys/bus/i2c/devices/5-0043/default/f0_comp_enable + chown system system /sys/bus/i2c/devices/4-0043/default/f0_comp_enable + chown system system /sys/bus/i2c/devices/6-0043/default/redc_comp_enable + chown system system /sys/bus/i2c/devices/5-0043/default/redc_comp_enable + chown system system /sys/bus/i2c/devices/4-0043/default/redc_comp_enable + chown system system /sys/bus/i2c/devices/6-0043/default/delay_before_stop_playback_us + chown system system /sys/bus/i2c/devices/5-0043/default/delay_before_stop_playback_us + chown system system /sys/bus/i2c/devices/4-0043/default/delay_before_stop_playback_us + + enable vendor.vibrator.cs40l26 + diff --git a/device-comet.mk b/device-comet.mk index 08e31bf..50277b7 100644 --- a/device-comet.mk +++ b/device-comet.mk @@ -24,7 +24,7 @@ $(call inherit-product-if-exists, vendor/google_devices/comet/proprietary/comet/ include device/google/zuma/device-shipping-common.mk include device/google/comet/audio/comet/audio-tables.mk -include device/google/comet/vibrator/cs40l26/device-comet.mk +include hardware/google/pixel/vibrator/cs40l26/device.mk include device/google/gs-common/bcmbt/bluetooth.mk include device/google/gs-common/touch/gti/gti.mk diff --git a/vibrator/Android.bp b/vibrator/Android.bp deleted file mode 100644 index 25e3842..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: "PixelVibratorDefaultsComet", - relative_install_path: "hw", - static_libs: [ - "PixelVibratorCommonComet", - ], - shared_libs: [ - "libbase", - "libbinder_ndk", - "libcutils", - "libhardware", - "liblog", - "libutils", - ], -} - -cc_defaults { - name: "PixelVibratorBinaryDefaultsComet", - defaults: ["PixelVibratorDefaultsComet"], - shared_libs: [ - "android.hardware.vibrator-V2-ndk", - ], -} - -cc_defaults { - name: "PixelVibratorTestDefaultsComet", - defaults: ["PixelVibratorDefaultsComet"], - 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 888d8c3..0000000 --- a/vibrator/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -chrispaulo@google.com -taikuo@google.com -chasewu@google.com diff --git a/vibrator/common/Android.bp b/vibrator/common/Android.bp deleted file mode 100644 index 02ec561..0000000 --- a/vibrator/common/Android.bp +++ /dev/null @@ -1,73 +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"], -} - -soong_config_module_type { - name: "haptics_feature_cc_defaults_comet", - module_type: "cc_defaults", - config_namespace: "haptics", - variables: [ - "actuator_model", - ], - properties: ["cflags"], -} - -soong_config_string_variable { - name: "actuator_model", - values: [ - "luxshare_ict_081545", - "luxshare_ict_lt_xlra1906d", - ], -} - -haptics_feature_cc_defaults_comet { - name: "haptics_feature_defaults_comet", - soong_config_variables: { - actuator_model: { - luxshare_ict_081545: { - cflags: [ - "-DLUXSHARE_ICT_081545", - ], - }, - luxshare_ict_lt_xlra1906d: { - cflags: [ - "-DLUXSHARE_ICT_LT_XLRA1906D", - ], - }, - }, - }, -} - -cc_library { - name: "PixelVibratorCommonComet", - 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 d9901ab..0000000 --- a/vibrator/common/HardwareBase.cpp +++ /dev/null @@ -1,154 +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() { - std::map ret; - - mPathPrefix = std::getenv("HWAPI_PATH_PREFIX") ?: ""; - - auto value = std::getenv("HWAPI_DEBUG_NODES"); - std::istringstream paths{value}; - std::string path; - - while (paths >> path) { - ret[path].open(mPathPrefix + path + "default/vibe_state"); - if (ret[path].good()) { - mPathPrefix += path; - ALOGE("Vibrator found at %s!", mPathPrefix.c_str()); - ret[path].close(); - break; - } - ret[path].close(); - } - - 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 4c2969e..0000000 --- a/vibrator/cs40l26/Android.bp +++ /dev/null @@ -1,91 +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. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_defaults { - name: "android.hardware.vibrator-defaults.cs40l26-comet", - cflags: [ - "-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)", - "-DLOG_TAG=\"android.hardware.vibrator-cs40l26\"", - ], - shared_libs: [ - "libbinder", - ], -} - -cc_defaults { - name: "VibratorHalCs40l26BinaryDefaultsComet", - defaults: [ - "PixelVibratorBinaryDefaultsComet", - "android.hardware.vibrator-defaults.cs40l26-comet", - ], - include_dirs: [ - "external/tinyalsa/include", - ], - shared_libs: [ - "libcutils", - "libtinyalsa", - ], -} - -cc_defaults { - name: "VibratorHalCs40l26TestDefaultsComet", - defaults: [ - "PixelVibratorTestDefaultsComet", - "android.hardware.vibrator-defaults.cs40l26-comet", - ], - static_libs: [ - "android.hardware.vibrator-impl.cs40l26-comet", - "libtinyalsa", - ], -} - -cc_library { - name: "android.hardware.vibrator-impl.cs40l26-comet", - defaults: [ - "VibratorHalCs40l26BinaryDefaultsComet", - "haptics_feature_defaults_comet", - ], - srcs: ["Vibrator.cpp"], - export_include_dirs: ["."], - vendor_available: true, - visibility: [":__subpackages__"], -} - -cc_binary { - name: "android.hardware.vibrator-service.cs40l26-comet", - defaults: ["VibratorHalCs40l26BinaryDefaultsComet"], - init_rc: ["android.hardware.vibrator-service.cs40l26-comet.rc"], - vintf_fragments: ["android.hardware.vibrator-service.cs40l26-comet.xml"], - srcs: ["service.cpp"], - shared_libs: ["android.hardware.vibrator-impl.cs40l26-comet"], - proprietary: true, -} - -cc_binary { - name: "android.hardware.vibrator-service.cs40l26-dual-comet", - defaults: ["VibratorHalCs40l26BinaryDefaultsComet"], - init_rc: ["android.hardware.vibrator-service.cs40l26-dual-comet.rc"], - vintf_fragments: ["android.hardware.vibrator-service.cs40l26-dual-comet.xml"], - srcs: ["service.cpp"], - shared_libs: ["android.hardware.vibrator-impl.cs40l26-comet"], - cflags: ["-DVIBRATOR_NAME=\"dual\""], - proprietary: true, -} - - diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h deleted file mode 100644 index f7cc857..0000000 --- a/vibrator/cs40l26/Hardware.h +++ /dev/null @@ -1,344 +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); } - // 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 float DEFAULT_DEVICE_MASS = 0.21; - static constexpr float DEFAULT_LOC_COEFF = 2.5; - 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 getDeviceMass(float *value) override { - return getProperty("device.mass", value, DEFAULT_DEVICE_MASS); - } - bool getLocCoeff(float *value) override { - return getProperty("loc.coeff", value, DEFAULT_LOC_COEFF); - } - 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); - } - 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 e4157c9..0000000 --- a/vibrator/cs40l26/Vibrator.cpp +++ /dev/null @@ -1,1514 +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 - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) -#endif - -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 ReDC. The LRA series resistance (ReDC), expressed as follows -// redc(ohms) = redc_measured / 2^Q15_BIT_SHIFT. -// This value represents the unit-specific ReDC input to the click compensation -// algorithm. It can be overwritten at a later time by writing to the redc_stored -// sysfs control. -// See the LRA Calibration Support documentation for more details. -static constexpr int32_t Q15_BIT_SHIFT = 15; - -// 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_MIN = -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 = 30.0f; -static constexpr float RESONANT_FREQUENCY_DEFAULT = 145.0f; -static constexpr float PWLE_FREQUENCY_MAX_HZ = 300.0f; -static constexpr float PWLE_BW_MAP_SIZE = - 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ); - -static uint16_t amplitudeToScale(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); -} - -enum class AlwaysOnId : uint32_t { - GPIO_RISE, - GPIO_FALL, -}; - -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, -}; - -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); -} - -// Discrete points of frequency:max_level pairs around resonant(145Hz default) frequency -// Initialize the actuator LUXSHARE_ICT_081545 limits to 0.447 and others 1.0 -#if defined(LUXSHARE_ICT_081545) -static std::map discretePwleMaxLevels = { - {120.0, 0.447}, {130.0, 0.346}, {140.0, 0.156}, {145.0, 0.1}, - {150.0, 0.167}, {160.0, 0.391}, {170.0, 0.447}}; -std::vector pwleMaxLevelLimitMap(PWLE_BW_MAP_SIZE, 0.447); -#else -static std::map discretePwleMaxLevels = {}; -std::vector pwleMaxLevelLimitMap(PWLE_BW_MAP_SIZE, 1.0); -#endif - -static float redcToFloat(std::string *caldata) { - return static_cast(std::stoul(*caldata, nullptr, 16)) / (1 << Q15_BIT_SHIFT); -} - -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); - mResonantFrequency = - static_cast(std::stoul(caldata, nullptr, 16)) / (1 << Q14_BIT_SHIFT); - } else { - ALOGE("Failed to get resonant frequency (%d): %s, using default resonant HZ: %f", errno, - strerror(errno), RESONANT_FREQUENCY_DEFAULT); - mResonantFrequency = RESONANT_FREQUENCY_DEFAULT; - } - if (mHwCal->getRedc(&caldata)) { - mHwApi->setRedc(caldata); - mRedc = redcToFloat(&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(true); - mHwApi->setRedcCompEnable(true); - - 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); - - createPwleMaxLevelLimitMap(); - createBandwidthAmplitudeMap(); -} - -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_ALWAYS_ON_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"); - if (mActiveId < 0) { - ALOGD("Vibrator is already off"); - return ndk::ScopedAStatus::ok(); - } - - /* Stop the active effect. */ - if (!mHwApi->setFFPlay(mInputFd, mActiveId, false)) { - ALOGE("Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && - (!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - mActiveId = -1; - setGlobalAmplitude(false); - if (mF0Offset) { - mHwApi->setF0Offset(0); - } - - return ndk::ScopedAStatus::ok(); -} - -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); - status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - goto end; - } - if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) { - ALOGE("Previous vibration pending: prev: %d, curr: %d", mActiveId, effectIndex); - status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - goto end; - } - - 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)); - status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - goto end; - } - } - - mActiveId = effectIndex; - /* Play the event now. */ - if (!mHwApi->setFFPlay(mInputFd, effectIndex, true)) { - ALOGE("Failed to play effect %d (%d): %s", effectIndex, errno, strerror(errno)); - status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - goto end; - } - - mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback); - -end: - return status; -} - -ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) { - uint16_t scale = amplitudeToScale(amplitude, maximum); - 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); -} - -ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector *_aidl_return) { - *_aidl_return = {Effect::TEXTURE_TICK, Effect::TICK, Effect::CLICK, Effect::HEAVY_CLICK}; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) { - ndk::ScopedAStatus status; - uint32_t effectIndex; - uint32_t timeMs; - uint32_t volLevel; - uint16_t scale; - status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel); - if (!status.isOk()) { - return status; - } - - scale = amplitudeToScale(volLevel, VOLTAGE_SCALE_MAX); - - switch (static_cast(id)) { - case AlwaysOnId::GPIO_RISE: - // mHwApi->setGpioRiseIndex(effectIndex); - // mHwApi->setGpioRiseScale(scale); - return ndk::ScopedAStatus::ok(); - case AlwaysOnId::GPIO_FALL: - // mHwApi->setGpioFallIndex(effectIndex); - // mHwApi->setGpioFallScale(scale); - return ndk::ScopedAStatus::ok(); - } - - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); -} -ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) { - switch (static_cast(id)) { - case AlwaysOnId::GPIO_RISE: - // mHwApi->setGpioRiseIndex(0); - return ndk::ScopedAStatus::ok(); - case AlwaysOnId::GPIO_FALL: - // mHwApi->setGpioFallIndex(0); - return ndk::ScopedAStatus::ok(); - } - - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); -} - -ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) { - *resonantFreqHz = mResonantFrequency; - - 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); - } -} - -void Vibrator::createPwleMaxLevelLimitMap() { - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (!(capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) { - ALOGE("Frequency control not support."); - return; - } - - if (discretePwleMaxLevels.empty()) { - ALOGE("Discrete PWLE max level maps are empty."); - return; - } - - int32_t pwleMaxLevelLimitMapIdx = 0; - std::map::iterator itr0 = discretePwleMaxLevels.begin(); - if (discretePwleMaxLevels.size() == 1) { - ALOGD("Discrete PWLE max level map size is 1"); - pwleMaxLevelLimitMapIdx = - (itr0->first - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ; - pwleMaxLevelLimitMap[pwleMaxLevelLimitMapIdx] = itr0->second; - return; - } - - auto itr1 = std::next(itr0, 1); - - while (itr1 != discretePwleMaxLevels.end()) { - float x0 = itr0->first; - float y0 = itr0->second; - float x1 = itr1->first; - float y1 = itr1->second; - const float ratioOfXY = ((y1 - y0) / (x1 - x0)); - pwleMaxLevelLimitMapIdx = - (itr0->first - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ; - - // FixLater: avoid floating point loop counters - // NOLINTBEGIN(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) - for (float xp = x0; xp < (x1 + PWLE_FREQUENCY_RESOLUTION_HZ); - xp += PWLE_FREQUENCY_RESOLUTION_HZ) { - // NOLINTEND(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) - float yp = y0 + ratioOfXY * (xp - x0); - - pwleMaxLevelLimitMap[pwleMaxLevelLimitMapIdx++] = yp; - } - - itr0++; - itr1++; - } -} - -void Vibrator::createBandwidthAmplitudeMap() { - // Use constant Q Factor of 10 from HW's suggestion - const float qFactor = 10.0f; - const float blSys = 1.1f; - const float gravity = 9.81f; - const float maxVoltage = 11.0f; - float deviceMass = 0, locCoeff = 0; - - mHwCal->getDeviceMass(&deviceMass); - mHwCal->getLocCoeff(&locCoeff); - if (!deviceMass || !locCoeff) { - ALOGE("Failed to get Device Mass: %f and Loc Coeff: %f", deviceMass, locCoeff); - return; - } - - // Resistance value need to be retrieved from calibration file - if (mRedc == 0.0) { - std::string caldata{8, '0'}; - if (mHwCal->getRedc(&caldata)) { - mHwApi->setRedc(caldata); - mRedc = redcToFloat(&caldata); - } else { - ALOGE("Failed to get resistance value from calibration file"); - return; - } - } - - std::vector bandwidthAmplitudeMap(PWLE_BW_MAP_SIZE, 1.0); - - const float wnSys = mResonantFrequency * 2 * M_PI; - const float powWnSys = pow(wnSys, 2); - const float var2Para = wnSys / qFactor; - - float frequencyHz = PWLE_FREQUENCY_MIN_HZ; - float frequencyRadians = 0.0f; - float vLevel = 0.4473f; - float vSys = (mLongEffectVol[1] / 100.0) * maxVoltage * vLevel; - float maxAsys = 0; - const float amplitudeSysPara = blSys * locCoeff / mRedc / deviceMass; - - for (int i = 0; i < PWLE_BW_MAP_SIZE; i++) { - frequencyRadians = frequencyHz * 2 * M_PI; - vLevel = pwleMaxLevelLimitMap[i]; - vSys = (mLongEffectVol[1] / 100.0) * maxVoltage * vLevel; - - float var1 = pow((powWnSys - pow(frequencyRadians, 2)), 2); - float var2 = pow((var2Para * frequencyRadians), 2); - - float psysAbs = sqrt(var1 + var2); - // The equation and all related details can be found in the bug - float amplitudeSys = - (vSys * amplitudeSysPara) * pow(frequencyRadians, 2) / psysAbs / gravity; - // Record the maximum acceleration for the next for loop - if (amplitudeSys > maxAsys) - maxAsys = amplitudeSys; - - bandwidthAmplitudeMap[i] = amplitudeSys; - frequencyHz += PWLE_FREQUENCY_RESOLUTION_HZ; - } - // Scaled the map between 0 and 1.0 - if (maxAsys > 0) { - for (int j = 0; j < PWLE_BW_MAP_SIZE; j++) { - bandwidthAmplitudeMap[j] = - std::floor((bandwidthAmplitudeMap[j] / maxAsys) * 1000) / 1000; - } - mBandwidthAmplitudeMap = bandwidthAmplitudeMap; - mCreateBandwidthAmplitudeMapDone = true; - } else { - mCreateBandwidthAmplitudeMapDone = false; - } -} - -ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector *_aidl_return) { - int32_t capabilities; - Vibrator::getCapabilities(&capabilities); - if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { - if (!mCreateBandwidthAmplitudeMapDone) { - createPwleMaxLevelLimitMap(); - createBandwidthAmplitudeMap(); - } - *_aidl_return = mBandwidthAmplitudeMap; - return (!mBandwidthAmplitudeMap.empty()) - ? ndk::ScopedAStatus::ok() - : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } 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_MIN, 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); - - 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); - - 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); - - if (mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) { - mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects); - } - 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 4b9767a..0000000 --- a/vibrator/cs40l26/Vibrator.h +++ /dev/null @@ -1,217 +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 - -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; - // 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 device mass for calculating the bandwidth amplitude map - virtual bool getDeviceMass(float *value) = 0; - // Obtains loc coeff for calculating the bandwidth amplitude map - virtual bool getLocCoeff(float *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; - // 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); - 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); - void createPwleMaxLevelLimitMap(); - void createBandwidthAmplitudeMap(); - - 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 mSupportedPrimitivesBits = 0x0; - float mRedc{0}; - float mResonantFrequency{0}; - std::vector mSupportedPrimitives; - bool mConfigHapticAlsaDeviceDone{false}; - std::vector mBandwidthAmplitudeMap{}; - bool mCreateBandwidthAmplitudeMapDone{false}; -}; - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-comet.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-comet.rc deleted file mode 100644 index d5d7d78..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-comet.rc +++ /dev/null @@ -1,74 +0,0 @@ -on property:vendor.all.modules.ready=1 - wait /sys/bus/i2c/devices/6-0043/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/6-0043/calibration/f0_stored - chown system system /sys/bus/i2c/devices/6-0043/calibration/q_stored - chown system system /sys/bus/i2c/devices/6-0043/calibration/redc_stored - chown system system /sys/bus/i2c/devices/6-0043/default/vibe_state - chown system system /sys/bus/i2c/devices/6-0043/default/num_waves - chown system system /sys/bus/i2c/devices/6-0043/default/f0_offset - chown system system /sys/bus/i2c/devices/6-0043/default/owt_free_space - chown system system /sys/bus/i2c/devices/6-0043/default/f0_comp_enable - chown system system /sys/bus/i2c/devices/6-0043/default/redc_comp_enable - chown system system /sys/bus/i2c/devices/6-0043/default/delay_before_stop_playback_us - - chown system system /sys/bus/i2c/devices/5-0043/calibration/f0_stored - chown system system /sys/bus/i2c/devices/5-0043/calibration/q_stored - chown system system /sys/bus/i2c/devices/5-0043/calibration/redc_stored - chown system system /sys/bus/i2c/devices/5-0043/default/vibe_state - chown system system /sys/bus/i2c/devices/5-0043/default/num_waves - chown system system /sys/bus/i2c/devices/5-0043/default/f0_offset - chown system system /sys/bus/i2c/devices/5-0043/default/owt_free_space - chown system system /sys/bus/i2c/devices/5-0043/default/f0_comp_enable - chown system system /sys/bus/i2c/devices/5-0043/default/redc_comp_enable - chown system system /sys/bus/i2c/devices/5-0043/default/delay_before_stop_playback_us - - chown system system /sys/bus/i2c/devices/4-0043/calibration/f0_stored - chown system system /sys/bus/i2c/devices/4-0043/calibration/q_stored - chown system system /sys/bus/i2c/devices/4-0043/calibration/redc_stored - chown system system /sys/bus/i2c/devices/4-0043/default/vibe_state - chown system system /sys/bus/i2c/devices/4-0043/default/num_waves - chown system system /sys/bus/i2c/devices/4-0043/default/f0_offset - chown system system /sys/bus/i2c/devices/4-0043/default/owt_free_space - chown system system /sys/bus/i2c/devices/4-0043/default/f0_comp_enable - chown system system /sys/bus/i2c/devices/4-0043/default/redc_comp_enable - chown system system /sys/bus/i2c/devices/4-0043/default/delay_before_stop_playback_us - - enable vendor.vibrator.cs40l26 - -service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-comet - class hal - user system - group system input - - 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/ - setenv HWAPI_DEBUG_NODES " - 6-0043/ - 5-0043/ - 4-0043/ - " - 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-comet.xml b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-comet.xml deleted file mode 100644 index 4db8f8c..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-comet.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - android.hardware.vibrator - 2 - IVibrator/default - - diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual-comet.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual-comet.rc deleted file mode 100644 index 985bbe9..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual-comet.rc +++ /dev/null @@ -1,74 +0,0 @@ -on property:vendor.all.modules.ready=1 - wait /sys/bus/i2c/devices/6-0042/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_dual.cal - chown system system /mnt/vendor/persist/haptics - chown system system /mnt/vendor/persist/haptics/cs40l26_dual.cal - - chown system system /sys/bus/i2c/devices/6-0042/calibration/f0_stored - chown system system /sys/bus/i2c/devices/6-0042/calibration/q_stored - chown system system /sys/bus/i2c/devices/6-0042/calibration/redc_stored - chown system system /sys/bus/i2c/devices/6-0042/default/vibe_state - chown system system /sys/bus/i2c/devices/6-0042/default/num_waves - chown system system /sys/bus/i2c/devices/6-0042/default/f0_offset - chown system system /sys/bus/i2c/devices/6-0042/default/owt_free_space - chown system system /sys/bus/i2c/devices/6-0042/default/f0_comp_enable - chown system system /sys/bus/i2c/devices/6-0042/default/redc_comp_enable - chown system system /sys/bus/i2c/devices/6-0042/default/delay_before_stop_playback_us - - chown system system /sys/bus/i2c/devices/5-0042/calibration/f0_stored - chown system system /sys/bus/i2c/devices/5-0042/calibration/q_stored - chown system system /sys/bus/i2c/devices/5-0042/calibration/redc_stored - chown system system /sys/bus/i2c/devices/5-0042/default/vibe_state - chown system system /sys/bus/i2c/devices/5-0042/default/num_waves - chown system system /sys/bus/i2c/devices/5-0042/default/f0_offset - chown system system /sys/bus/i2c/devices/5-0042/default/owt_free_space - chown system system /sys/bus/i2c/devices/5-0042/default/f0_comp_enable - chown system system /sys/bus/i2c/devices/5-0042/default/redc_comp_enable - chown system system /sys/bus/i2c/devices/5-0042/default/delay_before_stop_playback_us - - chown system system /sys/bus/i2c/devices/4-0042/calibration/f0_stored - chown system system /sys/bus/i2c/devices/4-0042/calibration/q_stored - chown system system /sys/bus/i2c/devices/4-0042/calibration/redc_stored - chown system system /sys/bus/i2c/devices/4-0042/default/vibe_state - chown system system /sys/bus/i2c/devices/4-0042/default/num_waves - chown system system /sys/bus/i2c/devices/4-0042/default/f0_offset - chown system system /sys/bus/i2c/devices/4-0042/default/owt_free_space - chown system system /sys/bus/i2c/devices/4-0042/default/f0_comp_enable - chown system system /sys/bus/i2c/devices/4-0042/default/redc_comp_enable - chown system system /sys/bus/i2c/devices/4-0042/default/delay_before_stop_playback_us - - enable vendor.vibrator.cs40l26-dual - -service vendor.vibrator.cs40l26-dual /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-dual-comet - class hal - user system - group system input - - setenv INPUT_EVENT_NAME cs40l26_dual_input - setenv INPUT_EVENT_PATH /dev/input/event* - setenv PROPERTY_PREFIX ro.vendor.vibrator.hal. - setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l26_dual.cal - - setenv HWAPI_PATH_PREFIX /sys/bus/i2c/devices/ - setenv HWAPI_DEBUG_NODES " - 6-0042/ - 5-0042/ - 4-0042/ - " - 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-dual-comet.xml b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual-comet.xml deleted file mode 100644 index 1bd3e7e..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual-comet.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - android.hardware.vibrator - 2 - IVibrator/dual - - diff --git a/vibrator/cs40l26/device-comet.mk b/vibrator/cs40l26/device-comet.mk deleted file mode 100644 index e6d0b6d..0000000 --- a/vibrator/cs40l26/device-comet.mk +++ /dev/null @@ -1,6 +0,0 @@ -PRODUCT_PACKAGES += \ - android.hardware.vibrator-service.cs40l26-comet - -BOARD_SEPOLICY_DIRS += \ - hardware/google/pixel-sepolicy/vibrator/common \ - device/google/comet-sepolicy/vibrator/cs40l26 diff --git a/vibrator/cs40l26/device-stereo-comet.mk b/vibrator/cs40l26/device-stereo-comet.mk deleted file mode 100644 index 4a30a40..0000000 --- a/vibrator/cs40l26/device-stereo-comet.mk +++ /dev/null @@ -1,7 +0,0 @@ -PRODUCT_PACKAGES += \ - android.hardware.vibrator-service.cs40l26-comet \ - android.hardware.vibrator-service.cs40l26-dual-comet - -BOARD_SEPOLICY_DIRS += \ - hardware/google/pixel-sepolicy/vibrator/common \ - device/google/comet-sepolicy/vibrator/cs40l26 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 6e8065d..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: "VibratorHalCs40l26TestSuiteComet", - defaults: ["VibratorHalCs40l26TestDefaultsComet"], - 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 0e8cba1..0000000 --- a/vibrator/cs40l26/tests/mocks.h +++ /dev/null @@ -1,80 +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_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_METHOD1(getDeviceMass, bool(float *value)); - MOCK_METHOD1(getLocCoeff, bool(float *value)); - 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 252e413..0000000 --- a/vibrator/cs40l26/tests/test-vibrator.cpp +++ /dev/null @@ -1,742 +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, 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, 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(*mMockApi, setF0CompEnable(true)).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, hasOwtFreeSpace()).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).WillOnce(Return(true)); - 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) { - 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); - } -} - -TEST_P(EffectsTest, alwaysOnEnable) { - // No real function now in P22+ - auto param = GetParam(); - auto effect = std::get<0>(param); - auto strength = std::get<1>(param); - auto scale = EFFECT_SCALE.find(param); - bool supported = (scale != EFFECT_SCALE.end()); - - if (supported) { - // Do nothing - } - - ndk::ScopedAStatus status = mVibrator->alwaysOnEnable(0, effect, strength); - if (supported) { - EXPECT_EQ(EX_NONE, status.getExceptionCode()); - } else { - EXPECT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode()); - } -} - -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); - -class AlwaysOnTest : public VibratorTest, public WithParamInterface { - public: - static auto PrintParam(const TestParamInfo &info) { - return std::to_string(info.param); - } -}; - -TEST_P(AlwaysOnTest, alwaysOnEnable) { - auto param = GetParam(); - auto scale = EFFECT_SCALE.begin(); - - std::advance(scale, std::rand() % EFFECT_SCALE.size()); - - auto effect = std::get<0>(scale->first); - auto strength = std::get<1>(scale->first); - - switch (param) { - case 0: - case 1: - // Do nothing - break; - } - - ndk::ScopedAStatus status = mVibrator->alwaysOnEnable(param, effect, strength); - EXPECT_EQ(EX_NONE, status.getExceptionCode()); -} - -TEST_P(AlwaysOnTest, alwaysOnDisable) { - auto param = GetParam(); - - switch (param) { - case 0: - case 1: - // Do nothing - break; - } - - ndk::ScopedAStatus status = mVibrator->alwaysOnDisable(param); - EXPECT_EQ(EX_NONE, status.getExceptionCode()); -} - -INSTANTIATE_TEST_CASE_P(VibratorTests, AlwaysOnTest, Range(0, 1), AlwaysOnTest::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