Android 15.0.0 Release 20 (BP1A.250305.019)

-----BEGIN PGP SIGNATURE-----
 
 iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZ8eo6gAKCRDorT+BmrEO
 eChJAKCAtiyGb/6641UG0H/a0uS9y0ltCQCfSmR94ePAO2Y4cvEy8jh+/wSrwac=
 =y5oH
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN SSH SIGNATURE-----
 U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgPpdpjxPACTIhnlvYz0GM4BR7FJ
 +rYv3jMbfxNKD3JvcAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
 AAAAQAVnJYkO0AMJEmrYOJ7pkipy7UOV05dOrkDRFt0Q90COzfpudNMFnRyT/dhLf/OUn/
 gE8jYUYlZvLZIsZ5wvEgY=
 -----END SSH SIGNATURE-----

Merge tag 'android-15.0.0_r20' into staging/lineage-22.2_merge-android-15.0.0_r20

Android 15.0.0 Release 20 (BP1A.250305.019)

# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZ8eo6gAKCRDorT+BmrEO
# eChJAKCAtiyGb/6641UG0H/a0uS9y0ltCQCfSmR94ePAO2Y4cvEy8jh+/wSrwac=
# =y5oH
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Mar  5 03:29:14 2025 EET
# gpg:                using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Good signature from "The Android Open Source Project <initial-contribution@android.com>" [ultimate]

# By Tai Kuo (5) and others
# Via Android Build Coastguard Worker (20) and others
* tag 'android-15.0.0_r20': (24 commits)
  modem_svc: use modem_svc_sit version sepolicy
  Revert "felix/haptics: Remove voltage restriction for haptics"
  felix/haptics: Remove voltage restriction for haptics
  Enable TAPreferHighCap for first frame
  Update F10 Bluetooth LEA unicast allowlist: Samsung Galaxy Buds 3 pro
  Disable Wifi BugReport for subsystem restart
  audio: fix cts AAudioTests failed on GSI image
  Update ISODEP routing setting
  Felix HAL: Fixed VibratorTest unit tests errors.
  cs40l26: add DBC bin info and reduce duplicates
  vibrator/cs40l26: update default scales of click, tick and long vib
  cs40l26: organize dump() AIDL section
  Add power profile config to reflect the presence of two displays
  Update OWNERS
  vibrator: correct debug() calibration file path
  modem_svc: use shared_modem_platform to replace all modem_svc_sit
  felix: Pull init.insmod.*.cfg from vendor_dlkm
  Move modem_svc_sit from gs201 to felix
  vibrator: Update location of PixelVibratorFlags
  gps: set default SUPL SSL method to SSLv23
  ...

Change-Id: I4da020f16b76d36569b0837e36d6a38ede64398c
This commit is contained in:
Michael Bestas 2025-03-09 11:05:16 +02:00
commit 656e2f203c
20 changed files with 267 additions and 116 deletions

View file

@ -59,7 +59,7 @@
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort> </mixPort>
<mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT" <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort> </mixPort>
<mixPort name="immersive_out" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER"> <mixPort name="immersive_out" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER">

View file

@ -59,7 +59,7 @@
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort> </mixPort>
<mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT" <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort> </mixPort>
<mixPort name="incall playback" role="source" <mixPort name="incall playback" role="source"

View file

@ -60,7 +60,7 @@
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort> </mixPort>
<mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT" <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort> </mixPort>
<mixPort name="immersive_out" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER"> <mixPort name="immersive_out" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER">

View file

@ -11,6 +11,7 @@
channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort> </mixPort>
<!-- Le Audio Audio Ports --> <!-- Le Audio Audio Ports -->
<mixPort name="le audio broadcast output" role="source" />
<mixPort name="le audio output" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER"> <mixPort name="le audio output" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT" <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="44100 48000" samplingRates="44100 48000"
@ -51,6 +52,7 @@
<devicePort tagName="BLE Headset Out" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"/> <devicePort tagName="BLE Headset Out" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"/>
<devicePort tagName="BLE Speaker Out" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"/> <devicePort tagName="BLE Speaker Out" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"/>
<devicePort tagName="BLE Headset In" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source"/> <devicePort tagName="BLE Headset In" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source"/>
<devicePort tagName="BLE Broadcast Out" type="AUDIO_DEVICE_OUT_BLE_BROADCAST" role="sink"/>
</devicePorts> </devicePorts>
<routes> <routes>
<route type="mix" sink="BT A2DP Out" <route type="mix" sink="BT A2DP Out"
@ -67,5 +69,7 @@
sources="BLE Headset In"/> sources="BLE Headset In"/>
<route type="mix" sink="BLE Speaker Out" <route type="mix" sink="BLE Speaker Out"
sources="le audio output"/> sources="le audio output"/>
<route type="mix" sink="BLE Broadcast Out"
sources="le audio broadcast output"/>
</routes> </routes>
</module> </module>

View file

@ -86,7 +86,7 @@ on early-boot
start insmod_sh_felix start insmod_sh_felix
chown system system /sys/class/power_supply/dualbatt/dbatt_stats chown system system /sys/class/power_supply/dualbatt/dbatt_stats
service insmod_sh_felix /vendor/bin/insmod.sh /vendor/etc/init.insmod.felix.cfg service insmod_sh_felix /vendor/bin/insmod.sh /vendor_dlkm/etc/init.insmod.felix.cfg
class main class main
user root user root
group root system group root system

