From 97a989bfbaec1a4ed5aec75acb3807aa1514e2af Mon Sep 17 00:00:00 2001 From: Chase Wu Date: Fri, 16 Dec 2022 17:45:45 +0800 Subject: [PATCH] [DO NOT MERGE] cs40l26: Fix the temporary no function symptom When device was stuck on the erased timeout process, user cannot feel the continuous haptic effects. Bug: 262675927 Test: Fold the device and unfold the device under OOBE thud effect Change-Id: Ia7b07b26e77f1e35d00075b91a31199575b61e3a Signed-off-by: Chase Wu --- vibrator/cs40l26/Hardware.h | 3 +- vibrator/cs40l26/Vibrator.cpp | 96 +++++++++++++++++++---------------- vibrator/cs40l26/Vibrator.h | 2 + 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h index 1b7e8ba..00ae2d2 100644 --- a/vibrator/cs40l26/Hardware.h +++ b/vibrator/cs40l26/Hardware.h @@ -220,7 +220,6 @@ 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); @@ -258,7 +257,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { } } // Turn on the waiting time for SVC init phase to complete - setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US); + setMinOnOffInterval(Vibrator::MIN_ON_OFF_INTERVAL_US); return true; } diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp index 6bb9165..f943323 100644 --- a/vibrator/cs40l26/Vibrator.cpp +++ b/vibrator/cs40l26/Vibrator.cpp @@ -53,8 +53,7 @@ static constexpr uint32_t WAVEFORM_LONG_VIBRATION_THRESHOLD_MS = 50; static constexpr uint8_t VOLTAGE_SCALE_MAX = 100; static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby -static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; // SVC initialization time -static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling +static constexpr 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 @@ -570,23 +569,22 @@ ndk::ScopedAStatus Vibrator::off() { ALOGE("Off: Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno)); ret = false; } + if (mIsDual && (!mHwApiDual->setFFPlay(mInputFdDual, mActiveId, false))) { + ALOGE("Off: Failed to stop flip's effect %d (%d): %s", mActiveId, errno, + strerror(errno)); + ret = false; + } + /* Do erase process */ if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && (!mHwApiDef->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { ALOGE("Off: Failed to clean up the composed effect %d", mActiveId); ret = false; } - 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 (mIsDual && (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)); @@ -596,7 +594,6 @@ ndk::ScopedAStatus Vibrator::off() { ALOGD("Off: Vibrator is already off"); } - mActiveId = -1; setGlobalAmplitude(false); if (mF0Offset) { mHwApiDef->setF0Offset(0); @@ -607,6 +604,7 @@ ndk::ScopedAStatus Vibrator::off() { if (ret) { ALOGD("Off: Done."); + mActiveId = -1; return ndk::ScopedAStatus::ok(); } else { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); @@ -725,6 +723,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector &composi ALOGD("Vibrator::compose"); uint16_t size; uint16_t nextEffectDelay; + uint16_t totalDuration = 0; auto ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_COMP]{0x00}, FF_CUSTOM_DATA_LEN_MAX_COMP); @@ -735,6 +734,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector &composi /* Check if there is a wait before the first effect. */ nextEffectDelay = composite.front().delayMs; + totalDuration += nextEffectDelay; if (nextEffectDelay > COMPOSE_DELAY_MAX_MS || nextEffectDelay < 0) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } else if (nextEffectDelay > 0) { @@ -769,6 +769,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector &composi return status; } effectVolLevel = intensityToVolLevel(e_curr.scale, effectIndex); + totalDuration += mEffectDurations[effectIndex]; } /* Fetch the next composite effect delay and fill into the current section */ @@ -781,6 +782,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector &composi return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } nextEffectDelay = delay; + totalDuration += delay; } if (effectIndex == 0 && nextEffectDelay == 0) { @@ -797,6 +799,10 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector &composi if (header_count == dspmem_chunk_bytes(ch)) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } else { + mFfEffects[WAVEFORM_COMPOSE].replay.length = totalDuration; + if (mIsDual) { + mFfEffectsDual[WAVEFORM_COMPOSE].replay.length = totalDuration; + } return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch, callback); } @@ -1325,7 +1331,7 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { } dprintf(fd, "Base: OWT waveform:\n"); - dprintf(fd, "\tId\tBytes\tData\ttrigger button\n"); + dprintf(fd, "\tId\tBytes\tData\tt\ttrigger button\n"); for (effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; effectId++) { uint32_t numBytes = mFfEffects[effectId].u.periodic.custom_len * 2; std::stringstream ss; @@ -1337,12 +1343,12 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { i)) << " "; } - dprintf(fd, "\t%d\t%d\t{%s}\t%X\n", mFfEffects[effectId].id, numBytes, ss.str().c_str(), - mFfEffects[effectId].trigger.button); + dprintf(fd, "\t%d\t%d\t{%s}\t%u\t%X\n", mFfEffects[effectId].id, numBytes, ss.str().c_str(), + mFfEffectsDual[effectId].replay.length, mFfEffects[effectId].trigger.button); } if (mIsDual) { dprintf(fd, "Flip: OWT waveform:\n"); - dprintf(fd, "\tId\tBytes\tData\ttrigger button\n"); + dprintf(fd, "\tId\tBytes\tData\tt\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; @@ -1354,8 +1360,9 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { 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, "\t%d\t%d\t{%s}\t%u\t%X\n", mFfEffectsDual[effectId].id, numBytes, + ss.str().c_str(), mFfEffectsDual[effectId].replay.length, + mFfEffectsDual[effectId].trigger.button); } } dprintf(fd, "\n"); @@ -1606,37 +1613,40 @@ void Vibrator::waitForComplete(std::shared_ptr &&callback) { ALOGD("waitForComplete: get STOP"); { const std::scoped_lock lock(mActiveId_mutex); - uint32_t effectCount; - mHwApiDef->getEffectCount(&effectCount); - if (mActiveId >= 0) { - if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && - (!mHwApiDef->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { + if (mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) { + if (!mHwApiDef->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects)) { ALOGE("Failed to clean up the composed effect %d", mActiveId); } - if (mIsDual && (mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && + if (mIsDual && (!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 { ALOGD("waitForComplete: Vibrator is already off"); } + mActiveId = -1; + if (mGPIOStatus && !mHwGPIO->setGPIOOutput(false)) { + ALOGE("waitForComplete: Failed to reset GPIO(%d): %s", errno, strerror(errno)); + } + // Do waveform number checking + uint32_t effectCount = WAVEFORM_MAX_PHYSICAL_INDEX; + mHwApiDef->getEffectCount(&effectCount); + if (effectCount > WAVEFORM_MAX_PHYSICAL_INDEX) { + // Forcibly clean all OWT waveforms + if (!mHwApiDef->eraseOwtEffect(mInputFd, WAVEFORM_MAX_INDEX, &mFfEffects)) { + ALOGE("Failed to clean up all base's composed effect"); + } + } + + if (mIsDual) { + // Forcibly clean all OWT waveforms + effectCount = WAVEFORM_MAX_PHYSICAL_INDEX; + mHwApiDual->getEffectCount(&effectCount); + if ((effectCount > WAVEFORM_MAX_PHYSICAL_INDEX) && + (!mHwApiDual->eraseOwtEffect(mInputFdDual, WAVEFORM_MAX_INDEX, &mFfEffectsDual))) { + ALOGE("Failed to clean up all flip's composed effect"); + } + } } if (callback) { diff --git a/vibrator/cs40l26/Vibrator.h b/vibrator/cs40l26/Vibrator.h index 9d37671..1f7ed70 100644 --- a/vibrator/cs40l26/Vibrator.h +++ b/vibrator/cs40l26/Vibrator.h @@ -175,6 +175,8 @@ class Vibrator : public BnVibrator { // BnCInterface APIs binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; + static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; // SVC initialization time + private: ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, struct dspmem_chunk *ch, const std::shared_ptr &callback);