Merge Android 14 QPR3 to AOSP main
Bug: 346855327 Merged-In: I4e10554e6f7abbac2e06953c68bfba6f7ffe77d3 Change-Id: I53bf20ef8d2ccf02642adeaadc0d2b2f77a0dd24
This commit is contained in:
commit
2a16a2c557
23 changed files with 483 additions and 332 deletions
|
@ -93,7 +93,7 @@
|
|||
samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
|
||||
</mixPort>
|
||||
<mixPort name="incall capture" role="sink">
|
||||
<mixPort name="incall capture" role="sink" maxActiveCount="2" maxOpenCount="2">
|
||||
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
|
||||
samplingRates="48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO"/>
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
|
||||
</mixPort>
|
||||
<mixPort name="incall capture" role="sink">
|
||||
<mixPort name="incall capture" role="sink" maxActiveCount="2" maxOpenCount="2">
|
||||
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
|
||||
samplingRates="48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO"/>
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
|
||||
</mixPort>
|
||||
<mixPort name="incall capture" role="sink">
|
||||
<mixPort name="incall capture" role="sink" maxActiveCount="2" maxOpenCount="2">
|
||||
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
|
||||
samplingRates="48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO"/>
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
|
||||
</mixPort>
|
||||
<mixPort name="incall capture" role="sink">
|
||||
<mixPort name="incall capture" role="sink" maxActiveCount="2" maxOpenCount="2">
|
||||
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
|
||||
samplingRates="48000"
|
||||
channelMasks="AUDIO_CHANNEL_IN_MONO"/>
|
||||
|
|
|
@ -18,6 +18,7 @@ on fs
|
|||
chown system system /sys/class/backlight/panel1-backlight/dimming_on
|
||||
chown system system /sys/class/backlight/panel1-backlight/hbm_mode
|
||||
chown system system /sys/class/backlight/panel1-backlight/local_hbm_mode
|
||||
chown system system /sys/class/backlight/panel1-backlight/allow_wakeup_by_state_change
|
||||
chown system system /sys/devices/platform/exynos-drm/secondary-panel/gamma
|
||||
chown system system /sys/devices/platform/exynos-drm/secondary-panel/min_vrefresh
|
||||
chown system system /sys/devices/platform/exynos-drm/secondary-panel/idle_delay_ms
|
||||
|
|
|
@ -21,6 +21,15 @@ 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
|
||||
|
||||
$(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)
|
||||
$(call inherit-product-if-exists, vendor/google_devices/gs201/proprietary/device-vendor.mk)
|
||||
|
@ -211,7 +220,7 @@ PRODUCT_SOONG_NAMESPACES += \
|
|||
|
||||
# Increment the SVN for any official public releases
|
||||
PRODUCT_VENDOR_PROPERTIES += \
|
||||
ro.vendor.build.svn=37
|
||||
ro.vendor.build.svn=51
|
||||
|
||||
# Vibrator HAL
|
||||
PRODUCT_VENDOR_PROPERTIES +=\
|
||||
|
@ -257,7 +266,7 @@ PRODUCT_PACKAGES += \
|
|||
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%,$(RELEASE_PLATFORM_VERSION)))
|
||||
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
|
||||
|
@ -395,3 +404,12 @@ PRODUCT_VENDOR_PROPERTIES += \
|
|||
PRODUCT_PRODUCT_PROPERTIES += \
|
||||
ro.quick_start.oem_id=00e0 \
|
||||
ro.quick_start.device_id=felix
|
||||
|
||||
# Set support hide display cutout feature
|
||||
PRODUCT_PRODUCT_PROPERTIES += \
|
||||
ro.support_hide_display_cutout=true
|
||||
|
||||
PRODUCT_PACKAGES += \
|
||||
NoCutoutOverlay \
|
||||
AvoidAppsInCutoutOverlay
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ 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%,$(RELEASE_PLATFORM_VERSION)))
|
||||
else ifneq (,$(filter AP2% AP3%,$(RELEASE_PLATFORM_VERSION)))
|
||||
RELEASE_GOOGLE_PRODUCT_BOOTLOADER_DIR := bootloader/24Q2
|
||||
else
|
||||
RELEASE_GOOGLE_PRODUCT_BOOTLOADER_DIR := bootloader/trunk
|
||||
|
|
|
@ -78,8 +78,17 @@
|
|||
m 589.2,66.53 a 49.5,49.5 0 0 1 -49.5,49.5 49.5,49.5 0 0 1 -49.5,-49.5 49.5,49.5 0 0 1 49.5,-49.5 49.5,49.5 0 0 1 49.5,49.5 z
|
||||
</string>
|
||||
|
||||
<!-- Camera 0 is the front camera -->
|
||||
<!-- 1 is the logical id of the front camera -->
|
||||
<string translatable="false" name="config_protectedCameraId">1</string>
|
||||
<!-- 5 is the physical id of the outer screen front camera -->
|
||||
<string translatable="false" name="config_protectedPhysicalCameraId">5</string>
|
||||
|
||||
<!-- The properties of the face auth front camera in pixels -->
|
||||
<integer-array name="config_face_auth_props">
|
||||
<item>540</item> <!-- sensorLocationX -->
|
||||
<item>66</item> <!-- sensorLocationY -->
|
||||
<item>50</item> <!--sensorRadius -->
|
||||
</integer-array>
|
||||
|
||||
<!-- Comma-separated list of packages to exclude from camera protection. In our case,
|
||||
ignore the gaze detection package -->
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
SuplVersion="2"
|
||||
SuplMinorVersion="0"
|
||||
SuplOtdoaCapable="true"
|
||||
SuplOtdoaCapable2="true"
|
||||
SuplOtdoaCapable2="false"
|
||||
SuplGlonassCapable = "true"
|
||||
SuplGalileoCapable = "true"
|
||||
SuplBdsCapable = "true"
|
||||
|
@ -60,7 +60,7 @@
|
|||
CpLppeUseAgnssLocForEmptyDbh="true"
|
||||
CpLppHighAccuracyShapeMode="1"
|
||||
ReAidingOnHotStart="false"
|
||||
ReAidingIntervalSec="1200"
|
||||
ReAidingIntervalSec="3600"
|
||||
RuntimeSwLteFilterEnable="true"
|
||||
PpsDevice="/sys/class/pps/pps0/assert_elapsed"
|
||||
SensorsMask="0x244"
|
||||
|
@ -93,6 +93,8 @@
|
|||
MinGpsWeekNumber="2216"
|
||||
OnChipAccMask="50"
|
||||
EnableB1C="false"
|
||||
|
||||
RTICacheTimeoutSec="3600"
|
||||
/>
|
||||
|
||||
<gll_features
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
SuplVersion="2"
|
||||
SuplMinorVersion="0"
|
||||
SuplOtdoaCapable="true"
|
||||
SuplOtdoaCapable2="true"
|
||||
SuplOtdoaCapable2="false"
|
||||
SuplGlonassCapable = "true"
|
||||
SuplGalileoCapable = "true"
|
||||
SuplBdsCapable = "true"
|
||||
|
@ -59,7 +59,7 @@
|
|||
CpLppeUseAgnssLocForEmptyDbh="true"
|
||||
CpLppHighAccuracyShapeMode="1"
|
||||
ReAidingOnHotStart="false"
|
||||
ReAidingIntervalSec="1200"
|
||||
ReAidingIntervalSec="3600"
|
||||
RuntimeSwLteFilterEnable="true"
|
||||
PpsDevice="/sys/class/pps/pps0/assert_elapsed"
|
||||
SensorsMask="0x244"
|
||||
|
@ -92,6 +92,8 @@
|
|||
MinGpsWeekNumber="2216"
|
||||
OnChipAccMask="50"
|
||||
EnableB1C="false"
|
||||
|
||||
RTICacheTimeoutSec="3600"
|
||||
/>
|
||||
|
||||
<gll_features
|
||||
|
|
|
@ -8,7 +8,7 @@ NFC_DEBUG_ENABLED=0
|
|||
|
||||
###############################################################################
|
||||
# Vendor specific mode to enable FW (RF & SWP) traces.
|
||||
STNFC_FW_DEBUG_ENABLED=0
|
||||
STNFC_FW_DEBUG_ENABLED=1
|
||||
|
||||
###############################################################################
|
||||
# File used for NFA storage
|
||||
|
|
|
@ -784,6 +784,17 @@
|
|||
"Type": "DoHint",
|
||||
"Value": "LAUNCH_EXTEND"
|
||||
},
|
||||
{
|
||||
"PowerHint": "LAUNCH",
|
||||
"Type": "DoHint",
|
||||
"Value": "LAUNCH_PMU"
|
||||
},
|
||||
{
|
||||
"PowerHint": "LAUNCH_PMU",
|
||||
"Node": "PMU_POLL",
|
||||
"Duration": 3000,
|
||||
"Value": "0"
|
||||
},
|
||||
{
|
||||
"PowerHint": "LAUNCH_EXTEND",
|
||||
"Node": "CPUBigClusterMaxFreq",
|
||||
|
@ -939,6 +950,12 @@
|
|||
"Duration": 1000,
|
||||
"Value": "4-7"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_LAUNCH",
|
||||
"Node": "PMU_POLL",
|
||||
"Duration": 1000,
|
||||
"Value": "0"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_LAUNCH_EXTENDED",
|
||||
"Node": "CPUBigClusterMaxFreq",
|
||||
|
@ -963,6 +980,12 @@
|
|||
"Duration": 2000,
|
||||
"Value": "0"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_LAUNCH_EXTENDED",
|
||||
"Node": "PMU_POLL",
|
||||
"Duration": 2000,
|
||||
"Value": "0"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_THERMAL_CPU_THROTTLE",
|
||||
"Node": "CPUBigClusterMaxFreq",
|
||||
|
@ -984,21 +1007,33 @@
|
|||
{
|
||||
"PowerHint": "CAMERA_CAPTURE_CPU_THROTTLE",
|
||||
"Node": "CPUBigClusterMaxFreq",
|
||||
"Duration": 1000,
|
||||
"Duration": 2500,
|
||||
"Value": "1826000"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_CAPTURE_CPU_THROTTLE",
|
||||
"Node": "CPUMidClusterMaxFreq",
|
||||
"Duration": 1000,
|
||||
"Duration": 2500,
|
||||
"Value": "1491000"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_CAPTURE_CPU_THROTTLE",
|
||||
"Node": "CPULittleClusterMaxFreq",
|
||||
"Duration": 1000,
|
||||
"Duration": 2500,
|
||||
"Value": "1401000"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_CAPTURE_CPU_THROTTLE",
|
||||
"Node": "PMU_POLL",
|
||||
"Duration": 2500,
|
||||
"Value": "0"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_CAPTURE_CPU_THROTTLE",
|
||||
"Node": "EM_Profile",
|
||||
"Duration": 2500,
|
||||
"Value": "default"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_SHOT",
|
||||
"Node": "MemFreq",
|
||||
|
@ -1467,12 +1502,6 @@
|
|||
"Duration": 0,
|
||||
"Value": "1"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_STREAMING_STANDARD",
|
||||
"Node": "CDPreferIdle",
|
||||
"Duration": 0,
|
||||
"Value": "0"
|
||||
},
|
||||
{
|
||||
"PowerHint": "CAMERA_STREAMING_STANDARD",
|
||||
"Node": "PMU_POLL",
|
||||
|
|
|
@ -38,36 +38,50 @@ using aidl::android::hardware::power::stats::PowerStatsEnergyConsumer;
|
|||
|
||||
void addDisplay(std::shared_ptr<PowerStats> p) {
|
||||
// Add display residency stats for inner display
|
||||
std::vector<std::string> inner_states = {
|
||||
"Off",
|
||||
"LP: 1840x2208@1",
|
||||
"LP: 1840x2208@30",
|
||||
"On: 1840x2208@1",
|
||||
"On: 1840x2208@10",
|
||||
"On: 1840x2208@60",
|
||||
"On: 1840x2208@120",
|
||||
"HBM: 1840x2208@60",
|
||||
"HBM: 1840x2208@120"};
|
||||
struct stat primaryBuffer;
|
||||
if (!stat("/sys/class/drm/card0/device/primary-panel/time_in_state", &primaryBuffer)) {
|
||||
// time_in_state exists
|
||||
addDisplayMrrByEntity(p, "Inner Display", "/sys/class/drm/card0/device/primary-panel/");
|
||||
} else {
|
||||
// time_in_state doesn't exist
|
||||
std::vector<std::string> inner_states = {
|
||||
"Off",
|
||||
"LP: 1840x2208@1",
|
||||
"LP: 1840x2208@30",
|
||||
"On: 1840x2208@1",
|
||||
"On: 1840x2208@10",
|
||||
"On: 1840x2208@60",
|
||||
"On: 1840x2208@120",
|
||||
"HBM: 1840x2208@60",
|
||||
"HBM: 1840x2208@120"};
|
||||
|
||||
p->addStateResidencyDataProvider(std::make_unique<DisplayStateResidencyDataProvider>(
|
||||
"Inner Display",
|
||||
"/sys/class/backlight/panel0-backlight/state",
|
||||
inner_states));
|
||||
p->addStateResidencyDataProvider(std::make_unique<DisplayStateResidencyDataProvider>(
|
||||
"Inner Display",
|
||||
"/sys/class/backlight/panel0-backlight/state",
|
||||
inner_states));
|
||||
}
|
||||
|
||||
// Add display residency stats for outer display
|
||||
std::vector<std::string> outer_states = {
|
||||
"Off",
|
||||
"LP: 1080x2092@30",
|
||||
"On: 1080x2092@10",
|
||||
"On: 1080x2092@60",
|
||||
"On: 1080x2092@120",
|
||||
"HBM: 1080x2092@60",
|
||||
"HBM: 1080x2092@120"};
|
||||
struct stat secondaryBuffer;
|
||||
if (!stat("/sys/class/drm/card0/device/secondary-panel/time_in_state", &secondaryBuffer)) {
|
||||
// time_in_state exists
|
||||
addDisplayMrrByEntity(p, "Outer Display", "/sys/class/drm/card0/device/secondary-panel/");
|
||||
} else {
|
||||
// time_in_state doesn't exist
|
||||
std::vector<std::string> outer_states = {
|
||||
"Off",
|
||||
"LP: 1080x2092@30",
|
||||
"On: 1080x2092@10",
|
||||
"On: 1080x2092@60",
|
||||
"On: 1080x2092@120",
|
||||
"HBM: 1080x2092@60",
|
||||
"HBM: 1080x2092@120"};
|
||||
|
||||
p->addStateResidencyDataProvider(std::make_unique<DisplayStateResidencyDataProvider>(
|
||||
"Outer Display",
|
||||
"/sys/class/backlight/panel1-backlight/state",
|
||||
outer_states));
|
||||
p->addStateResidencyDataProvider(std::make_unique<DisplayStateResidencyDataProvider>(
|
||||
"Outer Display",
|
||||
"/sys/class/backlight/panel1-backlight/state",
|
||||
outer_states));
|
||||
}
|
||||
|
||||
// Add display energy consumer
|
||||
p->addEnergyConsumer(PowerStatsEnergyConsumer::createMeterConsumer(
|
||||
|
@ -142,15 +156,7 @@ void addGPU(std::shared_ptr<PowerStats> p) {
|
|||
}
|
||||
|
||||
std::string getNfcPath() {
|
||||
struct stat buffer;
|
||||
int size = 128;
|
||||
char path[size];
|
||||
for (int i = 0; i < 10; i++) {
|
||||
std::snprintf(path, size,
|
||||
"/sys/devices/platform/10970000.hsi2c/i2c-%d/i2c-st21nfc/power_stats", i);
|
||||
if (!stat(path, &buffer)) break;
|
||||
}
|
||||
return std::string(path);
|
||||
return std::string("/sys/devices/platform/10970000.hsi2c/i2c-8/8-0008/power_stats");
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
|
|
@ -32,4 +32,5 @@
|
|||
<item>103</item>
|
||||
<item>103</item>
|
||||
</integer-array>
|
||||
<bool name="nfc_observe_mode_supported">true</bool>
|
||||
</resources>
|
||||
|
|
|
@ -167,4 +167,12 @@
|
|||
regulatory approval (for example, FCC pre-approval is required according to "594280 D01
|
||||
Software Configuration Control v02r01").-->
|
||||
<bool translatable="false" name ="config_wifiUpdateCountryCodeFromScanResultGeneric">true</bool>
|
||||
|
||||
<!-- Boolean indicating performing a partial initial scan is enabled -->
|
||||
<bool translatable="false" name="config_wifiEnablePartialInitialScan">true</bool>
|
||||
|
||||
<!-- Configure the max number of new channels to add into the initial partial scan list per network.
|
||||
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>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
system_ext/lib64/libmediaadaptor.so \
|
||||
system_ext/priv-app/ShannonRcs/ShannonRcs.apk \
|
||||
system_ext/priv-app/ShannonIms/ShannonIms.apk \
|
||||
system_ext/priv-app/PixelQualifiedNetworksService/PixelQualifiedNetworksService.apk \
|
||||
system_ext/priv-app/UwbVendorService/UwbVendorService.apk \
|
||||
"
|
||||
;;
|
||||
|
|
|
@ -22,22 +22,6 @@ ifneq ($(filter felix,$(TARGET_DEVICE)),)
|
|||
endif
|
||||
|
||||
ifneq ($(filter felix,$(TARGET_DEVICE)),)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
|
||||
LOCAL_MODULE := PixelQualifiedNetworksService
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_BUILT_MODULE_STEM := package.apk
|
||||
LOCAL_SYSTEM_EXT_MODULE := true
|
||||
LOCAL_PRIVILEGED_MODULE := true
|
||||
LOCAL_MODULE_OWNER := samsung
|
||||
LOCAL_MODULE_CLASS := APPS
|
||||
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
|
||||
LOCAL_CERTIFICATE := platform
|
||||
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
|
||||
LOCAL_LICENSE_CONDITIONS := notice
|
||||
LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../COPYRIGHT $(LOCAL_PATH)/../LICENSE
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
|
||||
LOCAL_MODULE := ShannonIms
|
||||
|
|
|
@ -17,7 +17,6 @@ PRODUCT_SOONG_NAMESPACES += \
|
|||
|
||||
# AOSP packages required by the blobs
|
||||
PRODUCT_PACKAGES := \
|
||||
PixelQualifiedNetworksService \
|
||||
ShannonIms \
|
||||
ShannonRcs \
|
||||
UwbVendorService \
|
||||
|
|
|
@ -104,18 +104,25 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
|||
.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).replay.length != timeoutMs) || (ioctl(fd, EVIOCSFF, effect) < 0)) {
|
||||
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 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
|||
*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 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
|||
(*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 @@ class HwApi : public Vibrator::HwApi, private HwApiBase {
|
|||
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);
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
|
@ -42,7 +44,6 @@ namespace aidl {
|
|||
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 uint8_t PWLE_AMP_REG_BIT = 0x2;
|
|||
|
||||
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 @@ enum vibe_state {
|
|||
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,25 +487,32 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> h
|
|||
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,
|
||||
.replay.length = static_cast<uint16_t>(mEffectDurations[effectIndex]),
|
||||
// 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) ||
|
||||
(strstr(inputEventName, "cs40l26_dual_input") != nullptr)) {
|
||||
// Let the firmware control the playback duration to avoid
|
||||
// cutting any effect that is played short
|
||||
if (!mHwApiDef->setFFEffect(
|
||||
mInputFd, &mFfEffects[effectIndex],
|
||||
static_cast<uint16_t>(mFfEffects[effectIndex].replay.length))) {
|
||||
mEffectDurations[effectIndex])) {
|
||||
ALOGE("Failed upload effect %d (%d): %s", effectIndex, errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -382,12 +521,16 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> h
|
|||
}
|
||||
} 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,
|
||||
};
|
||||
}
|
||||
|
@ -396,24 +539,30 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> h
|
|||
// ====================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,
|
||||
.replay.length = static_cast<uint16_t>(mEffectDurations[effectIndex]),
|
||||
// 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) ||
|
||||
(strstr(inputEventName, "cs40l26_dual_input") != nullptr)) {
|
||||
// Let the firmware control the playback duration to avoid
|
||||
// cutting any effect that is played short
|
||||
if (!mHwApiDual->setFFEffect(
|
||||
mInputFdDual, &mFfEffectsDual[effectIndex],
|
||||
static_cast<uint16_t>(mFfEffectsDual[effectIndex].replay.length))) {
|
||||
mEffectDurations[effectIndex])) {
|
||||
ALOGE("Failed upload flip's effect %d (%d): %s", effectIndex, errno,
|
||||
strerror(errno));
|
||||
}
|
||||
|
@ -424,12 +573,16 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwApiDefault, std::unique_ptr<HwCal> h
|
|||
}
|
||||
} 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,
|
||||
};
|
||||
}
|
||||
|
@ -712,9 +865,6 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi
|
|||
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);
|
||||
}
|
||||
|
@ -730,15 +880,13 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi
|
|||
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++) {
|
||||
|
@ -785,26 +933,29 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi
|
|||
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 {
|
||||
mFfEffects[WAVEFORM_COMPOSE].replay.length = totalDuration;
|
||||
// Composition duration should be 0 to allow firmware to play the whole effect
|
||||
mFfEffects[WAVEFORM_COMPOSE].replay.length = 0;
|
||||
if (mIsDual) {
|
||||
mFfEffectsDual[WAVEFORM_COMPOSE].replay.length = totalDuration;
|
||||
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();
|
||||
|
||||
|
@ -819,28 +970,28 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -853,20 +1004,17 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem
|
|||
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) {
|
||||
|
@ -1083,69 +1231,6 @@ static void incrementIndex(int *index) {
|
|||
*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");
|
||||
|
@ -1170,15 +1255,9 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
|
|||
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: {
|
||||
|
@ -1208,8 +1287,8 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
|
|||
|
||||
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);
|
||||
|
@ -1218,8 +1297,8 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
|
|||
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);
|
||||
|
@ -1242,12 +1321,12 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
|
|||
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);
|
||||
|
@ -1263,7 +1342,7 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
|
|||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
}
|
||||
dspmem_chunk_flush(ch);
|
||||
ch.flush();
|
||||
|
||||
/* Update wlength */
|
||||
totalDuration += MAX_COLD_START_LATENCY_MS;
|
||||
|
@ -1271,12 +1350,19 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -1453,7 +1539,7 @@ ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength stre
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -1461,23 +1547,14 @@ ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength st
|
|||
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;
|
||||
|
||||
|
@ -1488,12 +1565,13 @@ ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength st
|
|||
}
|
||||
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:
|
||||
|
@ -1501,9 +1579,10 @@ ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength st
|
|||
}
|
||||
|
||||
*outTimeMs = timeMs;
|
||||
mFfEffects[WAVEFORM_COMPOSE].replay.length = static_cast<uint16_t>(timeMs);
|
||||
// Compositions should have 0 duration
|
||||
mFfEffects[WAVEFORM_COMPOSE].replay.length = 0;
|
||||
if (mIsDual) {
|
||||
mFfEffectsDual[WAVEFORM_COMPOSE].replay.length = static_cast<uint16_t>(timeMs);
|
||||
mFfEffectsDual[WAVEFORM_COMPOSE].replay.length = 0;
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
|
@ -1560,7 +1639,7 @@ ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strengt
|
|||
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
|
||||
|
@ -1572,28 +1651,25 @@ ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strengt
|
|||
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);
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ class Vibrator : public BnVibrator {
|
|||
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 @@ class Vibrator : public BnVibrator {
|
|||
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 @@ class Vibrator : public BnVibrator {
|
|||
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 @@ class Vibrator : public BnVibrator {
|
|||
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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
on property:vendor.all.modules.ready=1
|
||||
wait /sys/bus/i2c/devices/i2c-cs40l26a/calibration/redc_cal_time_ms
|
||||
wait /sys/bus/i2c/devices/15-0043/calibration/redc_cal_time_ms
|
||||
|
||||
mkdir /mnt/vendor/persist/haptics 0770 system system
|
||||
chmod 770 /mnt/vendor/persist/haptics
|
||||
|
@ -9,26 +9,28 @@ on property:vendor.all.modules.ready=1
|
|||
chown system system /mnt/vendor/persist/haptics/cs40l26.cal
|
||||
chown system system /mnt/vendor/persist/haptics/cs40l26_dual.cal
|
||||
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/calibration/f0_stored
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/calibration/f0_stored
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/calibration/q_stored
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/calibration/q_stored
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/calibration/redc_stored
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/calibration/redc_stored
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/vibe_state
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/vibe_state
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/num_waves
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/num_waves
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/f0_offset
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/f0_offset
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/owt_free_space
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/owt_free_space
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/f0_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/f0_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/redc_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/redc_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a/default/delay_before_stop_playback_us
|
||||
chown system system /sys/bus/i2c/devices/i2c-cs40l26a-dual/default/delay_before_stop_playback_us
|
||||
chown system system /sys/bus/i2c/devices/15-0043/calibration/f0_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0043/calibration/q_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0043/calibration/redc_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/vibe_state
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/num_waves
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/f0_offset
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/owt_free_space
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/f0_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/redc_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/15-0043/default/delay_before_stop_playback_us
|
||||
|
||||
chown system system /sys/bus/i2c/devices/15-0042/calibration/f0_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0042/calibration/q_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0042/calibration/redc_stored
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/vibe_state
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/num_waves
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/f0_offset
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/owt_free_space
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/f0_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/redc_comp_enable
|
||||
chown system system /sys/bus/i2c/devices/15-0042/default/delay_before_stop_playback_us
|
||||
|
||||
chown system system /dev/gpiochip44
|
||||
|
||||
enable vendor.vibrator.cs40l26
|
||||
|
@ -46,8 +48,8 @@ service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service
|
|||
setenv CALIBRATION_FILEPATH /mnt/vendor/persist/haptics/cs40l26.cal
|
||||
setenv CALIBRATION_FILEPATH_DUAL /mnt/vendor/persist/haptics/cs40l26_dual.cal
|
||||
|
||||
setenv HWAPI_PATH_PREFIX /sys/bus/i2c/devices/i2c-cs40l26a/
|
||||
setenv HWAPI_PATH_PREFIX_DUAL /sys/bus/i2c/devices/i2c-cs40l26a-dual/
|
||||
setenv HWAPI_PATH_PREFIX /sys/bus/i2c/devices/15-0043/
|
||||
setenv HWAPI_PATH_PREFIX_DUAL /sys/bus/i2c/devices/15-0042/
|
||||
setenv HWAPI_DEBUG_PATHS "
|
||||
calibration/f0_stored
|
||||
calibration/redc_stored
|
||||
|
|
|
@ -51,7 +51,7 @@ class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi {
|
|||
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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue