[coastguard skipped] Merge sparse cherrypicks from sparse-11559474-L79500030002452450 into 24D1-release.
COASTGUARD_SKIP: I2937d91954470f2b28e4e719ae82139bd622084f
COASTGUARD_SKIP: I32258500ec02c2a8cbfc6d0b37aaea2c83c7c8b4
Change-Id: Ic8dff64f700bfde4e80ad473e95ca513e27aaf59
diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h
index af8d120..22667c9 100644
--- a/vibrator/cs40l26/Hardware.h
+++ b/vibrator/cs40l26/Hardware.h
@@ -184,7 +184,7 @@
*haptic_pcm = NULL;
return false;
}
- bool uploadOwtEffect(int fd, const uint8_t *owtData, const uint32_t numBytes, struct ff_effect *effect,
+ bool uploadOwtEffect(int fd, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect,
uint32_t *outEffectIndex, int *status) override {
(*effect).u.periodic.custom_len = numBytes / sizeof(uint16_t);
delete[] ((*effect).u.periodic.custom_data);
@@ -225,10 +225,6 @@
ALOGE("Invalid waveform index for OWT erase: %d", effectIndex);
return false;
}
- if (effect == nullptr || (*effect).empty()) {
- ALOGE("Invalid argument effect");
- return false;
- }
// Turn off the waiting time for SVC init phase to complete since chip
// should already under STOP state
setMinOnOffInterval(0);
diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp
index 2abe72e..bfb7cf1 100644
--- a/vibrator/cs40l26/Vibrator.cpp
+++ b/vibrator/cs40l26/Vibrator.cpp
@@ -27,8 +27,6 @@
#include <cmath>
#include <fstream>
#include <iostream>
-#include <memory>
-#include <optional>
#include <sstream>
#ifndef ARRAY_SIZE
@@ -87,7 +85,7 @@
static constexpr float PWLE_LEVEL_MIN = 0.0;
static constexpr float PWLE_LEVEL_MAX = 1.0;
-static constexpr float CS40L26_PWLE_LEVEL_MIN = -1.0;
+static constexpr float CS40L26_PWLE_LEVEL_MIX = -1.0;
static constexpr float CS40L26_PWLE_LEVEL_MAX = 0.9995118;
static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.00;
static constexpr float PWLE_FREQUENCY_MIN_HZ = 1.00;
@@ -159,211 +157,80 @@
VIBE_STATE_ASP,
};
-class DspMemChunk {
- private:
- std::unique_ptr<uint8_t[]> head;
- size_t bytes = 0;
- uint8_t waveformType;
- uint8_t *_current;
- const uint8_t *_max;
- uint32_t _cache = 0;
- int _cachebits = 0;
+static int min(int x, int y) {
+ return x < y ? x : y;
+}
- bool isEnd() const { return _current == _max; }
- int min(int x, int y) { return x < y ? x : y; }
+static int floatToUint16(float input, uint16_t *output, float scale, float min, float max) {
+ if (input < min || input > max)
+ return -ERANGE;
- int write(int nbits, uint32_t val) {
- int nwrite, i;
+ *output = roundf(input * scale);
+ return 0;
+}
- nwrite = min(24 - _cachebits, nbits);
- _cache <<= nwrite;
- _cache |= val >> (nbits - nwrite);
- _cachebits += nwrite;
- nbits -= nwrite;
+struct dspmem_chunk {
+ uint8_t *head;
+ uint8_t *current;
+ uint8_t *max;
+ int bytes;
- if (_cachebits == 24) {
- if (isEnd())
- return -ENOSPC;
-
- _cache &= 0xFFFFFF;
- for (i = 0; i < sizeof(_cache); i++, _cache <<= 8)
- *_current++ = (_cache & 0xFF000000) >> 24;
-
- bytes += sizeof(_cache);
- _cachebits = 0;
- }
-
- if (nbits)
- return write(nbits, val);
-
- return 0;
- }
-
- int fToU16(float input, uint16_t *output, float scale, float min, float max) {
- if (input < min || input > max)
- return -ERANGE;
-
- *output = roundf(input * scale);
- return 0;
- }
-
- void constructPwleSegment(uint16_t delay, uint16_t amplitude, uint16_t frequency, uint8_t flags,
- uint32_t vbemfTarget = 0) {
- write(16, delay);
- write(12, amplitude);
- write(12, frequency);
- /* feature flags to control the chirp, CLAB braking, back EMF amplitude regulation */
- write(8, (flags | 1) << 4);
- if (flags & PWLE_AMP_REG_BIT) {
- write(24, vbemfTarget); /* target back EMF voltage */
- }
- }
-
- public:
- uint8_t *front() const { return head.get(); }
- uint8_t type() const { return waveformType; }
- size_t size() const { return bytes; }
-
- DspMemChunk(uint8_t type, size_t size) : head(new uint8_t[size]{0x00}) {
- waveformType = type;
- _current = head.get();
- _max = _current + size;
-
- if (waveformType == WAVEFORM_COMPOSE) {
- write(8, 0); /* Padding */
- write(8, 0); /* nsections placeholder */
- write(8, 0); /* repeat */
- } else if (waveformType == WAVEFORM_PWLE) {
- write(24, 0); /* Waveform length placeholder */
- write(8, 0); /* Repeat */
- write(12, 0); /* Wait time between repeats */
- write(8, 0); /* nsections placeholder */
- } else {
- ALOGE("%s: Invalid type: %u", __func__, waveformType);
- }
- }
-
- int flush() {
- if (!_cachebits)
- return 0;
-
- return write(24 - _cachebits, 0);
- }
-
- int constructComposeSegment(uint32_t effectVolLevel, uint32_t effectIndex, uint8_t repeat,
- uint8_t flags, uint16_t nextEffectDelay) {
- if (waveformType != WAVEFORM_COMPOSE) {
- ALOGE("%s: Invalid type: %d", __func__, waveformType);
- return -EDOM;
- }
- if (effectVolLevel > 100 || effectIndex > WAVEFORM_MAX_PHYSICAL_INDEX) {
- ALOGE("%s: Invalid argument: %u, %u", __func__, effectVolLevel, effectIndex);
- return -EINVAL;
- }
- write(8, effectVolLevel); /* amplitude */
- write(8, effectIndex); /* index */
- write(8, repeat); /* repeat */
- write(8, flags); /* flags */
- write(16, nextEffectDelay); /* delay */
- return 0;
- }
-
- int constructActiveSegment(int duration, float amplitude, float frequency, bool chirp) {
- uint16_t delay = 0;
- uint16_t amp = 0;
- uint16_t freq = 0;
- uint8_t flags = 0x0;
- if (waveformType != WAVEFORM_PWLE) {
- ALOGE("%s: Invalid type: %d", __func__, waveformType);
- return -EDOM;
- }
- if ((fToU16(duration, &delay, 4, 0.0f, COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) < 0) ||
- (fToU16(amplitude, &, 2048, CS40L26_PWLE_LEVEL_MIN, CS40L26_PWLE_LEVEL_MAX) < 0) ||
- (fToU16(frequency, &freq, 4, PWLE_FREQUENCY_MIN_HZ, PWLE_FREQUENCY_MAX_HZ) < 0)) {
- ALOGE("%s: Invalid argument: %d, %f, %f", __func__, duration, amplitude, frequency);
- return -ERANGE;
- }
- if (chirp) {
- flags |= PWLE_CHIRP_BIT;
- }
- constructPwleSegment(delay, amp, freq, flags, 0 /*ignored*/);
- return 0;
- }
-
- int constructBrakingSegment(int duration, Braking brakingType) {
- uint16_t delay = 0;
- uint16_t freq = 0;
- uint8_t flags = 0x00;
- if (waveformType != WAVEFORM_PWLE) {
- ALOGE("%s: Invalid type: %d", __func__, waveformType);
- return -EDOM;
- }
- if (fToU16(duration, &delay, 4, 0.0f, COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) < 0) {
- ALOGE("%s: Invalid argument: %d", __func__, duration);
- return -ERANGE;
- }
- fToU16(PWLE_FREQUENCY_MIN_HZ, &freq, 4, PWLE_FREQUENCY_MIN_HZ, PWLE_FREQUENCY_MAX_HZ);
- if (static_cast<std::underlying_type<Braking>::type>(brakingType)) {
- flags |= PWLE_BRAKE_BIT;
- }
-
- constructPwleSegment(delay, 0 /*ignored*/, freq, flags, 0 /*ignored*/);
- return 0;
- }
-
- int updateWLength(uint32_t totalDuration) {
- uint8_t *f = front();
- if (f == nullptr) {
- ALOGE("%s: head does not exist!", __func__);
- return -ENOMEM;
- }
- if (waveformType != WAVEFORM_PWLE) {
- ALOGE("%s: Invalid type: %d", __func__, waveformType);
- return -EDOM;
- }
- if (totalDuration > 0x7FFFF) {
- ALOGE("%s: Invalid argument: %u", __func__, totalDuration);
- return -EINVAL;
- }
- totalDuration *= 8; /* Unit: 0.125 ms (since wlength played @ 8kHz). */
- totalDuration |=
- WT_LEN_CALCD; /* Bit 23 is for WT_LEN_CALCD; Bit 22 is for WT_INDEFINITE. */
- *(f + 0) = (totalDuration >> 24) & 0xFF;
- *(f + 1) = (totalDuration >> 16) & 0xFF;
- *(f + 2) = (totalDuration >> 8) & 0xFF;
- *(f + 3) = totalDuration & 0xFF;
- return 0;
- }
-
- int updateNSection(int segmentIdx) {
- uint8_t *f = front();
- if (f == nullptr) {
- ALOGE("%s: head does not exist!", __func__);
- return -ENOMEM;
- }
-
- if (waveformType == WAVEFORM_COMPOSE) {
- if (segmentIdx > COMPOSE_SIZE_MAX + 1 /*1st effect may have a delay*/) {
- ALOGE("%s: Invalid argument: %d", __func__, segmentIdx);
- return -EINVAL;
- }
- *(f + 2) = (0xFF & segmentIdx);
- } else if (waveformType == WAVEFORM_PWLE) {
- if (segmentIdx > COMPOSE_PWLE_SIZE_MAX_DEFAULT) {
- ALOGE("%s: Invalid argument: %d", __func__, segmentIdx);
- return -EINVAL;
- }
- *(f + 7) |= (0xF0 & segmentIdx) >> 4; /* Bit 4 to 7 */
- *(f + 9) |= (0x0F & segmentIdx) << 4; /* Bit 3 to 0 */
- } else {
- ALOGE("%s: Invalid type: %d", __func__, waveformType);
- return -EDOM;
- }
-
- return 0;
- }
+ uint32_t cache;
+ int cachebits;
};
+static dspmem_chunk *dspmem_chunk_create(void *data, int size) {
+ auto ch = new dspmem_chunk{
+ .head = reinterpret_cast<uint8_t *>(data),
+ .current = reinterpret_cast<uint8_t *>(data),
+ .max = reinterpret_cast<uint8_t *>(data) + size,
+ };
+
+ return ch;
+}
+
+static bool dspmem_chunk_end(struct dspmem_chunk *ch) {
+ return ch->current == ch->max;
+}
+
+static int dspmem_chunk_bytes(struct dspmem_chunk *ch) {
+ return ch->bytes;
+}
+
+static int dspmem_chunk_write(struct dspmem_chunk *ch, int nbits, uint32_t val) {
+ int nwrite, i;
+
+ nwrite = min(24 - ch->cachebits, nbits);
+ ch->cache <<= nwrite;
+ ch->cache |= val >> (nbits - nwrite);
+ ch->cachebits += nwrite;
+ nbits -= nwrite;
+
+ if (ch->cachebits == 24) {
+ if (dspmem_chunk_end(ch))
+ return -ENOSPC;
+
+ ch->cache &= 0xFFFFFF;
+ for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= 8)
+ *ch->current++ = (ch->cache & 0xFF000000) >> 24;
+
+ ch->bytes += sizeof(ch->cache);
+ ch->cachebits = 0;
+ }
+
+ if (nbits)
+ return dspmem_chunk_write(ch, nbits, val);
+
+ return 0;
+}
+
+static int dspmem_chunk_flush(struct dspmem_chunk *ch) {
+ if (!ch->cachebits)
+ return 0;
+
+ return dspmem_chunk_write(ch, 24 - ch->cachebits, 0);
+}
+
Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> hwCalDefault,
std::unique_ptr<HwApi> hwApiDual, std::unique_ptr<HwCal> hwCalDual,
std::unique_ptr<HwGPIO> hwgpio)
@@ -851,6 +718,9 @@
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);
+
if (composite.size() > COMPOSE_SIZE_MAX || composite.empty()) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
@@ -866,13 +736,15 @@
size = composite.size();
}
- DspMemChunk ch(WAVEFORM_COMPOSE, FF_CUSTOM_DATA_LEN_MAX_COMP);
- const uint8_t header_count = ch.size();
+ dspmem_chunk_write(ch, 8, 0); /* Padding */
+ dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & size)); /* nsections */
+ dspmem_chunk_write(ch, 8, 0); /* repeat */
+ uint8_t header_count = dspmem_chunk_bytes(ch);
/* Insert 1 section for a wait before the first effect. */
if (nextEffectDelay) {
- ch.constructComposeSegment(0 /*amplitude*/, 0 /*index*/, 0 /*repeat*/, 0 /*flags*/,
- nextEffectDelay /*delay*/);
+ dspmem_chunk_write(ch, 32, 0); /* amplitude, index, repeat & flags */
+ dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */
}
for (uint32_t i_curr = 0, i_next = 1; i_curr < composite.size(); i_curr++, i_next++) {
@@ -919,16 +791,14 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- ch.constructComposeSegment(effectVolLevel, effectIndex, 0 /*repeat*/, 0 /*flags*/,
- nextEffectDelay /*delay*/);
+ dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & effectVolLevel)); /* amplitude */
+ dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & effectIndex)); /* index */
+ dspmem_chunk_write(ch, 8, 0); /* repeat */
+ dspmem_chunk_write(ch, 8, 0); /* flags */
+ dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */
}
-
- ch.flush();
- if (ch.updateNSection(size) < 0) {
- ALOGE("%s: Failed to update the section count", __func__);
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- }
- if (header_count == ch.size()) {
+ dspmem_chunk_flush(ch);
+ if (header_count == dspmem_chunk_bytes(ch)) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
} else {
// Composition duration should be 0 to allow firmware to play the whole effect
@@ -936,12 +806,12 @@
if (mIsDual) {
mFfEffectsDual[WAVEFORM_COMPOSE].replay.length = 0;
}
- return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, &ch,
+ return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch,
callback);
}
}
-ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, const DspMemChunk *ch,
+ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem_chunk *ch,
const std::shared_ptr<IVibratorCallback> &callback) {
ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
@@ -956,28 +826,28 @@
if (ch) {
/* Upload OWT effect. */
- if (ch->front() == nullptr) {
+ if (ch->head == nullptr) {
ALOGE("Invalid OWT bank");
+ delete ch;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
-
- if (ch->type() != WAVEFORM_PWLE && ch->type() != WAVEFORM_COMPOSE) {
- ALOGE("Invalid OWT type");
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- }
- effectIndex = ch->type();
+ bool isPwle = (*reinterpret_cast<uint16_t *>(ch->head) != 0x0000);
+ effectIndex = isPwle ? WAVEFORM_PWLE : WAVEFORM_COMPOSE;
uint32_t freeBytes;
mHwApiDef->getOwtFreeSpace(&freeBytes);
- if (ch->size() > freeBytes) {
- ALOGE("Invalid OWT length: Effect %d: %zu > %d!", effectIndex, ch->size(), 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);
}
if (mIsDual) {
mHwApiDual->getOwtFreeSpace(&freeBytes);
- if (ch-> size() > freeBytes) {
+ if (dspmem_chunk_bytes(ch) > freeBytes) {
ALOGE("Invalid OWT length in flip: Effect %d: %d > %d!", effectIndex,
- ch-> size(), freeBytes);
+ dspmem_chunk_bytes(ch), freeBytes);
+ delete ch;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
}
@@ -990,17 +860,20 @@
ALOGD("Not dual haptics HAL and GPIO status fail");
}
- if (!mHwApiDef->uploadOwtEffect(mInputFd, ch->front(), ch->size(), &mFfEffects[effectIndex],
- &effectIndex, &errorStatus)) {
+ 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->front(), ch->size(),
+ 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) {
@@ -1217,6 +1090,69 @@
*index += 1;
}
+static void constructPwleSegment(dspmem_chunk *ch, uint16_t delay, uint16_t amplitude,
+ uint16_t frequency, uint8_t flags, uint32_t vbemfTarget = 0) {
+ dspmem_chunk_write(ch, 16, delay);
+ dspmem_chunk_write(ch, 12, amplitude);
+ dspmem_chunk_write(ch, 12, frequency);
+ /* feature flags to control the chirp, CLAB braking, back EMF amplitude regulation */
+ dspmem_chunk_write(ch, 8, (flags | 1) << 4);
+ if (flags & PWLE_AMP_REG_BIT) {
+ dspmem_chunk_write(ch, 24, vbemfTarget); /* target back EMF voltage */
+ }
+}
+
+static int constructActiveSegment(dspmem_chunk *ch, int duration, float amplitude, float frequency,
+ bool chirp) {
+ uint16_t delay = 0;
+ uint16_t amp = 0;
+ uint16_t freq = 0;
+ uint8_t flags = 0x0;
+ if ((floatToUint16(duration, &delay, 4, 0.0f, COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) < 0) ||
+ (floatToUint16(amplitude, &, 2048, CS40L26_PWLE_LEVEL_MIX, CS40L26_PWLE_LEVEL_MAX) <
+ 0) ||
+ (floatToUint16(frequency, &freq, 4, PWLE_FREQUENCY_MIN_HZ, PWLE_FREQUENCY_MAX_HZ) < 0)) {
+ ALOGE("Invalid argument: %d, %f, %f", duration, amplitude, frequency);
+ return -ERANGE;
+ }
+ if (chirp) {
+ flags |= PWLE_CHIRP_BIT;
+ }
+ constructPwleSegment(ch, delay, amp, freq, flags, 0 /*ignored*/);
+ return 0;
+}
+
+static int constructBrakingSegment(dspmem_chunk *ch, int duration, Braking brakingType) {
+ uint16_t delay = 0;
+ uint16_t freq = 0;
+ uint8_t flags = 0x00;
+ if (floatToUint16(duration, &delay, 4, 0.0f, COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) < 0) {
+ ALOGE("Invalid argument: %d", duration);
+ return -ERANGE;
+ }
+ floatToUint16(PWLE_FREQUENCY_MIN_HZ, &freq, 4, PWLE_FREQUENCY_MIN_HZ, PWLE_FREQUENCY_MAX_HZ);
+ if (static_cast<std::underlying_type<Braking>::type>(brakingType)) {
+ flags |= PWLE_BRAKE_BIT;
+ }
+
+ constructPwleSegment(ch, delay, 0 /*ignored*/, freq, flags, 0 /*ignored*/);
+ return 0;
+}
+
+static void updateWLength(dspmem_chunk *ch, uint32_t totalDuration) {
+ totalDuration *= 8; /* Unit: 0.125 ms (since wlength played @ 8kHz). */
+ totalDuration |= WT_LEN_CALCD; /* Bit 23 is for WT_LEN_CALCD; Bit 22 is for WT_INDEFINITE. */
+ *(ch->head + 0) = (totalDuration >> 24) & 0xFF;
+ *(ch->head + 1) = (totalDuration >> 16) & 0xFF;
+ *(ch->head + 2) = (totalDuration >> 8) & 0xFF;
+ *(ch->head + 3) = totalDuration & 0xFF;
+}
+
+static void updateNSection(dspmem_chunk *ch, int segmentIdx) {
+ *(ch->head + 7) |= (0xF0 & segmentIdx) >> 4; /* Bit 4 to 7 */
+ *(ch->head + 9) |= (0x0F & segmentIdx) << 4; /* Bit 3 to 0 */
+}
+
ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
const std::shared_ptr<IVibratorCallback> &callback) {
ATRACE_NAME("Vibrator::composePwle");
@@ -1241,9 +1177,15 @@
float prevEndAmplitude;
float prevEndFrequency;
resetPreviousEndAmplitudeEndFrequency(&prevEndAmplitude, &prevEndFrequency);
- DspMemChunk ch(WAVEFORM_PWLE, FF_CUSTOM_DATA_LEN_MAX_PWLE);
+ auto ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_PWLE]{0x00},
+ FF_CUSTOM_DATA_LEN_MAX_PWLE);
bool chirp = false;
+ dspmem_chunk_write(ch, 24, 0x000000); /* Waveform length placeholder */
+ dspmem_chunk_write(ch, 8, 0); /* Repeat */
+ dspmem_chunk_write(ch, 12, 0); /* Wait time between repeats */
+ dspmem_chunk_write(ch, 8, 0x00); /* nsections placeholder */
+
for (auto &e : composite) {
switch (e.getTag()) {
case PrimitivePwle::active: {
@@ -1273,8 +1215,8 @@
if (!((active.startAmplitude == prevEndAmplitude) &&
(active.startFrequency == prevEndFrequency))) {
- if (ch.constructActiveSegment(0, active.startAmplitude, active.startFrequency,
- false) < 0) {
+ if (constructActiveSegment(ch, 0, active.startAmplitude, active.startFrequency,
+ false) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
@@ -1283,8 +1225,8 @@
if (active.startFrequency != active.endFrequency) {
chirp = true;
}
- if (ch.constructActiveSegment(active.duration, active.endAmplitude,
- active.endFrequency, chirp) < 0) {
+ if (constructActiveSegment(ch, active.duration, active.endAmplitude,
+ active.endFrequency, chirp) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
@@ -1307,12 +1249,12 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- if (ch.constructBrakingSegment(0, braking.braking) < 0) {
+ if (constructBrakingSegment(ch, 0, braking.braking) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
- if (ch.constructBrakingSegment(braking.duration, braking.braking) < 0) {
+ if (constructBrakingSegment(ch, braking.duration, braking.braking) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
@@ -1328,7 +1270,7 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
}
- ch.flush();
+ dspmem_chunk_flush(ch);
/* Update wlength */
totalDuration += MAX_COLD_START_LATENCY_MS;
@@ -1336,19 +1278,12 @@
ALOGE("Total duration is too long (%d)!", totalDuration);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
-
- if (ch.updateWLength(totalDuration) < 0) {
- ALOGE("%s: Failed to update the waveform length length", __func__);
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- }
+ updateWLength(ch, totalDuration);
/* Update nsections */
- if (ch.updateNSection(segmentIdx) < 0) {
- ALOGE("%s: Failed to update the section count", __func__);
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- }
+ updateNSection(ch, segmentIdx);
- return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, &ch,
+ return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch,
callback);
}
@@ -1525,7 +1460,7 @@
}
ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
- uint32_t *outTimeMs, DspMemChunk *outCh) {
+ uint32_t *outTimeMs, dspmem_chunk *outCh) {
ndk::ScopedAStatus status;
uint32_t timeMs = 0;
uint32_t thisEffectIndex;
@@ -1533,14 +1468,23 @@
uint32_t thisVolLevel;
switch (effect) {
case Effect::DOUBLE_CLICK:
+ dspmem_chunk_write(outCh, 8, 0); /* Padding */
+ dspmem_chunk_write(outCh, 8, 2); /* nsections */
+ dspmem_chunk_write(outCh, 8, 0); /* repeat */
+
status = getSimpleDetails(Effect::CLICK, strength, &thisEffectIndex, &thisTimeMs,
&thisVolLevel);
if (!status.isOk()) {
return status;
}
timeMs += thisTimeMs;
- outCh->constructComposeSegment(thisVolLevel, thisEffectIndex, 0 /*repeat*/, 0 /*flags*/,
- WAVEFORM_DOUBLE_CLICK_SILENCE_MS);
+
+ dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisVolLevel)); /* amplitude */
+ dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisEffectIndex)); /* index */
+ dspmem_chunk_write(outCh, 8, 0); /* repeat */
+ dspmem_chunk_write(outCh, 8, 0); /* flags */
+ dspmem_chunk_write(outCh, 16,
+ (uint16_t)(0xFFFF & WAVEFORM_DOUBLE_CLICK_SILENCE_MS)); /* delay */
timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
@@ -1551,13 +1495,12 @@
}
timeMs += thisTimeMs;
- outCh->constructComposeSegment(thisVolLevel, thisEffectIndex, 0 /*repeat*/, 0 /*flags*/,
- 0 /*delay*/);
- outCh->flush();
- if (outCh->updateNSection(2) < 0) {
- ALOGE("%s: Failed to update the section count", __func__);
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- }
+ dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisVolLevel)); /* amplitude */
+ dspmem_chunk_write(outCh, 8, (uint8_t)(0xFF & thisEffectIndex)); /* index */
+ dspmem_chunk_write(outCh, 8, 0); /* repeat */
+ dspmem_chunk_write(outCh, 8, 0); /* flags */
+ dspmem_chunk_write(outCh, 16, 0); /* delay */
+ dspmem_chunk_flush(outCh);
break;
default:
@@ -1625,7 +1568,7 @@
uint32_t effectIndex;
uint32_t timeMs = 0;
uint32_t volLevel;
- std::optional<DspMemChunk> maybeCh;
+ dspmem_chunk *ch = nullptr;
switch (effect) {
case Effect::TEXTURE_TICK:
// fall-through
@@ -1637,25 +1580,28 @@
status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
break;
case Effect::DOUBLE_CLICK:
- maybeCh.emplace(WAVEFORM_COMPOSE, FF_CUSTOM_DATA_LEN_MAX_COMP);
- status = getCompoundDetails(effect, strength, &timeMs, &*maybeCh);
+ ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_COMP]{0x00},
+ FF_CUSTOM_DATA_LEN_MAX_COMP);
+ status = getCompoundDetails(effect, strength, &timeMs, ch);
volLevel = VOLTAGE_SCALE_MAX;
break;
default:
status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
break;
}
- if (status.isOk()) {
- DspMemChunk *ch = maybeCh ? &*maybeCh : nullptr;
- status = performEffect(effectIndex, volLevel, ch, callback);
+ if (!status.isOk()) {
+ goto exit;
}
+ status = performEffect(effectIndex, volLevel, ch, callback);
+
+exit:
*outTimeMs = timeMs;
return status;
}
ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
- const DspMemChunk *ch,
+ dspmem_chunk *ch,
const std::shared_ptr<IVibratorCallback> &callback) {
setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX);
diff --git a/vibrator/cs40l26/Vibrator.h b/vibrator/cs40l26/Vibrator.h
index 06bd6e5..5b1ff90 100644
--- a/vibrator/cs40l26/Vibrator.h
+++ b/vibrator/cs40l26/Vibrator.h
@@ -89,7 +89,7 @@
virtual bool setHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card,
int device) = 0;
// Set OWT waveform for compose or compose PWLE request
- virtual bool uploadOwtEffect(int fd, const uint8_t *owtData, const uint32_t numBytes,
+ virtual bool uploadOwtEffect(int fd, uint8_t *owtData, uint32_t numBytes,
struct ff_effect *effect, uint32_t *outEffectIndex,
int *status) = 0;
// Erase OWT waveform
@@ -178,7 +178,7 @@
static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; // SVC initialization time
private:
- ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, const class DspMemChunk *ch,
+ ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, struct dspmem_chunk *ch,
const std::shared_ptr<IVibratorCallback> &callback);
// set 'amplitude' based on an arbitrary scale determined by 'maximum'
ndk::ScopedAStatus setEffectAmplitude(float amplitude, float maximum);
@@ -189,13 +189,13 @@
uint32_t *outVolLevel);
// 'compound' effects are those composed by stringing multiple 'simple' effects
ndk::ScopedAStatus getCompoundDetails(Effect effect, EffectStrength strength,
- uint32_t *outTimeMs, class DspMemChunk *outCh);
+ uint32_t *outTimeMs, struct dspmem_chunk *outCh);
ndk::ScopedAStatus getPrimitiveDetails(CompositePrimitive primitive, uint32_t *outEffectIndex);
ndk::ScopedAStatus performEffect(Effect effect, EffectStrength strength,
const std::shared_ptr<IVibratorCallback> &callback,
int32_t *outTimeMs);
ndk::ScopedAStatus performEffect(uint32_t effectIndex, uint32_t volLevel,
- const class DspMemChunk *ch,
+ struct dspmem_chunk *ch,
const std::shared_ptr<IVibratorCallback> &callback);
ndk::ScopedAStatus setPwle(const std::string &pwleQueue);
bool isUnderExternalControl();
diff --git a/vibrator/cs40l26/tests/mocks.h b/vibrator/cs40l26/tests/mocks.h
index 641aba8..c85b0b5 100644
--- a/vibrator/cs40l26/tests/mocks.h
+++ b/vibrator/cs40l26/tests/mocks.h
@@ -51,7 +51,7 @@
MOCK_METHOD2(getHapticAlsaDevice, bool(int *card, int *device));
MOCK_METHOD4(setHapticPcmAmp, bool(struct pcm **haptic_pcm, bool enable, int card, int device));
MOCK_METHOD6(uploadOwtEffect,
- bool(int fd, const uint8_t *owtData, const uint32_t numBytes, struct ff_effect *effect,
+ 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<ff_effect> *effect));
MOCK_METHOD1(debug, void(int fd));