diff --git a/device-felix.mk b/device-felix.mk index e814842..4fc4fdb 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) {