View file

@ -41,8 +41,8 @@ $(call soong_config_set,fp_hal_feature,pixel_product, product_a)
include device/google/felix/vibrator/cs40l26/device.mk include device/google/felix/vibrator/cs40l26/device.mk
include device/google/gs-common/bcmbt/bluetooth.mk include device/google/gs-common/bcmbt/bluetooth.mk
include device/google/gs-common/display/dump_second_display.mk include device/google/gs-common/display/dump_second_display.mk
include device/google/gs-common/touch/gti/gti.mk include device/google/gs-common/touch/gti/predump_gti_dual.mk
include device/google/gs-common/touch/stm/stm6.mk include device/google/gs-common/touch/stm/predump_stm6.mk
ifeq ($(filter factory_felix, $(TARGET_PRODUCT)),) ifeq ($(filter factory_felix, $(TARGET_PRODUCT)),)
include device/google/felix/uwb/uwb_calibration.mk include device/google/felix/uwb/uwb_calibration.mk
endif endif
@ -60,9 +60,13 @@ PRODUCT_COPY_FILES += \
PRODUCT_COPY_FILES += \ PRODUCT_COPY_FILES += \
device/google/felix/conf/init.recovery.device.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.felix.rc device/google/felix/conf/init.recovery.device.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.felix.rc
# insmod files # insmod files. Kernel 5.10 prebuilts don't provide these yet, so provide our
# own copy if they're not in the prebuilts.
# TODO(b/369686096): drop this when 5.10 is gone.
ifeq ($(wildcard $(TARGET_KERNEL_DIR)/init.insmod.*.cfg),)
PRODUCT_COPY_FILES += \ PRODUCT_COPY_FILES += \
device/google/felix/init.insmod.felix.cfg:$(TARGET_COPY_OUT_VENDOR)/etc/init.insmod.felix.cfg device/google/felix/init.insmod.felix.cfg:$(TARGET_COPY_OUT_VENDOR_DLKM)/etc/init.insmod.felix.cfg
endif
# Camera # Camera
PRODUCT_COPY_FILES += \ PRODUCT_COPY_FILES += \
@ -108,6 +112,12 @@ PRODUCT_PACKAGES += \
android.hardware.nfc-service.st \ android.hardware.nfc-service.st \
NfcOverlayFelix NfcOverlayFelix
# Shared Modem Platform
SHARED_MODEM_PLATFORM_VENDOR := lassen
# Shared Modem Platform
include device/google/gs-common/modem/modem_svc_sit/shared_modem_platform.mk
# SecureElement # SecureElement
PRODUCT_PACKAGES += \ PRODUCT_PACKAGES += \
android.hardware.secure_element@1.2-service-gto \ android.hardware.secure_element@1.2-service-gto \
@ -423,7 +433,7 @@ PRODUCT_COPY_FILES += \
# LE Audio Unicast Allowlist # LE Audio Unicast Allowlist
PRODUCT_PRODUCT_PROPERTIES += \ PRODUCT_PRODUCT_PROPERTIES += \
persist.bluetooth.leaudio.allow_list=SM-R510,WF-1000XM5 persist.bluetooth.leaudio.allow_list=SM-R510,WF-1000XM5,SM-R630
# Bluetooth EWP test tool # Bluetooth EWP test tool
PRODUCT_PACKAGES_ENG += \ PRODUCT_PACKAGES_ENG += \

View file

@ -151,13 +151,17 @@
</array> </array>
<!-- Additional power used when screen is ambient mode --> <!-- Additional power used when screen is ambient mode -->
<item name="ambient.on">32</item> <item name="ambient.on.display0">32</item>
<item name="ambient.on.display1">32</item>
<!-- Additional power used when screen is turned on at minimum brightness --> <!-- Additional power used when screen is turned on at minimum brightness -->
<item name="screen.on">98</item> <item name="screen.on.display0">98</item>
<item name="screen.on.display1">98</item>
<!-- Additional power used when screen is at maximum brightness, compared to <!-- Additional power used when screen is at maximum brightness, compared to
screen at minimum brightness --> screen at minimum brightness -->
<item name="screen.full">470</item> <item name="screen.full.display0">470</item>
<item name="screen.full.display1">470</item>
<!-- Average power used by the camera flash module when on --> <!-- Average power used by the camera flash module when on -->
<item name="camera.flashlight">240.47</item> <item name="camera.flashlight">240.47</item>

View file

@ -135,7 +135,7 @@ OFFHOST_ROUTE_ESE={86}
# host 0x00 # host 0x00
# eSE 0x82 (eSE), 0x86 (eUICC/SPI-SE) # eSE 0x82 (eSE), 0x86 (eUICC/SPI-SE)
# UICC 0x81 (UICC_1), 0x85 (UICC_2) # UICC 0x81 (UICC_1), 0x85 (UICC_2)
DEFAULT_ISODEP_ROUTE=0x81 DEFAULT_ISODEP_ROUTE=0x00
############################################################################### ###############################################################################
# Configure the HAL Clock control # Configure the HAL Clock control

View file

@ -879,24 +879,30 @@
"Duration": 5000, "Duration": 5000,
"Value": "0" "Value": "0"
}, },
{
"PowerHint": "CPU_LOAD_RESET",
"Node": "GPUMinFreq",
"Duration": 50,
"Value": "302000"
},
{ {
"PowerHint": "DISPLAY_INACTIVE", "PowerHint": "DISPLAY_INACTIVE",
"Node": "MemFreq", "Node": "MemFreq",
"Duration": 0, "Duration": 0,
"Value": "421000" "Value": "421000"
}, },
{
"PowerHint": "CPU_LOAD_RESET",
"Node": "GPUMinFreq",
"Duration": 50,
"Value": "302000"
},
{ {
"PowerHint": "CPU_LOAD_RESET", "PowerHint": "CPU_LOAD_RESET",
"Node": "MemFreq", "Node": "MemFreq",
"Duration": 33, "Duration": 33,
"Value": "1014000" "Value": "1014000"
}, },
{
"PowerHint": "CPU_LOAD_RESET",
"Node": "TAPreferHighCap",
"Duration": 33,
"Value": "1"
},
{ {
"PowerHint": "CAMERA_LAUNCH", "PowerHint": "CAMERA_LAUNCH",
"Node": "MemFreq", "Node": "MemFreq",
@ -1107,6 +1113,18 @@
"Duration": 100, "Duration": 100,
"Value": "0" "Value": "0"
}, },
{
"PowerHint": "CAMERA_MULTICAM_BOOST",
"Node": "CDPreferIdle",
"Duration": 100,
"Value": "1"
},
{
"PowerHint": "CAMERA_MULTICAM_BOOST",
"Node": "PMU_POLL",
"Duration": 100,
"Value": "0"
},
{ {
"PowerHint": "GCA_CAMERA_SHOT_BIGCPU_RANK1", "PowerHint": "GCA_CAMERA_SHOT_BIGCPU_RANK1",
"Node": "TAPreferHighCap", "Node": "TAPreferHighCap",

View file

@ -175,4 +175,6 @@
false: firmware roaming will not be affected. --> false: firmware roaming will not be affected. -->
<bool translatable="false" name ="config_wifiDisableFirmwareRoamingInIdleMode">true</bool> <bool translatable="false" name ="config_wifiDisableFirmwareRoamingInIdleMode">true</bool>
<!-- Boolean indicating whether to trigger bugreport for WiFi subsystem restart issue -->
<bool translatable="false" name ="config_wifi_subsystem_restart_bugreport_enabled">false</bool>
</resources> </resources>

View file

@ -1 +1,3 @@
file:platform/hardware/google/pixel:/vibrator/OWNERS chrispaulo@google.com
nathankulczak@google.com
taikuo@google.com

View file

@ -69,6 +69,7 @@ HwCalBase::HwCalBase() {
std::ifstream calfile; std::ifstream calfile;
std::ifstream calfile_dual; std::ifstream calfile_dual;
auto propertyPrefix = std::getenv("PROPERTY_PREFIX"); auto propertyPrefix = std::getenv("PROPERTY_PREFIX");
auto calPath = std::getenv("CALIBRATION_FILEPATH");
if (propertyPrefix != NULL) { if (propertyPrefix != NULL) {
mPropertyPrefix = std::string(propertyPrefix); mPropertyPrefix = std::string(propertyPrefix);
@ -76,6 +77,14 @@ HwCalBase::HwCalBase() {
ALOGE("Failed get property prefix!"); ALOGE("Failed get property prefix!");
} }
// Keep the cal file path for the current HwCalBase instance.
if (calPath != NULL) {
mCalPath = std::string(calPath);
} else {
ALOGE("Failed get the calibration file path!");
}
// Read the cal data for the current instance.
utils::fileFromEnv("CALIBRATION_FILEPATH", &calfile); utils::fileFromEnv("CALIBRATION_FILEPATH", &calfile);
for (std::string line; std::getline(calfile, line);) { for (std::string line; std::getline(calfile, line);) {
@ -89,6 +98,7 @@ HwCalBase::HwCalBase() {
} }
} }
// Read the cal data for the other instance.
utils::fileFromEnv("CALIBRATION_FILEPATH_DUAL", &calfile_dual); utils::fileFromEnv("CALIBRATION_FILEPATH_DUAL", &calfile_dual);
for (std::string line; std::getline(calfile_dual, line);) { for (std::string line; std::getline(calfile_dual, line);) {
@ -106,7 +116,6 @@ HwCalBase::HwCalBase() {
void HwCalBase::debug(int fd) { void HwCalBase::debug(int fd) {
std::ifstream stream; std::ifstream stream;
std::string path;
std::string line; std::string line;
struct context { struct context {
HwCalBase *obj; HwCalBase *obj;
@ -133,9 +142,8 @@ void HwCalBase::debug(int fd) {
dprintf(fd, "Persist:\n"); dprintf(fd, "Persist:\n");
utils::fileFromEnv("CALIBRATION_FILEPATH", &stream, &path); utils::openNoCreate(mCalPath, &stream);
dprintf(fd, " %s:\n", mCalPath.c_str());
dprintf(fd, " %s:\n", path.c_str());
while (std::getline(stream, line)) { while (std::getline(stream, line)) {
dprintf(fd, " %s\n", line.c_str()); dprintf(fd, " %s\n", line.c_str());
} }

View file

@ -208,6 +208,7 @@ class HwCalBase {
private: private:
std::string mPropertyPrefix; std::string mPropertyPrefix;
std::string mCalPath;
std::map<std::string, std::string> mCalData; std::map<std::string, std::string> mCalData;
}; };

View file

@ -103,6 +103,19 @@ inline Enable_If_Unsigned<T, T> getProperty(const std::string &key, const T def)
return ::android::base::GetUintProperty(key, def); return ::android::base::GetUintProperty(key, def);
} }
template <typename T, size_t N>
inline std::array<T, N> getProperty(const std::string &key, const std::array<T, N> &def) {
std::string value = ::android::base::GetProperty(key, "");
if (!value.empty()) {
std::array<T, N> result{0};
std::stringstream stream{value};
utils::unpack(stream, &result);
if (stream && stream.eof())
return result;
}
return def;
}
template <> template <>
inline bool getProperty<bool>(const std::string &key, const bool def) { inline bool getProperty<bool>(const std::string &key, const bool def) {
return ::android::base::GetBoolProperty(key, def); return ::android::base::GetBoolProperty(key, def);

View file

@ -60,7 +60,7 @@ cc_library {
srcs: [ srcs: [
"Vibrator.cpp", "Vibrator.cpp",
], ],
shared_libs: ["//hardware/google/pixel:PixelVibratorFlagsL26"], shared_libs: ["//device/google/gs-common:PixelVibratorFlagsL26"],
export_include_dirs: ["."], export_include_dirs: ["."],
vendor_available: true, vendor_available: true,
visibility: [":__subpackages__"], visibility: [":__subpackages__"],

View file

@ -318,9 +318,9 @@ class HwCal : public Vibrator::HwCal, private HwCalBase {
static constexpr uint32_t VERSION_DEFAULT = 2; static constexpr uint32_t VERSION_DEFAULT = 2;
static constexpr int32_t DEFAULT_FREQUENCY_SHIFT = 0; static constexpr int32_t DEFAULT_FREQUENCY_SHIFT = 0;
static constexpr std::array<uint32_t, 2> V_TICK_DEFAULT = {1, 100}; static constexpr std::array<uint32_t, 2> V_TICK_DEFAULT = {5, 95};
static constexpr std::array<uint32_t, 2> V_CLICK_DEFAULT = {1, 100}; static constexpr std::array<uint32_t, 2> V_CLICK_DEFAULT = {5, 95};
static constexpr std::array<uint32_t, 2> V_LONG_DEFAULT = {1, 100}; static constexpr std::array<uint32_t, 2> V_LONG_DEFAULT = {5, 95};
public: public:
HwCal() {} HwCal() {}
@ -370,22 +370,19 @@ class HwCal : public Vibrator::HwCal, private HwCalBase {
if (getPersist(TICK_VOLTAGES_CONFIG, value)) { if (getPersist(TICK_VOLTAGES_CONFIG, value)) {
return true; return true;
} }
*value = V_TICK_DEFAULT; return getProperty(TICK_VOLTAGES_CONFIG, value, V_TICK_DEFAULT);
return true;
} }
bool getClickVolLevels(std::array<uint32_t, 2> *value) override { bool getClickVolLevels(std::array<uint32_t, 2> *value) override {
if (getPersist(CLICK_VOLTAGES_CONFIG, value)) { if (getPersist(CLICK_VOLTAGES_CONFIG, value)) {
return true; return true;
} }
*value = V_CLICK_DEFAULT; return getProperty(CLICK_VOLTAGES_CONFIG, value, V_CLICK_DEFAULT);
return true;
} }
bool getLongVolLevels(std::array<uint32_t, 2> *value) override { bool getLongVolLevels(std::array<uint32_t, 2> *value) override {
if (getPersist(LONG_VOLTAGES_CONFIG, value)) { if (getPersist(LONG_VOLTAGES_CONFIG, value)) {
return true; return true;
} }
*value = V_LONG_DEFAULT; return getProperty(LONG_VOLTAGES_CONFIG, value, V_LONG_DEFAULT);
return true;
} }
bool isChirpEnabled() override { bool isChirpEnabled() override {
return utils::getProperty("persist.vendor.vibrator.hal.chirp.enabled", false); return utils::getProperty("persist.vendor.vibrator.hal.chirp.enabled", false);

View file

@ -19,6 +19,7 @@
#include <glob.h> #include <glob.h>
#include <hardware/hardware.h> #include <hardware/hardware.h>
#include <hardware/vibrator.h> #include <hardware/vibrator.h>
#include <linux/version.h>
#include <log/log.h> #include <log/log.h>
#include <stdio.h> #include <stdio.h>
#include <utils/Trace.h> #include <utils/Trace.h>
@ -92,6 +93,30 @@ static constexpr uint8_t PWLE_CHIRP_BIT = 0x8; // Dynamic/static frequency and
static constexpr uint8_t PWLE_BRAKE_BIT = 0x4; static constexpr uint8_t PWLE_BRAKE_BIT = 0x4;
static constexpr uint8_t PWLE_AMP_REG_BIT = 0x2; static constexpr uint8_t PWLE_AMP_REG_BIT = 0x2;
static constexpr uint8_t PWLE_WT_TYPE = 12;
static constexpr uint8_t PWLE_HEADER_WORD_COUNT = 3;
static constexpr uint8_t PWLE_HEADER_FTR_SHIFT = 8;
static constexpr uint8_t PWLE_SVC_METADATA_WORD_COUNT = 3;
static constexpr uint32_t PWLE_SVC_METADATA_TERMINATOR = 0xFFFFFF;
static constexpr uint8_t PWLE_SEGMENT_WORD_COUNT = 2;
static constexpr uint8_t PWLE_HEADER_WCOUNT_WORD_OFFSET = 2;
static constexpr uint8_t PWLE_WORD_SIZE = sizeof(uint32_t);
static constexpr uint8_t PWLE_SVC_NO_BRAKING = -1;
static constexpr uint8_t PWLE_SVC_CAT_BRAKING = 0;
static constexpr uint8_t PWLE_SVC_OPEN_BRAKING = 1;
static constexpr uint8_t PWLE_SVC_CLOSED_BRAKING = 2;
static constexpr uint8_t PWLE_SVC_MIXED_BRAKING = 3;
static constexpr uint32_t PWLE_SVC_MAX_BRAKING_TIME_MS = 1000;
static constexpr uint8_t PWLE_FTR_BUZZ_BIT = 0x80;
static constexpr uint8_t PWLE_FTR_CLICK_BIT = 0x00;
static constexpr uint8_t PWLE_FTR_DYNAMIC_F0_BIT = 0x10;
static constexpr uint8_t PWLE_FTR_SVC_METADATA_BIT = 0x04;
static constexpr uint8_t PWLE_FTR_DVL_BIT = 0x02;
static constexpr uint8_t PWLE_FTR_LF0T_BIT = 0x01;
static constexpr float PWLE_LEVEL_MIN = 0.0; static constexpr float PWLE_LEVEL_MIN = 0.0;
static constexpr float PWLE_LEVEL_MAX = 1.0; static constexpr float PWLE_LEVEL_MAX = 1.0;
static constexpr float CS40L26_PWLE_LEVEL_MIN = -1.0; static constexpr float CS40L26_PWLE_LEVEL_MIN = -1.0;
@ -170,6 +195,8 @@ enum vibe_state {
VIBE_STATE_ASP, VIBE_STATE_ASP,
}; };
std::mutex mActiveId_mutex; // protects mActiveId
class DspMemChunk { class DspMemChunk {
private: private:
std::unique_ptr<uint8_t[]> head; std::unique_ptr<uint8_t[]> head;
@ -245,10 +272,18 @@ class DspMemChunk {
write(8, 0); /* nsections placeholder */ write(8, 0); /* nsections placeholder */
write(8, 0); /* repeat */ write(8, 0); /* repeat */
} else if (waveformType == WAVEFORM_PWLE) { } else if (waveformType == WAVEFORM_PWLE) {
write(16, (PWLE_FTR_BUZZ_BIT | PWLE_FTR_DVL_BIT)
<< PWLE_HEADER_FTR_SHIFT); /* Feature flag */
write(8, PWLE_WT_TYPE); /* type12 */
write(24, PWLE_HEADER_WORD_COUNT); /* Header word count */
write(24, 0); /* Body word count placeholder */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
write(24, 0); /* Waveform length placeholder */ write(24, 0); /* Waveform length placeholder */
write(8, 0); /* Repeat */ write(8, 0); /* Repeat */
write(12, 0); /* Wait time between repeats */ write(12, 0); /* Wait time between repeats */
write(8, 0); /* nsections placeholder */ write(8, 0); /* nsections placeholder */
#endif
} else { } else {
ALOGE("%s: Invalid type: %u", __func__, waveformType); ALOGE("%s: Invalid type: %u", __func__, waveformType);
} }
@ -336,6 +371,9 @@ class DspMemChunk {
ALOGE("%s: Invalid argument: %u", __func__, totalDuration); ALOGE("%s: Invalid argument: %u", __func__, totalDuration);
return -EINVAL; return -EINVAL;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
f += PWLE_HEADER_WORD_COUNT * PWLE_WORD_SIZE;
#endif
totalDuration *= 8; /* Unit: 0.125 ms (since wlength played @ 8kHz). */ totalDuration *= 8; /* Unit: 0.125 ms (since wlength played @ 8kHz). */
totalDuration |= totalDuration |=
WT_LEN_CALCD; /* Bit 23 is for WT_LEN_CALCD; Bit 22 is for WT_INDEFINITE. */ WT_LEN_CALCD; /* Bit 23 is for WT_LEN_CALCD; Bit 22 is for WT_INDEFINITE. */
@ -364,6 +402,9 @@ class DspMemChunk {
ALOGE("%s: Invalid argument: %d", __func__, segmentIdx); ALOGE("%s: Invalid argument: %d", __func__, segmentIdx);
return -EINVAL; return -EINVAL;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
f += PWLE_HEADER_WORD_COUNT * PWLE_WORD_SIZE;
#endif
*(f + 7) |= (0xF0 & segmentIdx) >> 4; /* Bit 4 to 7 */ *(f + 7) |= (0xF0 & segmentIdx) >> 4; /* Bit 4 to 7 */
*(f + 9) |= (0x0F & segmentIdx) << 4; /* Bit 3 to 0 */ *(f + 9) |= (0x0F & segmentIdx) << 4; /* Bit 3 to 0 */
} else { } else {
@ -373,6 +414,34 @@ class DspMemChunk {
return 0; return 0;
} }
int updateWCount(int segmentCount) {
uint8_t *f = front();
if (segmentCount > COMPOSE_SIZE_MAX + 1 /*1st effect may have a delay*/) {
ALOGE("%s: Invalid argument: %d", __func__, segmentCount);
return -EINVAL;
}
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 LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
f += PWLE_HEADER_WORD_COUNT * PWLE_WORD_SIZE;
#endif
uint32_t dataSize = segmentCount * PWLE_SEGMENT_WORD_COUNT + PWLE_HEADER_WORD_COUNT;
*(f + 0) = (dataSize >> 24) & 0xFF;
*(f + 1) = (dataSize >> 16) & 0xFF;
*(f + 2) = (dataSize >> 8) & 0xFF;
*(f + 3) = dataSize & 0xFF;
return 0;
}
}; };
Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> hwCalDefault, Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> hwCalDefault,
@ -1014,7 +1083,7 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, const
if (mIsDual) { if (mIsDual) {
mHwApiDual->getOwtFreeSpace(&freeBytes); mHwApiDual->getOwtFreeSpace(&freeBytes);
if (ch-> size() > freeBytes) { if (ch-> size() > freeBytes) {
ALOGE("Invalid OWT length in flip: Effect %d: %d > %d!", effectIndex, ALOGE("Invalid OWT length in flip: Effect %d: %zu > %d!", effectIndex,
ch-> size(), freeBytes); ch-> size(), freeBytes);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
} }
@ -1370,6 +1439,13 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
} }
/* Update word count */
if (ch.updateWCount(segmentIdx) < 0) {
ALOGE("%s: Failed to update the waveform word count", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
/* Update waveform length */
if (ch.updateWLength(totalDuration) < 0) { if (ch.updateWLength(totalDuration) < 0) {
ALOGE("%s: Failed to update the waveform length length", __func__); ALOGE("%s: Failed to update the waveform length length", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@ -1415,33 +1491,24 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mLongEffectVol[0], dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mLongEffectVol[0],
mLongEffectVol[1]); mLongEffectVol[1]);
dprintf(fd, " FF effect:\n");
dprintf(fd, " Physical waveform:\n");
dprintf(fd, "==== Base ====\n\tId\tIndex\tt ->\tt'\tBrake\ttrigger button\n");
uint8_t effectId; uint8_t effectId;
dprintf(fd, " Scales\n");
dprintf(fd, "\tId\tMinScale\tMaxScale\n");
for (effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) {
dprintf(fd, "\t%d\t%d\t\t%d\n", effectId, mPrimitiveMinScale[effectId],
mPrimitiveMaxScale[effectId]);
}
dprintf(fd, " Base FF effect:\n");
dprintf(fd, " Physical waveform:\n");
dprintf(fd, "\tId\tIndex\tt ->\tt'\tBrake\ttrigger button\n");
for (effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) { for (effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) {
dprintf(fd, "\t%d\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].u.periodic.custom_data[1], mEffectDurations[effectId],
mFfEffects[effectId].replay.length, mEffectBrakingDurations[effectId], mFfEffects[effectId].replay.length, mEffectBrakingDurations[effectId],
mFfEffects[effectId].trigger.button); mFfEffects[effectId].trigger.button);
} }
if (mIsDual) { dprintf(fd, " OWT waveform:\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%d\t%X\n", mFfEffectsDual[effectId].id,
mFfEffectsDual[effectId].u.periodic.custom_data[1], mEffectDurations[effectId],
mFfEffectsDual[effectId].replay.length, mEffectBrakingDurations[effectId],
mFfEffectsDual[effectId].trigger.button);
}
}
dprintf(fd, "==== Scales ====\n\tId\tMinScale\tMaxScale\n");
for (effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) {
dprintf(fd, "\t%d\t%d\t\t%d\n", effectId, mPrimitiveMinScale[effectId],
mPrimitiveMaxScale[effectId]);
}
dprintf(fd, "\nBase: OWT waveform:\n");
dprintf(fd, "\tId\tBytes\tData\tt\ttrigger button\n"); dprintf(fd, "\tId\tBytes\tData\tt\ttrigger button\n");
for (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; uint32_t numBytes = mFfEffects[effectId].u.periodic.custom_len * 2;
@ -1457,8 +1524,18 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
dprintf(fd, "\t%d\t%d\t{%s}\t%u\t%X\n", mFfEffects[effectId].id, numBytes, ss.str().c_str(), dprintf(fd, "\t%d\t%d\t{%s}\t%u\t%X\n", mFfEffects[effectId].id, numBytes, ss.str().c_str(),
mFfEffectsDual[effectId].replay.length, mFfEffects[effectId].trigger.button); mFfEffectsDual[effectId].replay.length, mFfEffects[effectId].trigger.button);
} }
if (mIsDual) { if (mIsDual) {
dprintf(fd, "Flip: OWT waveform:\n"); dprintf(fd, " Flip FF effect:\n");
dprintf(fd, " Physical waveform:\n");
dprintf(fd, "\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%d\t%X\n", mFfEffectsDual[effectId].id,
mFfEffectsDual[effectId].u.periodic.custom_data[1], mEffectDurations[effectId],
mFfEffectsDual[effectId].replay.length, mEffectBrakingDurations[effectId],
mFfEffectsDual[effectId].trigger.button);
}
dprintf(fd, " OWT waveform:\n");
dprintf(fd, "\tId\tBytes\tData\tt\ttrigger button\n"); dprintf(fd, "\tId\tBytes\tData\tt\ttrigger button\n");
for (effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; effectId++) { for (effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; effectId++) {
uint32_t numBytes = mFfEffectsDual[effectId].u.periodic.custom_len * 2; uint32_t numBytes = mFfEffectsDual[effectId].u.periodic.custom_len * 2;
@ -1479,78 +1556,67 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) {
dprintf(fd, "\n"); dprintf(fd, "\n");
dprintf(fd, "Versions:\n"); dprintf(fd, "Versions:\n");
const std::vector<std::pair<std::string, std::string>> moduleFolderNames = {
{"cs40l26_core", "Haptics"}, {"cl_dsp_core", "DSP"}};
const std::string firmwareFolder = "/vendor/firmware/";
const std::string waveformName = "cs40l26.bin";
const std::array<std::string, 2> firmwareFileNames = {"cs40l26.wmfw", "cs40l26-calib.wmfw"};
const std::array<std::string, 4> tuningFileNames = {"cs40l26-svc.bin", "cs40l26-calib.bin",
"cs40l26-dvl.bin", "cs40l26-dbc.bin"};
std::ifstream verFile; std::ifstream verFile;
const auto verBinFileMode = std::ifstream::in | std::ifstream::binary; const auto verBinFileMode = std::ifstream::in | std::ifstream::binary;
std::string ver; std::string ver;
verFile.open("/sys/module/cs40l26_core/version"); for (const auto &[folder, logTag] : moduleFolderNames) {
verFile.open("/sys/module/" + folder + "/version");
if (verFile.is_open()) { if (verFile.is_open()) {
getline(verFile, ver); getline(verFile, ver);
dprintf(fd, " Haptics Driver: %s\n", ver.c_str()); dprintf(fd, " %s Driver: %s\n", logTag.c_str(), ver.c_str());
verFile.close(); verFile.close();
} }
verFile.open("/sys/module/cl_dsp_core/version");
if (verFile.is_open()) {
getline(verFile, ver);
dprintf(fd, " DSP Driver: %s\n", ver.c_str());
verFile.close();
} }
verFile.open("/vendor/firmware/cs40l26.wmfw", verBinFileMode); for (auto &name : firmwareFileNames) {
verFile.open(firmwareFolder + name, verBinFileMode);
if (verFile.is_open()) { if (verFile.is_open()) {
verFile.seekg(113); verFile.seekg(113);
dprintf(fd, " cs40l26.wmfw: %d.%d.%d\n", verFile.get(), verFile.get(), verFile.get()); dprintf(fd, " %s: %d.%d.%d\n", name.c_str(), verFile.get(), verFile.get(),
verFile.close();
}
verFile.open("/vendor/firmware/cs40l26-calib.wmfw", verBinFileMode);
if (verFile.is_open()) {
verFile.seekg(113);
dprintf(fd, " cs40l26-calib.wmfw: %d.%d.%d\n", verFile.get(), verFile.get(),
verFile.get()); verFile.get());
verFile.close(); verFile.close();
} }
verFile.open("/vendor/firmware/cs40l26.bin", verBinFileMode); }
verFile.open(firmwareFolder + waveformName, verBinFileMode);
if (verFile.is_open()) { if (verFile.is_open()) {
while (getline(verFile, ver)) { while (getline(verFile, ver)) {
auto pos = ver.find("Date: "); auto pos = ver.find("Date: ");
if (pos != std::string::npos) { if (pos != std::string::npos) {
ver = ver.substr(pos + 6, pos + 15); ver = ver.substr(pos + 6, pos + 15);
dprintf(fd, " cs40l26.bin: %s\n", ver.c_str()); dprintf(fd, " %s: %s\n", waveformName.c_str(), ver.c_str());
break; break;
} }
} }
verFile.close(); verFile.close();
} }
verFile.open("/vendor/firmware/cs40l26-svc.bin", verBinFileMode); for (auto &name : tuningFileNames) {
verFile.open(firmwareFolder + name, verBinFileMode);
if (verFile.is_open()) { if (verFile.is_open()) {
verFile.seekg(36); verFile.seekg(36);
getline(verFile, ver); getline(verFile, ver);
ver = ver.substr(0, ver.find(".bin") + 4);
ver = ver.substr(ver.rfind('\\') + 1); ver = ver.substr(ver.rfind('\\') + 1);
dprintf(fd, " cs40l26-svc.bin: %s\n", ver.c_str()); dprintf(fd, " %s: %s\n", name.c_str(), ver.c_str());
verFile.close(); verFile.close();
} }
verFile.open("/vendor/firmware/cs40l26-calib.bin", verBinFileMode);
if (verFile.is_open()) {
verFile.seekg(36);
getline(verFile, ver);
ver = ver.substr(ver.rfind('\\') + 1);
dprintf(fd, " cs40l26-calib.bin: %s\n", ver.c_str());
verFile.close();
}
verFile.open("/vendor/firmware/cs40l26-dvl.bin", verBinFileMode);
if (verFile.is_open()) {
verFile.seekg(36);
getline(verFile, ver);
ver = ver.substr(0, ver.find('\0') + 1);
ver = ver.substr(ver.rfind('\\') + 1);
dprintf(fd, " cs40l26-dvl.bin: %s\n", ver.c_str());
verFile.close();
} }
dprintf(fd, "\n");
mHwApiDef->debug(fd); mHwApiDef->debug(fd);
dprintf(fd, "\n"); dprintf(fd, "\n");
mHwCalDef->debug(fd); mHwCalDef->debug(fd);
dprintf(fd, "\n");
if (mIsDual) { if (mIsDual) {
mHwApiDual->debug(fd); mHwApiDual->debug(fd);
dprintf(fd, "\n"); dprintf(fd, "\n");
@ -1856,7 +1922,6 @@ uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) {
volLevel = calc(intensity, mClickEffectVol); volLevel = calc(intensity, mClickEffectVol);
break; break;
} }
// The waveform being played must fall within the allowable scale range // The waveform being played must fall within the allowable scale range
if (effectIndex < WAVEFORM_MAX_INDEX) { if (effectIndex < WAVEFORM_MAX_INDEX) {
if (volLevel > mPrimitiveMaxScale[effectIndex]) { if (volLevel > mPrimitiveMaxScale[effectIndex]) {

View file

@ -250,7 +250,6 @@ class Vibrator : public BnVibrator {
bool mConfigHapticAlsaDeviceDone{false}; bool mConfigHapticAlsaDeviceDone{false};
bool mGPIOStatus; bool mGPIOStatus;
bool mIsDual{false}; bool mIsDual{false};
std::mutex mActiveId_mutex; // protects mActiveId
}; };
} // namespace vibrator } // namespace vibrator

View file

@ -30,9 +30,9 @@ using ::testing::Test;
class HwCalTest : public Test { class HwCalTest : public Test {
protected: protected:
static constexpr std::array<uint32_t, 2> V_TICK_DEFAULT = {1, 100}; static constexpr std::array<uint32_t, 2> V_TICK_DEFAULT = {5, 95};
static constexpr std::array<uint32_t, 2> V_CLICK_DEFAULT = {1, 100}; static constexpr std::array<uint32_t, 2> V_CLICK_DEFAULT = {5, 95};
static constexpr std::array<uint32_t, 2> V_LONG_DEFAULT = {1, 100}; static constexpr std::array<uint32_t, 2> V_LONG_DEFAULT = {5, 95};
public: public:
void SetUp() override { setenv("CALIBRATION_FILEPATH", mCalFile.path, true); } void SetUp() override { setenv("CALIBRATION_FILEPATH", mCalFile.path, true); }

View file

@ -87,7 +87,7 @@ static const std::map<Effect, EffectIndex> EFFECT_INDEX{
static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500;
static constexpr uint8_t VOLTAGE_SCALE_MAX = 100; static constexpr uint8_t VOLTAGE_SCALE_MAX = 100;
static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby
static constexpr auto POLLING_TIMEOUT = 20; static constexpr auto POLLING_TIMEOUT = 50;
enum WaveformIndex : uint16_t { enum WaveformIndex : uint16_t {
/* Physical waveform */ /* Physical waveform */
WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0, WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0,
@ -506,6 +506,23 @@ TEST_P(EffectsTest, perform) {
promise.set_value(); promise.set_value();
return ndk::ScopedAStatus::ok(); return ndk::ScopedAStatus::ok();
}; };
std::vector<uint32_t> primitiveMaxScale;
std::vector<uint32_t> primitiveMinScale;
primitiveMaxScale.resize(WAVEFORM_MAX_INDEX, 100);
primitiveMaxScale[WAVEFORM_CLICK_INDEX] = 95;
primitiveMaxScale[WAVEFORM_THUD_INDEX] = 75;
primitiveMaxScale[WAVEFORM_SPIN_INDEX] = 90;
primitiveMaxScale[WAVEFORM_LIGHT_TICK_INDEX] = 75;
primitiveMaxScale[WAVEFORM_LOW_TICK_INDEX] = 75;
primitiveMinScale.resize(WAVEFORM_MAX_INDEX, 0);
primitiveMinScale[WAVEFORM_CLICK_INDEX] = 1;
primitiveMinScale[WAVEFORM_THUD_INDEX] = 11;
primitiveMinScale[WAVEFORM_SPIN_INDEX] = 23;
primitiveMinScale[WAVEFORM_SLOW_RISE_INDEX] = 25;
primitiveMinScale[WAVEFORM_QUICK_FALL_INDEX] = 2;
primitiveMinScale[WAVEFORM_LIGHT_TICK_INDEX] = 3;
primitiveMinScale[WAVEFORM_LOW_TICK_INDEX] = 16;
bool composeEffect; bool composeEffect;
ExpectationSet eSetup; ExpectationSet eSetup;
@ -515,7 +532,18 @@ TEST_P(EffectsTest, perform) {
EffectIndex index = EFFECT_INDEX.at(effect); EffectIndex index = EFFECT_INDEX.at(effect);
duration = EFFECT_DURATIONS[index]; duration = EFFECT_DURATIONS[index];
eSetup += EXPECT_CALL(*mMockApi, setFFGain(_, levelToScale(scale->second))) auto updatedScale = levelToScale(scale->second);
if (index < WAVEFORM_MAX_INDEX) {
if (updatedScale > primitiveMaxScale[index]) {
updatedScale = primitiveMaxScale[index];
}
if (updatedScale < primitiveMinScale[index]) {
updatedScale = primitiveMinScale[index];
}
}
eSetup += EXPECT_CALL(*mMockApi, setFFGain(_, updatedScale))
.WillOnce(DoDefault()); .WillOnce(DoDefault());
eActivate = EXPECT_CALL(*mMockApi, setFFPlay(_, index, true)) eActivate = EXPECT_CALL(*mMockApi, setFFPlay(_, index, true))
.After(eSetup) .After(eSetup)