From 07468b074a1fc90139d9853e048524d98562f712 Mon Sep 17 00:00:00 2001 From: Chase Wu Date: Tue, 29 Nov 2022 16:39:31 +0800 Subject: [PATCH] [DO NOT MERGE] cs40l26: single HAL for dual haptics We need to sync both haptics on the single HAL architecture to reduce the time overhead and prevent the mismatch behavior from vibrator manager HAL implementation. Bug: 260090235 Bug: 261687849 Bug: 261841035 Bug: 261832151 Test: atest PtsVibratorHalTestSuite \ PtsHapticsTestCases \ PtsHapticsFeatureTestCases \ VibratorHalCs40l26TestSuite \ VtsHalVibratorManagerTargetTest \ VtsHalVibratorTargetTest \ android.os.cts.VibratorTest \ android.os.cts.VibratorManagerTest \ android.os.cts.VibrationEffectTest \ android.os.cts.VibrationAttributesTest \ android.os.cts.CombinedVibrationTest \ Change-Id: I084e1da952ab2f63e5c217a7f708ac3d34635336 Signed-off-by: Chase Wu --- device-felix.mk | 2 +- vibrator/common/HardwareBase.cpp | 8 +- vibrator/cs40l26/Android.bp | 18 - vibrator/cs40l26/Hardware.h | 33 +- vibrator/cs40l26/VibMgrHwApi.h | 16 +- vibrator/cs40l26/Vibrator.cpp | 580 ++++++++++++------ vibrator/cs40l26/Vibrator.h | 50 +- vibrator/cs40l26/VibratorManager.cpp | 229 ------- vibrator/cs40l26/VibratorManager.h | 83 --- vibrator/cs40l26/VibratorSync.cpp | 39 -- vibrator/cs40l26/VibratorSync.h | 46 -- vibrator/cs40l26/aidl/Android.bp | 22 - .../hardware/vibrator/IVibratorSync.aidl | 24 - .../vibrator/IVibratorSyncCallback.aidl | 21 - ...rdware.vibrator-service.cs40l26-private.rc | 35 +- ...dware.vibrator-service.cs40l26-private.xml | 5 - ...vibrator-service.cs40l26-stereo-private.rc | 15 - ...ibrator-service.cs40l26-stereo-private.xml | 7 - vibrator/cs40l26/device-stereo.mk | 7 - vibrator/cs40l26/device.mk | 4 +- vibrator/cs40l26/service-stereo.cpp | 82 --- vibrator/cs40l26/service.cpp | 58 +- vibrator/cs40l26/tests/Android.bp | 4 +- vibrator/cs40l26/tests/mocks.h | 12 +- vibrator/cs40l26/tests/test-vibrator.cpp | 26 +- 25 files changed, 542 insertions(+), 884 deletions(-) delete mode 100644 vibrator/cs40l26/VibratorManager.cpp delete mode 100644 vibrator/cs40l26/VibratorManager.h delete mode 100644 vibrator/cs40l26/VibratorSync.cpp delete mode 100644 vibrator/cs40l26/VibratorSync.h delete mode 100644 vibrator/cs40l26/aidl/Android.bp delete mode 100644 vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl delete mode 100644 vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl delete mode 100644 vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc delete mode 100644 vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml delete mode 100644 vibrator/cs40l26/device-stereo.mk delete mode 100644 vibrator/cs40l26/service-stereo.cpp diff --git a/device-felix.mk b/device-felix.mk index e6eec6d..83ca3ff 100644 --- a/device-felix.mk +++ b/device-felix.mk @@ -30,7 +30,7 @@ DEVICE_PACKAGE_OVERLAYS += device/google/felix/felix/overlay include device/google/felix/audio/felix/audio-tables.mk include device/google/gs201/device-shipping-common.mk $(call soong_config_set,fp_hal_feature,pixel_product, product_a) -include device/google/felix/vibrator/cs40l26/device-stereo.mk +include device/google/felix/vibrator/cs40l26/device.mk include device/google/gs101/bluetooth/bluetooth.mk ifeq ($(filter factory_felix, $(TARGET_PRODUCT)),) include device/google/felix/uwb/uwb_calibration.mk diff --git a/vibrator/common/HardwareBase.cpp b/vibrator/common/HardwareBase.cpp index 8e819bb..7d61b57 100644 --- a/vibrator/common/HardwareBase.cpp +++ b/vibrator/common/HardwareBase.cpp @@ -71,7 +71,7 @@ void HwApiBase::debug(int fd) { HwCalBase::HwCalBase() { std::ifstream calfile; - std::ifstream calfile_other; + std::ifstream calfile_dual; auto propertyPrefix = std::getenv("PROPERTY_PREFIX"); if (propertyPrefix != NULL) { @@ -93,16 +93,16 @@ HwCalBase::HwCalBase() { } } - utils::fileFromEnv("CALIBRATION_FILEPATH_OTHER", &calfile_other); + utils::fileFromEnv("CALIBRATION_FILEPATH_DUAL", &calfile_dual); - for (std::string line; std::getline(calfile_other, line);) { + for (std::string line; std::getline(calfile_dual, 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)) { - key = utils::trim(key) + "_other"; + key = utils::trim(key) + "_dual"; mCalData[key] = utils::trim(value); } } diff --git a/vibrator/cs40l26/Android.bp b/vibrator/cs40l26/Android.bp index 9c38418..9ac51d1 100644 --- a/vibrator/cs40l26/Android.bp +++ b/vibrator/cs40l26/Android.bp @@ -34,7 +34,6 @@ cc_defaults { "android.hardware.vibrator-defaults.cs40l26-private", ], shared_libs: [ - "android.hardware.vibrator.cs40l26-private-cpp", "libcutils", "libtinyalsa", ], @@ -53,9 +52,6 @@ cc_defaults { "android.hardware.vibrator-impl.cs40l26-private", "libtinyalsa", ], - shared_libs: [ - "android.hardware.vibrator.cs40l26-private-cpp", - ], } cc_library { @@ -63,8 +59,6 @@ cc_library { defaults: ["VibratorHalCs40l26BinaryDefaultsPrivate"], srcs: [ "Vibrator.cpp", - "VibratorSync.cpp", - "VibratorManager.cpp", ], export_include_dirs: ["."], vendor_available: true, @@ -82,15 +76,3 @@ cc_binary { ], proprietary: true, } - -cc_binary { - name: "android.hardware.vibrator-service.cs40l26-stereo-private", - defaults: ["VibratorHalCs40l26BinaryDefaultsPrivate"], - init_rc: ["android.hardware.vibrator-service.cs40l26-stereo-private.rc"], - vintf_fragments: ["android.hardware.vibrator-service.cs40l26-stereo-private.xml"], - srcs: ["service-stereo.cpp"], - shared_libs: [ - "android.hardware.vibrator-impl.cs40l26-private", - ], - proprietary: true, -} diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h index 4866287..1b7e8ba 100644 --- a/vibrator/cs40l26/Hardware.h +++ b/vibrator/cs40l26/Hardware.h @@ -67,6 +67,10 @@ namespace vibrator { class HwApi : public Vibrator::HwApi, private HwApiBase { public: + static std::unique_ptr Create() { + auto hwapi = std::unique_ptr(new HwApi()); + return hwapi; + } HwApi() { open("calibration/f0_stored", &mF0); open("default/f0_offset", &mF0Offset); @@ -216,12 +220,16 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { } bool eraseOwtEffect(int fd, int8_t effectIndex, std::vector *effect) override { uint32_t effectCountBefore, effectCountAfter, i, successFlush = 0; + static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; // SVC initialization time if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) { ALOGE("Invalid waveform index for OWT erase: %d", effectIndex); return false; } - + // Turn off the waiting time for SVC init phase to complete since chip + // should already under STOP state + setMinOnOffInterval(0); + // Do erase flow if (effectIndex < WAVEFORM_MAX_INDEX) { /* Normal situation. Only erase the effect which we just played. */ if (ioctl(fd, EVIOCRMFF, effectIndex) < 0) { @@ -249,19 +257,10 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { (*effect)[i].id = -1; } } + // Turn on the waiting time for SVC init phase to complete + setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US); return true; } - void clearTrigBtn(int fd, struct ff_effect *effect, int8_t id) override { - if ((*effect).trigger.button != 0x00) { - (*effect).trigger.button = 0x00; - if (id < WAVEFORM_MAX_PHYSICAL_INDEX) { - /* Clear the trigger pin setting */ - if ((ioctl(fd, EVIOCSFF, effect) < 0)) { - ALOGE("OFF: Failed to edit effect %d (%d): %s", id, errno, strerror(errno)); - } - } - } - } void debug(int fd) override { HwApiBase::debug(fd); } @@ -282,7 +281,7 @@ class HwCal : public Vibrator::HwCal, private HwCalBase { private: static constexpr char VERSION[] = "version"; static constexpr char F0_CONFIG[] = "f0_measured"; - static constexpr char F0_CONFIG_OTHER[] = "f0_measured_other"; + static constexpr char F0_CONFIG_DUAL[] = "f0_measured_dual"; static constexpr char REDC_CONFIG[] = "redc_measured"; static constexpr char Q_CONFIG[] = "q_measured"; static constexpr char TICK_VOLTAGES_CONFIG[] = "v_tick"; @@ -297,6 +296,10 @@ class HwCal : public Vibrator::HwCal, private HwCalBase { public: HwCal() {} + static std::unique_ptr Create() { + auto hwcal = std::unique_ptr(new HwCal()); + return hwcal; + } bool getVersion(uint32_t *value) override { if (getPersist(VERSION, value)) { @@ -313,7 +316,7 @@ class HwCal : public Vibrator::HwCal, private HwCalBase { std::string cal_0{8, '0'}; std::string cal_1{8, '0'}; - if (getPersist(F0_CONFIG, &cal_0) && getPersist(F0_CONFIG_OTHER, &cal_1)) { + if (getPersist(F0_CONFIG, &cal_0) && getPersist(F0_CONFIG_DUAL, &cal_1)) { float f0_0 = static_cast(std::stoul(cal_0, nullptr, 16)) / (1 << 14); float f0_1 = static_cast(std::stoul(cal_1, nullptr, 16)) / (1 << 14); float f0_offset = std::abs(f0_0 - f0_1)/2; @@ -328,7 +331,7 @@ class HwCal : public Vibrator::HwCal, private HwCalBase { return true; } else { - ALOGI("Vibrator: Unable to load F0_CONFIG or F0_CONFIG_OTHER config"); + ALOGE("Vibrator: Unable to load F0_CONFIG or F0_CONFIG_DUAL config"); *value = 0; return false; } diff --git a/vibrator/cs40l26/VibMgrHwApi.h b/vibrator/cs40l26/VibMgrHwApi.h index be6e062..a243f69 100644 --- a/vibrator/cs40l26/VibMgrHwApi.h +++ b/vibrator/cs40l26/VibMgrHwApi.h @@ -21,7 +21,7 @@ #include -#include "VibratorManager.h" +#include "Vibrator.h" #include "utils.h" namespace aidl { @@ -29,7 +29,7 @@ namespace android { namespace hardware { namespace vibrator { -class VibMgrHwApi : public VibratorManager::HwApi { +class VibMgrHwApi : public Vibrator::HwGPIO { private: const uint32_t DEBUG_GPI_PIN = UINT16_MAX; const uint32_t DEBUG_GPI_PIN_SHIFT = UINT16_MAX; @@ -68,9 +68,9 @@ class VibMgrHwApi : public VibratorManager::HwApi { } bool initGPIO() override { const auto gpio_dev = std::string() + "/dev/gpiochip" + std::to_string(mGPIOPin); - int fd = open(gpio_dev.c_str(), O_RDONLY); + int fd = open(gpio_dev.c_str(), O_CREAT | O_WRONLY, 0777); if (fd < 0) { - ALOGE("InitGPIO: Unabled to open gpio dev: %s", strerror(errno)); + ALOGE("InitGPIO: Unable to open gpio dev: %s", strerror(errno)); return false; } @@ -79,12 +79,15 @@ class VibMgrHwApi : public VibratorManager::HwApi { mRq.flags = GPIOHANDLE_REQUEST_OUTPUT; int ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &mRq); - close(fd); if (ret == -1) { ALOGE("InitGPIO: Unable to line handle from ioctl : %s", strerror(errno)); close(fd); return false; } + if (close(fd) == -1) { + ALOGE("Failed to close GPIO char dev"); + return false; + } // Reset gpio status to LOW struct gpiohandle_data data; data.values[0] = 0; @@ -97,7 +100,7 @@ class VibMgrHwApi : public VibratorManager::HwApi { } return true; } - bool setTrigger(bool value) override { + bool setGPIOOutput(bool value) override { struct gpiohandle_data data; data.values[0] = value; @@ -107,7 +110,6 @@ class VibMgrHwApi : public VibratorManager::HwApi { close(mRq.fd); return false; } - close(mRq.fd); return true; } diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp index cd3d373..6bb9165 100644 --- a/vibrator/cs40l26/Vibrator.cpp +++ b/vibrator/cs40l26/Vibrator.cpp @@ -33,6 +33,11 @@ #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) #endif +#ifdef LOG_TAG +#undef LOG_TAG +#define LOG_TAG std::getenv("HAPTIC_NAME") +#endif + namespace aidl { namespace android { namespace hardware { @@ -51,10 +56,14 @@ static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; // SVC initialization time static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling static constexpr uint32_t MAX_TIME_MS = UINT16_MAX; +static constexpr float SETTING_TIME_OVERHEAD = 26; // This time was combined by + // HAL set the effect to + // driver and the kernel + // executes the effect before + // chip play the effect static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100); static constexpr auto POLLING_TIMEOUT = 20; -static constexpr auto POLLING_TIMEOUT_IN_SYNC = 100; static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000; /* nsections is 8 bits. Need to preserve 1 section for the first delay before the first effect. */ @@ -93,24 +102,12 @@ static constexpr float PWLE_BW_MAP_SIZE = /* * [15] Edge, 0:Falling, 1:Rising * [14:12] GPI_NUM, 1:GPI1 (with CS40L26A, 1 is the only supported GPI) - * [8] BANK, 0:ROM, 1:RAM + * [8] BANK, 0:RAM, 1:R0M * [7] USE_BUZZGEN, 0:Not buzzgen, 1:buzzgen * [6:0] WAVEFORM_INDEX - * 0x9100 = 1001 0001 0000 0000: Rising + GPI1 + ROM + Not buzzgen + * 0x9100 = 1001 0001 0000 0000: Rising + GPI1 + RAM + Not buzzgen */ -static constexpr uint32_t GPIO_TRIGGER_CONFIG = 0x9100; - -const char *kHAPNAME = std::getenv("HAPTIC_NAME"); -#undef ALOGV -#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, kHAPNAME, __VA_ARGS__)) -#undef ALOGD -#define ALOGD(...) ((void)ALOG(LOG_DEBUG, kHAPNAME, __VA_ARGS__)) -#undef ALOGI -#define ALOGI(...) ((void)ALOG(LOG_INFO, kHAPNAME, __VA_ARGS__)) -#undef ALOGW -#define ALOGW(...) ((void)ALOG(LOG_WARN, kHAPNAME, __VA_ARGS__)) -#undef ALOGE -#define ALOGE(...) ((void)ALOG(LOG_ERROR, kHAPNAME, __VA_ARGS__)) +static constexpr uint16_t GPIO_TRIGGER_CONFIG = 0x9100; static uint16_t amplitudeToScale(float amplitude, float maximum) { float ratio = 100; /* Unit: % */ @@ -166,8 +163,6 @@ enum vibe_state { VIBE_STATE_ASP, }; -std::mutex mActiveId_mutex; // protects mActiveId - static int min(int x, int y) { return x < y ? x : y; } @@ -242,12 +237,24 @@ static int dspmem_chunk_flush(struct dspmem_chunk *ch) { return dspmem_chunk_write(ch, 24 - ch->cachebits, 0); } -Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) - : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)), mAsyncHandle(std::async([] {})) { +Vibrator::Vibrator(std::unique_ptr hwApiDefault, std::unique_ptr hwCalDefault, + std::unique_ptr hwApiDual, std::unique_ptr hwCalDual, + std::unique_ptr hwgpio) + : mHwApiDef(std::move(hwApiDefault)), + mHwCalDef(std::move(hwCalDefault)), + mHwApiDual(std::move(hwApiDual)), + mHwCalDual(std::move(hwCalDual)), + mHwGPIO(std::move(hwgpio)), + mAsyncHandle(std::async([] {})) { int32_t longFrequencyShift; std::string caldata{8, '0'}; uint32_t calVer; + // ==================Single actuators and dual actuators checking ============================= + if ((mHwApiDual != nullptr) && (mHwCalDual != nullptr)) + mIsDual = true; + + // ==================INPUT Devices== Base ================= const char *inputEventName = std::getenv("INPUT_EVENT_NAME"); const char *inputEventPathName = std::getenv("INPUT_EVENT_PATH"); if ((strstr(inputEventName, "cs40l26") != nullptr) || @@ -296,10 +303,63 @@ Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) ALOGE("The input name %s is not cs40l26_input or cs40l26_dual_input", inputEventName); } + // ==================INPUT Devices== Flip ================= + if (mIsDual) { + const char *inputEventNameDual = std::getenv("INPUT_EVENT_NAME_DUAL"); + if ((strstr(inputEventNameDual, "cs40l26_dual_input") != nullptr)) { + glob_t inputEventPaths; + int fd = -1; + int ret; + uint32_t val = 0; + char str[20] = {0x00}; + for (uint8_t retry = 0; retry < 10; retry++) { + ret = glob(inputEventPathName, 0, nullptr, &inputEventPaths); + if (ret) { + ALOGE("Failed to get flip's input event paths (%d): %s", errno, + strerror(errno)); + } else { + for (int i = 0; i < inputEventPaths.gl_pathc; i++) { + fd = TEMP_FAILURE_RETRY(open(inputEventPaths.gl_pathv[i], O_RDWR)); + if (fd > 0) { + if (ioctl(fd, EVIOCGBIT(0, sizeof(val)), &val) > 0 && + (val & (1 << EV_FF)) && + ioctl(fd, EVIOCGNAME(sizeof(str)), &str) > 0 && + strstr(str, inputEventNameDual) != nullptr) { + mInputFdDual.reset(fd); + ALOGI("Control %s through %s", inputEventNameDual, + inputEventPaths.gl_pathv[i]); + break; + } + close(fd); + } + } + } + + if (ret == 0) { + globfree(&inputEventPaths); + } + if (mInputFdDual.ok()) { + break; + } + + sleep(1); + ALOGW("Retry #%d to search in %zu input devices.", retry, inputEventPaths.gl_pathc); + } + + if (!mInputFdDual.ok()) { + ALOGE("Failed to get an input event with name %s", inputEventNameDual); + } + ALOGE("HWAPI: %s", std::getenv("HWAPI_PATH_PREFIX")); + } else { + ALOGE("The input name %s is not cs40l26_dual_input", inputEventNameDual); + } + } + // ====================HAL internal effect table== Base ================================== + mFfEffects.resize(WAVEFORM_MAX_INDEX); mEffectDurations.resize(WAVEFORM_MAX_INDEX); mEffectDurations = { - 1000, 100, 30, 1000, 300, 130, 150, 500, 100, 15, 20, 1000, 1000, 1000, + 1000, 100, 32, 1000, 300, 130, 150, 500, 100, 10, 12, 1000, 1000, 1000, }; /* 11+3 waveforms. The duration must < UINT16_MAX */ uint8_t effectIndex; @@ -317,7 +377,7 @@ Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) // Bypass the waveform update due to different input name if ((strstr(inputEventName, "cs40l26") != nullptr) || (strstr(inputEventName, "cs40l26_dual_input") != nullptr)) { - if (!mHwApi->setFFEffect( + if (!mHwApiDef->setFFEffect( mInputFd, &mFfEffects[effectIndex], static_cast(mFfEffects[effectIndex].replay.length))) { ALOGE("Failed upload effect %d (%d): %s", effectIndex, errno, strerror(errno)); @@ -339,50 +399,124 @@ Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) } } - if (mHwCal->getF0(&caldata)) { - mHwApi->setF0(caldata); + // ====================HAL internal effect table== Flip ================================== + if (mIsDual) { + mFfEffectsDual.resize(WAVEFORM_MAX_INDEX); + + for (effectIndex = 0; effectIndex < WAVEFORM_MAX_INDEX; effectIndex++) { + if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) { + /* Initialize physical waveforms. */ + mFfEffectsDual[effectIndex] = { + .type = FF_PERIODIC, + .id = -1, + .replay.length = static_cast(mEffectDurations[effectIndex]), + .u.periodic.waveform = FF_CUSTOM, + .u.periodic.custom_data = new int16_t[2]{RAM_WVFRM_BANK, effectIndex}, + .u.periodic.custom_len = FF_CUSTOM_DATA_LEN, + }; + // Bypass the waveform update due to different input name + if ((strstr(inputEventName, "cs40l26") != nullptr) || + (strstr(inputEventName, "cs40l26_dual_input") != nullptr)) { + if (!mHwApiDual->setFFEffect( + mInputFdDual, &mFfEffectsDual[effectIndex], + static_cast(mFfEffectsDual[effectIndex].replay.length))) { + ALOGE("Failed upload flip's effect %d (%d): %s", effectIndex, errno, + strerror(errno)); + } + } + if (mFfEffectsDual[effectIndex].id != effectIndex) { + ALOGW("Unexpected effect index: %d -> %d", effectIndex, + mFfEffectsDual[effectIndex].id); + } + } else { + /* Initiate placeholders for OWT effects. */ + mFfEffectsDual[effectIndex] = { + .type = FF_PERIODIC, + .id = -1, + .replay.length = 0, + .u.periodic.waveform = FF_CUSTOM, + .u.periodic.custom_data = nullptr, + .u.periodic.custom_len = 0, + }; + } + } } - if (mHwCal->getRedc(&caldata)) { - mHwApi->setRedc(caldata); + // ==============Calibration data checking====================================== + + if (mHwCalDef->getF0(&caldata)) { + mHwApiDef->setF0(caldata); } - if (mHwCal->getQ(&caldata)) { - mHwApi->setQ(caldata); + if (mHwCalDef->getRedc(&caldata)) { + mHwApiDef->setRedc(caldata); + } + if (mHwCalDef->getQ(&caldata)) { + mHwApiDef->setQ(caldata); } - if (mHwCal->getF0SyncOffset(&mF0Offset)) { - ALOGI("Vibrator::Vibrator: F0 offset calculated from both base and flip calibration data: %u", mF0Offset); + if (mHwCalDef->getF0SyncOffset(&mF0Offset)) { + ALOGD("Vibrator::Vibrator: F0 offset calculated from both base and flip calibration data: " + "%u", + mF0Offset); } else { - mHwCal->getLongFrequencyShift(&longFrequencyShift); - if (longFrequencyShift > 0) { - mF0Offset = longFrequencyShift * std::pow(2, 14); - } else if (longFrequencyShift < 0) { - mF0Offset = std::pow(2, 24) - std::abs(longFrequencyShift) * std::pow(2, 14); - } else { - mF0Offset = 0; - } - ALOGI("Vibrator::Vibrator: F0 offset calculated from long shift frequency: %u", mF0Offset); + mHwCalDef->getLongFrequencyShift(&longFrequencyShift); + if (longFrequencyShift > 0) { + mF0Offset = longFrequencyShift * std::pow(2, 14); + } else if (longFrequencyShift < 0) { + mF0Offset = std::pow(2, 24) - std::abs(longFrequencyShift) * std::pow(2, 14); + } else { + mF0Offset = 0; + } + ALOGD("Vibrator::Vibrator: F0 offset calculated from long shift frequency: %u", mF0Offset); } - mHwCal->getVersion(&calVer); + if (mIsDual) { + if (mHwCalDual->getF0(&caldata)) { + mHwApiDual->setF0(caldata); + } + if (mHwCalDual->getRedc(&caldata)) { + mHwApiDual->setRedc(caldata); + } + if (mHwCalDual->getQ(&caldata)) { + mHwApiDual->setQ(caldata); + } + + if (mHwCalDual->getF0SyncOffset(&mF0OffsetDual)) { + ALOGD("Vibrator::Vibrator: Dual: F0 offset calculated from both base and flip " + "calibration data: " + "%u", + mF0OffsetDual); + } + } + + mHwCalDef->getVersion(&calVer); if (calVer == 2) { - mHwCal->getTickVolLevels(&mTickEffectVol); - mHwCal->getClickVolLevels(&mClickEffectVol); - mHwCal->getLongVolLevels(&mLongEffectVol); + mHwCalDef->getTickVolLevels(&(mTickEffectVol)); + mHwCalDef->getClickVolLevels(&(mClickEffectVol)); + mHwCalDef->getLongVolLevels(&(mLongEffectVol)); } else { ALOGW("Unsupported calibration version! Using the default calibration value"); - mHwCal->getTickVolLevels(&mTickEffectVol); - mHwCal->getClickVolLevels(&mClickEffectVol); - mHwCal->getLongVolLevels(&mLongEffectVol); + mHwCalDef->getTickVolLevels(&(mTickEffectVol)); + mHwCalDef->getClickVolLevels(&(mClickEffectVol)); + mHwCalDef->getLongVolLevels(&(mLongEffectVol)); } - mHwApi->setF0CompEnable(mHwCal->isF0CompEnabled()); - mHwApi->setRedcCompEnable(mHwCal->isRedcCompEnabled()); + // ================Project specific setting to driver=============================== + mHwApiDef->setF0CompEnable(mHwCalDef->isF0CompEnabled()); + mHwApiDef->setRedcCompEnable(mHwCalDef->isRedcCompEnabled()); + mHwApiDef->setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US); + if (mIsDual) { + mHwApiDual->setF0CompEnable(mHwCalDual->isF0CompEnabled()); + mHwApiDual->setRedcCompEnable(mHwCalDual->isRedcCompEnabled()); + mHwApiDual->setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US); + } + // ===============Audio coupled haptics bool init ======== mIsUnderExternalControl = false; - mIsChirpEnabled = mHwCal->isChirpEnabled(); + // =============== Compose PWLE check ===================================== + mIsChirpEnabled = mHwCalDef->isChirpEnabled(); - mHwCal->getSupportedPrimitives(&mSupportedPrimitivesBits); + mHwCalDef->getSupportedPrimitives(&mSupportedPrimitivesBits); if (mSupportedPrimitivesBits > 0) { for (auto e : defaultSupportedPrimitives) { if (mSupportedPrimitivesBits & (1 << uint32_t(e))) { @@ -395,7 +529,12 @@ Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) } mSupportedPrimitives = defaultSupportedPrimitives; } - mHwApi->setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US); + + // ====== Get GPIO status and init it ================ + mGPIOStatus = mHwGPIO->getGPIO(); + if (!mGPIOStatus || !mHwGPIO->initGPIO()) { + ALOGE("Vibrator: GPIO initialization process error"); + } } ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) { @@ -409,7 +548,7 @@ ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) { } else { ALOGE("No haptics ALSA device"); } - if (mHwApi->hasOwtFreeSpace()) { + if (mHwApiDef->hasOwtFreeSpace()) { ret |= IVibrator::CAP_COMPOSE_EFFECTS; if (mIsChirpEnabled) { ret |= IVibrator::CAP_FREQUENCY_CONTROL | IVibrator::CAP_COMPOSE_PWLE_EFFECTS; @@ -425,31 +564,49 @@ ndk::ScopedAStatus Vibrator::off() { const std::scoped_lock lock(mActiveId_mutex); if (mActiveId >= 0) { - ALOGV("Off: Stop the active effect: %d", mActiveId); + ALOGD("Off: Stop the active effect: %d", mActiveId); /* Stop the active effect. */ - if (!mHwApi->setFFPlay(mInputFd, mActiveId, false)) { - ALOGE("Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno)); + if (!mHwApiDef->setFFPlay(mInputFd, mActiveId, false)) { + ALOGE("Off: Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno)); ret = false; } - if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && - (!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { - ALOGE("Failed to clean up the composed effect %d", mActiveId); + (!mHwApiDef->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { + ALOGE("Off: Failed to clean up the composed effect %d", mActiveId); ret = false; } - mHwApi->clearTrigBtn(mInputFd, &mFfEffects[mActiveId], mActiveId); + if (mIsDual) { + if (!mHwApiDual->setFFPlay(mInputFdDual, mActiveId, false)) { + ALOGE("Off: Failed to stop flip's effect %d (%d): %s", mActiveId, errno, + strerror(errno)); + ret = false; + } + if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && + (!mHwApiDual->eraseOwtEffect(mInputFdDual, mActiveId, &mFfEffectsDual))) { + ALOGE("Off: Failed to clean up flip's the composed effect %d", mActiveId); + ret = false; + } + } + if (!mHwGPIO->setGPIOOutput(false)) { + ALOGE("Off: Failed to reset GPIO(%d): %s", errno, strerror(errno)); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } } else { - ALOGV("Off: Vibrator is already off"); + ALOGD("Off: Vibrator is already off"); } mActiveId = -1; setGlobalAmplitude(false); if (mF0Offset) { - mHwApi->setF0Offset(0); + mHwApiDef->setF0Offset(0); + if (mIsDual && mF0OffsetDual) { + mHwApiDual->setF0Offset(0); + } } if (ret) { + ALOGD("Off: Done."); return ndk::ScopedAStatus::ok(); } else { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); @@ -458,13 +615,8 @@ ndk::ScopedAStatus Vibrator::off() { ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr &callback) { - std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::on"); - - if (isBusy()) { - ALOGD("Vibrator::on, isBusy"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } + ALOGD("Vibrator::on"); if (timeoutMs > MAX_TIME_MS) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); @@ -477,7 +629,10 @@ ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, } setGlobalAmplitude(true); if (mF0Offset) { - mHwApi->setF0Offset(mF0Offset); + mHwApiDef->setF0Offset(mF0Offset); + if (mIsDual && mF0OffsetDual) { + mHwApiDual->setF0Offset(mF0OffsetDual); + } } return on(timeoutMs, index, nullptr /*ignored*/, callback); } @@ -485,8 +640,8 @@ ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, const std::shared_ptr &callback, int32_t *_aidl_return) { - std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::perform"); + ALOGD("Vibrator::perform"); return performEffect(effect, strength, callback, _aidl_return); } @@ -497,7 +652,6 @@ ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector *_aidl_retu } ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { - std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::setAmplitude"); if (amplitude <= 0.0f || amplitude > 1.0f) { @@ -513,17 +667,12 @@ ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { } ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) { - std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::setExternalControl"); - if (isSynced()) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); - } - setGlobalAmplitude(enabled); if (mHasHapticAlsaDevice || mConfigHapticAlsaDeviceDone || hasHapticAlsaDevice()) { - if (!mHwApi->setHapticPcmAmp(&mHapticPcm, enabled, mCard, mDevice)) { + if (!mHwApiDef->setHapticPcmAmp(&mHapticPcm, enabled, mCard, mDevice)) { ALOGE("Failed to %s haptic pcm device: %d", (enabled ? "enable" : "disable"), mDevice); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } @@ -562,8 +711,8 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, if (!status.isOk()) { return status; } - - *durationMs = mEffectDurations[effectIndex]; + // Please check the overhead time detail in b/261841035 + *durationMs = mEffectDurations[effectIndex] + SETTING_TIME_OVERHEAD; } else { *durationMs = 0; } @@ -572,8 +721,8 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, ndk::ScopedAStatus Vibrator::compose(const std::vector &composite, const std::shared_ptr &callback) { - std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::compose"); + ALOGD("Vibrator::compose"); uint16_t size; uint16_t nextEffectDelay; @@ -677,68 +826,134 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem effectIndex = isPwle ? WAVEFORM_PWLE : WAVEFORM_COMPOSE; uint32_t freeBytes; - mHwApi->getOwtFreeSpace(&freeBytes); + mHwApiDef->getOwtFreeSpace(&freeBytes); if (dspmem_chunk_bytes(ch) > freeBytes) { ALOGE("Invalid OWT length: Effect %d: %d > %d!", effectIndex, dspmem_chunk_bytes(ch), freeBytes); delete ch; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } - int errorStatus; - if (isSynced()) { - mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + if (mIsDual) { + mHwApiDual->getOwtFreeSpace(&freeBytes); + if (dspmem_chunk_bytes(ch) > freeBytes) { + ALOGE("Invalid OWT length in flip: Effect %d: %d > %d!", effectIndex, + dspmem_chunk_bytes(ch), freeBytes); + delete ch; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } } - if (!mHwApi->uploadOwtEffect(mInputFd, ch->head, dspmem_chunk_bytes(ch), - &mFfEffects[effectIndex], &effectIndex, &errorStatus)) { + + int errorStatus; + if (mGPIOStatus && mIsDual) { + mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + mFfEffectsDual[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + } else { + ALOGD("Not dual haptics HAL and GPIO status fail"); + } + + if (!mHwApiDef->uploadOwtEffect(mInputFd, ch->head, dspmem_chunk_bytes(ch), + &mFfEffects[effectIndex], &effectIndex, &errorStatus)) { delete ch; ALOGE("Invalid uploadOwtEffect"); return ndk::ScopedAStatus::fromExceptionCode(errorStatus); } + if (mIsDual && !mHwApiDual->uploadOwtEffect(mInputFdDual, ch->head, dspmem_chunk_bytes(ch), + &mFfEffectsDual[effectIndex], &effectIndex, + &errorStatus)) { + delete ch; + ALOGE("Invalid uploadOwtEffect in flip"); + return ndk::ScopedAStatus::fromExceptionCode(errorStatus); + } delete ch; } else if (effectIndex == WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX || effectIndex == WAVEFORM_LONG_VIBRATION_EFFECT_INDEX) { /* Update duration for long/short vibration. */ mFfEffects[effectIndex].replay.length = static_cast(timeoutMs); - if (isSynced()) { + if (mGPIOStatus && mIsDual) { mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + mFfEffectsDual[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + } else { + ALOGD("Not dual haptics HAL and GPIO status fail"); } - if (!mHwApi->setFFEffect(mInputFd, &mFfEffects[effectIndex], - static_cast(timeoutMs))) { + if (!mHwApiDef->setFFEffect(mInputFd, &mFfEffects[effectIndex], + static_cast(timeoutMs))) { ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } - } - { - const std::scoped_lock lock(mActiveId_mutex); - mActiveId = effectIndex; - if (isSynced() && - (effectIndex == WAVEFORM_CLICK_INDEX || effectIndex == WAVEFORM_LIGHT_TICK_INDEX)) { - mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; - if (!mHwApi->setFFEffect(mInputFd, &mFfEffects[effectIndex], mFfEffects[effectIndex].replay.length)) { - ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno)); + if (mIsDual) { + mFfEffectsDual[effectIndex].replay.length = static_cast(timeoutMs); + if (!mHwApiDual->setFFEffect(mInputFdDual, &mFfEffectsDual[effectIndex], + static_cast(timeoutMs))) { + ALOGE("Failed to edit flip's effect %d (%d): %s", effectIndex, errno, + strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } - } else if (!isSynced()) { - // /* Play the event now. */ - if (!mHwApi->setFFPlay(mInputFd, effectIndex, true)) { + } + } + + { + const std::scoped_lock lock(mActiveId_mutex); + /* Play the event now. */ + mActiveId = effectIndex; + if (!mGPIOStatus) { + ALOGE("GetVibrator: GPIO status error"); + // Do playcode to play effect + if (!mHwApiDef->setFFPlay(mInputFd, effectIndex, true)) { ALOGE("Failed to play effect %d (%d): %s", effectIndex, errno, strerror(errno)); + mActiveId = -1; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (mIsDual && !mHwApiDual->setFFPlay(mInputFdDual, effectIndex, true)) { + ALOGE("Failed to play flip's effect %d (%d): %s", effectIndex, errno, + strerror(errno)); + mActiveId = -1; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } else { + // Using GPIO to play effect + if ((effectIndex == WAVEFORM_CLICK_INDEX || effectIndex == WAVEFORM_LIGHT_TICK_INDEX)) { + mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + if (!mHwApiDef->setFFEffect(mInputFd, &mFfEffects[effectIndex], + mFfEffects[effectIndex].replay.length)) { + ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno)); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (mIsDual) { + mFfEffectsDual[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + if (!mHwApiDual->setFFEffect(mInputFdDual, &mFfEffectsDual[effectIndex], + mFfEffectsDual[effectIndex].replay.length)) { + ALOGE("Failed to edit flip's effect %d (%d): %s", effectIndex, errno, + strerror(errno)); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } + } + if (!mHwGPIO->setGPIOOutput(true)) { + ALOGE("Failed to trigger effect %d (%d) by GPIO: %s", effectIndex, errno, + strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } } } mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback); - + ALOGD("Vibrator::on, set done."); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) { uint16_t scale = amplitudeToScale(amplitude, maximum); - if (!mHwApi->setFFGain(mInputFd, scale)) { + if (!mHwApiDef->setFFGain(mInputFd, scale)) { ALOGE("Failed to set the gain to %u (%d): %s", scale, errno, strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } + if (mIsDual) { + if (!mHwApiDual->setFFGain(mInputFdDual, scale)) { + ALOGE("Failed to set flip's gain to %u (%d): %s", scale, errno, strerror(errno)); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } return ndk::ScopedAStatus::ok(); } @@ -747,6 +962,7 @@ ndk::ScopedAStatus Vibrator::setGlobalAmplitude(bool set) { if (!set) { mLongEffectScale = 1.0; // Reset the scale for the later new effect. } + return setEffectAmplitude(amplitude, VOLTAGE_SCALE_MAX); } @@ -764,7 +980,7 @@ ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) { ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) { std::string caldata{8, '0'}; - if (!mHwCal->getF0(&caldata)) { + if (!mHwCalDef->getF0(&caldata)) { ALOGE("Failed to get resonant frequency (%d): %s", errno, strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } @@ -775,7 +991,7 @@ ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz) { ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor) { std::string caldata{8, '0'}; - if (!mHwCal->getQ(&caldata)) { + if (!mHwCalDef->getQ(&caldata)) { ALOGE("Failed to get q factor (%d): %s", errno, strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } @@ -1066,37 +1282,6 @@ bool Vibrator::isUnderExternalControl() { return mIsUnderExternalControl; } -// BnVibratorSync APIs - -Status Vibrator::prepareSynced(const sp &callback) { - std::scoped_lock lock(mApiMutex); - ATRACE_NAME("Vibrator::prepareSynced"); - - if (isBusy() || isSynced() || isUnderExternalControl()) { - ALOGE("Vibrator::prepareSynced, isBusy or isSynced"); - return Status::fromExceptionCode(EX_ILLEGAL_STATE); - } - - mSyncedCallback = callback; - - return Status::ok(); -} - -Status Vibrator::cancelSynced() { - std::scoped_lock lock(mApiMutex); - ATRACE_NAME("Vibrator::cancelSynced"); - - if (!isSynced()) { - ALOGE("Vibrator::cancelSynced, isSynced"); - return Status::fromExceptionCode(EX_ILLEGAL_STATE); - } - - off(); - mSyncedCallback = nullptr; - - return Status::ok(); -} - // BnCInterface APIs binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { @@ -1110,29 +1295,38 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { dprintf(fd, "AIDL:\n"); - dprintf(fd, " F0 Offset: %" PRIu32 "\n", mF0Offset); + dprintf(fd, " F0 Offset: base: %" PRIu32 " flip: %" PRIu32 "\n", mF0Offset, mF0OffsetDual); dprintf(fd, " Voltage Levels:\n"); - dprintf(fd, " Tick Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mTickEffectVol[0], + dprintf(fd, " Tick Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mTickEffectVol[0], mTickEffectVol[1]); - dprintf(fd, " Click Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mClickEffectVol[0], + dprintf(fd, " Click Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mClickEffectVol[0], mClickEffectVol[1]); - dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mLongEffectVol[0], + dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mLongEffectVol[0], mLongEffectVol[1]); dprintf(fd, " FF effect:\n"); dprintf(fd, " Physical waveform:\n"); - dprintf(fd, "\tId\tIndex\tt ->\tt'\ttrigger button\n"); - for (uint8_t effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) { + dprintf(fd, "==== Base ====\n\tId\tIndex\tt ->\tt'\ttrigger button\n"); + uint8_t effectId; + for (effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) { dprintf(fd, "\t%d\t%d\t%d\t%d\t%X\n", mFfEffects[effectId].id, mFfEffects[effectId].u.periodic.custom_data[1], mEffectDurations[effectId], mFfEffects[effectId].replay.length, mFfEffects[effectId].trigger.button); } + if (mIsDual) { + dprintf(fd, "==== Flip ====\n\tId\tIndex\tt ->\tt'\ttrigger button\n"); + for (effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) { + dprintf(fd, "\t%d\t%d\t%d\t%d\t%X\n", mFfEffectsDual[effectId].id, + mFfEffectsDual[effectId].u.periodic.custom_data[1], mEffectDurations[effectId], + mFfEffectsDual[effectId].replay.length, + mFfEffectsDual[effectId].trigger.button); + } + } - dprintf(fd, " OWT waveform:\n"); + dprintf(fd, "Base: OWT waveform:\n"); dprintf(fd, "\tId\tBytes\tData\ttrigger button\n"); - for (uint8_t effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; - effectId++) { + for (effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; effectId++) { uint32_t numBytes = mFfEffects[effectId].u.periodic.custom_len * 2; std::stringstream ss; ss << " "; @@ -1146,15 +1340,38 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { dprintf(fd, "\t%d\t%d\t{%s}\t%X\n", mFfEffects[effectId].id, numBytes, ss.str().c_str(), mFfEffects[effectId].trigger.button); } - + if (mIsDual) { + dprintf(fd, "Flip: OWT waveform:\n"); + dprintf(fd, "\tId\tBytes\tData\ttrigger button\n"); + for (effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; effectId++) { + uint32_t numBytes = mFfEffectsDual[effectId].u.periodic.custom_len * 2; + std::stringstream ss; + ss << " "; + for (int i = 0; i < numBytes; i++) { + ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex + << (uint16_t)(*(reinterpret_cast( + mFfEffectsDual[effectId].u.periodic.custom_data) + + i)) + << " "; + } + dprintf(fd, "\t%d\t%d\t{%s}\t%X\n", mFfEffectsDual[effectId].id, numBytes, + ss.str().c_str(), mFfEffectsDual[effectId].trigger.button); + } + } dprintf(fd, "\n"); dprintf(fd, "\n"); - mHwApi->debug(fd); + mHwApiDef->debug(fd); dprintf(fd, "\n"); - mHwCal->debug(fd); + mHwCalDef->debug(fd); + + if (mIsDual) { + mHwApiDual->debug(fd); + dprintf(fd, "\n"); + mHwCalDual->debug(fd); + } fsync(fd); return STATUS_OK; @@ -1165,7 +1382,7 @@ bool Vibrator::hasHapticAlsaDevice() { // constructor is too early in the boot process and the pcm file contents // are empty. Hence we make the call here once only right before we need to. if (!mConfigHapticAlsaDeviceDone) { - if (mHwApi->getHapticAlsaDevice(&mCard, &mDevice)) { + if (mHwApiDef->getHapticAlsaDevice(&mCard, &mDevice)) { mHasHapticAlsaDevice = true; mConfigHapticAlsaDeviceDone = true; } else { @@ -1373,26 +1590,52 @@ ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLev } void Vibrator::waitForComplete(std::shared_ptr &&callback) { - ALOGD("Callback status in waitForComplete(): mSync: %d, callBack: %d", isSynced(), + ALOGD("waitForComplete: Callback status in waitForComplete(): callBack: %d", (callback != nullptr)); - if (!mHwApi->pollVibeState(VIBE_STATE_HAPTIC, - (mSyncedCallback) ? POLLING_TIMEOUT_IN_SYNC : POLLING_TIMEOUT)) { - ALOGV("Failed to get state \"Haptic\""); + // Bypass checking flip part's haptic state + if (!mHwApiDef->pollVibeState(VIBE_STATE_HAPTIC, POLLING_TIMEOUT)) { + ALOGD("Failed to get state \"Haptic\""); } - mHwApi->pollVibeState(VIBE_STATE_STOPPED); + mHwApiDef->pollVibeState(VIBE_STATE_STOPPED); + // Check flip's state after base was done + if (mIsDual) { + mHwApiDual->pollVibeState(VIBE_STATE_STOPPED); + } + ALOGD("waitForComplete: get STOP"); { const std::scoped_lock lock(mActiveId_mutex); - if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && - (!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { - ALOGE("Failed to clean up the composed effect %d", mActiveId); - } + uint32_t effectCount; + mHwApiDef->getEffectCount(&effectCount); if (mActiveId >= 0) { - mHwApi->clearTrigBtn(mInputFd, &mFfEffects[mActiveId], mActiveId); + if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && + (!mHwApiDef->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { + ALOGE("Failed to clean up the composed effect %d", mActiveId); + } + if (mIsDual && (mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && + (!mHwApiDual->eraseOwtEffect(mInputFdDual, mActiveId, &mFfEffectsDual))) { + ALOGE("Failed to clean up flip's composed effect %d", mActiveId); + } + if (mGPIOStatus && !mHwGPIO->setGPIOOutput(false)) { + ALOGE("waitForComplete: Failed to reset GPIO(%d): %s", errno, strerror(errno)); + } + mActiveId = -1; + } else if (effectCount > WAVEFORM_MAX_PHYSICAL_INDEX) { + if (!mHwApiDef->eraseOwtEffect(mInputFd, effectCount - 1, &mFfEffects)) { + ALOGE("Failed to clean up the composed effect %d", effectCount - 1); + } + if (mIsDual) { + mHwApiDual->getEffectCount(&effectCount); + if ((effectCount > WAVEFORM_MAX_PHYSICAL_INDEX) && + (!mHwApiDual->eraseOwtEffect(mInputFdDual, effectCount - 1, &mFfEffectsDual))) { + ALOGE("Failed to clean up flip's composed effect %d", effectCount - 1); + } + } + } else { - ALOGV("waitForComplete: Vibrator is already off"); + ALOGD("waitForComplete: Vibrator is already off"); } } @@ -1402,14 +1645,7 @@ void Vibrator::waitForComplete(std::shared_ptr &&callback) { ALOGE("Failed completion callback: %d", ret.getExceptionCode()); } } - if (mSyncedCallback) { - auto ret = mSyncedCallback->onComplete(); - if (!ret.isOk()) { - ALOGE("Failed completion mSyncedCallback: %d", ret.exceptionCode()); - } - mSyncedCallback = nullptr; - } - ALOGV("waitForComplete: Done"); + ALOGD("waitForComplete: Done."); } uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) { @@ -1442,16 +1678,6 @@ uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) { return volLevel; } -bool Vibrator::isBusy() { - auto timeout = std::chrono::seconds::zero(); - auto status = mAsyncHandle.wait_for(timeout); - return status != std::future_status::ready; -} - -bool Vibrator::isSynced() { - return (mSyncedCallback != nullptr); -} - } // namespace vibrator } // namespace hardware } // namespace android diff --git a/vibrator/cs40l26/Vibrator.h b/vibrator/cs40l26/Vibrator.h index e96badb..9d37671 100644 --- a/vibrator/cs40l26/Vibrator.h +++ b/vibrator/cs40l26/Vibrator.h @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -30,12 +29,22 @@ namespace android { namespace hardware { namespace vibrator { -using ::android::sp; -using ::android::binder::Status; -using ::android::hardware::vibrator::IVibratorSyncCallback; - class Vibrator : public BnVibrator { public: + // APIs for interfacing with the GPIO pin. + class HwGPIO { + public: + virtual ~HwGPIO() = default; + // Get the GPIO pin num and address shift information + virtual bool getGPIO() = 0; + // Init the GPIO function + virtual bool initGPIO() = 0; + // Trigger the GPIO pin to synchronize both vibrators's play + virtual bool setGPIOOutput(bool value) = 0; + // Emit diagnostic information to the given file. + virtual void debug(int fd) = 0; + }; + // APIs for interfacing with the kernel driver. class HwApi { public: @@ -85,8 +94,6 @@ class Vibrator : public BnVibrator { int *status) = 0; // Erase OWT waveform virtual bool eraseOwtEffect(int fd, int8_t effectIndex, std::vector *effect) = 0; - // Erase trigger button information - virtual void clearTrigBtn(int fd, struct ff_effect *effect, int8_t id) = 0; // Emit diagnostic information to the given file. virtual void debug(int fd) = 0; }; @@ -129,7 +136,9 @@ class Vibrator : public BnVibrator { }; public: - Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal); + Vibrator(std::unique_ptr hwApiDefault, std::unique_ptr hwCalDefault, + std::unique_ptr hwApiDual, std::unique_ptr hwCalDual, + std::unique_ptr hwgpio); // BnVibrator APIs ndk::ScopedAStatus getCapabilities(int32_t *_aidl_return) override; @@ -163,10 +172,6 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus composePwle(const std::vector &composite, const std::shared_ptr &callback) override; - // BnVibratorSync APIs - Status prepareSynced(const sp &callback); - Status cancelSynced(); - // BnCInterface APIs binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; @@ -198,33 +203,36 @@ class Vibrator : public BnVibrator { bool hasHapticAlsaDevice(); bool enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device); - bool isBusy(); - bool isSynced(); - - std::unique_ptr mHwApi; - std::unique_ptr mHwCal; + std::unique_ptr mHwApiDef; + std::unique_ptr mHwCalDef; + std::unique_ptr mHwApiDual; + std::unique_ptr mHwCalDual; + std::unique_ptr mHwGPIO; uint32_t mF0Offset; + uint32_t mF0OffsetDual; std::array mTickEffectVol; std::array mClickEffectVol; std::array mLongEffectVol; std::vector mFfEffects; + std::vector mFfEffectsDual; std::vector mEffectDurations; std::future mAsyncHandle; ::android::base::unique_fd mInputFd; + ::android::base::unique_fd mInputFdDual; int8_t mActiveId{-1}; struct pcm *mHapticPcm; int mCard; int mDevice; bool mHasHapticAlsaDevice{false}; bool mIsUnderExternalControl; - float mLongEffectScale = 1.0; + float mLongEffectScale{1.0}; bool mIsChirpEnabled; uint32_t mSupportedPrimitivesBits = 0x0; std::vector mSupportedPrimitives; bool mConfigHapticAlsaDeviceDone{false}; - // prevent concurrent execution of IVibrator and IVibratorSync APIs - sp mSyncedCallback; - std::recursive_mutex mApiMutex; + bool mGPIOStatus; + bool mIsDual{false}; + std::mutex mActiveId_mutex; // protects mActiveId }; } // namespace vibrator diff --git a/vibrator/cs40l26/VibratorManager.cpp b/vibrator/cs40l26/VibratorManager.cpp deleted file mode 100644 index 6530bf8..0000000 --- a/vibrator/cs40l26/VibratorManager.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "VibratorManager.h" - -#include -#include -#include - -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -const char *kHAPMGRNAME = std::getenv("HAPTIC_MGR_NAME"); -#undef ALOGV -#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, kHAPMGRNAME, __VA_ARGS__)) -#undef ALOGD -#define ALOGD(...) ((void)ALOG(LOG_DEBUG, kHAPMGRNAME, __VA_ARGS__)) -#undef ALOGI -#define ALOGI(...) ((void)ALOG(LOG_INFO, kHAPMGRNAME, __VA_ARGS__)) -#undef ALOGW -#define ALOGW(...) ((void)ALOG(LOG_WARN, kHAPMGRNAME, __VA_ARGS__)) -#undef ALOGE -#define ALOGE(...) ((void)ALOG(LOG_ERROR, kHAPMGRNAME, __VA_ARGS__)) - -using ::android::sp; -using ::android::binder::Status; -using ::android::hardware::vibrator::BnVibratorSyncCallback; - -class VibratorSyncCallback : public BnVibratorSyncCallback { - public: - Status onComplete() override { - mPromise.set_value(); - return Status::ok(); - } - auto getFuture() { return mPromise.get_future(); } - - private: - std::promise mPromise; -}; - -VibratorManager::VibratorManager(std::unique_ptr hwapi, - const std::vector &&vibrators) - : mHwApi(std::move(hwapi)), mVibrators(std::move(vibrators)), mAsyncHandle(std::async([] {})) { - mGPIOStatus = mHwApi->getGPIO(); -} - -// BnVibratorManager APIs - -ndk::ScopedAStatus VibratorManager::getCapabilities(int32_t *_aidl_return) { - ATRACE_NAME("VibratorManager::getCapabilities"); - int32_t ret = - IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON | - IVibratorManager::CAP_PREPARE_PERFORM | IVibratorManager::CAP_PREPARE_COMPOSE | - IVibratorManager::CAP_MIXED_TRIGGER_ON | IVibratorManager::CAP_MIXED_TRIGGER_PERFORM | - IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE | IVibratorManager::CAP_TRIGGER_CALLBACK; - - *_aidl_return = ret; - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus VibratorManager::getVibratorIds(std::vector *_aidl_return) { - ATRACE_NAME("VibratorManager::getVibratorIds"); - _aidl_return->resize(mVibrators.size()); - std::iota(_aidl_return->begin(), _aidl_return->end(), 0); - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus VibratorManager::getVibrator(int vibratorId, - std::shared_ptr *_aidl_return) { - ATRACE_NAME("VibratorManager::getVibrator"); - if (!mGPIOStatus) { - ALOGE("GetVibrator: GPIO status error"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - if (vibratorId >= mVibrators.size()) { - ALOGE("GetVibrator: wrong requested vibrator ID"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - std::tie(*_aidl_return, std::ignore) = mVibrators.at(vibratorId); - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus VibratorManager::prepareSynced(const std::vector &ids) { - ATRACE_NAME("VibratorManager::prepareSynced"); - - if (!mGPIOStatus) { - ALOGE("prepareSynced: GPIO status error"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - if (ids.empty()) { - ALOGE("PrepareSynced: No vibrator could be synced"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); - } - - if (!mSyncContext.empty()) { - ALOGE("PrepareSynced: mSyncContext is not EMPTY!!!"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - if (isBusy()) { - ALOGE("PrepareSynced: IS BUSY!!!"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - for (auto &id : ids) { - auto &[vib, ext] = mVibrators.at(id); - auto callback = sp::make(); - - if (ext->prepareSynced(callback).isOk()) { - mSyncContext.emplace_back(id, callback->getFuture()); - } else { - cancelSynced(); - ALOGV("prepareSynced: Fail: %d", id); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - } - ALOGV("prepareSynced: Done"); - if (mHwApi->initGPIO()) { - return ndk::ScopedAStatus::ok(); - } else { - ALOGE("PrepareSynced: GPIO status init fail"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } -} - -ndk::ScopedAStatus VibratorManager::triggerSynced( - const std::shared_ptr &callback) { - ATRACE_NAME("VibratorManager::triggerSynced"); - ALOGV("TriggerSynced"); - if (isBusy()) { - ALOGE("TriggerSynced isBusy"); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } - - mHwApi->setTrigger(true); - - doAsync([=]() { - { - std::shared_lock lock(mContextMutex); - for (auto &[id, future] : mSyncContext) { - future.wait(); - } - } - { - std::unique_lock lock(mContextMutex); - mSyncContext.clear(); - } - if (callback) { - auto ret = callback->onComplete(); - if (!ret.isOk()) { - ALOGE("Failed completion callback: %d", ret.getExceptionCode()); - } - ALOGD("Callback in MANAGER onComplete()"); - } - }); - - return ndk::ScopedAStatus::ok(); -} - -ndk::ScopedAStatus VibratorManager::cancelSynced() { - ATRACE_NAME("VibratorManager::cancelSynced"); - - ALOGV("Do cancelSynced"); - mHwApi->setTrigger(false); - { - std::shared_lock lock(mContextMutex); - for (auto &[id, future] : mSyncContext) { - auto &[vib, ext] = mVibrators.at(id); - ext->cancelSynced(); - } - } - { - std::unique_lock lock(mContextMutex); - mSyncContext.clear(); - } - mAsyncHandle.wait(); - - return ndk::ScopedAStatus::ok(); -} - -// BnCInterface APIs - -binder_status_t VibratorManager::dump(int fd, const char ** /*args*/, uint32_t /*numArgs*/) { - if (fd < 0) { - ALOGE("Called debug() with invalid fd."); - return STATUS_OK; - } - - mHwApi->debug(fd); - - fsync(fd); - - return STATUS_OK; -} - -// Private Methods - -template -void VibratorManager::doAsync(Func &&func, Args &&...args) { - mAsyncHandle = std::async(func, std::forward(args)...); -} - -bool VibratorManager::isBusy() { - auto timeout = std::chrono::seconds::zero(); - auto status = mAsyncHandle.wait_for(timeout); - return status != std::future_status::ready; -} - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/VibratorManager.h b/vibrator/cs40l26/VibratorManager.h deleted file mode 100644 index e518a20..0000000 --- a/vibrator/cs40l26/VibratorManager.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include -#include -#include - -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace vibrator { - -using ::android::hardware::vibrator::IVibratorSync; - -class VibratorManager : public BnVibratorManager { - public: - // APIs for interfacing with the kernel driver. - class HwApi { - public: - virtual ~HwApi() = default; - // Get the GPIO pin num and address shift information - virtual bool getGPIO() = 0; - // Init the GPIO function - virtual bool initGPIO() = 0; - // Trigger activation of the synchronized vibrators. - virtual bool setTrigger(bool value) = 0; - // Emit diagnostic information to the given file. - virtual void debug(int fd) = 0; - }; - - using VibratorTuple = std::tuple, ::android::sp>; - - public: - VibratorManager(std::unique_ptr hwapi, const std::vector &&vibrators); - - // BnVibratorManager APIs - ndk::ScopedAStatus getCapabilities(int32_t *_aidl_return); - ndk::ScopedAStatus getVibratorIds(std::vector *_aidl_return); - ndk::ScopedAStatus getVibrator(int vibratorId, std::shared_ptr *_aidl_return); - ndk::ScopedAStatus prepareSynced(const std::vector &ids) override; - ndk::ScopedAStatus triggerSynced(const std::shared_ptr &callback) override; - ndk::ScopedAStatus cancelSynced() override; - - // BnCInterface APIs - binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; - - private: - template - void doAsync(Func &&func, Args &&...args); - bool isBusy(); - - private: - using SyncContext = std::tuple>; - - const std::unique_ptr mHwApi; - const std::vector mVibrators; - std::vector mSyncContext; - std::shared_mutex mContextMutex; - std::future mAsyncHandle; - bool mGPIOStatus; -}; - -} // namespace vibrator -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/vibrator/cs40l26/VibratorSync.cpp b/vibrator/cs40l26/VibratorSync.cpp deleted file mode 100644 index 437ee01..0000000 --- a/vibrator/cs40l26/VibratorSync.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "VibratorSync.h" - -namespace android { -namespace hardware { -namespace vibrator { - -VibratorSync::VibratorSync(std::shared_ptr vibrator) : mVibrator(vibrator) { - ALOGE("VibratorSync constructor"); -} - -// BnVibratorSync APIs - -binder::Status VibratorSync::prepareSynced(const sp &callback) { - return mVibrator->prepareSynced(callback); -} - -binder::Status VibratorSync::cancelSynced() { - return mVibrator->cancelSynced(); -} - -} // namespace vibrator -} // namespace hardware -} // namespace android diff --git a/vibrator/cs40l26/VibratorSync.h b/vibrator/cs40l26/VibratorSync.h deleted file mode 100644 index fd9195a..0000000 --- a/vibrator/cs40l26/VibratorSync.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include - -#include -#include -#include - -#include "Vibrator.h" - -namespace android { -namespace hardware { -namespace vibrator { - -using ::aidl::android::hardware::vibrator::Vibrator; - -class VibratorSync : public BnVibratorSync { - public: - VibratorSync(std::shared_ptr vibrator); - - // BnVibratorSync APIs - binder::Status prepareSynced(const android::sp &callback) override; - binder::Status cancelSynced() override; - - private: - std::shared_ptr mVibrator; -}; - -} // namespace vibrator -} // namespace hardware -} // namespace android diff --git a/vibrator/cs40l26/aidl/Android.bp b/vibrator/cs40l26/aidl/Android.bp deleted file mode 100644 index 8876278..0000000 --- a/vibrator/cs40l26/aidl/Android.bp +++ /dev/null @@ -1,22 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "device_google_felix_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["device_google_felix_license"], -} - -aidl_interface { - name: "android.hardware.vibrator.cs40l26-private", - srcs: [ - "android/hardware/vibrator/*.aidl" - ], - backend: { - java: { - enabled: false, - }, - }, - unstable: true, - vendor_available: true, -} diff --git a/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl b/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl deleted file mode 100644 index 5371b13..0000000 --- a/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.vibrator; - -import android.hardware.vibrator.IVibratorSyncCallback; - -interface IVibratorSync { - void prepareSynced(in IVibratorSyncCallback callback); - void cancelSynced(); -} diff --git a/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl b/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl deleted file mode 100644 index 5281229..0000000 --- a/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.vibrator; - -interface IVibratorSyncCallback { - oneway void onComplete(); -} diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.rc index 838b76f..2799cdc 100644 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.rc +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.rc @@ -29,23 +29,25 @@ on property:vendor.all.modules.ready=1 chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/redc_comp_enable chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/delay_before_stop_playback_us chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/delay_before_stop_playback_us + chown system system /dev/gpiochip44 enable vendor.vibrator.cs40l26 - enable vendor.vibrator.cs40l26-dual service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-private class hal user system group system input - setenv HAPTIC_NAME HapticsBase + setenv HAPTIC_NAME Haptics setenv INPUT_EVENT_NAME cs40l26_input + setenv INPUT_EVENT_NAME_DUAL cs40l26_dual_input setenv INPUT_EVENT_PATH /dev/input/event* setenv PROPERTY_PREFIX ro.vendor.vibrator.hal. setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l26.cal - setenv CALIBRATION_FILEPATH_OTHER /mnt/vendor/persist/haptics/cs40l26_dual.cal + setenv CALIBRATION_FILEPATH_DUAL /mnt/vendor/persist/haptics/cs40l26_dual.cal setenv HWAPI_PATH_PREFIX /sys/bus/i2c/devices/i2c-cs40l26a/ + setenv HWAPI_PATH_PREFIX_DUAL /sys/bus/i2c/devices/i2c-cs40l26a-dual/ setenv HWAPI_DEBUG_PATHS " calibration/f0_stored calibration/redc_stored @@ -61,30 +63,3 @@ service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service disabled -service vendor.vibrator.cs40l26-dual /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-private - class hal - user system - group system input - - setenv HAPTIC_NAME HapticsFlip - setenv INPUT_EVENT_NAME cs40l26_dual_input - setenv INPUT_EVENT_PATH /dev/input/event* - setenv PROPERTY_PREFIX ro.vendor.vibrator.hal. - setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l26_dual.cal - setenv CALIBRATION_FILEPATH_OTHER /mnt/vendor/persist/haptics/cs40l26.cal - - setenv HWAPI_PATH_PREFIX /sys/bus/i2c/devices/i2c-cs40l26a-dual/ - setenv HWAPI_DEBUG_PATHS " - calibration/f0_stored - calibration/redc_stored - calibration/q_stored - default/vibe_state - default/num_waves - default/f0_offset - default/owt_free_space - default/f0_comp_enable - default/redc_comp_enable - default/delay_before_stop_playback_us - " - - disabled diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.xml b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.xml index 38df26a..4db8f8c 100644 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.xml +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-private.xml @@ -4,9 +4,4 @@ 2 IVibrator/default - - android.hardware.vibrator - 2 - IVibrator/dual - diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc deleted file mode 100644 index 7137c6a..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc +++ /dev/null @@ -1,15 +0,0 @@ -on property:vendor.all.modules.ready=1 - wait_for_prop init.svc.vendor.vibrator.cs40l26 running - wait_for_prop init.svc.vendor.vibrator.cs40l26-dual running - - enable vendor.vibrator.cs40l26-stereo - -service vendor.vibrator.cs40l26-stereo /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-stereo-private - class hal - user root - group root - - setenv HAPTIC_MGR_NAME HapticsMgr - setenv PROPERTY_PREFIX ro.vendor.vibrator.hal. - - disabled diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml deleted file mode 100644 index 9056bd0..0000000 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - android.hardware.vibrator - 2 - IVibratorManager/default - - diff --git a/vibrator/cs40l26/device-stereo.mk b/vibrator/cs40l26/device-stereo.mk deleted file mode 100644 index 3bc187e..0000000 --- a/vibrator/cs40l26/device-stereo.mk +++ /dev/null @@ -1,7 +0,0 @@ -PRODUCT_PACKAGES += \ - android.hardware.vibrator-service.cs40l26-private \ - android.hardware.vibrator-service.cs40l26-stereo-private - -BOARD_SEPOLICY_DIRS += \ - hardware/google/pixel-sepolicy/vibrator/common \ - hardware/google/pixel-sepolicy/vibrator/cs40l26 diff --git a/vibrator/cs40l26/device.mk b/vibrator/cs40l26/device.mk index fe4bbc8..2c4b2e2 100644 --- a/vibrator/cs40l26/device.mk +++ b/vibrator/cs40l26/device.mk @@ -2,5 +2,5 @@ PRODUCT_PACKAGES += \ android.hardware.vibrator-service.cs40l26-private BOARD_SEPOLICY_DIRS += \ - device/google/felix-sepolicy/vibrator/common \ - device/google/felix-sepolicy/vibrator/cs40l26 + hardware/google/pixel-sepolicy/vibrator/common \ + hardware/google/pixel-sepolicy/vibrator/cs40l26 diff --git a/vibrator/cs40l26/service-stereo.cpp b/vibrator/cs40l26/service-stereo.cpp deleted file mode 100644 index cd05035..0000000 --- a/vibrator/cs40l26/service-stereo.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -#include "VibMgrHwApi.h" -#include "VibratorManager.h" - -using ::aidl::android::hardware::vibrator::IVibrator; -using ::aidl::android::hardware::vibrator::VibMgrHwApi; -using ::aidl::android::hardware::vibrator::VibratorManager; -using ::android::ProcessState; -using ::android::String16; -using ::android::waitForService; -using ::android::hardware::vibrator::IVibratorSync; - -#if !defined(VIBRATOR_NAME) -#define VIBRATOR_NAME "default" -#endif - -using ndk::SharedRefBase; -using ndk::SpAIBinder; - -int main() { - auto hwapi = VibMgrHwApi::Create(); - if (!hwapi) { - return EXIT_FAILURE; - } - - const std::string vibratorInstances[] = { - "default", - "dual", - }; - std::vector vibrators; - - ProcessState::initWithDriver("/dev/vndbinder"); - - for (auto &instance : vibratorInstances) { - const auto svcName = std::string() + IVibrator::descriptor + "/" + instance; - const auto extName = std::stringstream() << IVibratorSync::descriptor << "/" << instance; - - SpAIBinder svcBinder; - svcBinder = SpAIBinder(AServiceManager_getService(svcName.c_str())); - auto svc = IVibrator::fromBinder(svcBinder); - - auto ext = waitForService(String16(extName.str().c_str())); - - vibrators.emplace_back(svc, ext); - } - - auto mgr = ndk::SharedRefBase::make(std::move(hwapi), std::move(vibrators)); - binder_status_t status; - - const std::string mgrInst = std::string() + VibratorManager::descriptor + "/" VIBRATOR_NAME; - status = AServiceManager_addService(mgr->asBinder().get(), mgrInst.c_str()); - LOG_ALWAYS_FATAL_IF(status != STATUS_OK); - - // Only used for callbacks - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); - - ABinderProcess_setThreadPoolMaxThreadCount(0); - ABinderProcess_joinThreadPool(); - - return EXIT_FAILURE; // should not reach -} diff --git a/vibrator/cs40l26/service.cpp b/vibrator/cs40l26/service.cpp index 8bcd623..605de43 100644 --- a/vibrator/cs40l26/service.cpp +++ b/vibrator/cs40l26/service.cpp @@ -20,40 +20,60 @@ #include #include "Hardware.h" +#include "VibMgrHwApi.h" #include "Vibrator.h" -#include "VibratorSync.h" using ::aidl::android::hardware::vibrator::HwApi; using ::aidl::android::hardware::vibrator::HwCal; +using ::aidl::android::hardware::vibrator::VibMgrHwApi; using ::aidl::android::hardware::vibrator::Vibrator; using ::android::defaultServiceManager; using ::android::ProcessState; using ::android::sp; using ::android::String16; -using ::android::hardware::vibrator::VibratorSync; + +#if !defined(VIBRATOR_NAME) +#define VIBRATOR_NAME "default" +#endif int main() { - const char *inputEventName = std::getenv("INPUT_EVENT_NAME"); - std::string vibName = ""; - if (strstr(inputEventName, "cs40l26_input") != nullptr) { - vibName.assign("default"); - } else if (strstr(inputEventName, "cs40l26_dual_input") != nullptr) { - vibName.assign("dual"); - } else { - ALOGE("Failed to init vibrator HAL"); - return EXIT_FAILURE; // should not reach - } - auto svc = ndk::SharedRefBase::make(std::make_unique(), - std::make_unique()); - const auto svcName = std::string() + svc->descriptor + "/" + vibName; + const char *hwApiPathPrefixDual = std::getenv("HWAPI_PATH_PREFIX_DUAL"); + const char *calFilePath = std::getenv("CALIBRATION_FILEPATH"); + const char *calFilePathDual = std::getenv("CALIBRATION_FILEPATH_DUAL"); - auto ext = sp::make(svc); - const auto extName = std::stringstream() << ext->descriptor << "/" << vibName; + auto hwgpio = VibMgrHwApi::Create(); + if (!hwgpio) { + return EXIT_FAILURE; + } + auto hwApiDef = HwApi::Create(); + if (!hwApiDef) { + return EXIT_FAILURE; + } + auto hwCalDef = HwCal::Create(); + if (!hwCalDef) { + return EXIT_FAILURE; + } + + std::shared_ptr svc; + // Synchronize base and flip actuator F0. + // Replace dual cal file path to base and copy the base to dual's path. + if ((hwApiPathPrefixDual != nullptr) && !setenv("HWAPI_PATH_PREFIX", hwApiPathPrefixDual, 1) && + (calFilePathDual != nullptr) && !setenv("CALIBRATION_FILEPATH", calFilePathDual, 1) && + !setenv("CALIBRATION_FILEPATH_DUAL", calFilePath, 1)) { + ALOGD("Init dual HAL: %s", std::getenv("HWAPI_PATH_PREFIX")); + svc = ndk::SharedRefBase::make(std::move(hwApiDef), std::move(hwCalDef), + std::make_unique(), + std::make_unique(), std::move(hwgpio)); + } else { + ALOGD("Failed to init dual HAL"); + svc = ndk::SharedRefBase::make(std::move(hwApiDef), std::move(hwCalDef), nullptr, + nullptr, std::move(hwgpio)); + } + + const auto svcName = std::string() + svc->descriptor + "/" + VIBRATOR_NAME; ProcessState::initWithDriver("/dev/vndbinder"); - defaultServiceManager()->addService(String16(extName.str().c_str()), ext); - auto svcBinder = svc->asBinder(); binder_status_t status = AServiceManager_addService(svcBinder.get(), svcName.c_str()); LOG_ALWAYS_FATAL_IF(status != STATUS_OK); diff --git a/vibrator/cs40l26/tests/Android.bp b/vibrator/cs40l26/tests/Android.bp index 6061ce8..48baa90 100644 --- a/vibrator/cs40l26/tests/Android.bp +++ b/vibrator/cs40l26/tests/Android.bp @@ -22,8 +22,8 @@ cc_test { defaults: ["VibratorHalCs40l26TestDefaultsPrivate"], srcs: [ "test-hwcal.cpp", - "test-hwapi.cpp", - "test-vibrator.cpp", + "test-hwapi.cpp", + "test-vibrator.cpp", ], static_libs: [ "libc++fs", diff --git a/vibrator/cs40l26/tests/mocks.h b/vibrator/cs40l26/tests/mocks.h index cf33815..c85b0b5 100644 --- a/vibrator/cs40l26/tests/mocks.h +++ b/vibrator/cs40l26/tests/mocks.h @@ -20,6 +20,17 @@ #include "Vibrator.h" +class MockGPIO : public ::aidl::android::hardware::vibrator::Vibrator::HwGPIO { + public: + MOCK_METHOD0(destructor, void()); + MOCK_METHOD0(getGPIO, bool()); + MOCK_METHOD0(initGPIO, bool()); + MOCK_METHOD1(setGPIOOutput, bool(bool value)); + MOCK_METHOD1(debug, void(int fd)); + + ~MockGPIO() override { destructor(); }; +}; + class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi { public: MOCK_METHOD0(destructor, void()); @@ -43,7 +54,6 @@ class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi { bool(int fd, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect, uint32_t *outEffectIndex, int *status)); MOCK_METHOD3(eraseOwtEffect, bool(int fd, int8_t effectIndex, std::vector *effect)); - MOCK_METHOD3(clearTrigBtn, void(int fd, struct ff_effect *effect, int8_t index)); MOCK_METHOD1(debug, void(int fd)); ~MockApi() override { destructor(); }; diff --git a/vibrator/cs40l26/tests/test-vibrator.cpp b/vibrator/cs40l26/tests/test-vibrator.cpp index a8bedd5..3ea6bda 100644 --- a/vibrator/cs40l26/tests/test-vibrator.cpp +++ b/vibrator/cs40l26/tests/test-vibrator.cpp @@ -203,20 +203,24 @@ class VibratorTest : public Test { setenv("INPUT_EVENT_NAME", "CS40L26TestSuite", true); std::unique_ptr mockapi; std::unique_ptr mockcal; + std::unique_ptr mockgpio; - createMock(&mockapi, &mockcal); - createVibrator(std::move(mockapi), std::move(mockcal)); + createMock(&mockapi, &mockcal, &mockgpio); + createVibrator(std::move(mockapi), std::move(mockcal), std::move(mockgpio)); } void TearDown() override { deleteVibrator(); } protected: - void createMock(std::unique_ptr *mockapi, std::unique_ptr *mockcal) { + void createMock(std::unique_ptr *mockapi, std::unique_ptr *mockcal, + std::unique_ptr *mockgpio) { *mockapi = std::make_unique(); *mockcal = std::make_unique(); + *mockgpio = std::make_unique(); mMockApi = mockapi->get(); mMockCal = mockcal->get(); + mMockGpio = mockgpio->get(); ON_CALL(*mMockApi, destructor()).WillByDefault(Assign(&mMockApi, nullptr)); @@ -242,15 +246,20 @@ class VibratorTest : public Test { ON_CALL(*mMockCal, getLongVolLevels(_)) .WillByDefault(DoAll(SetArgPointee<0>(V_LONG_DEFAULT), Return(true))); + ON_CALL(*mMockGpio, destructor()).WillByDefault(Assign(&mMockGpio, nullptr)); + relaxMock(false); } void createVibrator(std::unique_ptr mockapi, std::unique_ptr mockcal, - bool relaxed = true) { + std::unique_ptr mockgpio, bool relaxed = true) { if (relaxed) { relaxMock(true); } - mVibrator = ndk::SharedRefBase::make(std::move(mockapi), std::move(mockcal)); + // TODO(b/261415845): Need to add dual parameters to test the vibrator HAL's code in haptics + // mock test + mVibrator = ndk::SharedRefBase::make(std::move(mockapi), std::move(mockcal), + nullptr, nullptr, std::move(mockgpio)); if (relaxed) { relaxMock(false); } @@ -306,6 +315,7 @@ class VibratorTest : public Test { protected: MockApi *mMockApi; MockCal *mMockCal; + MockGPIO *mMockGpio; std::shared_ptr mVibrator; uint32_t mEffectIndex; }; @@ -313,6 +323,7 @@ class VibratorTest : public Test { TEST_F(VibratorTest, Constructor) { std::unique_ptr mockapi; std::unique_ptr mockcal; + std::unique_ptr mockgpio; std::string f0Val = std::to_string(std::rand()); std::string redcVal = std::to_string(std::rand()); std::string qVal = std::to_string(std::rand()); @@ -323,10 +334,11 @@ TEST_F(VibratorTest, Constructor) { EXPECT_CALL(*mMockApi, destructor()).WillOnce(DoDefault()); EXPECT_CALL(*mMockCal, destructor()).WillOnce(DoDefault()); + EXPECT_CALL(*mMockGpio, destructor()).WillOnce(DoDefault()); deleteVibrator(false); - createMock(&mockapi, &mockcal); + createMock(&mockapi, &mockcal, &mockgpio); EXPECT_CALL(*mMockCal, getF0(_)) .InSequence(f0Seq) @@ -363,7 +375,7 @@ TEST_F(VibratorTest, Constructor) { .WillOnce(DoAll(SetArgPointee<0>(supportedPrimitivesBits), Return(true))); EXPECT_CALL(*mMockApi, setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US)).WillOnce(Return(true)); - createVibrator(std::move(mockapi), std::move(mockcal), false); + createVibrator(std::move(mockapi), std::move(mockcal), std::move(mockgpio), false); } TEST_F(VibratorTest, on) {