vibrator: Modify some delta and apply calibration fix
Reference the delta from the leading project.
Bug: 148918900
Test: manual haptics function check and logs
Change-Id: I777d3295a7a92e2ce8547b85886038cfbe32ac5a
Signed-off-by: chasewu <chasewu@google.com>
diff --git a/device-redfin.mk b/device-redfin.mk
index 2a6d20a..90c8b94 100644
--- a/device-redfin.mk
+++ b/device-redfin.mk
@@ -115,6 +115,20 @@
PRODUCT_PACKAGES += \
android.hardware.vibrator@1.3-service.redfin
+# DRV2624 Haptics Waveform
+PRODUCT_COPY_FILES += \
+ device/google/redfin/vibrator/drv2624/drv2624.bin:$(TARGET_COPY_OUT_VENDOR)/firmware/drv2624.bin
+
+# Vibrator HAL
+PRODUCT_PRODUCT_PROPERTIES +=\
+ ro.vibrator.hal.config.dynamic=1 \
+ ro.vibrator.hal.click.duration=8 \
+ ro.vibrator.hal.tick.duration=8 \
+ ro.vibrator.hal.heavyclick.duration=8 \
+ ro.vibrator.hal.long.voltage=161 \
+ ro.vibrator.hal.long.frequency.shift=0 \
+ ro.vibrator.hal.steady.shape=1
+
# Dumpstate HAL
PRODUCT_PACKAGES += \
android.hardware.dumpstate@1.0-service.redfin
diff --git a/init.insmod.redfin.cfg b/init.insmod.redfin.cfg
index f57ad6c..ad77b2d 100644
--- a/init.insmod.redfin.cfg
+++ b/init.insmod.redfin.cfg
@@ -5,7 +5,7 @@
#############################################
# Load kernel modules
-modprobe|adsp_loader_dlkm.ko apr_dlkm.ko atomic64_test.ko bolero_cdc_dlkm.ko br_netfilter.ko hdmi_dlkm.ko lcd.ko lkdtm.ko llcc_perfmon.ko locktorture.ko machine_dlkm.ko mbhc_dlkm.ko native_dlkm.ko pinctrl_lpi_dlkm.ko platform_dlkm.ko q6_dlkm.ko q6_notifier_dlkm.ko q6_pdr_dlkm.ko rcutorture.ko rx_macro_dlkm.ko snd_event_dlkm.ko stub_dlkm.ko swr_ctrl_dlkm.ko swr_dlkm.ko test_user_copy.ko torture.ko tx_macro_dlkm.ko usf_dlkm.ko va_macro_dlkm.ko wcd938x_dlkm.ko wcd938x_slave_dlkm.ko wcd9xxx_dlkm.ko wcd_core_dlkm.ko wlan.ko wsa881x_dlkm.ko wsa_macro_dlkm.ko heatmap.ko sec_touch.ko
+modprobe|adsp_loader_dlkm.ko apr_dlkm.ko atomic64_test.ko bolero_cdc_dlkm.ko br_netfilter.ko hdmi_dlkm.ko lcd.ko lkdtm.ko llcc_perfmon.ko locktorture.ko machine_dlkm.ko mbhc_dlkm.ko native_dlkm.ko pinctrl_lpi_dlkm.ko platform_dlkm.ko q6_dlkm.ko q6_notifier_dlkm.ko q6_pdr_dlkm.ko rcutorture.ko rx_macro_dlkm.ko snd_event_dlkm.ko stub_dlkm.ko swr_ctrl_dlkm.ko swr_dlkm.ko test_user_copy.ko torture.ko tx_macro_dlkm.ko usf_dlkm.ko va_macro_dlkm.ko wcd938x_dlkm.ko wcd938x_slave_dlkm.ko wcd9xxx_dlkm.ko wcd_core_dlkm.ko wlan.ko wsa881x_dlkm.ko wsa_macro_dlkm.ko heatmap.ko sec_touch.ko drv2624.ko
# All modules loaded
setprop|vendor.all.modules.ready
diff --git a/vibrator/Android.bp b/vibrator/Android.bp
index 261a26c..c19ddbd 100644
--- a/vibrator/Android.bp
+++ b/vibrator/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2017 The Android Open Source Project
+// 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.
@@ -14,69 +14,18 @@
// limitations under the License.
cc_defaults {
- name: "android.hardware.vibrator@1.3-defaults.redfin",
+ name: "PixelVibratorDefaultsRedfin",
defaults: ["hidl_defaults"],
relative_install_path: "hw",
- shared_libs: [
- "libhidlbase",
- "libcutils",
- "libhidltransport",
- "liblog",
- "libhwbinder",
- "libutils",
- "libhardware",
- "android.hardware.vibrator@1.0",
- "android.hardware.vibrator@1.1",
- "android.hardware.vibrator@1.2",
- "android.hardware.vibrator@1.3",
- ],
- proprietary: true,
-}
-
-cc_library {
- name: "android.hardware.vibrator@1.3-impl.redfin",
- defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
- srcs: [
- "Hardware.cpp",
- "Vibrator.cpp",
- ],
-}
-
-cc_binary {
- name: "android.hardware.vibrator@1.3-service.redfin",
- defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
- init_rc: ["android.hardware.vibrator@1.3-service.redfin.rc"],
- vintf_fragments: ["android.hardware.vibrator@1.3-service.redfin.xml"],
- srcs: ["service.cpp"],
- static_libs: ["android.hardware.vibrator@1.3-impl.redfin"],
-}
-
-cc_test {
- name: "PtsVibratorHalRedfinTestSuite",
- defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
- srcs: [
- "tests/main.cpp",
- "tests/test-hwapi.cpp",
- "tests/test-hwcal.cpp",
- "tests/test-vibrator.cpp",
- ],
static_libs: [
- "android.hardware.vibrator@1.3-impl.redfin",
- "libgmock",
+ "PixelVibratorCommonRedfin",
],
shared_libs: [
"libbase",
+ "libhidlbase",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libhardware",
],
- test_suites: [
- "general-tests",
- "pts",
- ],
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
}
diff --git a/vibrator/AndroidTest.xml b/vibrator/AndroidTest.xml
deleted file mode 100644
index a6ddf6d..0000000
--- a/vibrator/AndroidTest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2019 Google Inc.
-
- 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.
--->
-<configuration description="Runs PtsVibratorHalRedfinTestSuite.">
- <option name="test-suite-tag" value="pts" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="append-bitness" value="true" />
- <option name="cleanup" value="true" />
- <option name="push" value="PtsVibratorHalRedfinTestSuite->/data/local/tmp/PtsVibratorHalRedfinTestSuite" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="module-name" value="PtsVibratorHalRedfinTestSuite" />
- <option name="native-test-device-path" value="/data/local/tmp" />
- </test>
-</configuration>
diff --git a/vibrator/Hardware.cpp b/vibrator/Hardware.cpp
deleted file mode 100644
index 6f1d01d..0000000
--- a/vibrator/Hardware.cpp
+++ /dev/null
@@ -1,209 +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.
- */
-
-#define LOG_TAG "android.hardware.vibrator@1.3-service.redfin"
-
-#include "Hardware.h"
-
-#include <log/log.h>
-
-#include <iostream>
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-template <typename T>
-static void fileFromEnv(const char *env, T *outStream, std::string *outName = nullptr) {
- auto file = std::getenv(env);
- auto mode = std::is_base_of_v<std::ostream, T> ? std::ios_base::out : std::ios_base::in;
-
- if (file == nullptr) {
- ALOGE("Failed get env %s", env);
- return;
- }
-
- if (outName != nullptr) {
- *outName = std::string(file);
- }
-
- // Force 'in' mode to prevent file creation
- outStream->open(file, mode | std::ios_base::in);
- if (!*outStream) {
- ALOGE("Failed to open %s:%s (%d): %s", env, file, errno, strerror(errno));
- }
-}
-
-static auto pathsFromEnv(const char *env) {
- std::map<std::string, std::ifstream> ret;
- auto value = std::getenv(env);
-
- if (value == nullptr) {
- return ret;
- }
-
- std::istringstream paths{value};
- std::string path;
-
- while (paths >> path) {
- ret[path].open(path);
- }
-
- return ret;
-}
-
-static 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);
-}
-
-template <typename T>
-static Enable_If_Iterable<T, true> unpack(std::istream &stream, T *value) {
- for (auto &entry : *value) {
- stream >> entry;
- }
-}
-
-template <typename T>
-static Enable_If_Iterable<T, false> unpack(std::istream &stream, T *value) {
- stream >> *value;
-}
-
-HwApi::HwApi() {
- // ostreams below are required
- fileFromEnv("F0_FILEPATH", &mF0, &mNames[&mF0]);
- fileFromEnv("REDC_FILEPATH", &mRedc, &mNames[&mRedc]);
- fileFromEnv("Q_FILEPATH", &mQ, &mNames[&mQ]);
- fileFromEnv("ACTIVATE_PATH", &mActivate, &mNames[&mActivate]);
- fileFromEnv("DURATION_PATH", &mDuration, &mNames[&mDuration]);
- fileFromEnv("STATE_PATH", &mState, &mNames[&mState]);
- fileFromEnv("EFFECT_DURATION_PATH", &mEffectDuration, &mNames[&mEffectDuration]);
- fileFromEnv("EFFECT_INDEX_PATH", &mEffectIndex, &mNames[&mEffectIndex]);
- fileFromEnv("EFFECT_QUEUE_PATH", &mEffectQueue, &mNames[&mEffectQueue]);
- fileFromEnv("EFFECT_SCALE_PATH", &mEffectScale, &mNames[&mEffectScale]);
- fileFromEnv("GLOBAL_SCALE_PATH", &mGlobalScale, &mNames[&mGlobalScale]);
- fileFromEnv("ASP_ENABLE_PATH", &mAspEnable, &mNames[&mAspEnable]);
- fileFromEnv("GPIO_FALL_INDEX", &mGpioFallIndex, &mNames[&mGpioFallIndex]);
- fileFromEnv("GPIO_FALL_SCALE", &mGpioFallScale, &mNames[&mGpioFallScale]);
- fileFromEnv("GPIO_RISE_INDEX", &mGpioRiseIndex, &mNames[&mGpioRiseIndex]);
- fileFromEnv("GPIO_RISE_SCALE", &mGpioRiseScale, &mNames[&mGpioRiseScale]);
-}
-
-template <typename T>
-bool HwApi::has(T &stream) {
- return !!stream;
-}
-
-template <typename T, typename U>
-bool HwApi::get(T *value, U &stream) {
- 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();
- return ret;
-}
-
-template <typename T, typename U>
-bool HwApi::set(const T &value, U &stream) {
- 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();
- }
- return ret;
-}
-
-void HwApi::debug(int fd) {
- dprintf(fd, "Kernel:\n");
-
- for (auto &entry : pathsFromEnv("HWAPI_DEBUG_PATHS")) {
- 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());
- }
- }
-}
-
-HwCal::HwCal() {
- std::ifstream calfile;
-
- 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[trim(key)] = trim(value);
- }
- }
-}
-
-template <typename T>
-bool HwCal::get(const char *key, T *value) {
- auto it = mCalData.find(key);
- if (it == mCalData.end()) {
- ALOGE("Missing %s config!", key);
- return false;
- }
- std::stringstream stream{it->second};
- unpack(stream, value);
- if (!stream || !stream.eof()) {
- ALOGE("Invalid %s config!", key);
- return false;
- }
- return true;
-}
-
-void HwCal::debug(int fd) {
- std::ifstream stream;
- std::string path;
- std::string line;
-
- dprintf(fd, "Persist:\n");
-
- 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 implementation
-} // namespace V1_3
-} // namespace vibrator
-} // namespace hardware
-} // namespace android
diff --git a/vibrator/Hardware.h b/vibrator/Hardware.h
deleted file mode 100644
index 4b65f24..0000000
--- a/vibrator/Hardware.h
+++ /dev/null
@@ -1,134 +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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
-#define ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
-
-#include "Vibrator.h"
-#include "utils.h"
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class HwApi : public Vibrator::HwApi {
- public:
- HwApi();
- bool setF0(uint32_t value) override { return set(value, mF0); }
- bool setRedc(uint32_t value) override { return set(value, mRedc); }
- bool setQ(uint32_t value) override { return set(value, mQ); }
- bool setActivate(bool value) override { return set(value, mActivate); }
- bool setDuration(uint32_t value) override { return set(value, mDuration); }
- bool getEffectDuration(uint32_t *value) override { return get(value, mEffectDuration); }
- bool setEffectIndex(uint32_t value) override { return set(value, mEffectIndex); }
- bool setEffectQueue(std::string value) override { return set(value, mEffectQueue); }
- bool hasEffectScale() override { return has(mEffectScale); }
- bool setEffectScale(uint32_t value) override { return set(value, mEffectScale); }
- bool setGlobalScale(uint32_t value) override { return set(value, mGlobalScale); }
- bool setState(bool value) override { return set(value, mState); }
- bool hasAspEnable() override { return has(mAspEnable); }
- bool getAspEnable(bool *value) override { return get(value, mAspEnable); }
- bool setAspEnable(bool value) override { return set(value, mAspEnable); }
- bool setGpioFallIndex(uint32_t value) override { return set(value, mGpioFallIndex); }
- bool setGpioFallScale(uint32_t value) override { return set(value, mGpioFallScale); }
- bool setGpioRiseIndex(uint32_t value) override { return set(value, mGpioRiseIndex); }
- bool setGpioRiseScale(uint32_t value) override { return set(value, mGpioRiseScale); }
- void debug(int fd) override;
-
- private:
- template <typename T>
- bool has(T &stream);
- template <typename T, typename U>
- bool get(T *value, U &stream);
- template <typename T, typename U>
- bool set(const T &value, U &stream);
-
- private:
- std::map<void *, std::string> mNames;
- std::ofstream mF0;
- std::ofstream mRedc;
- std::ofstream mQ;
- std::ofstream mActivate;
- std::ofstream mDuration;
- std::ifstream mEffectDuration;
- std::ofstream mEffectIndex;
- std::ofstream mEffectQueue;
- std::ofstream mEffectScale;
- std::ofstream mGlobalScale;
- std::ofstream mState;
- std::fstream mAspEnable;
- std::ofstream mGpioFallIndex;
- std::ofstream mGpioFallScale;
- std::ofstream mGpioRiseIndex;
- std::ofstream mGpioRiseScale;
-};
-
-class HwCal : public Vibrator::HwCal {
- private:
- static constexpr char F0_CONFIG[] = "f0_measured";
- static constexpr char REDC_CONFIG[] = "redc_measured";
- static constexpr char Q_CONFIG[] = "q_measured";
- static constexpr char Q_INDEX[] = "q_index";
- static constexpr char VOLTAGES_CONFIG[] = "v_levels";
-
- static constexpr uint32_t Q_FLOAT_TO_FIXED = 1 << 16;
- static constexpr float Q_INDEX_TO_FLOAT = 1.5f;
- static constexpr uint32_t Q_INDEX_TO_FIXED = Q_INDEX_TO_FLOAT * Q_FLOAT_TO_FIXED;
- static constexpr uint32_t Q_INDEX_OFFSET = 2.0f * Q_FLOAT_TO_FIXED;
-
- static constexpr uint32_t Q_DEFAULT = 15.5 * Q_FLOAT_TO_FIXED;
- static constexpr std::array<uint32_t, 6> V_LEVELS_DEFAULT = {60, 70, 80, 90, 100, 76};
-
- public:
- HwCal();
- bool getF0(uint32_t *value) override { return get(F0_CONFIG, value); }
- bool getRedc(uint32_t *value) override { return get(REDC_CONFIG, value); }
- bool getQ(uint32_t *value) override {
- if (get(Q_CONFIG, value)) {
- return true;
- }
- if (get(Q_INDEX, value)) {
- *value = *value * Q_INDEX_TO_FIXED + Q_INDEX_OFFSET;
- return true;
- }
- *value = Q_DEFAULT;
- return true;
- }
- bool getVolLevels(std::array<uint32_t, 6> *value) override {
- if (get(VOLTAGES_CONFIG, value)) {
- return true;
- }
- *value = V_LEVELS_DEFAULT;
- return true;
- }
- void debug(int fd) override;
-
- private:
- template <typename T>
- bool get(const char *key, T *value);
-
- private:
- std::map<std::string, std::string> mCalData;
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace vibrator
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
diff --git a/vibrator/Vibrator.cpp b/vibrator/Vibrator.cpp
deleted file mode 100644
index 8bce7cc..0000000
--- a/vibrator/Vibrator.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "android.hardware.vibrator@1.3-service.redfin"
-
-#include <log/log.h>
-
-#include <cutils/properties.h>
-#include <hardware/hardware.h>
-#include <hardware/vibrator.h>
-
-#include "Vibrator.h"
-
-#include <cinttypes>
-#include <cmath>
-#include <fstream>
-#include <iostream>
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
-#endif
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-using Status = ::android::hardware::vibrator::V1_0::Status;
-using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
-
-static constexpr uint32_t WAVEFORM_SIMPLE_EFFECT_INDEX = 2;
-
-static constexpr uint32_t WAVEFORM_TEXTURE_TICK_EFFECT_LEVEL = 0;
-
-static constexpr uint32_t WAVEFORM_TICK_EFFECT_LEVEL = 1;
-
-static constexpr uint32_t WAVEFORM_CLICK_EFFECT_LEVEL = 2;
-
-static constexpr uint32_t WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL = 3;
-
-static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100;
-
-static constexpr uint32_t WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0;
-
-static constexpr uint32_t WAVEFORM_TRIGGER_QUEUE_INDEX = 65534;
-
-static constexpr uint32_t VOLTAGE_GLOBAL_SCALE_LEVEL = 5;
-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 int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling
-
-static constexpr float AMP_ATTENUATE_STEP_SIZE = 0.125f;
-static constexpr float EFFECT_FREQUENCY_KHZ = 48.0f;
-
-static uint8_t amplitudeToScale(uint8_t amplitude, uint8_t maximum) {
- return std::round((-20 * std::log10(amplitude / static_cast<float>(maximum))) /
- (AMP_ATTENUATE_STEP_SIZE));
-}
-
-Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
- : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
- uint32_t caldata;
- uint32_t effectDuration;
-
- if (!mHwApi->setState(true)) {
- ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
- }
-
- if (mHwCal->getF0(&caldata)) {
- mHwApi->setF0(caldata);
- }
- if (mHwCal->getRedc(&caldata)) {
- mHwApi->setRedc(caldata);
- }
- if (mHwCal->getQ(&caldata)) {
- mHwApi->setQ(caldata);
- }
- mHwCal->getVolLevels(&mVolLevels);
-
- mHwApi->setEffectIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
- mHwApi->getEffectDuration(&effectDuration);
-
- mSimpleEffectDuration = std::ceil(effectDuration / EFFECT_FREQUENCY_KHZ);
-
- const uint32_t scaleFall =
- amplitudeToScale(mVolLevels[WAVEFORM_CLICK_EFFECT_LEVEL], VOLTAGE_SCALE_MAX);
- const uint32_t scaleRise =
- amplitudeToScale(mVolLevels[WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL], VOLTAGE_SCALE_MAX);
-
- mHwApi->setGpioFallIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
- mHwApi->setGpioFallScale(scaleFall);
- mHwApi->setGpioRiseIndex(WAVEFORM_SIMPLE_EFFECT_INDEX);
- mHwApi->setGpioRiseScale(scaleRise);
-}
-
-Return<Status> Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex) {
- mHwApi->setEffectIndex(effectIndex);
- mHwApi->setDuration(timeoutMs);
- mHwApi->setActivate(1);
-
- return Status::OK;
-}
-
-// Methods from ::android::hardware::vibrator::V1_1::IVibrator follow.
-Return<Status> Vibrator::on(uint32_t timeoutMs) {
- if (MAX_COLD_START_LATENCY_MS <= UINT32_MAX - timeoutMs) {
- timeoutMs += MAX_COLD_START_LATENCY_MS;
- }
- setGlobalAmplitude(true);
- return on(timeoutMs, WAVEFORM_LONG_VIBRATION_EFFECT_INDEX);
-}
-
-Return<Status> Vibrator::off() {
- setGlobalAmplitude(false);
- if (!mHwApi->setActivate(0)) {
- ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
- return Status::UNKNOWN_ERROR;
- }
- return Status::OK;
-}
-
-Return<bool> Vibrator::supportsAmplitudeControl() {
- return !isUnderExternalControl() && mHwApi->hasEffectScale();
-}
-
-Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
- if (!amplitude) {
- return Status::BAD_VALUE;
- }
-
- if (!isUnderExternalControl()) {
- return setEffectAmplitude(amplitude, UINT8_MAX);
- } else {
- return Status::UNSUPPORTED_OPERATION;
- }
-}
-
-Return<Status> Vibrator::setEffectAmplitude(uint8_t amplitude, uint8_t maximum) {
- int32_t scale = amplitudeToScale(amplitude, maximum);
-
- if (!mHwApi->setEffectScale(scale)) {
- ALOGE("Failed to set effect amplitude (%d): %s", errno, strerror(errno));
- return Status::UNKNOWN_ERROR;
- }
-
- return Status::OK;
-}
-
-Return<Status> Vibrator::setGlobalAmplitude(bool set) {
- uint8_t amplitude = set ? mVolLevels[VOLTAGE_GLOBAL_SCALE_LEVEL] : VOLTAGE_SCALE_MAX;
- int32_t scale = amplitudeToScale(amplitude, VOLTAGE_SCALE_MAX);
-
- if (!mHwApi->setGlobalScale(scale)) {
- ALOGE("Failed to set global amplitude (%d): %s", errno, strerror(errno));
- return Status::UNKNOWN_ERROR;
- }
-
- return Status::OK;
-}
-
-// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
-
-Return<bool> Vibrator::supportsExternalControl() {
- return (mHwApi->hasAspEnable() ? true : false);
-}
-
-Return<Status> Vibrator::setExternalControl(bool enabled) {
- setGlobalAmplitude(enabled);
-
- if (!mHwApi->setAspEnable(enabled)) {
- ALOGE("Failed to set external control (%d): %s", errno, strerror(errno));
- return Status::UNKNOWN_ERROR;
- }
- return Status::OK;
-}
-
-bool Vibrator::isUnderExternalControl() {
- bool isAspEnabled;
- mHwApi->getAspEnable(&isAspEnabled);
- return isAspEnabled;
-}
-
-// Methods from ::android.hidl.base::V1_0::IBase follow.
-
-Return<void> Vibrator::debug(const hidl_handle &handle,
- const hidl_vec<hidl_string> & /* options */) {
- if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
- ALOGE("Called debug() with invalid fd.");
- return Void();
- }
-
- int fd = handle->data[0];
-
- dprintf(fd, "HIDL:\n");
-
- dprintf(fd, " Voltage Levels:");
- for (auto v : mVolLevels) {
- dprintf(fd, " %" PRIu32, v);
- }
- dprintf(fd, "\n");
-
- dprintf(fd, " Effect Duration: %" PRIu32 "\n", mSimpleEffectDuration);
-
- dprintf(fd, "\n");
-
- mHwApi->debug(fd);
-
- dprintf(fd, "\n");
-
- mHwCal->debug(fd);
-
- fsync(fd);
- return Void();
-}
-
-template <typename T>
-Return<void> Vibrator::performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb) {
- auto validRange = hidl_enum_range<T>();
- if (effect < *validRange.begin() || effect > *std::prev(validRange.end())) {
- _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
- return Void();
- }
- return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
- return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
- perform_cb _hidl_cb) {
- return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength,
- perform_cb _hidl_cb) {
- return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
- return performWrapper(effect, strength, _hidl_cb);
-}
-
-Return<Status> Vibrator::getSimpleDetails(Effect effect, EffectStrength strength,
- uint32_t *outTimeMs, uint32_t *outVolLevel) {
- uint32_t timeMs;
- uint32_t volLevel;
- uint32_t volIndex;
- int8_t volOffset;
-
- switch (strength) {
- case EffectStrength::LIGHT:
- volOffset = -1;
- break;
- case EffectStrength::MEDIUM:
- volOffset = 0;
- break;
- case EffectStrength::STRONG:
- volOffset = 1;
- break;
- default:
- return Status::UNSUPPORTED_OPERATION;
- }
-
- switch (effect) {
- case Effect::TEXTURE_TICK:
- volIndex = WAVEFORM_TEXTURE_TICK_EFFECT_LEVEL;
- volOffset = 0;
- break;
- case Effect::TICK:
- volIndex = WAVEFORM_TICK_EFFECT_LEVEL;
- volOffset = 0;
- break;
- case Effect::CLICK:
- volIndex = WAVEFORM_CLICK_EFFECT_LEVEL;
- break;
- case Effect::HEAVY_CLICK:
- volIndex = WAVEFORM_HEAVY_CLICK_EFFECT_LEVEL;
- break;
- default:
- return Status::UNSUPPORTED_OPERATION;
- }
-
- volLevel = mVolLevels[volIndex + volOffset];
- timeMs = mSimpleEffectDuration + MAX_COLD_START_LATENCY_MS;
-
- *outTimeMs = timeMs;
- *outVolLevel = volLevel;
-
- return Status::OK;
-}
-
-Return<Status> Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
- uint32_t *outTimeMs, uint32_t * /*outVolLevel*/,
- std::string *outEffectQueue) {
- Status status;
- uint32_t timeMs;
- std::ostringstream effectBuilder;
- uint32_t thisTimeMs;
- uint32_t thisVolLevel;
-
- switch (effect) {
- case Effect::DOUBLE_CLICK:
- timeMs = 0;
-
- status = getSimpleDetails(Effect::CLICK, strength, &thisTimeMs, &thisVolLevel);
- if (status != Status::OK) {
- return status;
- }
- effectBuilder << WAVEFORM_SIMPLE_EFFECT_INDEX << "." << thisVolLevel;
- timeMs += thisTimeMs;
-
- effectBuilder << ",";
-
- effectBuilder << WAVEFORM_DOUBLE_CLICK_SILENCE_MS;
- timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
-
- effectBuilder << ",";
-
- status = getSimpleDetails(Effect::HEAVY_CLICK, strength, &thisTimeMs, &thisVolLevel);
- if (status != Status::OK) {
- return status;
- }
- effectBuilder << WAVEFORM_SIMPLE_EFFECT_INDEX << "." << thisVolLevel;
- timeMs += thisTimeMs;
-
- break;
- default:
- return Status::UNSUPPORTED_OPERATION;
- }
-
- *outTimeMs = timeMs;
- *outEffectQueue = effectBuilder.str();
-
- return Status::OK;
-}
-
-Return<Status> Vibrator::setEffectQueue(const std::string &effectQueue) {
- if (!mHwApi->setEffectQueue(effectQueue)) {
- ALOGE("Failed to write \"%s\" to effect queue (%d): %s", effectQueue.c_str(), errno,
- strerror(errno));
- return Status::UNKNOWN_ERROR;
- }
-
- return Status::OK;
-}
-
-Return<void> Vibrator::performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
- Status status = Status::OK;
- uint32_t timeMs = 0;
- uint32_t effectIndex;
- uint32_t volLevel;
- std::string effectQueue;
-
- 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, &timeMs, &volLevel);
- break;
- case Effect::DOUBLE_CLICK:
- status = getCompoundDetails(effect, strength, &timeMs, &volLevel, &effectQueue);
- break;
- default:
- status = Status::UNSUPPORTED_OPERATION;
- break;
- }
- if (status != Status::OK) {
- goto exit;
- }
-
- if (!effectQueue.empty()) {
- status = setEffectQueue(effectQueue);
- if (status != Status::OK) {
- goto exit;
- }
- effectIndex = WAVEFORM_TRIGGER_QUEUE_INDEX;
- } else {
- setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
- effectIndex = WAVEFORM_SIMPLE_EFFECT_INDEX;
- }
-
- on(timeMs, effectIndex);
-
-exit:
-
- _hidl_cb(status, timeMs);
-
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace vibrator
-} // namespace hardware
-} // namespace android
diff --git a/vibrator/Vibrator.h b/vibrator/Vibrator.h
deleted file mode 100644
index b204dae..0000000
--- a/vibrator/Vibrator.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2017 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_V1_3_VIBRATOR_H
-#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
-
-#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <hidl/Status.h>
-
-#include <fstream>
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class Vibrator : public IVibrator {
- 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(uint32_t value) = 0;
- // Stores the LRA series resistance to be used for click
- // compensation.
- virtual bool setRedc(uint32_t value) = 0;
- // Stores the LRA Q factor to be used for Q-dependent waveform
- // selection.
- virtual bool setQ(uint32_t value) = 0;
- // Activates/deactivates the vibrator for durations specified by
- // setDuration().
- virtual bool setActivate(bool value) = 0;
- // Specifies the vibration duration in milliseconds.
- virtual bool setDuration(uint32_t value) = 0;
- // Reports the duration of the waveform selected by
- // setEffectIndex(), measured in 48-kHz periods.
- virtual bool getEffectDuration(uint32_t *value) = 0;
- // Selects the waveform associated with vibration calls from
- // the Android vibrator HAL.
- virtual bool setEffectIndex(uint32_t value) = 0;
- // Specifies an array of waveforms, delays, and repetition markers to
- // generate complex waveforms.
- virtual bool setEffectQueue(std::string value) = 0;
- // Reports whether setEffectScale() is supported.
- virtual bool hasEffectScale() = 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 setEffectScale(uint32_t value) = 0;
- // Indicates the number of 0.125-dB steps of attenuation to apply to
- // any output waveform (additive to all other set*Scale()
- // controls).
- virtual bool setGlobalScale(uint32_t value) = 0;
- // Specifies the active state of the vibrator
- // (true = enabled, false= disabled).
- virtual bool setState(bool value) = 0;
- // Reports whether getAspEnable()/setAspEnable() is supported.
- virtual bool hasAspEnable() = 0;
- // Enables/disables ASP playback.
- virtual bool getAspEnable(bool *value) = 0;
- // Reports enabled/disabled state of ASP playback.
- virtual bool setAspEnable(bool value) = 0;
- // Selects the waveform associated with a GPIO1 falling edge.
- virtual bool setGpioFallIndex(uint32_t value) = 0;
- // Indicates the number of 0.125-dB steps of attenuation to apply to
- // waveforms triggered in response to a GPIO1 falling edge.
- virtual bool setGpioFallScale(uint32_t value) = 0;
- // Selects the waveform associated with a GPIO1 rising edge.
- virtual bool setGpioRiseIndex(uint32_t value) = 0;
- // Indicates the number of 0.125-dB steps of attenuation to apply to
- // waveforms triggered in response to a GPIO1 rising edge.
- virtual bool setGpioRiseScale(uint32_t value) = 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;
- // Obtains the LRA resonant frequency to be used for PWLE playback
- // and click compensation.
- virtual bool getF0(uint32_t *value) = 0;
- // Obtains the LRA series resistance to be used for click
- // compensation.
- virtual bool getRedc(uint32_t *value) = 0;
- // Obtains the LRA Q factor to be used for Q-dependent waveform
- // selection.
- virtual bool getQ(uint32_t *value) = 0;
- // Obtains the discreet voltage levels to be applied for the various
- // waveforms, in units of 1%.
- virtual bool getVolLevels(std::array<uint32_t, 6> *value) = 0;
- // Emit diagnostic information to the given file.
- virtual void debug(int fd) = 0;
- };
-
- public:
- Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal);
-
- // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
- using Status = ::android::hardware::vibrator::V1_0::Status;
- Return<Status> on(uint32_t timeoutMs) override;
- Return<Status> off() override;
- Return<bool> supportsAmplitudeControl() override;
- Return<Status> setAmplitude(uint8_t amplitude) override;
-
- // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
- Return<bool> supportsExternalControl() override;
- Return<Status> setExternalControl(bool enabled) override;
-
- using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
- Return<void> perform(V1_0::Effect effect, EffectStrength strength,
- perform_cb _hidl_cb) override;
- Return<void> perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
- perform_cb _hidl_cb) override;
- Return<void> perform_1_2(V1_2::Effect effect, EffectStrength strength,
- perform_cb _hidl_cb) override;
- Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
-
- // Methods from ::android.hidl.base::V1_0::IBase follow.
- Return<void> debug(const hidl_handle &handle, const hidl_vec<hidl_string> &options) override;
-
- private:
- Return<Status> on(uint32_t timeoutMs, uint32_t effectIndex);
- template <typename T>
- Return<void> performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb);
- // set 'amplitude' based on an arbitrary scale determined by 'maximum'
- Return<Status> setEffectAmplitude(uint8_t amplitude, uint8_t maximum);
- Return<Status> setGlobalAmplitude(bool set);
- // 'simple' effects are those precompiled and loaded into the controller
- Return<Status> getSimpleDetails(Effect effect, EffectStrength strength, uint32_t *outTimeMs,
- uint32_t *outVolLevel);
- // 'compound' effects are those composed by stringing multiple 'simple' effects
- Return<Status> getCompoundDetails(Effect effect, EffectStrength strength, uint32_t *outTimeMs,
- uint32_t *outVolLevel, std::string *outEffectQueue);
- Return<Status> setEffectQueue(const std::string &effectQueue);
- Return<void> performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
- bool isUnderExternalControl();
- std::unique_ptr<HwApi> mHwApi;
- std::unique_ptr<HwCal> mHwCal;
- std::array<uint32_t, 6> mVolLevels;
- uint32_t mSimpleEffectDuration;
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace vibrator
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
diff --git a/vibrator/android.hardware.vibrator@1.3-service.redfin.rc b/vibrator/android.hardware.vibrator@1.3-service.redfin.rc
deleted file mode 100644
index a609ab0..0000000
--- a/vibrator/android.hardware.vibrator@1.3-service.redfin.rc
+++ /dev/null
@@ -1,38 +0,0 @@
-service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.redfin
- class hal
- user system
- group system
-
- setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l25a.cal
-
- setenv F0_FILEPATH /sys/class/leds/vibrator/device/f0_stored
- setenv REDC_FILEPATH /sys/class/leds/vibrator/device/redc_stored
- setenv Q_FILEPATH /sys/class/leds/vibrator/device/q_stored
- setenv ACTIVATE_PATH /sys/class/leds/vibrator/activate
- setenv DURATION_PATH /sys/class/leds/vibrator/duration
- setenv STATE_PATH /sys/class/leds/vibrator/state
- setenv EFFECT_DURATION_PATH /sys/class/leds/vibrator/device/cp_trigger_duration
- setenv EFFECT_INDEX_PATH /sys/class/leds/vibrator/device/cp_trigger_index
- setenv EFFECT_QUEUE_PATH /sys/class/leds/vibrator/device/cp_trigger_queue
- setenv EFFECT_SCALE_PATH /sys/class/leds/vibrator/device/cp_dig_scale
- setenv GLOBAL_SCALE_PATH /sys/class/leds/vibrator/device/dig_scale
- setenv ASP_ENABLE_PATH /sys/class/leds/vibrator/device/asp_enable
- setenv GPIO_FALL_INDEX /sys/class/leds/vibrator/device/gpio1_fall_index
- setenv GPIO_FALL_SCALE /sys/class/leds/vibrator/device/gpio1_fall_dig_scale
- setenv GPIO_RISE_INDEX /sys/class/leds/vibrator/device/gpio1_rise_index
- setenv GPIO_RISE_SCALE /sys/class/leds/vibrator/device/gpio1_rise_dig_scale
-
- setenv HWAPI_DEBUG_PATHS "
- /sys/class/leds/vibrator/device/asp_enable
- /sys/class/leds/vibrator/device/f0_stored
- /sys/class/leds/vibrator/device/fw_rev
- /sys/class/leds/vibrator/device/gpio1_fall_dig_scale
- /sys/class/leds/vibrator/device/gpio1_fall_index
- /sys/class/leds/vibrator/device/gpio1_rise_dig_scale
- /sys/class/leds/vibrator/device/gpio1_rise_index
- /sys/class/leds/vibrator/device/heartbeat
- /sys/class/leds/vibrator/device/num_waves
- /sys/class/leds/vibrator/device/q_stored
- /sys/class/leds/vibrator/device/redc_stored
- /sys/class/leds/vibrator/state
- "
diff --git a/vibrator/common/Android.bp b/vibrator/common/Android.bp
new file mode 100644
index 0000000..477aa05
--- /dev/null
+++ b/vibrator/common/Android.bp
@@ -0,0 +1,33 @@
+//
+// 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.
+
+cc_library {
+ name: "PixelVibratorCommonRedfin",
+ 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
new file mode 100644
index 0000000..f868b6a
--- /dev/null
+++ b/vibrator/common/HardwareBase.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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 <cutils/properties.h>
+#include <log/log.h>
+
+#include <fstream>
+#include <sstream>
+
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace common {
+namespace implementation {
+
+HwApiBase::HwApiBase() {
+ mPathPrefix = std::getenv("HWAPI_PATH_PREFIX") ?: "";
+ if (mPathPrefix.empty()) {
+ ALOGE("Failed get HWAPI path prefix!");
+ }
+}
+
+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<struct context *>(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 implementation
+} // namespace common
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
diff --git a/vibrator/common/HardwareBase.h b/vibrator/common/HardwareBase.h
new file mode 100644
index 0000000..46aa839
--- /dev/null
+++ b/vibrator/common/HardwareBase.h
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
+#define ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
+
+#include <android-base/unique_fd.h>
+#include <log/log.h>
+#include <sys/epoll.h>
+#include <utils/Trace.h>
+
+#include <list>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace common {
+namespace implementation {
+
+using base::unique_fd;
+
+class HwApiBase {
+ private:
+ using NamesMap = std::map<const std::ios *, std::string>;
+
+ class RecordInterface {
+ public:
+ virtual std::string toString(const NamesMap &names) = 0;
+ virtual ~RecordInterface() {}
+ };
+ template <typename T>
+ 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<std::unique_ptr<RecordInterface>>;
+
+ static constexpr uint32_t RECORDS_SIZE = 32;
+
+ public:
+ HwApiBase();
+ void debug(int fd);
+
+ protected:
+ template <typename T>
+ void open(const std::string &name, T *stream);
+ bool has(const std::ios &stream);
+ template <typename T>
+ bool get(T *value, std::istream *stream);
+ template <typename T>
+ bool set(const T &value, std::ostream *stream);
+ template <typename T>
+ bool poll(const T &value, std::istream *stream);
+ template <typename T>
+ 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;
+};
+
+#define HWAPI_RECORD(args...) HwApiBase::record(__FUNCTION__, ##args)
+
+template <typename T>
+void HwApiBase::open(const std::string &name, T *stream) {
+ mNames[stream] = name;
+ utils::openNoCreate(mPathPrefix + name, stream);
+}
+
+template <typename T>
+bool HwApiBase::get(T *value, std::istream *stream) {
+ ATRACE_NAME("HwApi::get");
+ 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 <typename T>
+bool HwApiBase::set(const T &value, std::ostream *stream) {
+ ATRACE_NAME("HwApi::set");
+ using utils::operator<<;
+ 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 <typename T>
+bool HwApiBase::poll(const T &value, std::istream *stream) {
+ 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;
+
+ 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)) {
+ epoll_wait(epollFd, &event, 1, -1);
+ }
+
+ HWAPI_RECORD(value, stream);
+ return ret;
+}
+
+template <typename T>
+void HwApiBase::record(const char *func, const T &value, const std::ios *stream) {
+ std::lock_guard<std::mutex> lock(mRecordsMutex);
+ mRecords.emplace_back(std::make_unique<Record<T>>(func, value, stream));
+ mRecords.pop_front();
+}
+
+template <typename T>
+std::string HwApiBase::Record<T>::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 <typename T>
+ bool getProperty(const char *key, T *value, const T defval);
+ template <typename T>
+ bool getPersist(const char *key, T *value);
+
+ private:
+ std::string mPropertyPrefix;
+ std::map<std::string, std::string> mCalData;
+};
+
+template <typename T>
+bool HwCalBase::getProperty(const char *key, T *outval, const T defval) {
+ ATRACE_NAME("HwCal::getProperty");
+ *outval = utils::getProperty(mPropertyPrefix + key, defval);
+ return true;
+}
+
+template <typename T>
+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 implementation
+} // namespace common
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
diff --git a/vibrator/common/TEST_MAPPING b/vibrator/common/TEST_MAPPING
new file mode 100644
index 0000000..c0e8e98
--- /dev/null
+++ b/vibrator/common/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+ "postsubmit": [
+ {
+ "name": "VibratorHalIntegrationBenchmark"
+ },
+ {
+ "name": "VibratorHalIntegrationBenchmark",
+ "keywords": [
+ "primary-device"
+ ]
+ }
+ ]
+}
diff --git a/vibrator/common/bench/Android.bp b/vibrator/common/bench/Android.bp
new file mode 100644
index 0000000..8df1d8d
--- /dev/null
+++ b/vibrator/common/bench/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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.
+
+cc_benchmark {
+ name: "VibratorHalIntegrationBenchmarkRedfin",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "benchmark.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.vibrator@1.0",
+ "android.hardware.vibrator@1.1",
+ "android.hardware.vibrator@1.2",
+ "android.hardware.vibrator@1.3",
+ "libhardware",
+ "libhidlbase",
+ "libutils",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/vibrator/common/bench/benchmark.cpp b/vibrator/common/bench/benchmark.cpp
new file mode 100644
index 0000000..06013f9
--- /dev/null
+++ b/vibrator/common/bench/benchmark.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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 "benchmark/benchmark.h"
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::Return;
+using ::android::hardware::details::hidl_enum_values;
+using ::benchmark::Counter;
+using ::benchmark::Fixture;
+using ::benchmark::kMicrosecond;
+using ::benchmark::State;
+using ::benchmark::internal::Benchmark;
+using ::std::chrono::duration;
+using ::std::chrono::duration_cast;
+using ::std::chrono::high_resolution_clock;
+
+namespace V1_0 = ::android::hardware::vibrator::V1_0;
+namespace V1_1 = ::android::hardware::vibrator::V1_1;
+namespace V1_2 = ::android::hardware::vibrator::V1_2;
+namespace V1_3 = ::android::hardware::vibrator::V1_3;
+
+template <typename I>
+class VibratorBench : public Fixture {
+ public:
+ void SetUp(State & /*state*/) override { mVibrator = I::getService(); }
+
+ void TearDown(State & /*state*/) override {
+ if (!mVibrator) {
+ return;
+ }
+ mVibrator->off();
+ }
+
+ static void DefaultConfig(Benchmark *b) { b->Unit(kMicrosecond); }
+
+ static void DefaultArgs(Benchmark * /*b*/) {
+ // none
+ }
+
+ protected:
+ auto getOtherArg(const State &state, std::size_t index) const {
+ return state.range(index + 0);
+ }
+
+ protected:
+ sp<I> mVibrator;
+};
+
+enum class EmptyEnum : uint32_t;
+template <>
+inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};
+
+template <typename T, typename U>
+std::set<T> difference(const hidl_enum_range<T> &t, const hidl_enum_range<U> &u) {
+ class Compare {
+ public:
+ bool operator()(const T &a, const U &b) { return a < static_cast<T>(b); }
+ bool operator()(const U &a, const T &b) { return static_cast<T>(a) < b; }
+ };
+ std::set<T> ret;
+
+ std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
+ std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());
+
+ return ret;
+}
+
+template <typename I, typename E1, typename E2 = EmptyEnum>
+class VibratorEffectsBench : public VibratorBench<I> {
+ public:
+ using Effect = E1;
+ using EffectStrength = V1_0::EffectStrength;
+ using Status = V1_0::Status;
+
+ public:
+ static void DefaultArgs(Benchmark *b) {
+ b->ArgNames({"Effect", "Strength"});
+ for (const auto &effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
+ for (const auto &strength : hidl_enum_range<EffectStrength>()) {
+ b->Args({static_cast<long>(effect), static_cast<long>(strength)});
+ }
+ }
+ }
+
+ void performBench(State *state, Return<void> (I::*performApi)(Effect, EffectStrength,
+ typename I::perform_cb)) {
+ auto effect = getEffect(*state);
+ auto strength = getStrength(*state);
+ bool supported = true;
+
+ (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
+ if (status == Status::UNSUPPORTED_OPERATION) {
+ supported = false;
+ }
+ });
+
+ if (!supported) {
+ return;
+ }
+
+ for (auto _ : *state) {
+ state->ResumeTiming();
+ (*this->mVibrator.*performApi)(effect, strength,
+ [](Status /*status*/, uint32_t /*lengthMs*/) {});
+ state->PauseTiming();
+ this->mVibrator->off();
+ }
+ }
+
+ protected:
+ auto getEffect(const State &state) const {
+ return static_cast<Effect>(this->getOtherArg(state, 0));
+ }
+
+ auto getStrength(const State &state) const {
+ return static_cast<EffectStrength>(this->getOtherArg(state, 1));
+ }
+};
+
+#define BENCHMARK_WRAPPER(fixt, test, code) \
+ BENCHMARK_DEFINE_F(fixt, test) \
+ /* NOLINTNEXTLINE */ \
+ (State & state) { \
+ if (!mVibrator) { \
+ return; \
+ } \
+ \
+ code \
+ } \
+ BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)
+
+using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
+ uint32_t ms = UINT32_MAX;
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->on(ms);
+ state.PauseTiming();
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
+ uint32_t ms = UINT32_MAX;
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ mVibrator->on(ms);
+ state.ResumeTiming();
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
+ for (auto _ : state) {
+ mVibrator->supportsAmplitudeControl();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
+ uint8_t amplitude = UINT8_MAX;
+
+ if (!mVibrator->supportsAmplitudeControl()) {
+ return;
+ }
+
+ mVibrator->on(UINT32_MAX);
+
+ for (auto _ : state) {
+ mVibrator->setAmplitude(amplitude);
+ }
+
+ mVibrator->off();
+});
+
+using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
+ { performBench(&state, &V1_0::IVibrator::perform); });
+
+using VibratorEffectsBench_V1_1 =
+ VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
+ { performBench(&state, &V1_1::IVibrator::perform_1_1); });
+
+using VibratorEffectsBench_V1_2 =
+ VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
+ { performBench(&state, &V1_2::IVibrator::perform_1_2); });
+
+using VibratorBench_V1_3 = VibratorBench<V1_3::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
+ for (auto _ : state) {
+ mVibrator->supportsExternalControl();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
+ bool enable = true;
+
+ if (!mVibrator->supportsExternalControl()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ state.ResumeTiming();
+ mVibrator->setExternalControl(enable);
+ state.PauseTiming();
+ mVibrator->setExternalControl(false);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
+ if (!mVibrator->supportsExternalControl()) {
+ return;
+ }
+
+ mVibrator->setExternalControl(true);
+
+ for (auto _ : state) {
+ mVibrator->supportsAmplitudeControl();
+ }
+
+ mVibrator->setExternalControl(false);
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
+ uint8_t amplitude = UINT8_MAX;
+
+ if (!mVibrator->supportsExternalControl()) {
+ return;
+ }
+
+ mVibrator->setExternalControl(true);
+
+ if (!mVibrator->supportsAmplitudeControl()) {
+ return;
+ }
+
+ for (auto _ : state) {
+ mVibrator->setAmplitude(amplitude);
+ }
+
+ mVibrator->setExternalControl(false);
+});
+
+using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
+ { performBench(&state, &V1_3::IVibrator::perform_1_3); });
+
+BENCHMARK_MAIN();
diff --git a/vibrator/common/utils.h b/vibrator/common/utils.h
new file mode 100644
index 0000000..2079256
--- /dev/null
+++ b/vibrator/common/utils.h
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_UTILS_H
+#define ANDROID_HARDWARE_VIBRATOR_UTILS_H
+
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <log/log.h>
+
+#include <fstream>
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace utils {
+
+template <typename T>
+class Is_Iterable {
+ private:
+ template <typename U>
+ static std::true_type test(typename U::iterator *u);
+
+ template <typename U>
+ static std::false_type test(U *u);
+
+ public:
+ static const bool value = decltype(test<T>(0))::value;
+};
+
+template <typename T, bool B>
+using Enable_If_Iterable = std::enable_if_t<Is_Iterable<T>::value == B>;
+
+template <typename T, typename U = void>
+using Enable_If_Signed = std::enable_if_t<std::is_signed_v<T>, U>;
+
+template <typename T, typename U = void>
+using Enable_If_Unsigned = std::enable_if_t<std::is_unsigned_v<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 <typename T>
+inline auto toUnderlying(const T value) {
+ return static_cast<std::underlying_type_t<T>>(value);
+}
+
+template <typename T>
+inline Enable_If_Iterable<T, true> unpack(std::istream &stream, T *value) {
+ for (auto &entry : *value) {
+ stream >> entry;
+ }
+}
+
+template <typename T>
+inline Enable_If_Iterable<T, false> unpack(std::istream &stream, T *value) {
+ stream >> *value;
+}
+
+template <>
+inline void unpack<std::string>(std::istream &stream, std::string *value) {
+ *value = std::string(std::istreambuf_iterator(stream), {});
+ stream.setstate(std::istream::eofbit);
+}
+
+template <typename T>
+inline Enable_If_Signed<T, T> getProperty(const std::string &key, const T def) {
+ return base::GetIntProperty(key, def);
+}
+
+template <typename T>
+inline Enable_If_Unsigned<T, T> getProperty(const std::string &key, const T def) {
+ return base::GetUintProperty(key, def);
+}
+
+template <>
+inline bool getProperty<bool>(const std::string &key, const bool def) {
+ return base::GetBoolProperty(key, def);
+}
+
+template <typename T>
+static void openNoCreate(const std::string &file, T *outStream) {
+ auto mode = std::is_base_of_v<std::ostream, T> ? 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 <typename T>
+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<std::string, std::ifstream> 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
+
+#endif // ANDROID_HARDWARE_VIBRATOR_UTILS_H
diff --git a/vibrator/drv2624/Android.bp b/vibrator/drv2624/Android.bp
new file mode 100644
index 0000000..cf75650
--- /dev/null
+++ b/vibrator/drv2624/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2017 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.
+
+cc_defaults {
+ name: "android.hardware.vibrator@1.3-defaults.redfin",
+ defaults: ["PixelVibratorDefaultsRedfin"],
+ shared_libs: [
+ "android.hardware.vibrator@1.0",
+ "android.hardware.vibrator@1.1",
+ "android.hardware.vibrator@1.2",
+ "android.hardware.vibrator@1.3",
+ ],
+ cflags: [
+ "-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)",
+ "-DLOG_TAG=\"android.hardware.vibrator@1.3-redfin\"",
+ ],
+}
+
+cc_defaults {
+ name: "VibratorHalDrv2624TestDefaultsRedfin",
+ defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
+ static_libs: ["android.hardware.vibrator@1.3-impl.redfin"],
+ test_suites: ["device-tests"],
+ require_root: true,
+}
+
+cc_library {
+ name: "android.hardware.vibrator@1.3-impl.redfin",
+ defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
+ srcs: ["Vibrator.cpp"],
+ export_include_dirs: ["."],
+ vendor_available: true,
+}
+
+cc_binary {
+ name: "android.hardware.vibrator@1.3-service.redfin",
+ defaults: ["android.hardware.vibrator@1.3-defaults.redfin"],
+ init_rc: ["android.hardware.vibrator@1.3-service.redfin.rc"],
+ vintf_fragments: ["android.hardware.vibrator@1.3-service.redfin.xml"],
+ srcs: ["service.cpp"],
+ static_libs: ["android.hardware.vibrator@1.3-impl.redfin"],
+ proprietary: true,
+}
diff --git a/vibrator/drv2624/Hardware.h b/vibrator/drv2624/Hardware.h
new file mode 100644
index 0000000..d43fa6d
--- /dev/null
+++ b/vibrator/drv2624/Hardware.h
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
+#define ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
+
+#include "HardwareBase.h"
+#include "Vibrator.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using common::implementation::HwApiBase;
+using common::implementation::HwCalBase;
+
+class HwApi : public Vibrator::HwApi, private HwApiBase {
+ public:
+ static std::unique_ptr<HwApi> Create() {
+ auto hwapi = std::unique_ptr<HwApi>(new HwApi());
+ // the following streams are required
+ if (!hwapi->mActivate.is_open() || !hwapi->mDuration.is_open() ||
+ !hwapi->mState.is_open()) {
+ return nullptr;
+ }
+ return hwapi;
+ }
+
+ bool setAutocal(std::string value) override { return set(value, &mAutocal); }
+ bool setOlLraPeriod(uint32_t value) override { return set(value, &mOlLraPeriod); }
+ bool setActivate(bool value) override { return set(value, &mActivate); }
+ bool setDuration(uint32_t value) override { return set(value, &mDuration); }
+ bool setState(bool value) override { return set(value, &mState); }
+ bool hasRtpInput() override { return has(mRtpInput); }
+ bool setRtpInput(int8_t value) override { return set(value, &mRtpInput); }
+ bool setMode(std::string value) override { return set(value, &mMode); }
+ bool setSequencer(std::string value) override { return set(value, &mSequencer); }
+ bool setScale(uint8_t value) override { return set(value, &mScale); }
+ bool setCtrlLoop(bool value) override { return set(value, &mCtrlLoop); }
+ bool setLpTriggerEffect(uint32_t value) override { return set(value, &mLpTrigger); }
+ bool setLraWaveShape(uint32_t value) override { return set(value, &mLraWaveShape); }
+ bool setOdClamp(uint32_t value) override { return set(value, &mOdClamp); }
+ void debug(int fd) override { HwApiBase::debug(fd); }
+
+ private:
+ HwApi() {
+ open("device/autocal", &mAutocal);
+ open("device/ol_lra_period", &mOlLraPeriod);
+ open("activate", &mActivate);
+ open("duration", &mDuration);
+ open("state", &mState);
+ open("device/rtp_input", &mRtpInput);
+ open("device/mode", &mMode);
+ open("device/set_sequencer", &mSequencer);
+ open("device/scale", &mScale);
+ open("device/ctrl_loop", &mCtrlLoop);
+ open("device/lp_trigger_effect", &mLpTrigger);
+ open("device/lra_wave_shape", &mLraWaveShape);
+ open("device/od_clamp", &mOdClamp);
+ }
+
+ private:
+ std::ofstream mAutocal;
+ std::ofstream mOlLraPeriod;
+ std::ofstream mActivate;
+ std::ofstream mDuration;
+ std::ofstream mState;
+ std::ofstream mRtpInput;
+ std::ofstream mMode;
+ std::ofstream mSequencer;
+ std::ofstream mScale;
+ std::ofstream mCtrlLoop;
+ std::ofstream mLpTrigger;
+ std::ofstream mLraWaveShape;
+ std::ofstream mOdClamp;
+};
+
+class HwCal : public Vibrator::HwCal, private HwCalBase {
+ private:
+ static constexpr char AUTOCAL_CONFIG[] = "autocal";
+ static constexpr char LRA_PERIOD_CONFIG[] = "lra_period";
+ static constexpr char EFFECT_COEFF_CONFIG[] = "haptic_coefficient";
+ static constexpr char STEADY_AMP_MAX_CONFIG[] = "vibration_amp_max";
+
+ static constexpr uint32_t WAVEFORM_CLICK_EFFECT_MS = 6;
+ static constexpr uint32_t WAVEFORM_TICK_EFFECT_MS = 2;
+ static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_EFFECT_MS = 144;
+ static constexpr uint32_t WAVEFORM_HEAVY_CLICK_EFFECT_MS = 8;
+
+ static constexpr uint32_t DEFAULT_LRA_PERIOD = 262;
+ static constexpr uint32_t DEFAULT_FREQUENCY_SHIFT = 10;
+ static constexpr uint32_t DEFAULT_VOLTAGE_MAX = 107; // 2.15V;
+
+ public:
+ HwCal() {}
+
+ bool getAutocal(std::string *value) override { return getPersist(AUTOCAL_CONFIG, value); }
+ bool getLraPeriod(uint32_t *value) override {
+ if (getPersist(LRA_PERIOD_CONFIG, value)) {
+ return true;
+ }
+ *value = DEFAULT_LRA_PERIOD;
+ return true;
+ }
+ bool getEffectCoeffs(std::array<float, 4> *value) override {
+ if (getPersist(EFFECT_COEFF_CONFIG, value)) {
+ return true;
+ }
+ return false;
+ }
+ bool getSteadyAmpMax(float *value) override {
+ if (getPersist(STEADY_AMP_MAX_CONFIG, value)) {
+ return true;
+ }
+ return false;
+ }
+ bool getCloseLoopThreshold(uint32_t *value) override {
+ return getProperty("closeloop.threshold", value, UINT32_MAX);
+ return true;
+ }
+ bool getDynamicConfig(bool *value) override {
+ return getProperty("config.dynamic", value, false);
+ }
+ bool getLongFrequencyShift(uint32_t *value) override {
+ return getProperty("long.frequency.shift", value, DEFAULT_FREQUENCY_SHIFT);
+ }
+ bool getShortVoltageMax(uint32_t *value) override {
+ return getProperty("short.voltage", value, DEFAULT_VOLTAGE_MAX);
+ }
+ bool getLongVoltageMax(uint32_t *value) override {
+ return getProperty("long.voltage", value, DEFAULT_VOLTAGE_MAX);
+ }
+ bool getClickDuration(uint32_t *value) override {
+ return getProperty("click.duration", value, WAVEFORM_CLICK_EFFECT_MS);
+ }
+ bool getTickDuration(uint32_t *value) override {
+ return getProperty("tick.duration", value, WAVEFORM_TICK_EFFECT_MS);
+ }
+ bool getDoubleClickDuration(uint32_t *value) override {
+ *value = WAVEFORM_DOUBLE_CLICK_EFFECT_MS;
+ return true;
+ }
+ bool getHeavyClickDuration(uint32_t *value) override {
+ return getProperty("heavyclick.duration", value, WAVEFORM_HEAVY_CLICK_EFFECT_MS);
+ }
+ bool getEffectShape(uint32_t *value) override {
+ return getProperty("effect.shape", value, UINT32_MAX);
+ }
+ bool getSteadyShape(uint32_t *value) override {
+ return getProperty("steady.shape", value, UINT32_MAX);
+ }
+ void debug(int fd) override { HwCalBase::debug(fd); }
+};
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_VIBRATOR_HARDWARE_H
diff --git a/vibrator/drv2624/TEST_MAPPING b/vibrator/drv2624/TEST_MAPPING
new file mode 100644
index 0000000..ec34f66
--- /dev/null
+++ b/vibrator/drv2624/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "VibratorHalDrv2624TestSuite"
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "VibratorHalDrv2624Benchmark",
+ "keywords": [
+ "primary-device"
+ ]
+ }
+ ]
+}
diff --git a/vibrator/drv2624/Vibrator.cpp b/vibrator/drv2624/Vibrator.cpp
new file mode 100644
index 0000000..02d786f
--- /dev/null
+++ b/vibrator/drv2624/Vibrator.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2017 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 <cutils/properties.h>
+#include <hardware/hardware.h>
+#include <hardware/vibrator.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <cinttypes>
+#include <cmath>
+#include <fstream>
+#include <iostream>
+
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+static constexpr int8_t MAX_RTP_INPUT = 127;
+static constexpr int8_t MIN_RTP_INPUT = 0;
+
+static constexpr char RTP_MODE[] = "rtp";
+static constexpr char WAVEFORM_MODE[] = "waveform";
+
+// Use effect #1 in the waveform library for CLICK effect
+static constexpr char WAVEFORM_CLICK_EFFECT_SEQ[] = "1 0";
+
+// Use effect #2 in the waveform library for TICK effect
+static constexpr char WAVEFORM_TICK_EFFECT_SEQ[] = "2 0";
+
+// Use effect #3 in the waveform library for DOUBLE_CLICK effect
+static constexpr char WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ[] = "3 0";
+
+// Use effect #4 in the waveform library for HEAVY_CLICK effect
+static constexpr char WAVEFORM_HEAVY_CLICK_EFFECT_SEQ[] = "4 0";
+
+// UT team design those target G values
+static constexpr std::array<float, 5> EFFECT_TARGET_G = {0.175, 0.325, 0.37, 0.475, 0.6};
+static constexpr std::array<float, 3> STEADY_TARGET_G = {1.38, 1.145, 0.905};
+
+#define FLOAT_EPS 1e-6
+
+static std::uint32_t freqPeriodFormula(std::uint32_t in) {
+ return 1000000000 / (24615 * in);
+}
+
+static std::uint32_t convertLevelsToOdClamp(float voltageLevel, uint32_t lraPeriod) {
+ float odClamp;
+
+ odClamp = voltageLevel /
+ ((21.32 / 1000.0) *
+ sqrt(1.0 - (static_cast<float>(freqPeriodFormula(lraPeriod)) * 8.0 / 10000.0)));
+
+ return round(odClamp);
+}
+
+static float targetGToVlevelsUnderLinearEquation(std::array<float, 4> inputCoeffs, float targetG) {
+ // Implement linear equation to get voltage levels, f(x) = ax + b
+ // 0 to 3.2 is our valid output
+ float outPutVal = 0.0f;
+ outPutVal = (targetG - inputCoeffs[1]) / inputCoeffs[0];
+ if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+ return outPutVal;
+ } else {
+ return 0.0f;
+ }
+}
+
+static float targetGToVlevelsUnderCubicEquation(std::array<float, 4> inputCoeffs, float targetG) {
+ // Implement cubic equation to get voltage levels, f(x) = ax^3 + bx^2 + cx + d
+ // 0 to 3.2 is our valid output
+ float AA = 0.0f, BB = 0.0f, CC = 0.0f, Delta = 0.0f;
+ float Y1 = 0.0f, Y2 = 0.0f, K = 0.0f, T = 0.0f, sita = 0.0f;
+ float outPutVal = 0.0f;
+ float oneHalf = 1.0 / 2.0, oneThird = 1.0 / 3.0;
+ float cosSita = 0.0f, sinSitaSqrt3 = 0.0f, sqrtA = 0.0f;
+
+ AA = inputCoeffs[1] * inputCoeffs[1] - 3.0 * inputCoeffs[0] * inputCoeffs[2];
+ BB = inputCoeffs[1] * inputCoeffs[2] - 9.0 * inputCoeffs[0] * (inputCoeffs[3] - targetG);
+ CC = inputCoeffs[2] * inputCoeffs[2] - 3.0 * inputCoeffs[1] * (inputCoeffs[3] - targetG);
+
+ Delta = BB * BB - 4.0 * AA * CC;
+
+ // There are four discriminants in Shengjin formula.
+ // https://zh.wikipedia.org/wiki/%E4%B8%89%E6%AC%A1%E6%96%B9%E7%A8%8B#%E7%9B%9B%E9%87%91%E5%85%AC%E5%BC%8F%E6%B3%95
+ if ((fabs(AA) <= FLOAT_EPS) && (fabs(BB) <= FLOAT_EPS)) {
+ // Case 1: A = B = 0
+ outPutVal = -inputCoeffs[1] / (3 * inputCoeffs[0]);
+ if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+ return outPutVal;
+ }
+ return 0.0f;
+ } else if (Delta > FLOAT_EPS) {
+ // Case 2: Delta > 0
+ Y1 = AA * inputCoeffs[1] + 3.0 * inputCoeffs[0] * (-BB + pow(Delta, oneHalf)) / 2.0;
+ Y2 = AA * inputCoeffs[1] + 3.0 * inputCoeffs[0] * (-BB - pow(Delta, oneHalf)) / 2.0;
+
+ if ((Y1 < -FLOAT_EPS) && (Y2 > FLOAT_EPS)) {
+ return (-inputCoeffs[1] + pow(-Y1, oneThird) - pow(Y2, oneThird)) /
+ (3.0 * inputCoeffs[0]);
+ } else if ((Y1 > FLOAT_EPS) && (Y2 < -FLOAT_EPS)) {
+ return (-inputCoeffs[1] - pow(Y1, oneThird) + pow(-Y2, oneThird)) /
+ (3.0 * inputCoeffs[0]);
+ } else if ((Y1 < -FLOAT_EPS) && (Y2 < -FLOAT_EPS)) {
+ return (-inputCoeffs[1] + pow(-Y1, oneThird) + pow(-Y2, oneThird)) /
+ (3.0 * inputCoeffs[0]);
+ } else {
+ return (-inputCoeffs[1] - pow(Y1, oneThird) - pow(Y2, oneThird)) /
+ (3.0 * inputCoeffs[0]);
+ }
+ return 0.0f;
+ } else if (Delta < -FLOAT_EPS) {
+ // Case 3: Delta < 0
+ T = (2 * AA * inputCoeffs[1] - 3 * inputCoeffs[0] * BB) / (2 * AA * sqrt(AA));
+ sita = acos(T);
+ cosSita = cos(sita / 3);
+ sinSitaSqrt3 = sqrt(3.0) * sin(sita / 3);
+ sqrtA = sqrt(AA);
+
+ outPutVal = (-inputCoeffs[1] - 2 * sqrtA * cosSita) / (3 * inputCoeffs[0]);
+ if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+ return outPutVal;
+ }
+ outPutVal = (-inputCoeffs[1] + sqrtA * (cosSita + sinSitaSqrt3)) / (3 * inputCoeffs[0]);
+ if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+ return outPutVal;
+ }
+ outPutVal = (-inputCoeffs[1] + sqrtA * (cosSita - sinSitaSqrt3)) / (3 * inputCoeffs[0]);
+ if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+ return outPutVal;
+ }
+ return 0.0f;
+ } else if (Delta <= FLOAT_EPS) {
+ // Case 4: Delta = 0
+ K = BB / AA;
+ outPutVal = (-inputCoeffs[1] / inputCoeffs[0] + K);
+ if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+ return outPutVal;
+ }
+ outPutVal = (-K / 2);
+ if ((outPutVal > FLOAT_EPS) && (outPutVal <= 3.2)) {
+ return outPutVal;
+ }
+ return 0.0f;
+ } else {
+ // Exception handling
+ return 0.0f;
+ }
+}
+
+using utils::toUnderlying;
+
+using Status = ::android::hardware::vibrator::V1_0::Status;
+using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
+
+Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal)
+ : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)) {
+ std::string autocal;
+ uint32_t lraPeriod = 0;
+ bool dynamicConfig = false;
+ bool hasEffectCoeffs = false;
+ std::array<float, 4> effectCoeffs = {0};
+
+ if (!mHwApi->setState(true)) {
+ ALOGE("Failed to set state (%d): %s", errno, strerror(errno));
+ }
+
+ if (mHwCal->getAutocal(&autocal)) {
+ mHwApi->setAutocal(autocal);
+ }
+ mHwCal->getLraPeriod(&lraPeriod);
+
+ mHwCal->getCloseLoopThreshold(&mCloseLoopThreshold);
+ mHwCal->getDynamicConfig(&dynamicConfig);
+
+ if (dynamicConfig) {
+ uint8_t i = 0;
+ float tempVolLevel = 0.0f;
+ float tempAmpMax = 0.0f;
+ uint32_t longFreqencyShift = 0;
+ uint32_t shortVoltageMax = 0, longVoltageMax = 0;
+ uint32_t shape = 0;
+
+ mHwCal->getLongFrequencyShift(&longFreqencyShift);
+ mHwCal->getShortVoltageMax(&shortVoltageMax);
+ mHwCal->getLongVoltageMax(&longVoltageMax);
+
+ hasEffectCoeffs = mHwCal->getEffectCoeffs(&effectCoeffs);
+ for (i = 0; i < 5; i++) {
+ if (hasEffectCoeffs) {
+ // Use linear approach to get the target voltage levels
+ if ((effectCoeffs[2] == 0) && (effectCoeffs[3] == 0)) {
+ tempVolLevel =
+ targetGToVlevelsUnderLinearEquation(effectCoeffs, EFFECT_TARGET_G[i]);
+ mEffectTargetOdClamp[i] = convertLevelsToOdClamp(tempVolLevel, lraPeriod);
+ } else {
+ // Use cubic approach to get the target voltage levels
+ tempVolLevel =
+ targetGToVlevelsUnderCubicEquation(effectCoeffs, EFFECT_TARGET_G[i]);
+ mEffectTargetOdClamp[i] = convertLevelsToOdClamp(tempVolLevel, lraPeriod);
+ }
+ } else {
+ mEffectTargetOdClamp[i] = shortVoltageMax;
+ }
+ }
+ // Add a boundary protection for level 5 only, since
+ // some devices might not be able to reach the maximum target G
+ if ((mEffectTargetOdClamp[4] <= 0) || (mEffectTargetOdClamp[4] > 161)) {
+ mEffectTargetOdClamp[4] = shortVoltageMax;
+ }
+
+ mHwCal->getEffectShape(&shape);
+ mEffectConfig.reset(new VibrationConfig({
+ .shape = (shape == UINT32_MAX) ? WaveShape::SINE : static_cast<WaveShape>(shape),
+ .odClamp = &mEffectTargetOdClamp[0],
+ .olLraPeriod = lraPeriod,
+ }));
+
+ mSteadyTargetOdClamp = mHwCal->getSteadyAmpMax(&tempAmpMax)
+ ? round((STEADY_TARGET_G[0] / tempAmpMax) * longVoltageMax)
+ : longVoltageMax;
+ mHwCal->getSteadyShape(&shape);
+ mSteadyConfig.reset(new VibrationConfig({
+ .shape = (shape == UINT32_MAX) ? WaveShape::SQUARE : static_cast<WaveShape>(shape),
+ .odClamp = &mSteadyTargetOdClamp,
+ // 1. Change long lra period to frequency
+ // 2. Get frequency': subtract the frequency shift from the frequency
+ // 3. Get final long lra period after put the frequency' to formula
+ .olLraPeriod = freqPeriodFormula(freqPeriodFormula(lraPeriod) - longFreqencyShift),
+ }));
+ } else {
+ mHwApi->setOlLraPeriod(lraPeriod);
+ }
+
+ mHwCal->getClickDuration(&mClickDuration);
+ mHwCal->getTickDuration(&mTickDuration);
+ mHwCal->getDoubleClickDuration(&mDoubleClickDuration);
+ mHwCal->getHeavyClickDuration(&mHeavyClickDuration);
+
+ // This enables effect #1 from the waveform library to be triggered by SLPI
+ // while the AP is in suspend mode
+ if (!mHwApi->setLpTriggerEffect(1)) {
+ ALOGW("Failed to set LP trigger mode (%d): %s", errno, strerror(errno));
+ }
+}
+
+Return<Status> Vibrator::on(uint32_t timeoutMs, const char mode[],
+ const std::unique_ptr<VibrationConfig> &config,
+ const int8_t volOffset) {
+ LoopControl loopMode = LoopControl::OPEN;
+
+ // Open-loop mode is used for short click for over-drive
+ // Close-loop mode is used for long notification for stability
+ if (mode == RTP_MODE && timeoutMs > mCloseLoopThreshold) {
+ loopMode = LoopControl::CLOSE;
+ }
+
+ mHwApi->setCtrlLoop(toUnderlying(loopMode));
+ if (!mHwApi->setDuration(timeoutMs)) {
+ ALOGE("Failed to set duration (%d): %s", errno, strerror(errno));
+ return Status::UNKNOWN_ERROR;
+ }
+
+ mHwApi->setMode(mode);
+ if (config != nullptr) {
+ mHwApi->setLraWaveShape(toUnderlying(config->shape));
+ mHwApi->setOdClamp(config->odClamp[volOffset]);
+ mHwApi->setOlLraPeriod(config->olLraPeriod);
+ }
+
+ if (!mHwApi->setActivate(1)) {
+ ALOGE("Failed to activate (%d): %s", errno, strerror(errno));
+ return Status::UNKNOWN_ERROR;
+ }
+
+ return Status::OK;
+}
+
+// Methods from ::android::hardware::vibrator::V1_2::IVibrator follow.
+Return<Status> Vibrator::on(uint32_t timeoutMs) {
+ ATRACE_NAME("Vibrator::on");
+ return on(timeoutMs, RTP_MODE, mSteadyConfig, 0);
+}
+
+Return<Status> Vibrator::off() {
+ ATRACE_NAME("Vibrator::off");
+ if (!mHwApi->setActivate(0)) {
+ ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
+ return Status::UNKNOWN_ERROR;
+ }
+ return Status::OK;
+}
+
+Return<bool> Vibrator::supportsAmplitudeControl() {
+ ATRACE_NAME("Vibrator::supportsAmplitudeControl");
+ return (mHwApi->hasRtpInput() ? true : false);
+}
+
+Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
+ ATRACE_NAME("Vibrator::setAmplitude");
+ if (amplitude == 0) {
+ return Status::BAD_VALUE;
+ }
+
+ int32_t rtp_input =
+ std::round((amplitude - 1) / 254.0 * (MAX_RTP_INPUT - MIN_RTP_INPUT) + MIN_RTP_INPUT);
+
+ if (!mHwApi->setRtpInput(rtp_input)) {
+ ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));
+ return Status::UNKNOWN_ERROR;
+ }
+
+ return Status::OK;
+}
+
+// Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
+
+Return<bool> Vibrator::supportsExternalControl() {
+ ATRACE_NAME("Vibrator::supportsExternalControl");
+ return false;
+}
+
+Return<Status> Vibrator::setExternalControl(bool enabled) {
+ ATRACE_NAME("Vibrator::setExternalControl");
+ ALOGE("Not support in DRV2624 solution, %d", enabled);
+ return Status::UNSUPPORTED_OPERATION;
+}
+
+// Methods from ::android.hidl.base::V1_0::IBase follow.
+
+Return<void> Vibrator::debug(const hidl_handle &handle,
+ const hidl_vec<hidl_string> & /* options */) {
+ if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
+ ALOGE("Called debug() with invalid fd.");
+ return Void();
+ }
+
+ int fd = handle->data[0];
+
+ dprintf(fd, "HIDL:\n");
+
+ dprintf(fd, " Close Loop Thresh: %" PRIu32 "\n", mCloseLoopThreshold);
+ if (mSteadyConfig) {
+ dprintf(fd, " Steady Shape: %" PRIu32 "\n", mSteadyConfig->shape);
+ dprintf(fd, " Steady OD Clamp: %" PRIu32 "\n", mSteadyConfig->odClamp[0]);
+ dprintf(fd, " Steady OL LRA Period: %" PRIu32 "\n", mSteadyConfig->olLraPeriod);
+ }
+ if (mEffectConfig) {
+ dprintf(fd, " Effect Shape: %" PRIu32 "\n", mEffectConfig->shape);
+ dprintf(fd,
+ " Effect OD Clamp: %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
+ mEffectConfig->odClamp[0], mEffectConfig->odClamp[1], mEffectConfig->odClamp[2],
+ mEffectConfig->odClamp[3], mEffectConfig->odClamp[4]);
+ dprintf(fd, " Effect OL LRA Period: %" PRIu32 "\n", mEffectConfig->olLraPeriod);
+ }
+ dprintf(fd, " Click Duration: %" PRIu32 "\n", mClickDuration);
+ dprintf(fd, " Tick Duration: %" PRIu32 "\n", mTickDuration);
+ dprintf(fd, " Double Click Duration: %" PRIu32 "\n", mDoubleClickDuration);
+ dprintf(fd, " Heavy Click Duration: %" PRIu32 "\n", mHeavyClickDuration);
+
+ dprintf(fd, "\n");
+
+ mHwApi->debug(fd);
+
+ dprintf(fd, "\n");
+
+ mHwCal->debug(fd);
+
+ fsync(fd);
+ return Void();
+}
+
+Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+ return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
+ perform_cb _hidl_cb) {
+ return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_2(V1_2::Effect effect, EffectStrength strength,
+ perform_cb _hidl_cb) {
+ return performWrapper(effect, strength, _hidl_cb);
+}
+
+Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+ return performWrapper(effect, strength, _hidl_cb);
+}
+
+template <typename T>
+Return<void> Vibrator::performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb) {
+ ATRACE_NAME("Vibrator::performWrapper");
+ auto validEffectRange = hidl_enum_range<T>();
+ if (effect < *validEffectRange.begin() || effect > *std::prev(validEffectRange.end())) {
+ _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+ return Void();
+ }
+ auto validStrengthRange = hidl_enum_range<EffectStrength>();
+ if (strength < *validStrengthRange.begin() || strength > *std::prev(validStrengthRange.end())) {
+ _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+ return Void();
+ }
+ return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
+}
+
+Return<void> Vibrator::performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+ Status status = Status::OK;
+ uint32_t timeMS;
+ int8_t volOffset;
+
+ switch (strength) {
+ case EffectStrength::LIGHT:
+ volOffset = 0;
+ break;
+ case EffectStrength::MEDIUM:
+ volOffset = 1;
+ break;
+ case EffectStrength::STRONG:
+ volOffset = 1;
+ break;
+ default:
+ status = Status::UNSUPPORTED_OPERATION;
+ break;
+ }
+
+ switch (effect) {
+ case Effect::TEXTURE_TICK:
+ mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
+ timeMS = mTickDuration;
+ volOffset = TEXTURE_TICK;
+ break;
+ case Effect::CLICK:
+ mHwApi->setSequencer(WAVEFORM_CLICK_EFFECT_SEQ);
+ timeMS = mClickDuration;
+ volOffset += CLICK;
+ break;
+ case Effect::DOUBLE_CLICK:
+ mHwApi->setSequencer(WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ);
+ timeMS = mDoubleClickDuration;
+ volOffset += CLICK;
+ break;
+ case Effect::TICK:
+ mHwApi->setSequencer(WAVEFORM_TICK_EFFECT_SEQ);
+ timeMS = mTickDuration;
+ volOffset += TICK;
+ break;
+ case Effect::HEAVY_CLICK:
+ mHwApi->setSequencer(WAVEFORM_HEAVY_CLICK_EFFECT_SEQ);
+ timeMS = mHeavyClickDuration;
+ volOffset += HEAVY_CLICK;
+ break;
+ default:
+ _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
+ return Void();
+ }
+ on(timeMS, WAVEFORM_MODE, mEffectConfig, volOffset);
+ _hidl_cb(status, timeMS);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
diff --git a/vibrator/drv2624/Vibrator.h b/vibrator/drv2624/Vibrator.h
new file mode 100644
index 0000000..16cd8e8
--- /dev/null
+++ b/vibrator/drv2624/Vibrator.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 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_V1_3_VIBRATOR_H
+#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <hidl/Status.h>
+
+#include <fstream>
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+class Vibrator : public IVibrator {
+ public:
+ // APIs for interfacing with the kernel driver.
+ class HwApi {
+ public:
+ virtual ~HwApi() = default;
+ // Stores the COMP, BEMF, and GAIN calibration values to use.
+ // <COMP> <BEMF> <GAIN>
+ virtual bool setAutocal(std::string value) = 0;
+ // Stores the open-loop LRA frequency to be used.
+ virtual bool setOlLraPeriod(uint32_t value) = 0;
+ // Activates/deactivates the vibrator for durations specified by
+ // setDuration().
+ virtual bool setActivate(bool value) = 0;
+ // Specifies the vibration duration in milliseconds.
+ virtual bool setDuration(uint32_t value) = 0;
+ // Specifies the active state of the vibrator
+ // (true = enabled, false = disabled).
+ virtual bool setState(bool value) = 0;
+ // Reports whether setRtpInput() is supported.
+ virtual bool hasRtpInput() = 0;
+ // Specifies the playback amplitude of the haptic waveforms in RTP mode.
+ // Negative numbers indicates braking.
+ virtual bool setRtpInput(int8_t value) = 0;
+ // Specifies the mode of operation.
+ // rtp - RTP Mode
+ // waveform - Waveform Sequencer Mode
+ // diag - Diagnostics Routine
+ // autocal - Automatic Level Calibration Routine
+ virtual bool setMode(std::string value) = 0;
+ // Specifies a waveform sequence in index-count pairs.
+ // <index-1> <count-1> [<index-2> <cound-2> ...]
+ virtual bool setSequencer(std::string value) = 0;
+ // Specifies the scaling of effects in Waveform mode.
+ // 0 - 100%
+ // 1 - 75%
+ // 2 - 50%
+ // 3 - 25%
+ virtual bool setScale(uint8_t value) = 0;
+ // Selects either closed loop or open loop mode.
+ // (true = open, false = closed).
+ virtual bool setCtrlLoop(bool value) = 0;
+ // Specifies waveform index to be played in low-power trigger mode.
+ // 0 - Disabled
+ // 1+ - Waveform Index
+ virtual bool setLpTriggerEffect(uint32_t value) = 0;
+ // Specifies which shape to use for driving the LRA when in open loop
+ // mode.
+ // 0 - Square Wave
+ // 1 - Sine Wave
+ virtual bool setLraWaveShape(uint32_t value) = 0;
+ // Specifies the maximum voltage for automatic overdrive and automatic
+ // braking periods.
+ virtual bool setOdClamp(uint32_t value) = 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;
+ // Obtains the COMP, BEMF, and GAIN calibration values to use.
+ virtual bool getAutocal(std::string *value) = 0;
+ // Obtains the open-loop LRA frequency to be used.
+ virtual bool getLraPeriod(uint32_t *value) = 0;
+ // Obtains the effect coeffs to calculate the target voltage
+ virtual bool getEffectCoeffs(std::array<float, 4> *value) = 0;
+ // Obtain the max steady G value
+ virtual bool getSteadyAmpMax(float *value) = 0;
+ // Obtains threshold in ms, above which close-loop should be used.
+ virtual bool getCloseLoopThreshold(uint32_t *value) = 0;
+ // Obtains dynamic/static configuration choice.
+ virtual bool getDynamicConfig(bool *value) = 0;
+ // Obtains LRA frequency shift for long (steady) vibrations.
+ virtual bool getLongFrequencyShift(uint32_t *value) = 0;
+ // Obtains maximum voltage for short (effect) vibrations
+ virtual bool getShortVoltageMax(uint32_t *value) = 0;
+ // Obtains maximum voltage for long (steady) vibrations
+ virtual bool getLongVoltageMax(uint32_t *value) = 0;
+ // Obtains the duration for the click effect
+ virtual bool getClickDuration(uint32_t *value) = 0;
+ // Obtains the duration for the tick effect
+ virtual bool getTickDuration(uint32_t *value) = 0;
+ // Obtains the duration for the double-click effect
+ virtual bool getDoubleClickDuration(uint32_t *value) = 0;
+ // Obtains the duration for the heavy-click effect
+ virtual bool getHeavyClickDuration(uint32_t *value) = 0;
+ // Obtains the wave shape for effect haptics
+ virtual bool getEffectShape(uint32_t *value) = 0;
+ // Obtains the wave shape for steady vibration
+ virtual bool getSteadyShape(uint32_t *value) = 0;
+ // Emit diagnostic information to the given file.
+ virtual void debug(int fd) = 0;
+ };
+
+ private:
+ enum class LoopControl : bool {
+ CLOSE = false,
+ OPEN = true,
+ };
+
+ enum class WaveShape : uint32_t {
+ SQUARE = 0,
+ SINE = 1,
+ };
+
+ struct VibrationConfig {
+ WaveShape shape;
+ uint32_t *odClamp;
+ uint32_t olLraPeriod;
+ };
+
+ enum OdClampOffset : uint32_t {
+ TEXTURE_TICK,
+ TICK,
+ CLICK,
+ HEAVY_CLICK,
+ };
+
+ public:
+ Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal);
+
+ // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow.
+ using Status = ::android::hardware::vibrator::V1_0::Status;
+ Return<Status> on(uint32_t timeoutMs) override;
+ Return<Status> off() override;
+ Return<bool> supportsAmplitudeControl() override;
+ Return<Status> setAmplitude(uint8_t amplitude) override;
+
+ // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
+ Return<bool> supportsExternalControl() override;
+ Return<Status> setExternalControl(bool enabled) override;
+
+ using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
+ Return<void> perform(V1_0::Effect effect, EffectStrength strength,
+ perform_cb _hidl_cb) override;
+ Return<void> perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
+ perform_cb _hidl_cb) override;
+ Return<void> perform_1_2(V1_2::Effect effect, EffectStrength strength,
+ perform_cb _hidl_cb) override;
+ Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+
+ // Methods from ::android.hidl.base::V1_0::IBase follow.
+ Return<void> debug(const hidl_handle &handle, const hidl_vec<hidl_string> &options) override;
+
+ private:
+ Return<Status> on(uint32_t timeoutMs, const char mode[],
+ const std::unique_ptr<VibrationConfig> &config, const int8_t volOffset);
+ template <typename T>
+ Return<void> performWrapper(T effect, EffectStrength strength, perform_cb _hidl_cb);
+ Return<void> performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
+ std::unique_ptr<HwApi> mHwApi;
+ std::unique_ptr<HwCal> mHwCal;
+ uint32_t mCloseLoopThreshold;
+ std::unique_ptr<VibrationConfig> mSteadyConfig;
+ std::unique_ptr<VibrationConfig> mEffectConfig;
+ uint32_t mClickDuration;
+ uint32_t mTickDuration;
+ uint32_t mDoubleClickDuration;
+ uint32_t mHeavyClickDuration;
+ std::array<uint32_t, 5> mEffectTargetOdClamp;
+ uint32_t mSteadyTargetOdClamp;
+};
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
diff --git a/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.rc b/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.rc
new file mode 100644
index 0000000..02d6ea4
--- /dev/null
+++ b/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.rc
@@ -0,0 +1,15 @@
+service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.redfin
+ class hal
+ user system
+ group system
+
+ setenv PROPERTY_PREFIX ro.vibrator.hal.
+ setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/drv2624.cal
+
+ setenv HWAPI_PATH_PREFIX /sys/class/leds/vibrator/
+ setenv HWAPI_DEBUG_PATHS "
+ device/autocal
+ device/lp_trigger_effect
+ device/ol_lra_period
+ state
+ "
diff --git a/vibrator/android.hardware.vibrator@1.3-service.redfin.xml b/vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.xml
similarity index 100%
rename from vibrator/android.hardware.vibrator@1.3-service.redfin.xml
rename to vibrator/drv2624/android.hardware.vibrator@1.3-service.redfin.xml
diff --git a/vibrator/drv2624/bench/Android.bp b/vibrator/drv2624/bench/Android.bp
new file mode 100644
index 0000000..d7b63ef
--- /dev/null
+++ b/vibrator/drv2624/bench/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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.
+
+cc_benchmark {
+ name: "VibratorHalDrv2624BenchmarkRedfin",
+ defaults: ["VibratorHalDrv2624TestDefaultsRedfin"],
+ srcs: [
+ "benchmark.cpp",
+ ],
+ static_libs: [
+ "libc++fs",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ // TODO(b/135767253): Remove when fixed.
+ test_suites: ["device-tests"],
+ // TODO(b/142024316): Remove when fixed.
+ require_root: true,
+}
diff --git a/vibrator/drv2624/bench/benchmark.cpp b/vibrator/drv2624/bench/benchmark.cpp
new file mode 100644
index 0000000..e63da43
--- /dev/null
+++ b/vibrator/drv2624/bench/benchmark.cpp
@@ -0,0 +1,203 @@
+/* * 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 "benchmark/benchmark.h"
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <cutils/fs.h>
+
+#include "Hardware.h"
+#include "Vibrator.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::base::SetProperty;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_0::Status;
+
+class VibratorBench : public benchmark::Fixture {
+ private:
+ static constexpr const char *FILE_NAMES[]{
+ "device/autocal",
+ "device/ol_lra_period",
+ "activate",
+ "duration",
+ "state",
+ "device/rtp_input",
+ "device/mode",
+ "device/set_sequencer",
+ "device/scale",
+ "device/ctrl_loop",
+ "device/lp_trigger_effect",
+ "device/lra_wave_shape",
+ "device/od_clamp",
+ };
+ static constexpr char PROPERTY_PREFIX[] = "test.vibrator.hal.";
+
+ public:
+ void SetUp(::benchmark::State &state) override {
+ auto prefix = std::filesystem::path(mFilesDir.path) / "";
+
+ setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
+
+ for (auto n : FILE_NAMES) {
+ const auto name = std::filesystem::path(n);
+ const auto path = std::filesystem::path(mFilesDir.path) / name;
+
+ fs_mkdirs(path.c_str(), S_IRWXU);
+ symlink("/dev/null", path.c_str());
+ }
+
+ setenv("PROPERTY_PREFIX", PROPERTY_PREFIX, true);
+
+ SetProperty(std::string() + PROPERTY_PREFIX + "config.dynamic", getDynamicConfig(state));
+
+ mVibrator = new Vibrator(HwApi::Create(), std::make_unique<HwCal>());
+ }
+
+ static void DefaultConfig(benchmark::internal::Benchmark *b) {
+ b->Unit(benchmark::kMicrosecond);
+ }
+
+ static void DefaultArgs(benchmark::internal::Benchmark *b) {
+ b->ArgNames({"DynamicConfig"});
+ b->Args({false});
+ b->Args({true});
+ }
+
+ protected:
+ std::string getDynamicConfig(const ::benchmark::State &state) const {
+ return std::to_string(state.range(0));
+ }
+
+ auto getOtherArg(const ::benchmark::State &state, std::size_t index) const {
+ return state.range(index + 1);
+ }
+
+ protected:
+ TemporaryDir mFilesDir;
+ sp<IVibrator> mVibrator;
+};
+
+#define BENCHMARK_WRAPPER(fixt, test, code) \
+ BENCHMARK_DEFINE_F(fixt, test) \
+ /* NOLINTNEXTLINE */ \
+ (benchmark::State & state){code} BENCHMARK_REGISTER_F(fixt, test) \
+ ->Apply(fixt::DefaultConfig) \
+ ->Apply(fixt::DefaultArgs)
+
+BENCHMARK_WRAPPER(VibratorBench, on, {
+ uint32_t duration = std::rand() ?: 1;
+
+ for (auto _ : state) {
+ mVibrator->on(duration);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, off, {
+ for (auto _ : state) {
+ mVibrator->off();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, supportsAmplitudeControl, {
+ for (auto _ : state) {
+ mVibrator->supportsAmplitudeControl();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, setAmplitude, {
+ uint8_t amplitude = std::rand() ?: 1;
+
+ for (auto _ : state) {
+ mVibrator->setAmplitude(amplitude);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, supportsExternalControl, {
+ for (auto _ : state) {
+ mVibrator->supportsExternalControl();
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, setExternalControl_enable, {
+ for (auto _ : state) {
+ mVibrator->setExternalControl(true);
+ }
+});
+
+BENCHMARK_WRAPPER(VibratorBench, setExternalControl_disable, {
+ for (auto _ : state) {
+ mVibrator->setExternalControl(false);
+ }
+});
+
+class VibratorEffectsBench : public VibratorBench {
+ public:
+ static void DefaultArgs(benchmark::internal::Benchmark *b) {
+ b->ArgNames({"DynamicConfig", "Effect", "Strength"});
+ for (const auto &dynamic : {false, true}) {
+ for (const auto &effect : hidl_enum_range<Effect>()) {
+ for (const auto &strength : hidl_enum_range<EffectStrength>()) {
+ b->Args({dynamic, static_cast<long>(effect), static_cast<long>(strength)});
+ }
+ }
+ }
+ }
+
+ protected:
+ auto getEffect(const ::benchmark::State &state) const {
+ return static_cast<Effect>(getOtherArg(state, 0));
+ }
+
+ auto getStrength(const ::benchmark::State &state) const {
+ return static_cast<EffectStrength>(getOtherArg(state, 1));
+ }
+};
+
+BENCHMARK_WRAPPER(VibratorEffectsBench, perform_1_3, {
+ Effect effect = getEffect(state);
+ EffectStrength strength = getStrength(state);
+ bool supported = true;
+
+ mVibrator->perform_1_3(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
+ if (status == Status::UNSUPPORTED_OPERATION) {
+ supported = false;
+ }
+ });
+
+ if (!supported) {
+ return;
+ }
+
+ for (auto _ : state) {
+ mVibrator->perform_1_3(effect, strength, [](Status /*status*/, uint32_t /*lengthMs*/) {});
+ }
+});
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+
+BENCHMARK_MAIN();
diff --git a/vibrator/drv2624/drv2624.bin b/vibrator/drv2624/drv2624.bin
new file mode 100644
index 0000000..e6f896d
--- /dev/null
+++ b/vibrator/drv2624/drv2624.bin
Binary files differ
diff --git a/vibrator/service.cpp b/vibrator/drv2624/service.cpp
similarity index 80%
rename from vibrator/service.cpp
rename to vibrator/drv2624/service.cpp
index 32eec89..c0447a7 100644
--- a/vibrator/service.cpp
+++ b/vibrator/drv2624/service.cpp
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.vibrator@1.3-service.redfin"
+#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/Errors.h>
@@ -23,15 +23,24 @@
#include "Hardware.h"
#include "Vibrator.h"
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::UNKNOWN_ERROR;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::vibrator::V1_3::implementation::HwApi;
using android::hardware::vibrator::V1_3::implementation::HwCal;
using android::hardware::vibrator::V1_3::implementation::Vibrator;
-using namespace android;
status_t registerVibratorService() {
- sp<Vibrator> vibrator = new Vibrator(std::make_unique<HwApi>(), std::make_unique<HwCal>());
+ auto hwapi = HwApi::Create();
+
+ if (!hwapi) {
+ return UNKNOWN_ERROR;
+ }
+
+ sp<Vibrator> vibrator = new Vibrator(std::move(hwapi), std::make_unique<HwCal>());
return vibrator->registerAsService();
}
diff --git a/vibrator/drv2624/tests/Android.bp b/vibrator/drv2624/tests/Android.bp
new file mode 100644
index 0000000..2adfc84
--- /dev/null
+++ b/vibrator/drv2624/tests/Android.bp
@@ -0,0 +1,31 @@
+//
+// 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.
+
+cc_test {
+ name: "VibratorHalDrv2624TestSuiteRedfin",
+ defaults: ["VibratorHalDrv2624TestDefaultsRedfin"],
+ srcs: [
+ "test-hwapi.cpp",
+ "test-hwcal.cpp",
+ "test-vibrator.cpp",
+ ],
+ static_libs: [
+ "libc++fs",
+ "libgmock",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+}
diff --git a/vibrator/drv2624/tests/mocks.h b/vibrator/drv2624/tests/mocks.h
new file mode 100644
index 0000000..d4867df
--- /dev/null
+++ b/vibrator/drv2624/tests/mocks.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
+#define ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
+
+#include "Vibrator.h"
+
+class MockApi : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwApi {
+ public:
+ MOCK_METHOD0(destructor, void());
+ MOCK_METHOD1(setAutocal, bool(std::string value));
+ MOCK_METHOD1(setOlLraPeriod, bool(uint32_t value));
+ MOCK_METHOD1(setActivate, bool(bool value));
+ MOCK_METHOD1(setDuration, bool(uint32_t value));
+ MOCK_METHOD1(setState, bool(bool value));
+ MOCK_METHOD0(hasRtpInput, bool());
+ MOCK_METHOD1(setRtpInput, bool(int8_t value));
+ MOCK_METHOD1(setMode, bool(std::string value));
+ MOCK_METHOD1(setSequencer, bool(std::string value));
+ MOCK_METHOD1(setScale, bool(uint8_t value));
+ MOCK_METHOD1(setCtrlLoop, bool(bool value));
+ MOCK_METHOD1(setLpTriggerEffect, bool(uint32_t value));
+ MOCK_METHOD1(setLraWaveShape, bool(uint32_t value));
+ MOCK_METHOD1(setOdClamp, bool(uint32_t value));
+ MOCK_METHOD1(debug, void(int fd));
+
+ ~MockApi() override { destructor(); };
+};
+
+class MockCal : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwCal {
+ public:
+ MOCK_METHOD0(destructor, void());
+ MOCK_METHOD1(getAutocal, bool(std::string &value)); // NOLINT
+ MOCK_METHOD1(getLraPeriod, bool(uint32_t *value));
+ MOCK_METHOD1(getEffectCoeffs, bool(std::array<float, 4> *value));
+ MOCK_METHOD1(getSteadyAmpMax, bool(float *value));
+ MOCK_METHOD1(getCloseLoopThreshold, bool(uint32_t *value));
+ MOCK_METHOD1(getDynamicConfig, bool(bool *value));
+ MOCK_METHOD1(getLongFrequencyShift, bool(uint32_t *value));
+ MOCK_METHOD1(getShortVoltageMax, bool(uint32_t *value));
+ MOCK_METHOD1(getLongVoltageMax, bool(uint32_t *value));
+ MOCK_METHOD1(getClickDuration, bool(uint32_t *value));
+ MOCK_METHOD1(getTickDuration, bool(uint32_t *value));
+ MOCK_METHOD1(getDoubleClickDuration, bool(uint32_t *value));
+ MOCK_METHOD1(getHeavyClickDuration, bool(uint32_t *value));
+ MOCK_METHOD1(getEffectShape, bool(uint32_t *value));
+ MOCK_METHOD1(getSteadyShape, bool(uint32_t *value));
+ MOCK_METHOD1(debug, void(int fd));
+
+ ~MockCal() override { destructor(); };
+ // b/132668253: Workaround gMock Compilation Issue
+ bool getAutocal(std::string *value) { return getAutocal(*value); }
+};
+
+#endif // ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
diff --git a/vibrator/drv2624/tests/test-hwapi.cpp b/vibrator/drv2624/tests/test-hwapi.cpp
new file mode 100644
index 0000000..fc57f85
--- /dev/null
+++ b/vibrator/drv2624/tests/test-hwapi.cpp
@@ -0,0 +1,401 @@
+/*
+ * 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 <android-base/file.h>
+#include <cutils/fs.h>
+#include <gtest/gtest.h>
+
+#include <cstdlib>
+#include <fstream>
+
+#include "Hardware.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::testing::Test;
+using ::testing::TestParamInfo;
+using ::testing::ValuesIn;
+using ::testing::WithParamInterface;
+
+class HwApiTest : public Test {
+ protected:
+ static constexpr const char *FILE_NAMES[]{
+ "device/autocal",
+ "device/ol_lra_period",
+ "activate",
+ "duration",
+ "state",
+ "device/rtp_input",
+ "device/mode",
+ "device/set_sequencer",
+ "device/scale",
+ "device/ctrl_loop",
+ "device/lp_trigger_effect",
+ "device/lra_wave_shape",
+ "device/od_clamp",
+ };
+
+ static constexpr const char *REQUIRED[]{
+ "activate",
+ "duration",
+ "state",
+ };
+
+ 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 = HwApi::Create();
+
+ for (auto n : REQUIRED) {
+ auto name = std::filesystem::path(n);
+ auto path = std::filesystem::path(mEmptyDir.path) / name;
+ fs_mkdirs(path.c_str(), S_IRWXU);
+ std::ofstream touch{path};
+ }
+ prefix = std::filesystem::path(mEmptyDir.path) / "";
+ setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
+ mNoApi = HwApi::Create();
+ }
+
+ void TearDown() override { verifyContents(); }
+
+ protected:
+ // Set expected file content for a test.
+ template <typename T>
+ void expectContent(const std::string &name, const T &value) {
+ mExpectedContent[name] << value << std::endl;
+ }
+
+ // Set actual file content for an input test.
+ template <typename T>
+ void updateContent(const std::string &name, const T &value) {
+ std::ofstream(mFileMap[name]) << value << std::endl;
+ }
+
+ template <typename T>
+ 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<char>(file),
+ std::istreambuf_iterator<char>());
+ EXPECT_EQ(expect, actual) << a.first;
+ }
+ }
+
+ // TODO(eliptus): Determine how to induce errors in required files
+ static bool isRequired(const std::string &name) {
+ for (auto n : REQUIRED) {
+ if (std::string(n) == name) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static auto ParamNameFixup(std::string str) {
+ std::replace(str.begin(), str.end(), '/', '_');
+ return str;
+ }
+
+ protected:
+ std::unique_ptr<Vibrator::HwApi> mHwApi;
+ std::unique_ptr<Vibrator::HwApi> mNoApi;
+ std::map<std::string, std::string> mFileMap;
+ TemporaryDir mFilesDir;
+ TemporaryDir mEmptyDir;
+ std::map<std::string, std::stringstream> mExpectedContent;
+};
+
+class CreateTest : public HwApiTest, public WithParamInterface<const char *> {
+ public:
+ void SetUp() override{};
+ void TearDown() override{};
+
+ static auto PrintParam(const TestParamInfo<CreateTest::ParamType> &info) {
+ return ParamNameFixup(info.param);
+ }
+ static auto &AllParams() { return FILE_NAMES; }
+};
+
+TEST_P(CreateTest, file_missing) {
+ auto skip = std::string(GetParam());
+ TemporaryDir dir;
+ std::unique_ptr<HwApi> hwapi;
+ std::string prefix;
+
+ for (auto n : FILE_NAMES) {
+ auto name = std::string(n);
+ auto path = std::string(dir.path) + "/" + name;
+ if (name == skip) {
+ continue;
+ }
+ fs_mkdirs(path.c_str(), S_IRWXU);
+ std::ofstream touch{path};
+ }
+
+ prefix = std::filesystem::path(dir.path) / "";
+ setenv("HWAPI_PATH_PREFIX", prefix.c_str(), true);
+ hwapi = HwApi::Create();
+ if (isRequired(skip)) {
+ EXPECT_EQ(nullptr, hwapi);
+ } else {
+ EXPECT_NE(nullptr, hwapi);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, CreateTest, ValuesIn(CreateTest::AllParams()),
+ CreateTest::PrintParam);
+
+template <typename T>
+class HwApiTypedTest : public HwApiTest,
+ public WithParamInterface<std::tuple<std::string, std::function<T>>> {
+ public:
+ static auto PrintParam(const TestParamInfo<typename HwApiTypedTest::ParamType> &info) {
+ return ParamNameFixup(std::get<0>(info.param));
+ }
+ static auto MakeParam(std::string name, std::function<T> func) {
+ return std::make_tuple(name, func);
+ }
+};
+
+using HasTest = HwApiTypedTest<bool(Vibrator::HwApi &)>;
+
+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("device/rtp_input", &Vibrator::HwApi::hasRtpInput),
+ }),
+ HasTest::PrintParam);
+
+using SetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool)>;
+
+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 name = std::get<0>(param);
+ auto func = std::get<1>(param);
+
+ if (isRequired(name)) {
+ GTEST_SKIP();
+ }
+
+ EXPECT_FALSE(func(*mNoApi, true));
+ EXPECT_FALSE(func(*mNoApi, false));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetBoolTest,
+ ValuesIn({
+ SetBoolTest::MakeParam("activate", &Vibrator::HwApi::setActivate),
+ SetBoolTest::MakeParam("state", &Vibrator::HwApi::setState),
+ SetBoolTest::MakeParam("device/ctrl_loop",
+ &Vibrator::HwApi::setCtrlLoop),
+ }),
+ SetBoolTest::PrintParam);
+
+using SetInt8Test = HwApiTypedTest<bool(Vibrator::HwApi &, int8_t)>;
+
+TEST_P(SetInt8Test, success) {
+ auto param = GetParam();
+ auto name = std::get<0>(param);
+ auto func = std::get<1>(param);
+ int8_t value = std::rand();
+
+ expectContent(name, +value);
+
+ EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetInt8Test, failure) {
+ auto param = GetParam();
+ auto name = std::get<0>(param);
+ auto func = std::get<1>(param);
+ int8_t value = std::rand();
+
+ if (isRequired(name)) {
+ GTEST_SKIP();
+ }
+
+ EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetInt8Test,
+ ValuesIn({
+ SetInt8Test::MakeParam("device/rtp_input",
+ &Vibrator::HwApi::setRtpInput),
+ }),
+ SetInt8Test::PrintParam);
+
+using SetUint8Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint8_t)>;
+
+TEST_P(SetUint8Test, success) {
+ auto param = GetParam();
+ auto name = std::get<0>(param);
+ auto func = std::get<1>(param);
+ uint8_t value = std::rand();
+
+ expectContent(name, +value);
+
+ EXPECT_TRUE(func(*mHwApi, value));
+}
+
+TEST_P(SetUint8Test, failure) {
+ auto param = GetParam();
+ auto name = std::get<0>(param);
+ auto func = std::get<1>(param);
+ uint8_t value = std::rand();
+
+ if (isRequired(name)) {
+ GTEST_SKIP();
+ }
+
+ EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(HwApiTests, SetUint8Test,
+ ValuesIn({
+ SetUint8Test::MakeParam("device/scale", &Vibrator::HwApi::setScale),
+ }),
+ SetUint8Test::PrintParam);
+
+using SetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t)>;
+
+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 name = std::get<0>(param);
+ auto func = std::get<1>(param);
+ uint32_t value = std::rand();
+
+ if (isRequired(name)) {
+ GTEST_SKIP();
+ }
+
+ EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ HwApiTests, SetUint32Test,
+ ValuesIn({
+ SetUint32Test::MakeParam("device/ol_lra_period", &Vibrator::HwApi::setOlLraPeriod),
+ SetUint32Test::MakeParam("duration", &Vibrator::HwApi::setDuration),
+ SetUint32Test::MakeParam("device/lp_trigger_effect", &Vibrator::HwApi::setLpTriggerEffect),
+ SetUint32Test::MakeParam("device/lra_wave_shape", &Vibrator::HwApi::setLraWaveShape),
+ SetUint32Test::MakeParam("device/od_clamp", &Vibrator::HwApi::setOdClamp),
+ }),
+ SetUint32Test::PrintParam);
+
+using SetStringTest = HwApiTypedTest<bool(Vibrator::HwApi &, std::string)>;
+
+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 name = std::get<0>(param);
+ auto func = std::get<1>(param);
+ std::string value = TemporaryFile().path;
+
+ if (isRequired(name)) {
+ GTEST_SKIP();
+ }
+
+ EXPECT_FALSE(func(*mNoApi, value));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ HwApiTests, SetStringTest,
+ ValuesIn({
+ SetStringTest::MakeParam("device/autocal", &Vibrator::HwApi::setAutocal),
+ SetStringTest::MakeParam("device/mode", &Vibrator::HwApi::setMode),
+ SetStringTest::MakeParam("device/set_sequencer", &Vibrator::HwApi::setSequencer),
+ }),
+ SetStringTest::PrintParam);
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
diff --git a/vibrator/drv2624/tests/test-hwcal.cpp b/vibrator/drv2624/tests/test-hwcal.cpp
new file mode 100644
index 0000000..b95f943
--- /dev/null
+++ b/vibrator/drv2624/tests/test-hwcal.cpp
@@ -0,0 +1,396 @@
+/*
+ * 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 <android-base/file.h>
+#include <android-base/properties.h>
+#include <gtest/gtest.h>
+
+#include <fstream>
+
+#include "Hardware.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::base::SetProperty;
+using ::android::base::WaitForProperty;
+
+using ::testing::Test;
+
+class HwCalTest : public Test {
+ protected:
+ static constexpr char PROPERTY_PREFIX[] = "test.vibrator.hal.";
+
+ static constexpr uint32_t DEFAULT_LRA_PERIOD = 262;
+
+ static constexpr uint32_t DEFAULT_FREQUENCY_SHIFT = 10;
+ static constexpr uint32_t DEFAULT_VOLTAGE_MAX = 107;
+
+ static constexpr uint32_t DEFAULT_CLICK_DURATION_MS = 6;
+ static constexpr uint32_t DEFAULT_TICK_DURATION_MS = 2;
+ static constexpr uint32_t DEFAULT_DOUBLE_CLICK_DURATION_MS = 135;
+ static constexpr uint32_t DEFAULT_HEAVY_CLICK_DURATION_MS = 8;
+
+ public:
+ void SetUp() override {
+ setenv("PROPERTY_PREFIX", PROPERTY_PREFIX, true);
+ setenv("CALIBRATION_FILEPATH", mCalFile.path, true);
+ }
+
+ private:
+ template <typename T>
+ static void pack(std::ostream &stream, const T &value, std::string lpad, std::string rpad) {
+ stream << lpad << value << rpad;
+ }
+
+ protected:
+ void createHwCal() { mHwCal = std::make_unique<HwCal>(); }
+
+ template <typename T>
+ 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<Vibrator::HwCal> mHwCal;
+ TemporaryFile mCalFile;
+};
+
+TEST_F(HwCalTest, closeloop_present) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "closeloop.threshold", std::to_string(expect)));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getCloseLoopThreshold(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, closeloop_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = UINT32_MAX;
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "closeloop.threshold", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getCloseLoopThreshold(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, dynamicconfig_presentFalse) {
+ std::string prefix{PROPERTY_PREFIX};
+ bool expect = false;
+ bool actual = !expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "config.dynamic", "0"));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getDynamicConfig(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, dynamicconfig_presentTrue) {
+ std::string prefix{PROPERTY_PREFIX};
+ bool expect = true;
+ bool actual = !expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "config.dynamic", "1"));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getDynamicConfig(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, dynamicconfig_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ bool expect = false;
+ bool actual = !expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "config.dynamic", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getDynamicConfig(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, freqshift_present) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "long.frequency.shift", std::to_string(expect)));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getLongFrequencyShift(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, freqshift_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = DEFAULT_FREQUENCY_SHIFT;
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "long.frequency.shift", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getLongFrequencyShift(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, shortvolt_present) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "short.voltage", std::to_string(expect)));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getShortVoltageMax(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, shortvolt_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = DEFAULT_VOLTAGE_MAX;
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "short.voltage", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getShortVoltageMax(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, longvolt_present) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "long.voltage", std::to_string(expect)));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getLongVoltageMax(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, longvolt_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = DEFAULT_VOLTAGE_MAX;
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "long.voltage", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getLongVoltageMax(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, click_present) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "click.duration", std::to_string(expect)));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getClickDuration(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, click_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = DEFAULT_CLICK_DURATION_MS;
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "click.duration", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getClickDuration(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, tick_present) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "tick.duration", std::to_string(expect)));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getTickDuration(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, tick_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = DEFAULT_TICK_DURATION_MS;
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "tick.duration", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getTickDuration(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, doubleclick) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = DEFAULT_DOUBLE_CLICK_DURATION_MS;
+ uint32_t actual = ~expect;
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getDoubleClickDuration(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, heavyclick_present) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "heavyclick.duration", std::to_string(expect)));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getHeavyClickDuration(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, heavyclick_missing) {
+ std::string prefix{PROPERTY_PREFIX};
+ uint32_t expect = DEFAULT_HEAVY_CLICK_DURATION_MS;
+ uint32_t actual = ~expect;
+
+ EXPECT_TRUE(SetProperty(prefix + "heavyclick.duration", std::string()));
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getHeavyClickDuration(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, autocal_present) {
+ std::string expect = std::to_string(std::rand()) + " " + std::to_string(std::rand()) + " " +
+ std::to_string(std::rand());
+ std::string actual = "";
+
+ write("autocal", expect);
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getAutocal(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, autocal_missing) {
+ std::string actual;
+
+ createHwCal();
+
+ EXPECT_FALSE(mHwCal->getAutocal(&actual));
+}
+
+TEST_F(HwCalTest, lra_period_present) {
+ uint32_t expect = std::rand();
+ uint32_t actual = ~expect;
+
+ write("lra_period", expect);
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getLraPeriod(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, lra_period_missing) {
+ uint32_t expect = DEFAULT_LRA_PERIOD;
+ uint32_t actual = ~expect;
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getLraPeriod(&actual));
+ EXPECT_EQ(expect, actual);
+}
+
+TEST_F(HwCalTest, multiple) {
+ std::string autocalExpect = std::to_string(std::rand()) + " " + std::to_string(std::rand()) +
+ " " + std::to_string(std::rand());
+ std::string autocalActual = "";
+ uint32_t lraPeriodExpect = std::rand();
+ uint32_t lraPeriodActual = ~lraPeriodExpect;
+
+ write("autocal", autocalExpect);
+ write("lra_period", lraPeriodExpect);
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getAutocal(&autocalActual));
+ EXPECT_EQ(autocalExpect, autocalActual);
+ EXPECT_TRUE(mHwCal->getLraPeriod(&lraPeriodActual));
+ EXPECT_EQ(lraPeriodExpect, lraPeriodActual);
+}
+
+TEST_F(HwCalTest, trimming) {
+ std::string autocalExpect = std::to_string(std::rand()) + " " + std::to_string(std::rand()) +
+ " " + std::to_string(std::rand());
+ std::string autocalActual = "";
+ uint32_t lraPeriodExpect = std::rand();
+ uint32_t lraPeriodActual = ~lraPeriodExpect;
+
+ write("autocal", autocalExpect, " \t", "\t ");
+ write("lra_period", lraPeriodExpect, " \t", "\t ");
+
+ createHwCal();
+
+ EXPECT_TRUE(mHwCal->getAutocal(&autocalActual));
+ EXPECT_EQ(autocalExpect, autocalActual);
+ EXPECT_TRUE(mHwCal->getLraPeriod(&lraPeriodActual));
+ EXPECT_EQ(lraPeriodExpect, lraPeriodActual);
+}
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
diff --git a/vibrator/drv2624/tests/test-vibrator.cpp b/vibrator/drv2624/tests/test-vibrator.cpp
new file mode 100644
index 0000000..47bdfad
--- /dev/null
+++ b/vibrator/drv2624/tests/test-vibrator.cpp
@@ -0,0 +1,449 @@
+/*
+ * 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 <android-base/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "Vibrator.h"
+#include "mocks.h"
+#include "types.h"
+#include "utils.h"
+
+namespace android {
+namespace hardware {
+namespace vibrator {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_0::Status;
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::AnyOf;
+using ::testing::Assign;
+using ::testing::Combine;
+using ::testing::DoAll;
+using ::testing::DoDefault;
+using ::testing::Exactly;
+using ::testing::ExpectationSet;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::Sequence;
+using ::testing::SetArgPointee;
+using ::testing::SetArgReferee;
+using ::testing::Test;
+using ::testing::TestParamInfo;
+using ::testing::ValuesIn;
+using ::testing::WithParamInterface;
+
+// Constants With Prescribed Values
+
+static const std::map<EffectTuple, EffectSequence> EFFECT_SEQUENCES{
+ {{Effect::CLICK, EffectStrength::LIGHT}, {"1 0", 2}},
+ {{Effect::CLICK, EffectStrength::MEDIUM}, {"1 0", 0}},
+ {{Effect::CLICK, EffectStrength::STRONG}, {"1 0", 0}},
+ {{Effect::TICK, EffectStrength::LIGHT}, {"2 0", 2}},
+ {{Effect::TICK, EffectStrength::MEDIUM}, {"2 0", 0}},
+ {{Effect::TICK, EffectStrength::STRONG}, {"2 0", 0}},
+ {{Effect::DOUBLE_CLICK, EffectStrength::LIGHT}, {"3 0", 2}},
+ {{Effect::DOUBLE_CLICK, EffectStrength::MEDIUM}, {"3 0", 0}},
+ {{Effect::DOUBLE_CLICK, EffectStrength::STRONG}, {"3 0", 0}},
+ {{Effect::HEAVY_CLICK, EffectStrength::LIGHT}, {"4 0", 2}},
+ {{Effect::HEAVY_CLICK, EffectStrength::MEDIUM}, {"4 0", 0}},
+ {{Effect::HEAVY_CLICK, EffectStrength::STRONG}, {"4 0", 0}},
+ {{Effect::TEXTURE_TICK, EffectStrength::LIGHT}, {"2 0", 2}},
+ {{Effect::TEXTURE_TICK, EffectStrength::MEDIUM}, {"2 0", 0}},
+ {{Effect::TEXTURE_TICK, EffectStrength::STRONG}, {"2 0", 0}},
+};
+
+static uint32_t freqPeriodFormula(uint32_t in) {
+ return 1000000000 / (24615 * in);
+}
+
+template <typename... T>
+class VibratorTestTemplate : public Test, public WithParamInterface<std::tuple<bool, T...>> {
+ public:
+ static auto GetDynamicConfig(typename VibratorTestTemplate::ParamType param) {
+ return std::get<0>(param);
+ }
+ template <std::size_t I>
+ static auto GetOtherParam(typename VibratorTestTemplate::ParamType param) {
+ return std::get<I + 1>(param);
+ }
+
+ static auto PrintParam(const TestParamInfo<typename VibratorTestTemplate::ParamType> &info) {
+ auto dynamic = GetDynamicConfig(info.param);
+ return std::string() + (dynamic ? "Dynamic" : "Static") + "Config";
+ }
+
+ static auto MakeParam(bool dynamicConfig, T... others) {
+ return std::make_tuple(dynamicConfig, others...);
+ }
+
+ void SetUp() override {
+ std::unique_ptr<MockApi> mockapi;
+ std::unique_ptr<MockCal> mockcal;
+
+ mCloseLoopThreshold = std::rand();
+ // ensure close-loop test is possible
+ if (mCloseLoopThreshold == UINT32_MAX) {
+ mCloseLoopThreshold--;
+ }
+
+ mShortLraPeriod = std::rand();
+ if (getDynamicConfig()) {
+ mLongFrequencyShift = std::rand();
+ mLongLraPeriod =
+ freqPeriodFormula(freqPeriodFormula(mShortLraPeriod) - mLongFrequencyShift);
+ mShortVoltageMax = std::rand();
+ mLongVoltageMax = std::rand();
+ }
+
+ mEffectDurations[Effect::CLICK] = std::rand();
+ mEffectDurations[Effect::TICK] = std::rand();
+ mEffectDurations[Effect::DOUBLE_CLICK] = std::rand();
+ mEffectDurations[Effect::HEAVY_CLICK] = std::rand();
+ mEffectDurations[Effect::TEXTURE_TICK] = mEffectDurations[Effect::TICK];
+
+ createMock(&mockapi, &mockcal);
+ createVibrator(std::move(mockapi), std::move(mockcal));
+ }
+
+ void TearDown() override { deleteVibrator(); }
+
+ protected:
+ auto getDynamicConfig() const { return GetDynamicConfig(VibratorTestTemplate::GetParam()); }
+
+ void createMock(std::unique_ptr<MockApi> *mockapi, std::unique_ptr<MockCal> *mockcal) {
+ *mockapi = std::make_unique<MockApi>();
+ *mockcal = std::make_unique<MockCal>();
+
+ mMockApi = mockapi->get();
+ mMockCal = mockcal->get();
+
+ ON_CALL(*mMockApi, destructor()).WillByDefault(Assign(&mMockApi, nullptr));
+ ON_CALL(*mMockApi, setOlLraPeriod(_)).WillByDefault(Return(true));
+ ON_CALL(*mMockApi, setActivate(_)).WillByDefault(Return(true));
+ ON_CALL(*mMockApi, setDuration(_)).WillByDefault(Return(true));
+ ON_CALL(*mMockApi, setMode(_)).WillByDefault(Return(true));
+ ON_CALL(*mMockApi, setCtrlLoop(_)).WillByDefault(Return(true));
+ ON_CALL(*mMockApi, setLraWaveShape(_)).WillByDefault(Return(true));
+ ON_CALL(*mMockApi, setOdClamp(_)).WillByDefault(Return(true));
+
+ ON_CALL(*mMockCal, destructor()).WillByDefault(Assign(&mMockCal, nullptr));
+ ON_CALL(*mMockCal, getLraPeriod(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(mShortLraPeriod), Return(true)));
+ ON_CALL(*mMockCal, getCloseLoopThreshold(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(mCloseLoopThreshold), Return(true)));
+ ON_CALL(*mMockCal, getDynamicConfig(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(getDynamicConfig()), Return(true)));
+
+ if (getDynamicConfig()) {
+ ON_CALL(*mMockCal, getLongFrequencyShift(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(mLongFrequencyShift), Return(true)));
+ ON_CALL(*mMockCal, getShortVoltageMax(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(mShortVoltageMax), Return(true)));
+ ON_CALL(*mMockCal, getLongVoltageMax(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(mLongVoltageMax), Return(true)));
+ }
+
+ ON_CALL(*mMockCal, getClickDuration(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(mEffectDurations[Effect::CLICK]), Return(true)));
+ ON_CALL(*mMockCal, getTickDuration(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(mEffectDurations[Effect::TICK]), Return(true)));
+ ON_CALL(*mMockCal, getDoubleClickDuration(_))
+ .WillByDefault(
+ DoAll(SetArgPointee<0>(mEffectDurations[Effect::DOUBLE_CLICK]), Return(true)));
+ ON_CALL(*mMockCal, getHeavyClickDuration(_))
+ .WillByDefault(
+ DoAll(SetArgPointee<0>(mEffectDurations[Effect::HEAVY_CLICK]), Return(true)));
+
+ relaxMock(false);
+ }
+
+ void createVibrator(std::unique_ptr<MockApi> mockapi, std::unique_ptr<MockCal> mockcal,
+ bool relaxed = true) {
+ if (relaxed) {
+ relaxMock(true);
+ }
+ mVibrator = new Vibrator(std::move(mockapi), std::move(mockcal));
+ if (relaxed) {
+ relaxMock(false);
+ }
+ }
+
+ void deleteVibrator(bool relaxed = true) {
+ if (relaxed) {
+ relaxMock(true);
+ }
+ mVibrator.clear();
+ }
+
+ 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, setAutocal(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setOlLraPeriod(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setActivate(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setDuration(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setState(_)).Times(times);
+ EXPECT_CALL(*mMockApi, hasRtpInput()).Times(times);
+ EXPECT_CALL(*mMockApi, setRtpInput(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setMode(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setSequencer(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setScale(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setCtrlLoop(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setLpTriggerEffect(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setLraWaveShape(_)).Times(times);
+ EXPECT_CALL(*mMockApi, setOdClamp(_)).Times(times);
+ EXPECT_CALL(*mMockApi, debug(_)).Times(times);
+
+ EXPECT_CALL(*mMockCal, destructor()).Times(times);
+ EXPECT_CALL(*mMockCal, getAutocal(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getLraPeriod(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getCloseLoopThreshold(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getDynamicConfig(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getLongFrequencyShift(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getShortVoltageMax(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getLongVoltageMax(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getClickDuration(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getTickDuration(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getDoubleClickDuration(_)).Times(times);
+ EXPECT_CALL(*mMockCal, getHeavyClickDuration(_)).Times(times);
+ EXPECT_CALL(*mMockCal, debug(_)).Times(times);
+ }
+
+ protected:
+ MockApi *mMockApi;
+ MockCal *mMockCal;
+ sp<IVibrator> mVibrator;
+
+ EffectDuration mCloseLoopThreshold;
+ uint32_t mLongFrequencyShift;
+ uint32_t mShortLraPeriod;
+ uint32_t mLongLraPeriod;
+ uint32_t mShortVoltageMax;
+ uint32_t mLongVoltageMax;
+ std::map<Effect, EffectDuration> mEffectDurations;
+};
+
+using BasicTest = VibratorTestTemplate<>;
+
+TEST_P(BasicTest, Constructor) {
+ std::unique_ptr<MockApi> mockapi;
+ std::unique_ptr<MockCal> mockcal;
+ std::string autocalVal = std::to_string(std::rand()) + " " + std::to_string(std::rand()) +
+ " " + std::to_string(std::rand());
+ Sequence autocalSeq, lraPeriodSeq;
+
+ EXPECT_CALL(*mMockApi, destructor()).WillOnce(DoDefault());
+ EXPECT_CALL(*mMockCal, destructor()).WillOnce(DoDefault());
+
+ deleteVibrator(false);
+
+ createMock(&mockapi, &mockcal);
+
+ EXPECT_CALL(*mMockApi, setState(true)).WillOnce(Return(true));
+
+ EXPECT_CALL(*mMockCal, getAutocal(_))
+ .InSequence(autocalSeq)
+ .WillOnce(DoAll(SetArgReferee<0>(autocalVal), Return(true)));
+ EXPECT_CALL(*mMockApi, setAutocal(autocalVal)).InSequence(autocalSeq).WillOnce(DoDefault());
+
+ EXPECT_CALL(*mMockCal, getLraPeriod(_)).InSequence(lraPeriodSeq).WillOnce(DoDefault());
+
+ EXPECT_CALL(*mMockCal, getCloseLoopThreshold(_)).WillOnce(DoDefault());
+ EXPECT_CALL(*mMockCal, getDynamicConfig(_)).WillOnce(DoDefault());
+
+ if (getDynamicConfig()) {
+ EXPECT_CALL(*mMockCal, getLongFrequencyShift(_)).WillOnce(DoDefault());
+ EXPECT_CALL(*mMockCal, getShortVoltageMax(_)).WillOnce(DoDefault());
+ EXPECT_CALL(*mMockCal, getLongVoltageMax(_)).WillOnce(DoDefault());
+ } else {
+ EXPECT_CALL(*mMockApi, setOlLraPeriod(mShortLraPeriod))
+ .InSequence(lraPeriodSeq)
+ .WillOnce(DoDefault());
+ }
+
+ EXPECT_CALL(*mMockCal, getClickDuration(_)).WillOnce(DoDefault());
+ EXPECT_CALL(*mMockCal, getTickDuration(_)).WillOnce(DoDefault());
+ EXPECT_CALL(*mMockCal, getDoubleClickDuration(_)).WillOnce(DoDefault());
+ EXPECT_CALL(*mMockCal, getHeavyClickDuration(_)).WillOnce(DoDefault());
+
+ EXPECT_CALL(*mMockApi, setLpTriggerEffect(1)).WillOnce(Return(true));
+
+ createVibrator(std::move(mockapi), std::move(mockcal), false);
+}
+
+TEST_P(BasicTest, on) {
+ EffectDuration duration = std::rand();
+ ExpectationSet e;
+
+ e += EXPECT_CALL(*mMockApi, setCtrlLoop(_)).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setMode("rtp")).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setDuration(duration)).WillOnce(DoDefault());
+
+ if (getDynamicConfig()) {
+ e += EXPECT_CALL(*mMockApi, setLraWaveShape(0)).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setOdClamp(mLongVoltageMax)).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setOlLraPeriod(mLongLraPeriod)).WillOnce(DoDefault());
+ }
+
+ EXPECT_CALL(*mMockApi, setActivate(true)).After(e).WillOnce(DoDefault());
+
+ EXPECT_EQ(Status::OK, mVibrator->on(duration));
+}
+
+TEST_P(BasicTest, on_openLoop) {
+ EffectDuration duration = mCloseLoopThreshold;
+
+ relaxMock(true);
+
+ EXPECT_CALL(*mMockApi, setCtrlLoop(true)).WillOnce(DoDefault());
+
+ EXPECT_EQ(Status::OK, mVibrator->on(duration));
+}
+
+TEST_P(BasicTest, on_closeLoop) {
+ EffectDuration duration = mCloseLoopThreshold + 1;
+
+ relaxMock(true);
+
+ EXPECT_CALL(*mMockApi, setCtrlLoop(false)).WillOnce(DoDefault());
+
+ EXPECT_EQ(Status::OK, mVibrator->on(duration));
+}
+
+TEST_P(BasicTest, off) {
+ EXPECT_CALL(*mMockApi, setActivate(false)).WillOnce(DoDefault());
+
+ EXPECT_EQ(Status::OK, mVibrator->off());
+}
+
+TEST_P(BasicTest, supportsAmplitudeControl_supported) {
+ EXPECT_CALL(*mMockApi, hasRtpInput()).WillOnce(Return(true));
+
+ EXPECT_EQ(true, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_P(BasicTest, supportsAmplitudeControl_unsupported) {
+ EXPECT_CALL(*mMockApi, hasRtpInput()).WillOnce(Return(false));
+
+ EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
+}
+
+TEST_P(BasicTest, setAmplitude) {
+ EffectAmplitude amplitude = std::rand();
+
+ EXPECT_CALL(*mMockApi, setRtpInput(amplitudeToRtpInput(amplitude))).WillOnce(Return(true));
+
+ EXPECT_EQ(Status::OK, mVibrator->setAmplitude(amplitude));
+}
+
+TEST_P(BasicTest, supportsExternalControl_unsupported) {
+ EXPECT_EQ(false, mVibrator->supportsExternalControl());
+}
+
+TEST_P(BasicTest, setExternalControl_enable) {
+ EXPECT_EQ(Status::UNSUPPORTED_OPERATION, mVibrator->setExternalControl(true));
+}
+
+TEST_P(BasicTest, setExternalControl_disable) {
+ EXPECT_EQ(Status::UNSUPPORTED_OPERATION, mVibrator->setExternalControl(false));
+}
+
+INSTANTIATE_TEST_CASE_P(VibratorTests, BasicTest,
+ ValuesIn({BasicTest::MakeParam(false), BasicTest::MakeParam(true)}),
+ BasicTest::PrintParam);
+
+class EffectsTest : public VibratorTestTemplate<EffectTuple> {
+ public:
+ static auto GetEffectTuple(ParamType param) { return GetOtherParam<0>(param); }
+
+ static auto PrintParam(const TestParamInfo<ParamType> &info) {
+ auto prefix = VibratorTestTemplate::PrintParam(info);
+ auto tuple = GetEffectTuple(info.param);
+ auto effect = std::get<0>(tuple);
+ auto strength = std::get<1>(tuple);
+ return prefix + "_" + toString(effect) + "_" + toString(strength);
+ }
+
+ protected:
+ auto getEffectTuple() const { return GetEffectTuple(GetParam()); }
+};
+
+TEST_P(EffectsTest, perform) {
+ auto tuple = getEffectTuple();
+ auto effect = std::get<0>(tuple);
+ auto strength = std::get<1>(tuple);
+ auto seqIter = EFFECT_SEQUENCES.find(tuple);
+ auto durIter = mEffectDurations.find(effect);
+ EffectDuration duration;
+
+ if (seqIter != EFFECT_SEQUENCES.end() && durIter != mEffectDurations.end()) {
+ auto sequence = std::get<0>(seqIter->second);
+ auto scale = std::get<1>(seqIter->second);
+ ExpectationSet e;
+
+ duration = durIter->second;
+
+ e += EXPECT_CALL(*mMockApi, setSequencer(sequence)).WillOnce(Return(true));
+ e += EXPECT_CALL(*mMockApi, setScale(scale)).WillOnce(Return(true));
+ e += EXPECT_CALL(*mMockApi, setCtrlLoop(1)).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setMode("waveform")).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setDuration(duration)).WillOnce(DoDefault());
+
+ if (getDynamicConfig()) {
+ e += EXPECT_CALL(*mMockApi, setLraWaveShape(1)).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setOdClamp(mShortVoltageMax)).WillOnce(DoDefault());
+ e += EXPECT_CALL(*mMockApi, setOlLraPeriod(mShortLraPeriod)).WillOnce(DoDefault());
+ }
+
+ EXPECT_CALL(*mMockApi, setActivate(true)).After(e).WillOnce(DoDefault());
+ } else {
+ duration = 0;
+ }
+
+ mVibrator->perform_1_3(effect, strength, [&](Status status, uint32_t lengthMs) {
+ if (duration) {
+ EXPECT_EQ(Status::OK, status);
+ EXPECT_LE(duration, lengthMs);
+ } else {
+ EXPECT_EQ(Status::UNSUPPORTED_OPERATION, status);
+ EXPECT_EQ(0, lengthMs);
+ }
+ });
+}
+
+INSTANTIATE_TEST_CASE_P(VibratorTests, EffectsTest,
+ Combine(ValuesIn({false, true}),
+ Combine(ValuesIn(hidl_enum_range<Effect>().begin(),
+ hidl_enum_range<Effect>().end()),
+ ValuesIn(hidl_enum_range<EffectStrength>().begin(),
+ hidl_enum_range<EffectStrength>().end()))),
+ EffectsTest::PrintParam);
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
diff --git a/vibrator/tests/types.h b/vibrator/drv2624/tests/types.h
similarity index 81%
rename from vibrator/tests/types.h
rename to vibrator/drv2624/tests/types.h
index 94535c2..60be69c 100644
--- a/vibrator/tests/types.h
+++ b/vibrator/drv2624/tests/types.h
@@ -18,16 +18,10 @@
#include <android/hardware/vibrator/1.3/IVibrator.h>
-using EffectIndex = uint16_t;
-using EffectLevel = uint32_t;
using EffectAmplitude = uint8_t;
-using EffectScale = uint16_t;
using EffectDuration = uint32_t;
-using EffectQueue = std::tuple<std::string, EffectDuration>;
+using EffectSequence = std::tuple<std::string, uint8_t>;
using EffectTuple = std::tuple<::android::hardware::vibrator::V1_3::Effect,
::android::hardware::vibrator::V1_0::EffectStrength>;
-using QueueEffect = std::tuple<EffectIndex, EffectLevel>;
-using QueueDelay = uint32_t;
-
#endif // ANDROID_HARDWARE_VIBRATOR_TEST_TYPES_H
diff --git a/vibrator/tests/main.cpp b/vibrator/drv2624/tests/utils.h
similarity index 66%
rename from vibrator/tests/main.cpp
rename to vibrator/drv2624/tests/utils.h
index 87b18a4..5fe4b62 100644
--- a/vibrator/tests/main.cpp
+++ b/vibrator/drv2624/tests/utils.h
@@ -13,10 +13,15 @@
* 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 <gmock/gmock.h>
+#include <cmath>
-int main(int argc, char **argv) {
- ::testing::InitGoogleMock(&argc, argv);
- return RUN_ALL_TESTS();
+#include "types.h"
+
+static inline int32_t amplitudeToRtpInput(EffectAmplitude amplitude) {
+ return std::round((amplitude - 1) / 254.0 * 127);
}
+
+#endif // ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
diff --git a/vibrator/tests/mocks.h b/vibrator/tests/mocks.h
deleted file mode 100644
index 4e0544d..0000000
--- a/vibrator/tests/mocks.h
+++ /dev/null
@@ -1,60 +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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
-#define ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
-
-#include "Vibrator.h"
-
-class MockApi : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwApi {
- public:
- MOCK_METHOD0(destructor, void());
- MOCK_METHOD1(setF0, bool(uint32_t value));
- MOCK_METHOD1(setRedc, bool(uint32_t value));
- MOCK_METHOD1(setQ, bool(uint32_t value));
- MOCK_METHOD1(setActivate, bool(bool value));
- MOCK_METHOD1(setDuration, bool(uint32_t value));
- MOCK_METHOD1(getEffectDuration, bool(uint32_t *value));
- MOCK_METHOD1(setEffectIndex, bool(uint32_t value));
- MOCK_METHOD1(setEffectQueue, bool(std::string value));
- MOCK_METHOD0(hasEffectScale, bool());
- MOCK_METHOD1(setEffectScale, bool(uint32_t value));
- MOCK_METHOD1(setGlobalScale, bool(uint32_t value));
- MOCK_METHOD1(setState, bool(bool value));
- MOCK_METHOD0(hasAspEnable, bool());
- MOCK_METHOD1(getAspEnable, bool(bool *value));
- MOCK_METHOD1(setAspEnable, bool(bool value));
- MOCK_METHOD1(setGpioFallIndex, bool(uint32_t value));
- MOCK_METHOD1(setGpioFallScale, bool(uint32_t value));
- MOCK_METHOD1(setGpioRiseIndex, bool(uint32_t value));
- MOCK_METHOD1(setGpioRiseScale, bool(uint32_t value));
- MOCK_METHOD1(debug, void(int fd));
-
- ~MockApi() override { destructor(); };
-};
-
-class MockCal : public ::android::hardware::vibrator::V1_3::implementation::Vibrator::HwCal {
- public:
- MOCK_METHOD0(destructor, void());
- MOCK_METHOD1(getF0, bool(uint32_t *value));
- MOCK_METHOD1(getRedc, bool(uint32_t *value));
- MOCK_METHOD1(getQ, bool(uint32_t *value));
- MOCK_METHOD1(getVolLevels, bool(std::array<uint32_t, 6> *value));
- MOCK_METHOD1(debug, void(int fd));
-
- ~MockCal() override { destructor(); };
-};
-
-#endif // ANDROID_HARDWARE_VIBRATOR_TEST_MOCKS_H
diff --git a/vibrator/tests/test-hwapi.cpp b/vibrator/tests/test-hwapi.cpp
deleted file mode 100644
index 87fdae2..0000000
--- a/vibrator/tests/test-hwapi.cpp
+++ /dev/null
@@ -1,322 +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.
- */
-#define LOG_TAG "android.hardware.vibrator@1.3-tests.redfin"
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#include <cstdlib>
-#include <fstream>
-
-#include "Hardware.h"
-
-using namespace ::testing;
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class HwApiTest : public Test {
- private:
- static constexpr const char *FILE_NAMES[]{
- "F0_FILEPATH", "REDC_FILEPATH", "Q_FILEPATH", "ACTIVATE_PATH",
- "DURATION_PATH", "STATE_PATH", "EFFECT_DURATION_PATH", "EFFECT_INDEX_PATH",
- "EFFECT_QUEUE_PATH", "EFFECT_SCALE_PATH", "GLOBAL_SCALE_PATH", "ASP_ENABLE_PATH",
- "GPIO_FALL_INDEX", "GPIO_FALL_SCALE", "GPIO_RISE_INDEX", "GPIO_RISE_SCALE",
- };
-
- public:
- void SetUp() override {
- for (auto n : FILE_NAMES) {
- auto name = std::string(n);
- auto path = std::string(mFilesDir.path) + "/" + name;
- std::ofstream touch{path};
- setenv(name.c_str(), path.c_str(), true);
- mFileMap[name] = path;
- }
- mHwApi = std::make_unique<HwApi>();
-
- for (auto n : FILE_NAMES) {
- auto name = std::string(n);
- auto path = std::string(mEmptyDir.path) + "/" + name;
- setenv(name.c_str(), path.c_str(), true);
- }
- mNoApi = std::make_unique<HwApi>();
- }
-
- void TearDown() override { verifyContents(); }
-
- protected:
- // Set expected file content for a test.
- template <typename T>
- void expectContent(const std::string &name, const T &value) {
- mExpectedContent[name] << value << std::endl;
- }
-
- // Set actual file content for an input test.
- template <typename T>
- void updateContent(const std::string &name, const T &value) {
- std::ofstream(mFileMap[name]) << value << std::endl;
- }
-
- template <typename T>
- 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<char>(file),
- std::istreambuf_iterator<char>());
- EXPECT_EQ(expect, actual) << a.first;
- }
- }
-
- protected:
- std::unique_ptr<Vibrator::HwApi> mHwApi;
- std::unique_ptr<Vibrator::HwApi> mNoApi;
- std::map<std::string, std::string> mFileMap;
- TemporaryDir mFilesDir;
- TemporaryDir mEmptyDir;
- std::map<std::string, std::stringstream> mExpectedContent;
-};
-
-template <typename T>
-class HwApiTypedTest
- : public HwApiTest,
- public testing::WithParamInterface<std::tuple<std::string, std::function<T>>> {
- public:
- static auto PrintParam(const testing::TestParamInfo<typename HwApiTypedTest::ParamType> &info) {
- return std::get<0>(info.param);
- };
- static auto MakeParam(std::string name, std::function<T> func) {
- return std::make_tuple(name, func);
- }
-};
-
-using HasTest = HwApiTypedTest<bool(Vibrator::HwApi &)>;
-
-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("EFFECT_SCALE_PATH",
- &Vibrator::HwApi::hasEffectScale),
- HasTest::MakeParam("ASP_ENABLE_PATH", &Vibrator::HwApi::hasAspEnable),
- }),
- HasTest::PrintParam);
-
-using GetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool *)>;
-
-TEST_P(GetBoolTest, success_returnsTrue) {
- auto param = GetParam();
- auto name = std::get<0>(param);
- auto func = std::get<1>(param);
- bool expect = true;
- bool actual = !expect;
-
- expectAndUpdateContent(name, "1");
-
- EXPECT_TRUE(func(*mHwApi, &actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_P(GetBoolTest, success_returnsFalse) {
- auto param = GetParam();
- auto name = std::get<0>(param);
- auto func = std::get<1>(param);
- bool expect = false;
- bool actual = !expect;
-
- expectAndUpdateContent(name, "0");
-
- EXPECT_TRUE(func(*mHwApi, &actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_P(GetBoolTest, failure) {
- auto param = GetParam();
- auto func = std::get<1>(param);
- bool value;
-
- EXPECT_FALSE(func(*mNoApi, &value));
-}
-
-INSTANTIATE_TEST_CASE_P(HwApiTests, GetBoolTest,
- ValuesIn({
- GetBoolTest::MakeParam("ASP_ENABLE_PATH",
- &Vibrator::HwApi::getAspEnable),
- }),
- GetBoolTest::PrintParam);
-
-using GetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t *)>;
-
-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("EFFECT_DURATION_PATH",
- &Vibrator::HwApi::getEffectDuration),
- }),
- GetUint32Test::PrintParam);
-
-using SetBoolTest = HwApiTypedTest<bool(Vibrator::HwApi &, bool)>;
-
-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("ACTIVATE_PATH", &Vibrator::HwApi::setActivate),
- SetBoolTest::MakeParam("STATE_PATH", &Vibrator::HwApi::setState),
- SetBoolTest::MakeParam("ASP_ENABLE_PATH",
- &Vibrator::HwApi::setAspEnable),
- }),
- SetBoolTest::PrintParam);
-
-using SetUint32Test = HwApiTypedTest<bool(Vibrator::HwApi &, uint32_t)>;
-
-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("F0_FILEPATH", &Vibrator::HwApi::setF0),
- SetUint32Test::MakeParam("REDC_FILEPATH", &Vibrator::HwApi::setRedc),
- SetUint32Test::MakeParam("Q_FILEPATH", &Vibrator::HwApi::setQ),
- SetUint32Test::MakeParam("DURATION_PATH", &Vibrator::HwApi::setDuration),
- SetUint32Test::MakeParam("EFFECT_INDEX_PATH", &Vibrator::HwApi::setEffectIndex),
- SetUint32Test::MakeParam("EFFECT_SCALE_PATH", &Vibrator::HwApi::setEffectScale),
- SetUint32Test::MakeParam("GLOBAL_SCALE_PATH", &Vibrator::HwApi::setGlobalScale),
- SetUint32Test::MakeParam("GPIO_FALL_INDEX", &Vibrator::HwApi::setGpioFallIndex),
- SetUint32Test::MakeParam("GPIO_FALL_SCALE", &Vibrator::HwApi::setGpioFallScale),
- SetUint32Test::MakeParam("GPIO_RISE_INDEX", &Vibrator::HwApi::setGpioRiseIndex),
- SetUint32Test::MakeParam("GPIO_RISE_SCALE", &Vibrator::HwApi::setGpioRiseScale),
- }),
- SetUint32Test::PrintParam);
-
-using SetStringTest = HwApiTypedTest<bool(Vibrator::HwApi &, std::string)>;
-
-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("EFFECT_QUEUE_PATH",
- &Vibrator::HwApi::setEffectQueue),
- }),
- SetStringTest::PrintParam);
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace vibrator
-} // namespace hardware
-} // namespace android
diff --git a/vibrator/tests/test-hwcal.cpp b/vibrator/tests/test-hwcal.cpp
deleted file mode 100644
index 42c7702..0000000
--- a/vibrator/tests/test-hwcal.cpp
+++ /dev/null
@@ -1,302 +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.
- */
-#define LOG_TAG "android.hardware.vibrator@1.3-tests.redfin"
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#include <fstream>
-
-#include "Hardware.h"
-
-using namespace ::testing;
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-class HwCalTest : public Test {
- protected:
- static constexpr uint32_t Q_DEFAULT = 15.5f * (1 << 16);
- static constexpr std::array<uint32_t, 6> V_DEFAULT = {60, 70, 80, 90, 100, 76};
-
- public:
- void SetUp() override { setenv("CALIBRATION_FILEPATH", mCalFile.path, true); }
-
- private:
- static void pack(std::ostream &stream, const uint32_t &value, std::string lpad,
- std::string rpad) {
- stream << lpad << value << rpad;
- }
-
- template <typename T, typename std::array<T, 0>::size_type N>
- static void pack(std::ostream &stream, const std::array<T, N> &value, std::string lpad,
- std::string rpad) {
- for (auto &entry : value) {
- pack(stream, entry, lpad, rpad);
- }
- }
-
- protected:
- void createHwCal() { mHwCal = std::make_unique<HwCal>(); }
-
- template <typename T>
- 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<Vibrator::HwCal> mHwCal;
- TemporaryFile mCalFile;
-};
-
-TEST_F(HwCalTest, f0_measured) {
- uint32_t expect = std::rand();
- uint32_t actual = ~expect;
-
- write("f0_measured", expect);
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getF0(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, f0_missing) {
- uint32_t actual;
-
- createHwCal();
-
- EXPECT_FALSE(mHwCal->getF0(&actual));
-}
-
-TEST_F(HwCalTest, redc_measured) {
- uint32_t expect = std::rand();
- uint32_t actual = ~expect;
-
- write("redc_measured", expect);
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getRedc(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, redc_missing) {
- uint32_t actual;
-
- createHwCal();
-
- EXPECT_FALSE(mHwCal->getRedc(&actual));
-}
-
-TEST_F(HwCalTest, q_measured) {
- uint32_t expect = std::rand();
- uint32_t actual = ~expect;
-
- write("q_measured", expect);
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getQ(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, q_index) {
- uint8_t value = std::rand();
- uint32_t expect = value * 1.5f * (1 << 16) + 2.0f * (1 << 16);
- uint32_t actual = ~expect;
-
- write("q_index", value);
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getQ(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, q_missing) {
- uint32_t expect = Q_DEFAULT;
- uint32_t actual = ~expect;
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getQ(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, q_nofile) {
- uint32_t expect = Q_DEFAULT;
- uint32_t actual = ~expect;
-
- write("q_measured", actual);
- unlink();
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getQ(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_levels) {
- std::array<uint32_t, 6> expect;
- std::array<uint32_t, 6> actual;
-
- std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) {
- e = std::rand();
- return ~e;
- });
-
- write("v_levels", expect);
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getVolLevels(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_missing) {
- std::array<uint32_t, 6> expect = V_DEFAULT;
- std::array<uint32_t, 6> actual;
-
- std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getVolLevels(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_short) {
- std::array<uint32_t, 6> expect = V_DEFAULT;
- std::array<uint32_t, 6> actual;
-
- std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
- write("v_levels", std::array<uint32_t, expect.size() - 1>());
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getVolLevels(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_long) {
- std::array<uint32_t, 6> expect = V_DEFAULT;
- std::array<uint32_t, 6> actual;
-
- std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
- write("v_levels", std::array<uint32_t, expect.size() + 1>());
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getVolLevels(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, v_nofile) {
- std::array<uint32_t, 6> expect = V_DEFAULT;
- std::array<uint32_t, 6> actual;
-
- std::transform(expect.begin(), expect.end(), actual.begin(), [](uint32_t &e) { return ~e; });
-
- write("v_levels", actual);
- unlink();
-
- createHwCal();
-
- EXPECT_TRUE(mHwCal->getVolLevels(&actual));
- EXPECT_EQ(expect, actual);
-}
-
-TEST_F(HwCalTest, multiple) {
- uint32_t f0Expect = std::rand();
- uint32_t f0Actual = ~f0Expect;
- uint32_t redcExpect = std::rand();
- uint32_t redcActual = ~redcExpect;
- uint32_t qExpect = std::rand();
- uint32_t qActual = ~qExpect;
- std::array<uint32_t, 6> volExpect;
- std::array<uint32_t, 6> volActual;
-
- std::transform(volExpect.begin(), volExpect.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_levels", volExpect);
-
- 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->getVolLevels(&volActual));
- EXPECT_EQ(volExpect, volActual);
-}
-
-TEST_F(HwCalTest, trimming) {
- uint32_t f0Expect = std::rand();
- uint32_t f0Actual = ~f0Expect;
- uint32_t redcExpect = std::rand();
- uint32_t redcActual = ~redcExpect;
- uint32_t qExpect = std::rand();
- uint32_t qActual = ~qExpect;
- std::array<uint32_t, 6> volExpect;
- std::array<uint32_t, 6> volActual;
-
- std::transform(volExpect.begin(), volExpect.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_levels", volExpect, " \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->getVolLevels(&volActual));
- EXPECT_EQ(volExpect, volActual);
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace vibrator
-} // namespace hardware
-} // namespace android
diff --git a/vibrator/tests/test-vibrator.cpp b/vibrator/tests/test-vibrator.cpp
deleted file mode 100644
index 85109eb..0000000
--- a/vibrator/tests/test-vibrator.cpp
+++ /dev/null
@@ -1,464 +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.
- */
-#define LOG_TAG "PtsVibratorHalRedfinTestSuite"
-
-#include <android-base/logging.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "Vibrator.h"
-#include "mocks.h"
-#include "types.h"
-#include "utils.h"
-
-using namespace ::testing;
-
-namespace android {
-namespace hardware {
-namespace vibrator {
-namespace V1_3 {
-namespace implementation {
-
-using ::android::hardware::vibrator::V1_0::EffectStrength;
-using ::android::hardware::vibrator::V1_0::Status;
-
-// Forward Declarations
-
-static EffectQueue Queue(const QueueEffect &effect);
-static EffectQueue Queue(const QueueDelay &delay);
-template <typename T, typename U, typename... Args>
-static EffectQueue Queue(const T &first, const U &second, Args... rest);
-
-// Constants With Arbitrary Values
-
-static constexpr std::array<EffectLevel, 6> V_LEVELS{40, 50, 60, 70, 80, 90};
-static constexpr EffectDuration EFFECT_DURATION{15};
-
-// Constants With Prescribed Values
-
-static constexpr EffectIndex EFFECT_INDEX{2};
-static constexpr EffectIndex QUEUE_INDEX{65534};
-
-static constexpr EffectIndex GPIO_FALL_INDEX{EFFECT_INDEX};
-static const EffectScale GPIO_FALL_SCALE{levelToScale(V_LEVELS[2])};
-static constexpr EffectIndex GPIO_RISE_INDEX{EFFECT_INDEX};
-static const EffectScale GPIO_RISE_SCALE{levelToScale(V_LEVELS[3])};
-
-static const EffectScale ON_GLOBAL_SCALE{levelToScale(V_LEVELS[5])};
-static const EffectIndex ON_EFFECT_INDEX{0};
-
-static const std::map<EffectTuple, EffectScale> EFFECT_SCALE{
- {{Effect::CLICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[1])},
- {{Effect::CLICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[2])},
- {{Effect::CLICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[3])},
- {{Effect::TICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[1])},
- {{Effect::TICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[1])},
- {{Effect::TICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[1])},
- {{Effect::HEAVY_CLICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[2])},
- {{Effect::HEAVY_CLICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[3])},
- {{Effect::HEAVY_CLICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[4])},
- {{Effect::TEXTURE_TICK, EffectStrength::LIGHT}, levelToScale(V_LEVELS[0])},
- {{Effect::TEXTURE_TICK, EffectStrength::MEDIUM}, levelToScale(V_LEVELS[0])},
- {{Effect::TEXTURE_TICK, EffectStrength::STRONG}, levelToScale(V_LEVELS[0])},
-};
-
-static const std::map<EffectTuple, EffectQueue> EFFECT_QUEUE{
- {{Effect::DOUBLE_CLICK, EffectStrength::LIGHT},
- Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[1]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[2]})},
- {{Effect::DOUBLE_CLICK, EffectStrength::MEDIUM},
- Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[2]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[3]})},
- {{Effect::DOUBLE_CLICK, EffectStrength::STRONG},
- Queue(QueueEffect{EFFECT_INDEX, V_LEVELS[3]}, 100, QueueEffect{EFFECT_INDEX, V_LEVELS[4]})},
-};
-
-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_DURATION;
- return {string, duration};
-}
-
-EffectQueue Queue(const QueueDelay &delay) {
- auto string = std::to_string(delay);
- return {string, delay};
-}
-
-template <typename T, typename U, typename... Args>
-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};
-}
-
-class VibratorTest : public Test, public WithParamInterface<EffectTuple> {
- public:
- void SetUp() override {
- std::unique_ptr<MockApi> mockapi;
- std::unique_ptr<MockCal> mockcal;
-
- createMock(&mockapi, &mockcal);
- createVibrator(std::move(mockapi), std::move(mockcal));
- }
-
- void TearDown() override { deleteVibrator(); }
-
- protected:
- void createMock(std::unique_ptr<MockApi> *mockapi, std::unique_ptr<MockCal> *mockcal) {
- *mockapi = std::make_unique<MockApi>();
- *mockcal = std::make_unique<MockCal>();
-
- mMockApi = mockapi->get();
- mMockCal = mockcal->get();
-
- ON_CALL(*mMockApi, destructor()).WillByDefault(Assign(&mMockApi, nullptr));
-
- ON_CALL(*mMockApi, getEffectDuration(_))
- .WillByDefault(
- DoAll(SetArgPointee<0>(msToCycles(EFFECT_DURATION)), ::testing::Return(true)));
-
- ON_CALL(*mMockCal, destructor()).WillByDefault(Assign(&mMockCal, nullptr));
-
- ON_CALL(*mMockCal, getVolLevels(_))
- .WillByDefault(DoAll(SetArgPointee<0>(V_LEVELS), ::testing::Return(true)));
-
- relaxMock(false);
- }
-
- void createVibrator(std::unique_ptr<MockApi> mockapi, std::unique_ptr<MockCal> mockcal,
- bool relaxed = true) {
- std::vector<uint32_t> vlevels{std::begin(V_LEVELS), std::end(V_LEVELS)};
- if (relaxed) {
- relaxMock(true);
- }
- mVibrator = new Vibrator(std::move(mockapi), std::move(mockcal));
- if (relaxed) {
- relaxMock(false);
- }
- }
-
- void deleteVibrator(bool relaxed = true) {
- if (relaxed) {
- relaxMock(true);
- }
- mVibrator.clear();
- }
-
- 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, setRedc(_)).Times(times);
- EXPECT_CALL(*mMockApi, setQ(_)).Times(times);
- EXPECT_CALL(*mMockApi, setActivate(_)).Times(times);
- EXPECT_CALL(*mMockApi, setDuration(_)).Times(times);
- EXPECT_CALL(*mMockApi, getEffectDuration(_)).Times(times);
- EXPECT_CALL(*mMockApi, setEffectIndex(_)).Times(times);
- EXPECT_CALL(*mMockApi, setEffectQueue(_)).Times(times);
- EXPECT_CALL(*mMockApi, hasEffectScale()).Times(times);
- EXPECT_CALL(*mMockApi, setEffectScale(_)).Times(times);
- EXPECT_CALL(*mMockApi, setGlobalScale(_)).Times(times);
- EXPECT_CALL(*mMockApi, setState(_)).Times(times);
- EXPECT_CALL(*mMockApi, hasAspEnable()).Times(times);
- EXPECT_CALL(*mMockApi, getAspEnable(_)).Times(times);
- EXPECT_CALL(*mMockApi, setAspEnable(_)).Times(times);
- EXPECT_CALL(*mMockApi, setGpioFallIndex(_)).Times(times);
- EXPECT_CALL(*mMockApi, setGpioFallScale(_)).Times(times);
- EXPECT_CALL(*mMockApi, setGpioRiseIndex(_)).Times(times);
- EXPECT_CALL(*mMockApi, setGpioRiseScale(_)).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, getVolLevels(_)).Times(times);
- EXPECT_CALL(*mMockApi, debug(_)).Times(times);
- }
-
- protected:
- MockApi *mMockApi;
- MockCal *mMockCal;
- sp<IVibrator> mVibrator;
-};
-
-TEST_F(VibratorTest, HwApi) {
- std::unique_ptr<MockApi> mockapi;
- std::unique_ptr<MockCal> mockcal;
- uint32_t f0Val = std::rand();
- uint32_t redcVal = std::rand();
- uint32_t qVal = std::rand();
- Expectation volGet;
- Sequence f0Seq, redcSeq, qSeq, volSeq, durSeq;
-
- 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(SetArgPointee<0>(f0Val), ::testing::Return(true)));
- EXPECT_CALL(*mMockApi, setF0(f0Val)).InSequence(f0Seq).WillOnce(::testing::Return(true));
-
- EXPECT_CALL(*mMockCal, getRedc(_))
- .InSequence(redcSeq)
- .WillOnce(DoAll(SetArgPointee<0>(redcVal), ::testing::Return(true)));
- EXPECT_CALL(*mMockApi, setRedc(redcVal)).InSequence(redcSeq).WillOnce(::testing::Return(true));
-
- EXPECT_CALL(*mMockCal, getQ(_))
- .InSequence(qSeq)
- .WillOnce(DoAll(SetArgPointee<0>(qVal), ::testing::Return(true)));
- EXPECT_CALL(*mMockApi, setQ(qVal)).InSequence(qSeq).WillOnce(::testing::Return(true));
-
- volGet = EXPECT_CALL(*mMockCal, getVolLevels(_)).WillOnce(DoDefault());
-
- EXPECT_CALL(*mMockApi, setState(true)).WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setEffectIndex(EFFECT_INDEX))
- .InSequence(durSeq)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, getEffectDuration(_)).InSequence(durSeq).WillOnce(DoDefault());
-
- EXPECT_CALL(*mMockApi, setGpioFallIndex(GPIO_FALL_INDEX)).WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setGpioFallScale(GPIO_FALL_SCALE))
- .After(volGet)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setGpioRiseIndex(GPIO_RISE_INDEX)).WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setGpioRiseScale(GPIO_RISE_SCALE))
- .After(volGet)
- .WillOnce(::testing::Return(true));
-
- createVibrator(std::move(mockapi), std::move(mockcal), false);
-}
-
-TEST_F(VibratorTest, on) {
- Sequence s1, s2, s3;
- uint16_t duration = std::rand() + 1;
-
- EXPECT_CALL(*mMockApi, setGlobalScale(ON_GLOBAL_SCALE))
- .InSequence(s1)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setEffectIndex(ON_EFFECT_INDEX))
- .InSequence(s2)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
- .InSequence(s3)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setActivate(true))
- .InSequence(s1, s2, s3)
- .WillOnce(::testing::Return(true));
-
- EXPECT_EQ(Status::OK, mVibrator->on(duration));
-}
-
-TEST_F(VibratorTest, off) {
- EXPECT_CALL(*mMockApi, setActivate(false)).WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setGlobalScale(0)).WillOnce(::testing::Return(true));
-
- EXPECT_EQ(Status::OK, mVibrator->off());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_supported) {
- EXPECT_CALL(*mMockApi, hasEffectScale()).WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, getAspEnable(_))
- .WillOnce(DoAll(SetArgPointee<0>(false), ::testing::Return(true)));
-
- EXPECT_EQ(true, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_unsupported1) {
- MockFunction<void()> either;
-
- EXPECT_CALL(*mMockApi, hasEffectScale())
- .Times(AtMost(1))
- .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
- ::testing::Return(false)));
- EXPECT_CALL(*mMockApi, getAspEnable(_))
- .Times(AtMost(1))
- .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
- SetArgPointee<0>(false), ::testing::Return(true)));
- EXPECT_CALL(either, Call()).Times(AtLeast(1));
-
- EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_unsupported2) {
- MockFunction<void()> either;
-
- EXPECT_CALL(*mMockApi, hasEffectScale())
- .Times(AtMost(1))
- .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
- ::testing::Return(false)));
- EXPECT_CALL(*mMockApi, getAspEnable(_))
- .Times(AtMost(1))
- .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
- SetArgPointee<0>(true), ::testing::Return(true)));
- EXPECT_CALL(either, Call()).Times(AtLeast(1));
-
- EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, supportsAmplitudeControl_unsupported3) {
- MockFunction<void()> either;
-
- EXPECT_CALL(*mMockApi, hasEffectScale())
- .Times(AtMost(1))
- .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
- ::testing::Return(true)));
- EXPECT_CALL(*mMockApi, getAspEnable(_))
- .Times(AtMost(1))
- .WillOnce(DoAll(InvokeWithoutArgs(&either, &MockFunction<void()>::Call),
- SetArgPointee<0>(true), ::testing::Return(true)));
- EXPECT_CALL(either, Call()).Times(AtLeast(1));
-
- EXPECT_EQ(false, mVibrator->supportsAmplitudeControl());
-}
-
-TEST_F(VibratorTest, setAmplitude_supported) {
- Sequence s;
- EffectAmplitude amplitude = std::rand() + 1;
-
- EXPECT_CALL(*mMockApi, getAspEnable(_))
- .InSequence(s)
- .WillOnce(DoAll(SetArgPointee<0>(false), ::testing::Return(true)));
- EXPECT_CALL(*mMockApi, setEffectScale(amplitudeToScale(amplitude)))
- .InSequence(s)
- .WillOnce(::testing::Return(true));
-
- EXPECT_EQ(Status::OK, mVibrator->setAmplitude(amplitude));
-}
-
-TEST_F(VibratorTest, setAmplitude_unsupported) {
- EXPECT_CALL(*mMockApi, getAspEnable(_))
- .WillOnce(DoAll(SetArgPointee<0>(true), ::testing::Return(true)));
-
- EXPECT_EQ(Status::UNSUPPORTED_OPERATION, mVibrator->setAmplitude(1));
-}
-
-TEST_F(VibratorTest, supportsExternalControl_supported) {
- EXPECT_CALL(*mMockApi, hasAspEnable()).WillOnce(::testing::Return(true));
-
- EXPECT_EQ(true, mVibrator->supportsExternalControl());
-}
-
-TEST_F(VibratorTest, supportsExternalControl_unsupported) {
- EXPECT_CALL(*mMockApi, hasAspEnable()).WillOnce(::testing::Return(false));
-
- EXPECT_EQ(false, mVibrator->supportsExternalControl());
-}
-
-TEST_F(VibratorTest, setExternalControl_enable) {
- Sequence s;
-
- EXPECT_CALL(*mMockApi, setGlobalScale(ON_GLOBAL_SCALE))
- .InSequence(s)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setAspEnable(true)).InSequence(s).WillOnce(::testing::Return(true));
-
- EXPECT_EQ(Status::OK, mVibrator->setExternalControl(true));
-}
-
-TEST_F(VibratorTest, setExternalControl_disable) {
- EXPECT_CALL(*mMockApi, setAspEnable(false)).WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setGlobalScale(0)).WillOnce(::testing::Return(true));
-
- EXPECT_EQ(Status::OK, mVibrator->setExternalControl(false));
-}
-
-TEST_P(VibratorTest, 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;
-
- if (scale != EFFECT_SCALE.end()) {
- Sequence s1, s2, s3;
-
- duration = EFFECT_DURATION;
-
- EXPECT_CALL(*mMockApi, setEffectIndex(EFFECT_INDEX))
- .InSequence(s1)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setEffectScale(scale->second))
- .InSequence(s2)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
- .InSequence(s3)
- .WillOnce(::testing::Return(true));
-
- EXPECT_CALL(*mMockApi, setActivate(true))
- .InSequence(s1, s2, s3)
- .WillOnce(::testing::Return(true));
- } else if (queue != EFFECT_QUEUE.end()) {
- Sequence s1, s2, s3;
-
- duration = std::get<1>(queue->second);
-
- EXPECT_CALL(*mMockApi, setEffectIndex(QUEUE_INDEX))
- .InSequence(s1)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setEffectQueue(std::get<0>(queue->second)))
- .InSequence(s2)
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(*mMockApi, setDuration(Ge(duration)))
- .InSequence(s3)
- .WillOnce(::testing::Return(true));
-
- EXPECT_CALL(*mMockApi, setActivate(true))
- .InSequence(s1, s2, s3)
- .WillOnce(::testing::Return(true));
- } else {
- duration = 0;
- }
-
- mVibrator->perform_1_3(effect, strength, [&](Status status, uint32_t lengthMs) {
- if (duration) {
- EXPECT_EQ(Status::OK, status);
- EXPECT_LE(duration, lengthMs);
- } else {
- EXPECT_EQ(Status::UNSUPPORTED_OPERATION, status);
- EXPECT_EQ(0, lengthMs);
- }
- });
-}
-
-INSTANTIATE_TEST_CASE_P(VibratorEffects, VibratorTest,
- Combine(ValuesIn(hidl_enum_range<Effect>().begin(),
- hidl_enum_range<Effect>().end()),
- ValuesIn(hidl_enum_range<EffectStrength>().begin(),
- hidl_enum_range<EffectStrength>().end())),
- [](const testing::TestParamInfo<VibratorTest::ParamType> &info) {
- auto effect = std::get<0>(info.param);
- auto strength = std::get<1>(info.param);
- return toString(effect) + "_" + toString(strength);
- });
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace vibrator
-} // namespace hardware
-} // namespace android
diff --git a/vibrator/tests/utils.h b/vibrator/tests/utils.h
deleted file mode 100644
index 86cb944..0000000
--- a/vibrator/tests/utils.h
+++ /dev/null
@@ -1,39 +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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
-#define ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
-
-#include <cmath>
-
-#include "types.h"
-
-static inline EffectScale toScale(uint8_t target, uint8_t maximum) {
- return std::round((-20 * std::log10(target / static_cast<float>(maximum))) / 0.125f);
-}
-
-static inline EffectScale levelToScale(EffectLevel level) {
- return toScale(level, 100);
-}
-
-static inline EffectScale amplitudeToScale(EffectAmplitude amplitude) {
- return toScale(amplitude, UINT8_MAX);
-}
-
-static inline uint32_t msToCycles(EffectDuration ms) {
- return ms * 48;
-}
-
-#endif // ANDROID_HARDWARE_VIBRATOR_TEST_UTILS_H
diff --git a/vibrator/utils.h b/vibrator/utils.h
deleted file mode 100644
index 078310e..0000000
--- a/vibrator/utils.h
+++ /dev/null
@@ -1,35 +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.
- */
-#ifndef ANDROID_HARDWARE_VIBRATOR_UTILS_H
-#define ANDROID_HARDWARE_VIBRATOR_UTILS_H
-
-template <typename T>
-class Is_Iterable {
- private:
- template <typename U>
- static std::true_type test(typename U::iterator *u);
-
- template <typename U>
- static std::false_type test(U *u);
-
- public:
- static const bool value = decltype(test<T>(0))::value;
-};
-
-template <typename T, bool B>
-using Enable_If_Iterable = std::enable_if_t<Is_Iterable<T>::value == B>;
-
-#endif // ANDROID_HARDWARE_VIBRATOR_UTILS_H