vibrator: cs40l26: Implement braking duration for haptic effects
1. Add sysfs nodes for querying braking duration - braking_time_bank - braking_time_index - braking_time_ms 2. Set delay time between effects to include the whole braking duration 3. Add braking effect durations in HAL dumpsys logs Bug: 325121485 Test: Plotted acceleration Test: Checked HAL dumpsys Test: atest VibratorHalCs40l26TestSuite Flag: EXEMPT bugfix Change-Id: Ifacc94db4224adbab971e8d2c01c54422838760c Signed-off-by: leonardian <leonardian@google.com>
This commit is contained in:
parent
7eeceadfac
commit
0dcee74707
7 changed files with 67 additions and 16 deletions
|
@ -110,10 +110,12 @@ inline bool getProperty<bool>(const std::string &key, const bool def) {
|
|||
|
||||
template <typename T>
|
||||
static void openNoCreate(const std::string &file, T *outStream) {
|
||||
auto mode = std::is_base_of_v<std::ostream, T> ? std::ios_base::out : std::ios_base::in;
|
||||
if (!std::filesystem::exists(file)) {
|
||||
ALOGE("File does not exist: %s", file.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Force 'in' mode to prevent file creation
|
||||
outStream->open(file, mode | std::ios_base::in);
|
||||
outStream->open(file);
|
||||
if (!*outStream) {
|
||||
ALOGE("Failed to open %s (%d): %s", file.c_str(), errno, strerror(errno));
|
||||
}
|
||||
|
|
|
@ -78,6 +78,9 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
|||
open("calibration/q_stored", &mQ);
|
||||
open("default/vibe_state", &mVibeState);
|
||||
open("default/num_waves", &mEffectCount);
|
||||
open("default/braking_time_bank", &mEffectBrakingTimeBank);
|
||||
open("default/braking_time_index", &mEffectBrakingTimeIndex);
|
||||
open("default/braking_time_ms", &mEffectBrakingTimeMs);
|
||||
open("default/owt_free_space", &mOwtFreeSpace);
|
||||
open("default/f0_comp_enable", &mF0CompEnable);
|
||||
open("default/redc_comp_enable", &mRedcCompEnable);
|
||||
|
@ -89,6 +92,16 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
|||
bool setRedc(std::string value) override { return set(value, &mRedc); }
|
||||
bool setQ(std::string value) override { return set(value, &mQ); }
|
||||
bool getEffectCount(uint32_t *value) override { return get(value, &mEffectCount); }
|
||||
bool hasEffectBrakingTimeBank() override { return mEffectBrakingTimeBank.is_open(); }
|
||||
bool setEffectBrakingTimeBank(uint32_t value) override {
|
||||
return set(value, &mEffectBrakingTimeBank);
|
||||
}
|
||||
bool setEffectBrakingTimeIndex(uint32_t value) override {
|
||||
return set(value, &mEffectBrakingTimeIndex);
|
||||
}
|
||||
bool getEffectBrakingTimeMs(uint32_t *value) override {
|
||||
return get(value, &mEffectBrakingTimeMs);
|
||||
}
|
||||
bool pollVibeState(uint32_t value, int32_t timeoutMs) override {
|
||||
return poll(value, &mVibeState, timeoutMs);
|
||||
}
|
||||
|
@ -282,6 +295,9 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
|||
std::ofstream mRedc;
|
||||
std::ofstream mQ;
|
||||
std::ifstream mEffectCount;
|
||||
std::ofstream mEffectBrakingTimeBank;
|
||||
std::ofstream mEffectBrakingTimeIndex;
|
||||
std::ifstream mEffectBrakingTimeMs;
|
||||
std::ifstream mVibeState;
|
||||
std::ifstream mOwtFreeSpace;
|
||||
std::ofstream mF0CompEnable;
|
||||
|
|
|
@ -485,8 +485,9 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> h
|
|||
mFfEffects.resize(WAVEFORM_MAX_INDEX);
|
||||
mEffectDurations.resize(WAVEFORM_MAX_INDEX);
|
||||
mEffectDurations = {
|
||||
1000, 100, 12, 1000, 300, 130, 150, 500, 100, 5, 12, 1000, 1000, 1000,
|
||||
1000, 100, 9, 1000, 300, 130, 150, 500, 100, 5, 12, 1000, 1000, 1000,
|
||||
}; /* 11+3 waveforms. The duration must < UINT16_MAX */
|
||||
mEffectBrakingDurations.resize(WAVEFORM_MAX_INDEX);
|
||||
mEffectCustomData.reserve(WAVEFORM_MAX_INDEX);
|
||||
|
||||
uint8_t effectIndex;
|
||||
|
@ -519,6 +520,11 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> h
|
|||
if (mFfEffects[effectIndex].id != effectIndex) {
|
||||
ALOGW("Unexpected effect index: %d -> %d", effectIndex, mFfEffects[effectIndex].id);
|
||||
}
|
||||
|
||||
if (mHwApiDef->hasEffectBrakingTimeBank()) {
|
||||
mHwApiDef->setEffectBrakingTimeIndex(effectIndex);
|
||||
mHwApiDef->getEffectBrakingTimeMs(&mEffectBrakingDurations[effectIndex]);
|
||||
}
|
||||
} else {
|
||||
/* Initiate placeholders for OWT effects. */
|
||||
numBytes = effectIndex == WAVEFORM_COMPOSE ? FF_CUSTOM_DATA_LEN_MAX_COMP
|
||||
|
@ -850,7 +856,7 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
|
|||
return status;
|
||||
}
|
||||
|
||||
*durationMs = mEffectDurations[effectIndex];
|
||||
*durationMs = mEffectDurations[effectIndex] + mEffectBrakingDurations[effectIndex];
|
||||
} else {
|
||||
*durationMs = 0;
|
||||
}
|
||||
|
@ -863,7 +869,6 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi
|
|||
ALOGD("Vibrator::compose");
|
||||
uint16_t size;
|
||||
uint16_t nextEffectDelay;
|
||||
uint16_t totalDuration = 0;
|
||||
|
||||
if (composite.size() > COMPOSE_SIZE_MAX || composite.empty()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
|
@ -871,7 +876,6 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &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) {
|
||||
|
@ -913,7 +917,6 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi
|
|||
effectScale = mPrimitiveMinScale[static_cast<uint32_t>(e_curr.primitive)];
|
||||
}
|
||||
effectVolLevel = intensityToVolLevel(effectScale, effectIndex);
|
||||
totalDuration += mEffectDurations[effectIndex];
|
||||
}
|
||||
|
||||
/* Fetch the next composite effect delay and fill into the current section */
|
||||
|
@ -926,13 +929,14 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi
|
|||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
nextEffectDelay = delay;
|
||||
totalDuration += delay;
|
||||
}
|
||||
|
||||
if (effectIndex == 0 && nextEffectDelay == 0) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
nextEffectDelay += mEffectBrakingDurations[effectIndex];
|
||||
|
||||
ch.constructComposeSegment(effectVolLevel, effectIndex, 0 /*repeat*/, 0 /*flags*/,
|
||||
nextEffectDelay /*delay*/);
|
||||
}
|
||||
|
@ -1395,19 +1399,20 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
|
|||
|
||||
dprintf(fd, " FF effect:\n");
|
||||
dprintf(fd, " Physical waveform:\n");
|
||||
dprintf(fd, "==== Base ====\n\tId\tIndex\tt ->\tt'\ttrigger button\n");
|
||||
dprintf(fd, "==== Base ====\n\tId\tIndex\tt ->\tt'\tBrake\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,
|
||||
dprintf(fd, "\t%d\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);
|
||||
mFfEffects[effectId].replay.length, mEffectBrakingDurations[effectId],
|
||||
mFfEffects[effectId].trigger.button);
|
||||
}
|
||||
if (mIsDual) {
|
||||
dprintf(fd, "==== Flip ====\n\tId\tIndex\tt ->\tt'\ttrigger button\n");
|
||||
dprintf(fd, "==== Flip ====\n\tId\tIndex\tt ->\tt'\tBrake\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,
|
||||
dprintf(fd, "\t%d\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].replay.length, mEffectBrakingDurations[effectId],
|
||||
mFfEffectsDual[effectId].trigger.button);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,15 @@ class Vibrator : public BnVibrator {
|
|||
virtual bool setQ(std::string value) = 0;
|
||||
// Reports the number of effect waveforms loaded in firmware.
|
||||
virtual bool getEffectCount(uint32_t *value) = 0;
|
||||
// Checks whether braking time bank is supported.
|
||||
virtual bool hasEffectBrakingTimeBank() = 0;
|
||||
// Specifies the bank of the effect for querying braking time.
|
||||
// 0: RAM bank, 2: OWT bank
|
||||
virtual bool setEffectBrakingTimeBank(uint32_t value) = 0;
|
||||
// Specifies the index of an effect whose braking time is to be read.
|
||||
virtual bool setEffectBrakingTimeIndex(uint32_t value) = 0;
|
||||
// Gets the braking time duration of SVC effects (returns 0 if not SVC).
|
||||
virtual bool getEffectBrakingTimeMs(uint32_t *value) = 0;
|
||||
// Blocks until timeout or vibrator reaches desired state
|
||||
// (2 = ASP enabled, 1 = haptic enabled, 0 = disabled).
|
||||
virtual bool pollVibeState(uint32_t value, int32_t timeoutMs = -1) = 0;
|
||||
|
@ -218,6 +227,7 @@ class Vibrator : public BnVibrator {
|
|||
std::vector<ff_effect> mFfEffects;
|
||||
std::vector<ff_effect> mFfEffectsDual;
|
||||
std::vector<uint32_t> mEffectDurations;
|
||||
std::vector<uint32_t> mEffectBrakingDurations;
|
||||
std::vector<std::vector<int16_t>> mEffectCustomData;
|
||||
std::vector<std::vector<int16_t>> mEffectCustomDataDual;
|
||||
std::future<void> mAsyncHandle;
|
||||
|
|
|
@ -14,6 +14,9 @@ on property:vendor.all.modules.ready=1
|
|||
chown system system /sys/bus/i2c/devices/15-0043/calibration/redc_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/vibe_state
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/num_waves
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/braking_time_bank
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/braking_time_index
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/braking_time_ms
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/f0_offset
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/owt_free_space
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/f0_comp_enable
|
||||
|
@ -25,6 +28,9 @@ on property:vendor.all.modules.ready=1
|
|||
chown system system /sys/bus/i2c/devices/15-0042/calibration/redc_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/vibe_state
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/num_waves
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/braking_time_bank
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/braking_time_index
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/braking_time_ms
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/f0_offset
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/owt_free_space
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/f0_comp_enable
|
||||
|
@ -56,6 +62,9 @@ service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service
|
|||
calibration/q_stored
|
||||
default/vibe_state
|
||||
default/num_waves
|
||||
default/braking_time_bank
|
||||
default/braking_time_index
|
||||
default/braking_time_ms
|
||||
default/f0_offset
|
||||
default/owt_free_space
|
||||
default/f0_comp_enable
|
||||
|
|
|
@ -39,6 +39,10 @@ class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi {
|
|||
MOCK_METHOD1(setRedc, bool(std::string value));
|
||||
MOCK_METHOD1(setQ, bool(std::string value));
|
||||
MOCK_METHOD1(getEffectCount, bool(uint32_t *value));
|
||||
MOCK_METHOD0(hasEffectBrakingTimeBank, bool());
|
||||
MOCK_METHOD1(setEffectBrakingTimeBank, bool(uint32_t value));
|
||||
MOCK_METHOD1(setEffectBrakingTimeIndex, bool(uint32_t value));
|
||||
MOCK_METHOD1(getEffectBrakingTimeMs, bool(uint32_t *value));
|
||||
MOCK_METHOD2(pollVibeState, bool(uint32_t value, int32_t timeoutMs));
|
||||
MOCK_METHOD0(hasOwtFreeSpace, bool());
|
||||
MOCK_METHOD1(getOwtFreeSpace, bool(uint32_t *value));
|
||||
|
|
|
@ -74,7 +74,7 @@ static constexpr std::array<EffectLevel, 2> V_TICK_DEFAULT = {1, 100};
|
|||
static constexpr std::array<EffectLevel, 2> V_CLICK_DEFAULT{1, 100};
|
||||
static constexpr std::array<EffectLevel, 2> V_LONG_DEFAULT{1, 100};
|
||||
static constexpr std::array<EffectDuration, 14> EFFECT_DURATIONS{
|
||||
0, 100, 30, 1000, 300, 130, 150, 500, 100, 15, 20, 1000, 1000, 1000};
|
||||
1000, 100, 9, 1000, 300, 130, 150, 500, 100, 5, 12, 1000, 1000, 1000};
|
||||
|
||||
// Constants With Prescribed Values
|
||||
|
||||
|
@ -375,6 +375,11 @@ TEST_F(VibratorTest, Constructor) {
|
|||
.WillOnce(DoAll(SetArgPointee<0>(supportedPrimitivesBits), Return(true)));
|
||||
|
||||
EXPECT_CALL(*mMockApi, setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*mMockApi, setEffectBrakingTimeBank(0)).WillRepeatedly(Return(true));
|
||||
for (uint32_t i = 0; i < WAVEFORM_MAX_PHYSICAL_INDEX; i++) {
|
||||
EXPECT_CALL(*mMockApi, setEffectBrakingTimeIndex(i)).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(*mMockApi, getEffectBrakingTimeMs(_)).WillRepeatedly(Return(true));
|
||||
}
|
||||
createVibrator(std::move(mockapi), std::move(mockcal), std::move(mockgpio), false);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue