Switch makefile owners to MK_OWNERS am: 5537f0189d am: 3353815bc3
Original change: https://android-review.googlesource.com/c/device/google/felix/+/3107247
Change-Id: Ieecb018967c147ad3fcd822359d93ed0e358123c
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/audio/felix/aidl_config/mixer_paths_aidl.xml b/audio/felix/aidl_config/mixer_paths_aidl.xml
index d44e685..d71c0bf 100644
--- a/audio/felix/aidl_config/mixer_paths_aidl.xml
+++ b/audio/felix/aidl_config/mixer_paths_aidl.xml
@@ -1344,7 +1344,7 @@
<path name="bluetooth-sco-headset-microphones" />
</path>
- <path name="usb-headset-microphones">
+ <path name="usb-microphones">
<ctl name="BUILDIN MIC ID CAPTURE LIST" id="0" value="0" />
<ctl name="BUILDIN MIC ID CAPTURE LIST" id="1" value="3" />
<ctl name="BUILDIN MIC ID CAPTURE LIST" id="2" value="2" />
@@ -1354,6 +1354,15 @@
<ctl name="MIC Record Soft Gain (dB)" value="0" />
</path>
+ <path name="usb-headset-microphones">
+ <path name="usb-microphones" />
+ </path>
+
+ <path name="usb-device-microphones">
+ <path name="usb-microphones" />
+ </path>
+
+
<!-- cs35l41 specific path to load firmware in cs35l41.c -->
<path name="cs35l41-load-protection-firmware-start">
<!-- Enable it after get the protection firmware -->
diff --git a/bluetooth/bt_vendor_overlay.conf b/bluetooth/bt_vendor_overlay.conf
index 5685ae7..b7b419b 100644
--- a/bluetooth/bt_vendor_overlay.conf
+++ b/bluetooth/bt_vendor_overlay.conf
@@ -3,4 +3,7 @@
# Uart port name
UartPort = /dev/ttySAC18
+# Update BQR Event Mask property value
+BqrEventMaskValueUpdate = 262238
+
BtOpusEnabled = true
diff --git a/device-felix.mk b/device-felix.mk
index 1166a1f..199e2c9 100644
--- a/device-felix.mk
+++ b/device-felix.mk
@@ -17,18 +17,12 @@
# Restrict the visibility of Android.bp files to improve build analysis time
$(call inherit-product-if-exists, vendor/google/products/sources_pixel.mk)
-TARGET_KERNEL_DIR ?= device/google/felix-kernel
-TARGET_BOARD_KERNEL_HEADERS := device/google/felix-kernel/kernel-headers
TARGET_RECOVERY_DEFAULT_ROTATION := ROTATION_RIGHT
-ifdef RELEASE_GOOGLE_FELIX_KERNEL_VERSION
-TARGET_LINUX_KERNEL_VERSION := $(RELEASE_GOOGLE_FELIX_KERNEL_VERSION)
-endif
-
-ifdef RELEASE_GOOGLE_FELIX_KERNEL_DIR
-TARGET_KERNEL_DIR := $(RELEASE_GOOGLE_FELIX_KERNEL_DIR)
-TARGET_BOARD_KERNEL_HEADERS := $(RELEASE_GOOGLE_FELIX_KERNEL_DIR)/kernel-headers
-endif
+TARGET_LINUX_KERNEL_VERSION := $(RELEASE_KERNEL_FELIX_VERSION)
+# Keeps flexibility for kasan and ufs builds
+TARGET_KERNEL_DIR ?= $(RELEASE_KERNEL_FELIX_DIR)
+TARGET_BOARD_KERNEL_HEADERS ?= $(RELEASE_KERNEL_FELIX_DIR)/kernel-headers
$(call inherit-product-if-exists, vendor/google_devices/felix/prebuilts/device-vendor-felix.mk)
$(call inherit-product-if-exists, vendor/google_devices/gs201/prebuilts/device-vendor.mk)
@@ -146,6 +140,10 @@
persist.bluetooth.a2dp_offload.disabled=false \
persist.bluetooth.a2dp_offload.cap=sbc-aac-aptx-aptxhd-ldac-opus
+# Enable Bluetooth AutoOn feature
+PRODUCT_PRODUCT_PROPERTIES += \
+ bluetooth.server.automatic_turn_on=true
+
# Bluetooth Tx power caps
PRODUCT_COPY_FILES += \
device/google/felix/bluetooth/bluetooth_power_limits_felix_US.csv:$(TARGET_COPY_OUT_VENDOR)/etc/bluetooth_power_limits.csv \
@@ -220,9 +218,10 @@
# Increment the SVN for any official public releases
PRODUCT_VENDOR_PROPERTIES += \
- ro.vendor.build.svn=43
+ ro.vendor.build.svn=52
# Vibrator HAL
+$(call soong_config_set,haptics,kernel_ver,v$(subst .,_,$(TARGET_LINUX_KERNEL_VERSION)))
PRODUCT_VENDOR_PROPERTIES +=\
ro.vendor.vibrator.hal.long.frequency.shift=0 \
ro.vendor.vibrator.hal.gpio.num=44 \
@@ -264,13 +263,6 @@
# Trusty liboemcrypto.so
PRODUCT_SOONG_NAMESPACES += vendor/google_devices/felix/prebuilts
-ifneq (,$(filter AP1%,$(RELEASE_PLATFORM_VERSION)))
-PRODUCT_SOONG_NAMESPACES += vendor/google_devices/felix/prebuilts/trusty/24Q1
-else ifneq (,$(filter AP2% AP3%,$(RELEASE_PLATFORM_VERSION)))
-PRODUCT_SOONG_NAMESPACES += vendor/google_devices/felix/prebuilts/trusty/24Q2
-else
-PRODUCT_SOONG_NAMESPACES += vendor/google_devices/felix/prebuilts/trusty/trunk
-endif
# Set zram size
PRODUCT_VENDOR_PROPERTIES += \
diff --git a/device_framework_matrix_product_felix.xml b/device_framework_matrix_product_felix.xml
index 90ef723..3fd94a9 100644
--- a/device_framework_matrix_product_felix.xml
+++ b/device_framework_matrix_product_felix.xml
@@ -1,7 +1,7 @@
<compatibility-matrix version="1.0" type="framework" level="7">
<hal format="aidl" optional="true">
<name>com.google.hardware.pixel.display</name>
- <version>10</version>
+ <version>11-12</version>
<interface>
<name>IDisplay</name>
<instance>secondary</instance>
diff --git a/felix/BoardConfig.mk b/felix/BoardConfig.mk
index a1ed5db..fdd4c79 100644
--- a/felix/BoardConfig.mk
+++ b/felix/BoardConfig.mk
@@ -21,18 +21,15 @@
BOARD_KERNEL_CMDLINE += swiotlb=noforce
RELEASE_GOOGLE_PRODUCT_RADIO_DIR := $(RELEASE_GOOGLE_FELIX_RADIO_DIR)
-ifneq (,$(filter AP1%,$(RELEASE_PLATFORM_VERSION)))
-RELEASE_GOOGLE_PRODUCT_BOOTLOADER_DIR := bootloader/24Q1
-else ifneq (,$(filter AP2% AP3%,$(RELEASE_PLATFORM_VERSION)))
-RELEASE_GOOGLE_PRODUCT_BOOTLOADER_DIR := bootloader/24Q2
-else
-RELEASE_GOOGLE_PRODUCT_BOOTLOADER_DIR := bootloader/trunk
-endif
+RELEASE_GOOGLE_BOOTLOADER_FELIX_DIR ?= pdk# Keep this for pdk TODO: b/327119000
+RELEASE_GOOGLE_PRODUCT_BOOTLOADER_DIR := bootloader/$(RELEASE_GOOGLE_BOOTLOADER_FELIX_DIR)
+$(call soong_config_set,felix_bootloader,prebuilt_dir,$(RELEASE_GOOGLE_BOOTLOADER_FELIX_DIR))
# Enable load module in parallel
BOARD_BOOTCONFIG += androidboot.load_modules_parallel=true
# The modules which need to be loaded in sequential
+BOARD_KERNEL_CMDLINE += fips140.load_sequential=1
BOARD_KERNEL_CMDLINE += exynos_drm.load_sequential=1
BOARD_KERNEL_CMDLINE += panel-samsung-ana6707-f10.load_sequential=1
BOARD_KERNEL_CMDLINE += s2mpg12-regulator.load_sequential=1
diff --git a/felix/overlay/frameworks/base/core/res/res/values/config.xml b/felix/overlay/frameworks/base/core/res/res/values/config.xml
index 7d50be7..bf2d14e 100644
--- a/felix/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/felix/overlay/frameworks/base/core/res/res/values/config.xml
@@ -221,6 +221,9 @@
<!-- Indicates whether to enable hinge angle sensor when using unfold animation -->
<bool name="config_unfoldTransitionHingeAngle">true</bool>
+ <!-- Indicates whether to enable haptics during unfold animation -->
+ <bool name="config_unfoldTransitionHapticsEnabled">true</bool>
+
<!-- Timeout for receiving the keyguard drawn event from System UI. -->
<integer name="config_keyguardDrawnTimeout">1700</integer>
diff --git a/felix/overlay/frameworks/base/packages/SystemUI/res/values-sw600dp-land/styles.xml b/felix/overlay/frameworks/base/packages/SystemUI/res/values-sw600dp-land/styles.xml
index b104587..b14ff4f 100644
--- a/felix/overlay/frameworks/base/packages/SystemUI/res/values-sw600dp-land/styles.xml
+++ b/felix/overlay/frameworks/base/packages/SystemUI/res/values-sw600dp-land/styles.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="AuthCredentialPatternContainerStyle">
+ <style name="AuthNonBioCredentialPatternContainerStyle">
<item name="android:gravity">center</item>
<item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
<item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
diff --git a/felix/overlay/frameworks/base/packages/SystemUI/res/values/config.xml b/felix/overlay/frameworks/base/packages/SystemUI/res/values/config.xml
index 9d91e32..5a97b1d 100644
--- a/felix/overlay/frameworks/base/packages/SystemUI/res/values/config.xml
+++ b/felix/overlay/frameworks/base/packages/SystemUI/res/values/config.xml
@@ -148,5 +148,8 @@
4 : DEVICE_POSTURE_FLIPPED
-->
<integer name="config_face_auth_supported_posture">1</integer>
+
+ <!-- Whether to use a machine learning model for back gesture falsing. -->
+ <bool name="config_useBackGestureML">false</bool>
</resources>
diff --git a/felix/radio/felix_display_secondary_mipi_coex_table.csv b/felix/radio/felix_display_secondary_mipi_coex_table.csv
index e28cbcc..8394e1c 100644
--- a/felix/radio/felix_display_secondary_mipi_coex_table.csv
+++ b/felix/radio/felix_display_secondary_mipi_coex_table.csv
@@ -1,7 +1,7 @@
-730000,670000
+365000,335000
-1810000,1835000,670000
-720000,740000,670000
-0,710000,730000
-750000,1800000,730000
-1845000,50000000,730000
+1810000,1835000,335000
+720000,740000,335000
+0,710000,365000
+750000,1800000,365000
+1845000,50000000,365000
diff --git a/location/gps.xml.f10 b/location/gps.xml.f10
index a47afb2..da3e110 100644
--- a/location/gps.xml.f10
+++ b/location/gps.xml.f10
@@ -70,7 +70,7 @@
<gll
PpsEnable="true"
LogPriMask="LOG_INFO"
- LogFacMask="LOG_NMEA | LOG_GLLIOS | LOG_GLLAPI | LOG_MEASAPI"
+ LogFacMask="LOG_NMEA | LOG_GLLIOS | LOG_GLLAPI"
FrqPlan="FRQ_PLAN_26MHZ_2PPM_49_152MHZ_300PPB"
MultiCarrRFMode="GL_MULTI_CARR_RF_MODE_L1_L5"
MultiCarrLnaMask="L1_EXT_ON|L5_EXT_ON"
diff --git a/powerhint.json b/powerhint.json
index 20cd066..926d7c4 100644
--- a/powerhint.json
+++ b/powerhint.json
@@ -2112,25 +2112,19 @@
{
"PowerHint": "FACE_UNLOCK_BOOST",
"Node": "CPUBigClusterMaxFreq",
- "Duration": 1000,
+ "Duration": 500,
"Value": "9999999"
},
{
"PowerHint": "FACE_UNLOCK_BOOST",
- "Node": "CPU_LITTLE_TSKIN_BYPASS",
- "Duration": 1000,
- "Value": "1"
- },
- {
- "PowerHint": "FACE_UNLOCK_BOOST",
- "Node": "CPU_MID_TSKIN_BYPASS",
- "Duration": 1000,
- "Value": "1"
+ "Node": "CPUBigClusterMinFreq",
+ "Duration": 500,
+ "Value": "1826000"
},
{
"PowerHint": "FACE_UNLOCK_BOOST",
"Node": "CPU_BIG_TSKIN_BYPASS",
- "Duration": 1000,
+ "Duration": 500,
"Value": "1"
},
{
@@ -2202,16 +2196,27 @@
"PID_Du": 0.0,
"UclampMin_On": true,
"UclampMin_Init": 232,
+ "UclampMin_LoadUp": 480,
+ "UclampMin_LoadReset": 480,
"UclampMin_High": 480,
"UclampMin_Low": 2,
+ "UclampMax_EfficientBase": 500,
+ "UclampMax_EfficientOffset": 200,
"SamplingWindow_P": 1,
"SamplingWindow_I": 0,
"SamplingWindow_D": 1,
"ReportingRateLimitNs": 83333330,
- "EarlyBoost_On": false,
- "EarlyBoost_TimeFactor": 0.0,
"TargetTimeFactor": 1.0,
- "StaleTimeFactor": 15.0
+ "StaleTimeFactor": 15.0,
+ "HeuristicBoost_On": true,
+ "HBoostOnMissedCycles": 8,
+ "HBoostOffMaxAvgRatio": 4.0,
+ "HBoostOffMissedCycles": 5,
+ "HBoostPidPuFactor": 0.5,
+ "HBoostUclampMin": 722,
+ "JankCheckTimeFactor": 1.2,
+ "LowFrameRateThreshold": 25,
+ "MaxRecordsNum": 300
},
{
"Name": "REFRESH_90FPS",
@@ -2226,16 +2231,27 @@
"PID_Du": 0.0,
"UclampMin_On": true,
"UclampMin_Init": 162,
+ "UclampMin_LoadUp": 480,
+ "UclampMin_LoadReset": 480,
"UclampMin_High": 480,
"UclampMin_Low": 2,
+ "UclampMax_EfficientBase": 500,
+ "UclampMax_EfficientOffset": 200,
"SamplingWindow_P": 1,
"SamplingWindow_I": 0,
"SamplingWindow_D": 1,
"ReportingRateLimitNs": 111111110,
- "EarlyBoost_On": false,
- "EarlyBoost_TimeFactor": 0.0,
"TargetTimeFactor": 1.0,
- "StaleTimeFactor": 15.0
+ "StaleTimeFactor": 15.0,
+ "HeuristicBoost_On": true,
+ "HBoostOnMissedCycles": 8,
+ "HBoostOffMaxAvgRatio": 4.0,
+ "HBoostOffMissedCycles": 5,
+ "HBoostPidPuFactor": 0.5,
+ "HBoostUclampMin": 722,
+ "JankCheckTimeFactor": 1.2,
+ "LowFrameRateThreshold": 25,
+ "MaxRecordsNum": 300
},
{
"Name": "REFRESH_60FPS",
@@ -2250,16 +2266,27 @@
"PID_Du": 0.0,
"UclampMin_On": true,
"UclampMin_Init": 162,
+ "UclampMin_LoadUp": 480,
+ "UclampMin_LoadReset": 480,
"UclampMin_High": 480,
"UclampMin_Low": 2,
+ "UclampMax_EfficientBase": 500,
+ "UclampMax_EfficientOffset": 200,
"SamplingWindow_P": 1,
"SamplingWindow_I": 0,
"SamplingWindow_D": 1,
"ReportingRateLimitNs": 166666660,
- "EarlyBoost_On": false,
- "EarlyBoost_TimeFactor": 0.0,
"TargetTimeFactor": 1.0,
- "StaleTimeFactor": 15.0
+ "StaleTimeFactor": 15.0,
+ "HeuristicBoost_On": true,
+ "HBoostOnMissedCycles": 8,
+ "HBoostOffMaxAvgRatio": 4.0,
+ "HBoostOffMissedCycles": 5,
+ "HBoostPidPuFactor": 0.5,
+ "HBoostUclampMin": 722,
+ "JankCheckTimeFactor": 1.2,
+ "LowFrameRateThreshold": 25,
+ "MaxRecordsNum": 300
},
{
"Name": "UiHighBoostWithoutPid",
@@ -2279,9 +2306,9 @@
"UclampMin_Init": 250,
"UclampMin_High": 197,
"UclampMin_Low": 197,
+ "UclampMax_EfficientBase": 500,
+ "UclampMax_EfficientOffset": 200,
"ReportingRateLimitNs": 1,
- "EarlyBoost_On": false,
- "EarlyBoost_TimeFactor": 0.0,
"TargetTimeFactor": 1.0,
"StaleTimeFactor": 5.0
},
@@ -2303,9 +2330,9 @@
"UclampMin_Init": 250,
"UclampMin_High": 53,
"UclampMin_Low": 53,
+ "UclampMax_EfficientBase": 500,
+ "UclampMax_EfficientOffset": 200,
"ReportingRateLimitNs": 1,
- "EarlyBoost_On": false,
- "EarlyBoost_TimeFactor": 0.0,
"TargetTimeFactor": 1.0,
"StaleTimeFactor": 5.0
},
@@ -2327,9 +2354,9 @@
"UclampMin_Init": 250,
"UclampMin_High": 0,
"UclampMin_Low": 0,
+ "UclampMax_EfficientBase": 500,
+ "UclampMax_EfficientOffset": 200,
"ReportingRateLimitNs": 1,
- "EarlyBoost_On": false,
- "EarlyBoost_TimeFactor": 0.0,
"TargetTimeFactor": 1.0,
"StaleTimeFactor": 5.0
}
diff --git a/rro_overlays/WifiOverlay/res/values/config.xml b/rro_overlays/WifiOverlay/res/values/config.xml
index 8079614..989a868 100644
--- a/rro_overlays/WifiOverlay/res/values/config.xml
+++ b/rro_overlays/WifiOverlay/res/values/config.xml
@@ -175,4 +175,10 @@
If equals to 0, it means there's no limit on the max number of channels to include per network.-->
<integer translatable="false" name="config_wifiInitialPartialScanMaxNewChannelsPerNetwork">3</integer>
+ <!-- Boolean indicating whether to disable firmware roaming when the device goes into idle mode.
+ true: firmware roaming will be disabled when the device goes into idle mode, and then
+ re-activated when the device exits idle mode.
+ false: firmware roaming will not be affected. -->
+ <bool translatable="false" name ="config_wifiDisableFirmwareRoamingInIdleMode">true</bool>
+
</resources>
diff --git a/thermal_info_config_felix.json b/thermal_info_config_felix.json
index 013d18e..a0bc0f2 100644
--- a/thermal_info_config_felix.json
+++ b/thermal_info_config_felix.json
@@ -836,36 +836,6 @@
"HotThreshold":["NAN", "NAN", "NAN", "NAN", 12000, "NAN", "NAN"],
"HotHysteresis":[0.0, 0.0, 0.0, 0.0, 100, 0.0, 0.0],
"Multiplier":1
- },
- {
- "Name":"soft_ocp_cpu2",
- "Type":"BCL_CURRENT",
- "HotThreshold":["NAN", "NAN", "NAN", "NAN", 12000, "NAN", "NAN"],
- "HotHysteresis":[0.0, 0.0, 0.0, 0.0, 100, 0.0, 0.0],
- "Multiplier":1
- },
- {
- "Name":"soft_ocp_cpu1",
- "Type":"BCL_CURRENT",
- "HotThreshold":["NAN", "NAN", "NAN", "NAN", 8000, "NAN", "NAN"],
- "HotHysteresis":[0.0, 0.0, 0.0, 0.0, 100, 0.0, 0.0],
- "Multiplier":1
- },
- {
- "Name":"soft_ocp_tpu",
- "Type":"BCL_CURRENT",
- "HotThreshold":["NAN", "NAN", "NAN", "NAN", 8500, "NAN", "NAN"],
- "HotHysteresis":[0.0, 0.0, 0.0, 0.0, 100, 0.0, 0.0],
- "Multiplier":1,
- "Hidden":true
- },
- {
- "Name":"soft_ocp_gpu",
- "Type":"BCL_CURRENT",
- "HotThreshold":["NAN", "NAN", "NAN", "NAN", 9000, "NAN", "NAN"],
- "HotHysteresis":[0.0, 0.0, 0.0, 0.0, 100, 0.0, 0.0],
- "Multiplier":1,
- "Hidden":true
}
],
"CoolingDevices":[
diff --git a/vibrator/cs40l26/Android.bp b/vibrator/cs40l26/Android.bp
index 9ac51d1..bd5047a 100644
--- a/vibrator/cs40l26/Android.bp
+++ b/vibrator/cs40l26/Android.bp
@@ -60,6 +60,7 @@
srcs: [
"Vibrator.cpp",
],
+ shared_libs: ["//hardware/google/pixel:PixelVibratorFlagsL26"],
export_include_dirs: ["."],
vendor_available: true,
visibility: [":__subpackages__"],
diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h
index 22667c9..69cf9ae 100644
--- a/vibrator/cs40l26/Hardware.h
+++ b/vibrator/cs40l26/Hardware.h
@@ -104,18 +104,25 @@
.code = FF_GAIN,
.value = value,
};
+ if (value > 100) {
+ ALOGE("Invalid gain");
+ return false;
+ }
if (write(fd, (const void *)&gain, sizeof(gain)) != sizeof(gain)) {
return false;
}
return true;
}
bool setFFEffect(int fd, struct ff_effect *effect, uint16_t timeoutMs) override {
+ if (effect == nullptr) {
+ ALOGE("Invalid ff_effect");
+ return false;
+ }
if (ioctl(fd, EVIOCSFF, effect) < 0) {
ALOGE("setFFEffect fail");
return false;
- } else {
- return true;
}
+ return true;
}
bool setFFPlay(int fd, int8_t index, bool value) override {
struct input_event play = {
@@ -184,16 +191,19 @@
*haptic_pcm = NULL;
return false;
}
- bool uploadOwtEffect(int fd, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect,
+ bool uploadOwtEffect(int fd, const uint8_t *owtData, const 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);
- (*effect).u.periodic.custom_data = new int16_t[(*effect).u.periodic.custom_len]{0x0000};
- if ((*effect).u.periodic.custom_data == nullptr) {
- ALOGE("Failed to allocate memory for custom data\n");
+ if (owtData == nullptr || effect == nullptr || outEffectIndex == nullptr) {
+ ALOGE("Invalid argument owtData, ff_effect or outEffectIndex");
*status = EX_NULL_POINTER;
return false;
}
+ if (status == nullptr) {
+ ALOGE("Invalid argument status");
+ return false;
+ }
+
+ (*effect).u.periodic.custom_len = numBytes / sizeof(uint16_t);
memcpy((*effect).u.periodic.custom_data, owtData, numBytes);
if ((*effect).id != -1) {
@@ -204,7 +214,6 @@
(*effect).id = -1;
if (ioctl(fd, EVIOCSFF, effect) < 0) {
ALOGE("Failed to upload effect %d (%d): %s", *outEffectIndex, errno, strerror(errno));
- delete[] ((*effect).u.periodic.custom_data);
*status = EX_ILLEGAL_STATE;
return false;
}
@@ -225,6 +234,10 @@
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 bfb7cf1..b3ce88e 100644
--- a/vibrator/cs40l26/Vibrator.cpp
+++ b/vibrator/cs40l26/Vibrator.cpp
@@ -27,6 +27,8 @@
#include <cmath>
#include <fstream>
#include <iostream>
+#include <memory>
+#include <optional>
#include <sstream>
#ifndef ARRAY_SIZE
@@ -42,7 +44,6 @@
namespace android {
namespace hardware {
namespace vibrator {
-static constexpr uint8_t FF_CUSTOM_DATA_LEN = 2;
static constexpr uint16_t FF_CUSTOM_DATA_LEN_MAX_COMP = 2044; // (COMPOSE_SIZE_MAX + 1) * 8 + 4
static constexpr uint16_t FF_CUSTOM_DATA_LEN_MAX_PWLE = 2302;
@@ -85,7 +86,7 @@
static constexpr float PWLE_LEVEL_MIN = 0.0;
static constexpr float PWLE_LEVEL_MAX = 1.0;
-static constexpr float CS40L26_PWLE_LEVEL_MIX = -1.0;
+static constexpr float CS40L26_PWLE_LEVEL_MIN = -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;
@@ -157,79 +158,210 @@
VIBE_STATE_ASP,
};
-static int min(int x, int y) {
- return x < y ? x : y;
-}
+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 floatToUint16(float input, uint16_t *output, float scale, float min, float max) {
- if (input < min || input > max)
- return -ERANGE;
+ bool isEnd() const { return _current == _max; }
+ int min(int x, int y) { return x < y ? x : y; }
- *output = roundf(input * scale);
- return 0;
-}
+ int write(int nbits, uint32_t val) {
+ int nwrite, i;
-struct dspmem_chunk {
- uint8_t *head;
- uint8_t *current;
- uint8_t *max;
- int bytes;
+ nwrite = min(24 - _cachebits, nbits);
+ _cache <<= nwrite;
+ _cache |= val >> (nbits - nwrite);
+ _cachebits += nwrite;
+ nbits -= nwrite;
- uint32_t cache;
- int cachebits;
-};
+ if (_cachebits == 24) {
+ if (isEnd())
+ return -ENOSPC;
-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,
- };
+ _cache &= 0xFFFFFF;
+ for (i = 0; i < sizeof(_cache); i++, _cache <<= 8)
+ *_current++ = (_cache & 0xFF000000) >> 24;
- return ch;
-}
+ bytes += sizeof(_cache);
+ _cachebits = 0;
+ }
-static bool dspmem_chunk_end(struct dspmem_chunk *ch) {
- return ch->current == ch->max;
-}
+ if (nbits)
+ return write(nbits, val);
-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;
+ return 0;
}
- if (nbits)
- return dspmem_chunk_write(ch, nbits, val);
+ int fToU16(float input, uint16_t *output, float scale, float min, float max) {
+ if (input < min || input > max)
+ return -ERANGE;
- return 0;
-}
-
-static int dspmem_chunk_flush(struct dspmem_chunk *ch) {
- if (!ch->cachebits)
+ *output = roundf(input * scale);
return 0;
+ }
- return dspmem_chunk_write(ch, 24 - ch->cachebits, 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;
+ }
+};
Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> hwCalDefault,
std::unique_ptr<HwApi> hwApiDual, std::unique_ptr<HwCal> hwCalDual,
@@ -355,19 +487,23 @@
mEffectDurations = {
1000, 100, 12, 1000, 300, 130, 150, 500, 100, 5, 12, 1000, 1000, 1000,
}; /* 11+3 waveforms. The duration must < UINT16_MAX */
+ mEffectCustomData.reserve(WAVEFORM_MAX_INDEX);
uint8_t effectIndex;
+ uint16_t numBytes = 0;
for (effectIndex = 0; effectIndex < WAVEFORM_MAX_INDEX; effectIndex++) {
if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) {
/* Initialize physical waveforms. */
+ mEffectCustomData.push_back({RAM_WVFRM_BANK, effectIndex});
mFfEffects[effectIndex] = {
.type = FF_PERIODIC,
.id = -1,
// Length == 0 to allow firmware control of the duration
.replay.length = 0,
.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,
+ .u.periodic.custom_data = mEffectCustomData[effectIndex].data(),
+ .u.periodic.custom_len =
+ static_cast<uint32_t>(mEffectCustomData[effectIndex].size()),
};
// Bypass the waveform update due to different input name
if ((strstr(inputEventName, "cs40l26") != nullptr) ||
@@ -385,12 +521,16 @@
}
} else {
/* Initiate placeholders for OWT effects. */
+ numBytes = effectIndex == WAVEFORM_COMPOSE ? FF_CUSTOM_DATA_LEN_MAX_COMP
+ : FF_CUSTOM_DATA_LEN_MAX_PWLE;
+ std::vector<int16_t> tempVec(numBytes, 0);
+ mEffectCustomData.push_back(std::move(tempVec));
mFfEffects[effectIndex] = {
.type = FF_PERIODIC,
.id = -1,
.replay.length = 0,
.u.periodic.waveform = FF_CUSTOM,
- .u.periodic.custom_data = nullptr,
+ .u.periodic.custom_data = mEffectCustomData[effectIndex].data(),
.u.periodic.custom_len = 0,
};
}
@@ -399,18 +539,21 @@
// ====================HAL internal effect table== Flip ==================================
if (mIsDual) {
mFfEffectsDual.resize(WAVEFORM_MAX_INDEX);
+ mEffectCustomDataDual.reserve(WAVEFORM_MAX_INDEX);
for (effectIndex = 0; effectIndex < WAVEFORM_MAX_INDEX; effectIndex++) {
if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) {
/* Initialize physical waveforms. */
+ mEffectCustomDataDual.push_back({RAM_WVFRM_BANK, effectIndex});
mFfEffectsDual[effectIndex] = {
.type = FF_PERIODIC,
.id = -1,
// Length == 0 to allow firmware control of the duration
.replay.length = 0,
.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,
+ .u.periodic.custom_data = mEffectCustomDataDual[effectIndex].data(),
+ .u.periodic.custom_len =
+ static_cast<uint32_t>(mEffectCustomDataDual[effectIndex].size()),
};
// Bypass the waveform update due to different input name
if ((strstr(inputEventName, "cs40l26") != nullptr) ||
@@ -430,12 +573,16 @@
}
} else {
/* Initiate placeholders for OWT effects. */
+ numBytes = effectIndex == WAVEFORM_COMPOSE ? FF_CUSTOM_DATA_LEN_MAX_COMP
+ : FF_CUSTOM_DATA_LEN_MAX_PWLE;
+ std::vector<int16_t> tempVec(numBytes, 0);
+ mEffectCustomDataDual.push_back(std::move(tempVec));
mFfEffectsDual[effectIndex] = {
.type = FF_PERIODIC,
.id = -1,
.replay.length = 0,
.u.periodic.waveform = FF_CUSTOM,
- .u.periodic.custom_data = nullptr,
+ .u.periodic.custom_data = mEffectCustomDataDual[effectIndex].data(),
.u.periodic.custom_len = 0,
};
}
@@ -718,9 +865,6 @@
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);
}
@@ -736,15 +880,13 @@
size = composite.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);
+ DspMemChunk ch(WAVEFORM_COMPOSE, FF_CUSTOM_DATA_LEN_MAX_COMP);
+ const uint8_t header_count = ch.size();
/* Insert 1 section for a wait before the first effect. */
if (nextEffectDelay) {
- dspmem_chunk_write(ch, 32, 0); /* amplitude, index, repeat & flags */
- dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */
+ ch.constructComposeSegment(0 /*amplitude*/, 0 /*index*/, 0 /*repeat*/, 0 /*flags*/,
+ nextEffectDelay /*delay*/);
}
for (uint32_t i_curr = 0, i_next = 1; i_curr < composite.size(); i_curr++, i_next++) {
@@ -791,14 +933,16 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- 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.constructComposeSegment(effectVolLevel, effectIndex, 0 /*repeat*/, 0 /*flags*/,
+ nextEffectDelay /*delay*/);
}
- dspmem_chunk_flush(ch);
- if (header_count == dspmem_chunk_bytes(ch)) {
+
+ 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()) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
} else {
// Composition duration should be 0 to allow firmware to play the whole effect
@@ -806,12 +950,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, dspmem_chunk *ch,
+ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, const DspMemChunk *ch,
const std::shared_ptr<IVibratorCallback> &callback) {
ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
@@ -826,28 +970,28 @@
if (ch) {
/* Upload OWT effect. */
- if (ch->head == nullptr) {
+ if (ch->front() == nullptr) {
ALOGE("Invalid OWT bank");
- delete ch;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- bool isPwle = (*reinterpret_cast<uint16_t *>(ch->head) != 0x0000);
- effectIndex = isPwle ? WAVEFORM_PWLE : WAVEFORM_COMPOSE;
+
+ if (ch->type() != WAVEFORM_PWLE && ch->type() != WAVEFORM_COMPOSE) {
+ ALOGE("Invalid OWT type");
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ effectIndex = ch->type();
uint32_t 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;
+ if (ch->size() > freeBytes) {
+ ALOGE("Invalid OWT length: Effect %d: %zu > %d!", effectIndex, ch->size(), freeBytes);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (mIsDual) {
mHwApiDual->getOwtFreeSpace(&freeBytes);
- if (dspmem_chunk_bytes(ch) > freeBytes) {
+ if (ch-> size() > freeBytes) {
ALOGE("Invalid OWT length in flip: Effect %d: %d > %d!", effectIndex,
- dspmem_chunk_bytes(ch), freeBytes);
- delete ch;
+ ch-> size(), freeBytes);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
}
@@ -860,20 +1004,17 @@
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;
+ if (!mHwApiDef->uploadOwtEffect(mInputFd, ch->front(), ch->size(), &mFfEffects[effectIndex],
+ &effectIndex, &errorStatus)) {
ALOGE("Invalid uploadOwtEffect");
return ndk::ScopedAStatus::fromExceptionCode(errorStatus);
}
- if (mIsDual && !mHwApiDual->uploadOwtEffect(mInputFdDual, ch->head, dspmem_chunk_bytes(ch),
+ if (mIsDual && !mHwApiDual->uploadOwtEffect(mInputFdDual, ch->front(), ch->size(),
&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) {
@@ -1090,69 +1231,6 @@
*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");
@@ -1177,15 +1255,9 @@
float prevEndAmplitude;
float prevEndFrequency;
resetPreviousEndAmplitudeEndFrequency(&prevEndAmplitude, &prevEndFrequency);
- auto ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_PWLE]{0x00},
- FF_CUSTOM_DATA_LEN_MAX_PWLE);
+ DspMemChunk ch(WAVEFORM_PWLE, 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: {
@@ -1215,8 +1287,8 @@
if (!((active.startAmplitude == prevEndAmplitude) &&
(active.startFrequency == prevEndFrequency))) {
- if (constructActiveSegment(ch, 0, active.startAmplitude, active.startFrequency,
- false) < 0) {
+ if (ch.constructActiveSegment(0, active.startAmplitude, active.startFrequency,
+ false) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
@@ -1225,8 +1297,8 @@
if (active.startFrequency != active.endFrequency) {
chirp = true;
}
- if (constructActiveSegment(ch, active.duration, active.endAmplitude,
- active.endFrequency, chirp) < 0) {
+ if (ch.constructActiveSegment(active.duration, active.endAmplitude,
+ active.endFrequency, chirp) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
@@ -1249,12 +1321,12 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- if (constructBrakingSegment(ch, 0, braking.braking) < 0) {
+ if (ch.constructBrakingSegment(0, braking.braking) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
- if (constructBrakingSegment(ch, braking.duration, braking.braking) < 0) {
+ if (ch.constructBrakingSegment(braking.duration, braking.braking) < 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
incrementIndex(&segmentIdx);
@@ -1270,7 +1342,7 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
}
- dspmem_chunk_flush(ch);
+ ch.flush();
/* Update wlength */
totalDuration += MAX_COLD_START_LATENCY_MS;
@@ -1278,12 +1350,19 @@
ALOGE("Total duration is too long (%d)!", totalDuration);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- updateWLength(ch, totalDuration);
+
+ if (ch.updateWLength(totalDuration) < 0) {
+ ALOGE("%s: Failed to update the waveform length length", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
/* Update nsections */
- updateNSection(ch, segmentIdx);
+ if (ch.updateNSection(segmentIdx) < 0) {
+ ALOGE("%s: Failed to update the section count", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
- return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch,
+ return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, &ch,
callback);
}
@@ -1460,7 +1539,7 @@
}
ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength strength,
- uint32_t *outTimeMs, dspmem_chunk *outCh) {
+ uint32_t *outTimeMs, DspMemChunk *outCh) {
ndk::ScopedAStatus status;
uint32_t timeMs = 0;
uint32_t thisEffectIndex;
@@ -1468,23 +1547,14 @@
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;
-
- 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 */
+ outCh->constructComposeSegment(thisVolLevel, thisEffectIndex, 0 /*repeat*/, 0 /*flags*/,
+ WAVEFORM_DOUBLE_CLICK_SILENCE_MS);
timeMs += WAVEFORM_DOUBLE_CLICK_SILENCE_MS + MAX_PAUSE_TIMING_ERROR_MS;
@@ -1495,12 +1565,13 @@
}
timeMs += thisTimeMs;
- 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);
+ 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);
+ }
break;
default:
@@ -1568,7 +1639,7 @@
uint32_t effectIndex;
uint32_t timeMs = 0;
uint32_t volLevel;
- dspmem_chunk *ch = nullptr;
+ std::optional<DspMemChunk> maybeCh;
switch (effect) {
case Effect::TEXTURE_TICK:
// fall-through
@@ -1580,28 +1651,25 @@
status = getSimpleDetails(effect, strength, &effectIndex, &timeMs, &volLevel);
break;
case Effect::DOUBLE_CLICK:
- 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);
+ maybeCh.emplace(WAVEFORM_COMPOSE, FF_CUSTOM_DATA_LEN_MAX_COMP);
+ status = getCompoundDetails(effect, strength, &timeMs, &*maybeCh);
volLevel = VOLTAGE_SCALE_MAX;
break;
default:
status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
break;
}
- if (!status.isOk()) {
- goto exit;
+ if (status.isOk()) {
+ DspMemChunk *ch = maybeCh ? &*maybeCh : nullptr;
+ status = performEffect(effectIndex, volLevel, ch, callback);
}
- status = performEffect(effectIndex, volLevel, ch, callback);
-
-exit:
*outTimeMs = timeMs;
return status;
}
ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel,
- dspmem_chunk *ch,
+ const DspMemChunk *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 5b1ff90..8f89713 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, uint8_t *owtData, uint32_t numBytes,
+ virtual bool uploadOwtEffect(int fd, const uint8_t *owtData, const 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, struct dspmem_chunk *ch,
+ ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, const class DspMemChunk *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, struct dspmem_chunk *outCh);
+ uint32_t *outTimeMs, class DspMemChunk *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,
- struct dspmem_chunk *ch,
+ const class DspMemChunk *ch,
const std::shared_ptr<IVibratorCallback> &callback);
ndk::ScopedAStatus setPwle(const std::string &pwleQueue);
bool isUnderExternalControl();
@@ -218,6 +218,8 @@
std::vector<ff_effect> mFfEffects;
std::vector<ff_effect> mFfEffectsDual;
std::vector<uint32_t> mEffectDurations;
+ std::vector<std::vector<int16_t>> mEffectCustomData;
+ std::vector<std::vector<int16_t>> mEffectCustomDataDual;
std::future<void> mAsyncHandle;
::android::base::unique_fd mInputFd;
::android::base::unique_fd mInputFdDual;
diff --git a/vibrator/cs40l26/tests/mocks.h b/vibrator/cs40l26/tests/mocks.h
index c85b0b5..641aba8 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, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect,
+ bool(int fd, const uint8_t *owtData, const 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));