blob: c4a992ff1e8982ccef80cda9a665b587472755d1 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/hardware/vibrator/BnVibrator.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <linux/input.h>
#include <tinyalsa/asoundlib.h>
#include <array>
#include <chrono>
#include <ctime>
#include <fstream>
#include <future>
#include "CapoDetector.h"
using CapoDetector = android::chre::CapoDetector;
namespace aidl {
namespace android {
namespace hardware {
namespace vibrator {
using ::android::base::StringPrintf;
class Vibrator : public BnVibrator {
public:
// APIs for interfacing with the kernel driver.
class HwApi {
public:
virtual ~HwApi() = default;
// Stores the LRA resonant frequency to be used for PWLE playback
// and click compensation.
virtual bool setF0(std::string value) = 0;
// Stores the frequency offset for long vibrations.
virtual bool setF0Offset(uint32_t value) = 0;
// Stores the LRA series resistance to be used for click
// compensation.
virtual bool setRedc(std::string value) = 0;
// Stores the LRA Q factor to be used for Q-dependent waveform
// selection.
virtual bool setQ(std::string value) = 0;
// Reports the number of effect waveforms loaded in firmware.
virtual bool getEffectCount(uint32_t *value) = 0;
// Blocks until timeout or vibrator reaches desired state
// (2 = ASP enabled, 1 = haptic enabled, 0 = disabled).
virtual bool pollVibeState(uint32_t value, int32_t timeoutMs = -1) = 0;
// Reports whether getOwtFreeSpace() is supported.
virtual bool hasOwtFreeSpace() = 0;
// Reports the available OWT bytes.
virtual bool getOwtFreeSpace(uint32_t *value) = 0;
// Enables/Disables F0 compensation enable status
virtual bool setF0CompEnable(bool value) = 0;
// Enables/Disables Redc compensation enable status
virtual bool setRedcCompEnable(bool value) = 0;
// Stores the minumun delay time between playback and stop effects.
virtual bool setMinOnOffInterval(uint32_t value) = 0;
// Determine the /dev and /sys paths for input force-feedback control.
virtual bool initFF() = 0;
// Gets the scaling factor for contextual haptic events.
virtual uint32_t getContextScale() = 0;
// Gets the enable status for contextual haptic events.
virtual bool getContextEnable() = 0;
// Gets the settling time for contextual haptic events.
// This will allow the device to stay face up for the duration given,
// even if InMotion events were detected.
virtual uint32_t getContextSettlingTime() = 0;
// Gets the cooldown time for contextual haptic events.
// This is used to avoid changing the scale of close playback events.
virtual uint32_t getContextCooldownTime() = 0;
// Checks the enable status for contextual haptics fade feature. When enabled
// this feature will cause the scaling factor to fade back up to max over
// the setting time set, instead of instantaneously changing it back to max.
virtual bool getContextFadeEnable() = 0;
// Indicates the number of 0.125-dB steps of attenuation to apply to
// waveforms triggered in response to vibration calls from the
// Android vibrator HAL.
virtual bool setFFGain(uint16_t value) = 0;
// Create/modify custom effects for all physical waveforms.
virtual bool setFFEffect(struct ff_effect *effect, uint16_t timeoutMs) = 0;
// Activates/deactivates the effect index after setFFGain() and setFFEffect().
virtual bool setFFPlay(int8_t index, bool value) = 0;
// Get the Alsa device for the audio coupled haptics effect
virtual bool getHapticAlsaDevice(int *card, int *device) = 0;
// Set haptics PCM amplifier before triggering audio haptics feature
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(const uint8_t *owtData, const uint32_t numBytes,
struct ff_effect *effect, uint32_t *outEffectIndex,
int *status) = 0;
// Erase OWT waveform
virtual bool eraseOwtEffect(int8_t effectIndex, std::vector<ff_effect> *effect) = 0;
// Checks to see if DBC (Dynamic Boost Control) feature is supported
// by the target device.
virtual bool isDbcSupported() = 0;
// Configures and enables the DBC feature and all associated parameters
virtual bool enableDbc() = 0;
// Emit diagnostic information to the given file.
virtual void debug(int fd) = 0;
};
// APIs for obtaining calibration/configuration data from persistent memory.
class HwCal {
public:
virtual ~HwCal() = default;
// Obtain the calibration version
virtual bool getVersion(uint32_t *value) = 0;
// Obtains the LRA resonant frequency to be used for PWLE playback
// and click compensation.
virtual bool getF0(std::string *value) = 0;
// Obtains the LRA series resistance to be used for click
// compensation.
virtual bool getRedc(std::string *value) = 0;
// Obtains the LRA Q factor to be used for Q-dependent waveform
// selection.
virtual bool getQ(std::string *value) = 0;
// Obtains frequency shift for long vibrations.
virtual bool getLongFrequencyShift(int32_t *value) = 0;
// Obtains device mass for calculating the bandwidth amplitude map
virtual bool getDeviceMass(float *value) = 0;
// Obtains loc coeff for calculating the bandwidth amplitude map
virtual bool getLocCoeff(float *value) = 0;
// Obtains the v0/v1(min/max) voltage levels to be applied for
// tick/click/long in units of 1%.
virtual bool getTickVolLevels(std::array<uint32_t, 2> *value) = 0;
virtual bool getClickVolLevels(std::array<uint32_t, 2> *value) = 0;
virtual bool getLongVolLevels(std::array<uint32_t, 2> *value) = 0;
// Checks if the chirp feature is enabled.
virtual bool isChirpEnabled() = 0;
// Obtains the supported primitive effects.
virtual bool getSupportedPrimitives(uint32_t *value) = 0;
// Checks if the f0 compensation feature needs to be enabled.
virtual bool isF0CompEnabled() = 0;
// Checks if the redc compensation feature needs to be enabled.
virtual bool isRedcCompEnabled() = 0;
// Emit diagnostic information to the given file.
virtual void debug(int fd) = 0;
};
// APIs for logging data to statistics backend
class StatsApi {
public:
virtual ~StatsApi() = default;
// Increment count for effect
virtual bool logPrimitive(uint16_t effectIndex) = 0;
// Increment count for long/short waveform and duration bucket
virtual bool logWaveform(uint16_t effectIndex, int32_t duration) = 0;
// Increment count for error
virtual bool logError(uint16_t errorIndex) = 0;
// Start new latency measurement
virtual bool logLatencyStart(uint16_t latencyIndex) = 0;
// Finish latency measurement and update latency statistics with result
virtual bool logLatencyEnd() = 0;
// Emit diagnostic information to the given file.
virtual void debug(int fd) = 0;
};
public:
Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal,
std::unique_ptr<StatsApi> statsapi);
ndk::ScopedAStatus getCapabilities(int32_t *_aidl_return) override;
ndk::ScopedAStatus off() override;
ndk::ScopedAStatus on(int32_t timeoutMs,
const std::shared_ptr<IVibratorCallback> &callback) override;
ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
const std::shared_ptr<IVibratorCallback> &callback,
int32_t *_aidl_return) override;
ndk::ScopedAStatus getSupportedEffects(std::vector<Effect> *_aidl_return) override;
ndk::ScopedAStatus setAmplitude(float amplitude) override;
ndk::ScopedAStatus setExternalControl(bool enabled) override;
ndk::ScopedAStatus getCompositionDelayMax(int32_t *maxDelayMs);
ndk::ScopedAStatus getCompositionSizeMax(int32_t *maxSize);
ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive> *supported) override;
ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
int32_t *durationMs) override;
ndk::ScopedAStatus compose(const std::vector<CompositeEffect> &composite,
const std::shared_ptr<IVibratorCallback> &callback) override;
ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect> *_aidl_return) override;
ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
ndk::ScopedAStatus getResonantFrequency(float *resonantFreqHz) override;
ndk::ScopedAStatus getQFactor(float *qFactor) override;
ndk::ScopedAStatus getFrequencyResolution(float *freqResolutionHz) override;
ndk::ScopedAStatus getFrequencyMinimum(float *freqMinimumHz) override;
ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) override;
ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t *durationMs) override;
ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t *maxSize) override;
ndk::ScopedAStatus getSupportedBraking(std::vector<Braking> *supported) override;
ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle> &composite,
const std::shared_ptr<IVibratorCallback> &callback) override;
binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
private:
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, bool scalable);
ndk::ScopedAStatus setGlobalAmplitude(bool set);
// 'simple' effects are those precompiled and loaded into the controller
ndk::ScopedAStatus getSimpleDetails(Effect effect, EffectStrength strength,
uint32_t *outEffectIndex, uint32_t *outTimeMs,
uint32_t *outVolLevel);
// 'compound' effects are those composed by stringing multiple 'simple' effects
ndk::ScopedAStatus getCompoundDetails(Effect effect, EffectStrength strength,
uint32_t *outTimeMs, class DspMemChunk *outCh);
ndk::ScopedAStatus getPrimitiveDetails(CompositePrimitive primitive, uint32_t *outEffectIndex);
ndk::ScopedAStatus performEffect(Effect effect, EffectStrength strength,
const std::shared_ptr<IVibratorCallback> &callback,
int32_t *outTimeMs);
ndk::ScopedAStatus performEffect(uint32_t effectIndex, uint32_t volLevel,
const class DspMemChunk *ch,
const std::shared_ptr<IVibratorCallback> &callback);
ndk::ScopedAStatus setPwle(const std::string &pwleQueue);
bool isUnderExternalControl();
void waitForComplete(std::shared_ptr<IVibratorCallback> &&callback);
uint32_t intensityToVolLevel(float intensity, uint32_t effectIndex);
bool findHapticAlsaDevice(int *card, int *device);
bool hasHapticAlsaDevice();
bool enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device);
void createPwleMaxLevelLimitMap();
void createBandwidthAmplitudeMap();
uint16_t amplitudeToScale(float amplitude, float maximum, bool scalable);
void updateContext();
std::unique_ptr<HwApi> mHwApi;
std::unique_ptr<HwCal> mHwCal;
std::unique_ptr<StatsApi> mStatsApi;
uint32_t mF0Offset;
std::array<uint32_t, 2> mTickEffectVol;
std::array<uint32_t, 2> mClickEffectVol;
std::array<uint32_t, 2> mLongEffectVol;
std::vector<ff_effect> mFfEffects;
std::vector<uint32_t> mEffectDurations;
std::vector<std::vector<int16_t>> mEffectCustomData;
std::future<void> mAsyncHandle;
int8_t mActiveId{-1};
struct pcm *mHapticPcm;
int mCard;
int mDevice;
bool mHasHapticAlsaDevice{false};
bool mIsUnderExternalControl;
float mLongEffectScale = 1.0;
bool mIsChirpEnabled;
uint32_t mSupportedPrimitivesBits = 0x0;
float mRedc{0};
float mResonantFrequency{0};
std::vector<CompositePrimitive> mSupportedPrimitives;
bool mConfigHapticAlsaDeviceDone{false};
std::vector<float> mBandwidthAmplitudeMap{};
bool mCreateBandwidthAmplitudeMapDone{false};
uint32_t mScaleTime;
bool mFadeEnable;
uint32_t mScalingFactor;
uint32_t mScaleCooldown;
bool mContextEnable;
bool mContextEnabledPreviously{false};
uint32_t mLastEffectPlayedTime = 0;
float mLastPlayedScale = 0;
sp<CapoDetector> mContextListener;
enum hal_state {
IDLE,
PREPARING,
ISSUED,
PLAYING,
STOPPED,
RESTORED,
};
hal_state halState = IDLE;
};
} // namespace vibrator
} // namespace hardware
} // namespace android
} // namespace aidl