• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <glob.h>
19 
20 #include <algorithm>
21 
22 #include "HardwareBase.h"
23 #include "Vibrator.h"
24 
25 #define PROC_SND_PCM "/proc/asound/pcm"
26 #define HAPTIC_PCM_DEVICE_SYMBOL "haptic nohost playback"
27 
28 static struct pcm_config haptic_nohost_config = {
29         .channels = 1,
30         .rate = 48000,
31         .period_size = 80,
32         .period_count = 2,
33         .format = PCM_FORMAT_S16_LE,
34 };
35 
36 enum WaveformIndex : uint16_t {
37     /* Physical waveform */
38     WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0,
39     WAVEFORM_RESERVED_INDEX_1 = 1,
40     WAVEFORM_CLICK_INDEX = 2,
41     WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX = 3,
42     WAVEFORM_THUD_INDEX = 4,
43     WAVEFORM_SPIN_INDEX = 5,
44     WAVEFORM_QUICK_RISE_INDEX = 6,
45     WAVEFORM_SLOW_RISE_INDEX = 7,
46     WAVEFORM_QUICK_FALL_INDEX = 8,
47     WAVEFORM_LIGHT_TICK_INDEX = 9,
48     WAVEFORM_LOW_TICK_INDEX = 10,
49     WAVEFORM_RESERVED_MFG_1,
50     WAVEFORM_RESERVED_MFG_2,
51     WAVEFORM_RESERVED_MFG_3,
52     WAVEFORM_MAX_PHYSICAL_INDEX,
53     /* OWT waveform */
54     WAVEFORM_COMPOSE = WAVEFORM_MAX_PHYSICAL_INDEX,
55     WAVEFORM_PWLE,
56     /*
57      * Refer to <linux/input.h>, the WAVEFORM_MAX_INDEX must not exceed 96.
58      * #define FF_GAIN          0x60  // 96 in decimal
59      * #define FF_MAX_EFFECTS   FF_GAIN
60      */
61     WAVEFORM_MAX_INDEX,
62 };
63 
64 namespace aidl {
65 namespace android {
66 namespace hardware {
67 namespace vibrator {
68 
69 class HwApi : public Vibrator::HwApi, private HwApiBase {
70   public:
HwApi()71     HwApi() {
72         HwApi::initFF();
73         open("calibration/f0_stored", &mF0);
74         open("default/f0_offset", &mF0Offset);
75         open("calibration/redc_stored", &mRedc);
76         open("calibration/q_stored", &mQ);
77         open("default/vibe_state", &mVibeState);
78         open("default/num_waves", &mEffectCount);
79         open("default/owt_free_space", &mOwtFreeSpace);
80         open("default/f0_comp_enable", &mF0CompEnable);
81         open("default/redc_comp_enable", &mRedcCompEnable);
82         open("default/delay_before_stop_playback_us", &mMinOnOffInterval);
83     }
84 
setF0(std::string value)85     bool setF0(std::string value) override { return set(value, &mF0); }
setF0Offset(uint32_t value)86     bool setF0Offset(uint32_t value) override { return set(value, &mF0Offset); }
setRedc(std::string value)87     bool setRedc(std::string value) override { return set(value, &mRedc); }
setQ(std::string value)88     bool setQ(std::string value) override { return set(value, &mQ); }
getEffectCount(uint32_t * value)89     bool getEffectCount(uint32_t *value) override { return get(value, &mEffectCount); }
pollVibeState(uint32_t value,int32_t timeoutMs)90     bool pollVibeState(uint32_t value, int32_t timeoutMs) override {
91         return poll(value, &mVibeState, timeoutMs);
92     }
hasOwtFreeSpace()93     bool hasOwtFreeSpace() override { return has(mOwtFreeSpace); }
getOwtFreeSpace(uint32_t * value)94     bool getOwtFreeSpace(uint32_t *value) override { return get(value, &mOwtFreeSpace); }
setF0CompEnable(bool value)95     bool setF0CompEnable(bool value) override { return set(value, &mF0CompEnable); }
setRedcCompEnable(bool value)96     bool setRedcCompEnable(bool value) override { return set(value, &mRedcCompEnable); }
setMinOnOffInterval(uint32_t value)97     bool setMinOnOffInterval(uint32_t value) override { return set(value, &mMinOnOffInterval); }
getContextScale()98     uint32_t getContextScale() override {
99         return utils::getProperty("persist.vendor.vibrator.hal.context.scale", 100);
100     }
getContextEnable()101     bool getContextEnable() override {
102         return utils::getProperty("persist.vendor.vibrator.hal.context.enable", false);
103     }
getContextSettlingTime()104     uint32_t getContextSettlingTime() override {
105         return utils::getProperty("persist.vendor.vibrator.hal.context.settlingtime", 3000);
106     }
getContextCooldownTime()107     uint32_t getContextCooldownTime() override {
108         return utils::getProperty("persist.vendor.vibrator.hal.context.cooldowntime", 1000);
109     }
getContextFadeEnable()110     bool getContextFadeEnable() override {
111         return utils::getProperty("persist.vendor.vibrator.hal.context.fade", false);
112     }
113 
114     // TODO(b/234338136): Need to add the force feedback HW API test cases
initFF()115     bool initFF() override {
116         ATRACE_NAME(__func__);
117         const std::string INPUT_EVENT_NAME = std::getenv("INPUT_EVENT_NAME") ?: "";
118         if (INPUT_EVENT_NAME.find("cs40l26") == std::string::npos) {
119             ALOGE("Invalid input name: %s", INPUT_EVENT_NAME.c_str());
120             return false;
121         }
122 
123         glob_t g = {};
124         const std::string INPUT_EVENT_PATH = "/dev/input/event*";
125         int fd = -1, ret;
126         uint32_t val = 0;
127         char str[256] = {0x00};
128         // Scan /dev/input/event* to get the correct input device path for FF effects manipulation.
129         // Then constructs the /sys/class/input/event*/../../../ for driver attributes accessing
130         // across different platforms and different kernels.
131         for (uint8_t retry = 1; retry < 11 && !mInputFd.ok(); retry++) {
132             ret = glob(INPUT_EVENT_PATH.c_str(), 0, nullptr, &g);
133             if (ret) {
134                 ALOGE("Failed to get input event paths (%d): %s", errno, strerror(errno));
135             } else {
136                 for (size_t i = 0; i < g.gl_pathc; i++) {
137                     fd = TEMP_FAILURE_RETRY(::open(g.gl_pathv[i], O_RDWR));
138                     if (fd < 0) {
139                         continue;
140                     }
141                     // Determine the input device path:
142                     // 1. Check if EV_FF is flagged in event bits.
143                     // 2. Match device name(s) with this CS40L26 HAL instance.
144                     if (ioctl(fd, EVIOCGBIT(0, sizeof(val)), &val) > 0 && (val & (1 << EV_FF)) &&
145                         ioctl(fd, EVIOCGNAME(sizeof(str)), &str) > 0 &&
146                         strcmp(str, INPUT_EVENT_NAME.c_str()) == 0) {
147                         // Get fd ready for input event ioctl().
148                         mInputFd.reset(fd);  // mInputFd.ok() becomes true.
149                         ALOGI("Control %s through %s", INPUT_EVENT_NAME.c_str(), g.gl_pathv[i]);
150 
151                         std::string path = g.gl_pathv[i];
152                         // Get fstream ready for input event write().
153                         saveName(path, &mInputIoStream);
154                         mInputIoStream.open(
155                                 path, std::fstream::out | std::fstream::in | std::fstream::binary);
156                         if (!mInputIoStream) {
157                             ALOGE("Failed to open %s (%d): %s", path.c_str(), errno,
158                                   strerror(errno));
159                         }
160 
161                         // Construct the sysfs device path.
162                         path = "/sys/class/input/" +
163                                path.substr(path.find("event"), std::string::npos) + "/../../../";
164                         updatePathPrefix(path);
165                         break;
166                     }
167                     close(fd);
168                     memset(str, 0x00, sizeof(str));
169                     val = 0;
170                 }
171             }
172 
173             if (!mInputFd.ok()) {
174                 sleep(1);
175                 ALOGW("Retry #%d to search in %zu input devices...", retry, g.gl_pathc);
176             }
177         }
178         globfree(&g);
179 
180         if (!mInputFd.ok()) {
181             ALOGE("Failed to get an input event with name %s", INPUT_EVENT_NAME.c_str());
182             return false;
183         }
184 
185         return true;
186     }
setFFGain(uint16_t value)187     bool setFFGain(uint16_t value) override {
188         ATRACE_NAME(StringPrintf("%s %d%%", __func__, value).c_str());
189         struct input_event gain = {
190                 .type = EV_FF,
191                 .code = FF_GAIN,
192                 .value = value,
193         };
194         if (value > 100) {
195             ALOGE("Invalid gain");
196             return false;
197         }
198         mInputIoStream.write((const char *)&gain, sizeof(gain));
199         mInputIoStream.flush();
200         if (mInputIoStream.fail()) {
201             ALOGE("setFFGain fail");
202             return false;
203         }
204         HWAPI_RECORD(StringPrintf("%d%%", value), &mInputIoStream);
205         return true;
206     }
setFFEffect(struct ff_effect * effect,uint16_t timeoutMs)207     bool setFFEffect(struct ff_effect *effect, uint16_t timeoutMs) override {
208         ATRACE_NAME(StringPrintf("%s %dms", __func__, timeoutMs).c_str());
209         if (effect == nullptr) {
210             ALOGE("Invalid ff_effect");
211             return false;
212         }
213         if (ioctl(mInputFd, EVIOCSFF, effect) < 0) {
214             ALOGE("setFFEffect fail");
215             return false;
216         }
217         HWAPI_RECORD(StringPrintf("#%d: %dms", (*effect).id, timeoutMs), &mInputIoStream);
218         return true;
219     }
setFFPlay(int8_t index,bool value)220     bool setFFPlay(int8_t index, bool value) override {
221         ATRACE_NAME(StringPrintf("%s index:%d %s", __func__, index, value ? "on" : "off").c_str());
222         struct input_event play = {
223                 .type = EV_FF,
224                 .code = static_cast<uint16_t>(index),
225                 .value = value,
226         };
227         mInputIoStream.write((const char *)&play, sizeof(play));
228         mInputIoStream.flush();
229         if (mInputIoStream.fail()) {
230             ALOGE("setFFPlay fail");
231             return false;
232         }
233         HWAPI_RECORD(StringPrintf("#%d: %b", index, value), &mInputIoStream);
234         return true;
235     }
getHapticAlsaDevice(int * card,int * device)236     bool getHapticAlsaDevice(int *card, int *device) override {
237         ATRACE_NAME(__func__);
238         std::string line;
239         std::ifstream myfile(PROC_SND_PCM);
240         if (myfile.is_open()) {
241             while (getline(myfile, line)) {
242                 if (line.find(HAPTIC_PCM_DEVICE_SYMBOL) != std::string::npos) {
243                     std::stringstream ss(line);
244                     std::string currentToken;
245                     std::getline(ss, currentToken, ':');
246                     sscanf(currentToken.c_str(), "%d-%d", card, device);
247                     saveName(StringPrintf("/dev/snd/pcmC%uD%up", *card, *device), &mPcmStream);
248                     return true;
249                 }
250             }
251             myfile.close();
252         } else {
253             ALOGE("Failed to read file: %s", PROC_SND_PCM);
254         }
255         return false;
256     }
setHapticPcmAmp(struct pcm ** haptic_pcm,bool enable,int card,int device)257     bool setHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device) override {
258         ATRACE_NAME(StringPrintf("%s %s", __func__, enable ? "enable" : "disable").c_str());
259         int ret = 0;
260 
261         if (enable) {
262             *haptic_pcm = pcm_open(card, device, PCM_OUT, &haptic_nohost_config);
263             if (!pcm_is_ready(*haptic_pcm)) {
264                 ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm));
265                 goto fail;
266             }
267             HWAPI_RECORD(std::string("pcm_open"), &mPcmStream);
268 
269             ret = pcm_prepare(*haptic_pcm);
270             if (ret < 0) {
271                 ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm));
272                 goto fail;
273             }
274             HWAPI_RECORD(std::string("pcm_prepare"), &mPcmStream);
275 
276             ret = pcm_start(*haptic_pcm);
277             if (ret < 0) {
278                 ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm));
279                 goto fail;
280             }
281             HWAPI_RECORD(std::string("pcm_start"), &mPcmStream);
282 
283             return true;
284         } else {
285             if (*haptic_pcm) {
286                 pcm_close(*haptic_pcm);
287                 HWAPI_RECORD(std::string("pcm_close"), &mPcmStream);
288                 *haptic_pcm = NULL;
289             }
290             return true;
291         }
292 
293     fail:
294         pcm_close(*haptic_pcm);
295         HWAPI_RECORD(std::string("pcm_close"), &mPcmStream);
296         *haptic_pcm = NULL;
297         return false;
298     }
isPassthroughI2sHapticSupported()299     bool isPassthroughI2sHapticSupported() override {
300         return utils::getProperty("ro.vendor.vibrator.hal.passthrough_i2s_supported", false);
301     }
uploadOwtEffect(const uint8_t * owtData,const uint32_t numBytes,struct ff_effect * effect,uint32_t * outEffectIndex,int * status)302     bool uploadOwtEffect(const uint8_t *owtData, const uint32_t numBytes, struct ff_effect *effect,
303                          uint32_t *outEffectIndex, int *status) override {
304         ATRACE_NAME(__func__);
305         if (owtData == nullptr || effect == nullptr || outEffectIndex == nullptr) {
306             ALOGE("Invalid argument owtData, ff_effect or outEffectIndex");
307             *status = EX_NULL_POINTER;
308             return false;
309         }
310         if (status == nullptr) {
311             ALOGE("Invalid argument status");
312             return false;
313         }
314 
315         (*effect).u.periodic.custom_len = numBytes / sizeof(uint16_t);
316         memcpy((*effect).u.periodic.custom_data, owtData, numBytes);
317 
318         if ((*effect).id != -1) {
319             ALOGE("(*effect).id != -1");
320         }
321 
322         /* Create a new OWT waveform to update the PWLE or composite effect. */
323         (*effect).id = -1;
324         if (ioctl(mInputFd, EVIOCSFF, effect) < 0) {
325             ALOGE("Failed to upload effect %d (%d): %s", *outEffectIndex, errno, strerror(errno));
326             *status = EX_ILLEGAL_STATE;
327             return false;
328         }
329 
330         if ((*effect).id >= FF_MAX_EFFECTS || (*effect).id < 0) {
331             ALOGE("Invalid waveform index after upload OWT effect: %d", (*effect).id);
332             *status = EX_ILLEGAL_ARGUMENT;
333             return false;
334         }
335         *outEffectIndex = (*effect).id;
336         *status = 0;
337         HWAPI_RECORD(StringPrintf("#%d: %dB", *outEffectIndex, numBytes), &mInputIoStream);
338         return true;
339     }
eraseOwtEffect(int8_t effectIndex,std::vector<ff_effect> * effect)340     bool eraseOwtEffect(int8_t effectIndex, std::vector<ff_effect> *effect) override {
341         ATRACE_NAME(__func__);
342         uint32_t effectCountBefore, effectCountAfter, i, successFlush = 0;
343 
344         if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) {
345             ALOGE("Invalid waveform index for OWT erase: %d", effectIndex);
346             return false;
347         }
348         if (effect == nullptr || (*effect).empty()) {
349             ALOGE("Invalid argument effect");
350             return false;
351         }
352 
353         if (effectIndex < WAVEFORM_MAX_INDEX) {
354             /* Normal situation. Only erase the effect which we just played. */
355             if (ioctl(mInputFd, EVIOCRMFF, effectIndex) < 0) {
356                 ALOGE("Failed to erase effect %d (%d): %s", effectIndex, errno, strerror(errno));
357             }
358             for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) {
359                 if ((*effect)[i].id == effectIndex) {
360                     (*effect)[i].id = -1;
361                     break;
362                 }
363             }
364             HWAPI_RECORD(StringPrintf("#%d", effectIndex), &mInputIoStream);
365         } else {
366             /* Flush all non-prestored effects of ff-core and driver. */
367             getEffectCount(&effectCountBefore);
368             for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < FF_MAX_EFFECTS; i++) {
369                 if (ioctl(mInputFd, EVIOCRMFF, i) >= 0) {
370                     successFlush++;
371                     HWAPI_RECORD(StringPrintf("#%d", i), &mInputIoStream);
372                 }
373             }
374             getEffectCount(&effectCountAfter);
375             ALOGW("Flushed effects: ff: %d; driver: %d -> %d; success: %d", effectIndex,
376                   effectCountBefore, effectCountAfter, successFlush);
377             /* Reset all OWT effect index of HAL. */
378             for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) {
379                 (*effect)[i].id = -1;
380             }
381         }
382         return true;
383     }
isDbcSupported()384     bool isDbcSupported() override {
385         ATRACE_NAME(__func__);
386         return utils::getProperty("ro.vendor.vibrator.hal.dbc.enable", false);
387     }
388 
enableDbc()389     bool enableDbc() override {
390         ATRACE_NAME(__func__);
391         if (isDbcSupported()) {
392             open("dbc/dbc_env_rel_coef", &mDbcEnvRelCoef);
393             open("dbc/dbc_rise_headroom", &mDbcRiseHeadroom);
394             open("dbc/dbc_fall_headroom", &mDbcFallHeadroom);
395             open("dbc/dbc_tx_lvl_thresh_fs", &mDbcTxLvlThreshFs);
396             open("dbc/dbc_tx_lvl_hold_off_ms", &mDbcTxLvlHoldOffMs);
397             open("default/pm_active_timeout_ms", &mPmActiveTimeoutMs);
398             open("dbc/dbc_enable", &mDbcEnable);
399 
400             // Set values from config. Default if not found.
401             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.envrelcoef", kDbcDefaultEnvRelCoef),
402                 &mDbcEnvRelCoef);
403             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.riseheadroom",
404                                    kDbcDefaultRiseHeadroom),
405                 &mDbcRiseHeadroom);
406             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.fallheadroom",
407                                    kDbcDefaultFallHeadroom),
408                 &mDbcFallHeadroom);
409             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlthreshfs",
410                                    kDbcDefaultTxLvlThreshFs),
411                 &mDbcTxLvlThreshFs);
412             set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlholdoffms",
413                                    kDbcDefaultTxLvlHoldOffMs),
414                 &mDbcTxLvlHoldOffMs);
415             set(utils::getProperty("ro.vendor.vibrator.hal.pm.activetimeout",
416                                    kDefaultPmActiveTimeoutMs),
417                 &mPmActiveTimeoutMs);
418             set(kDbcEnable, &mDbcEnable);
419             return true;
420         }
421         return false;
422     }
423 
debug(int fd)424     void debug(int fd) override { HwApiBase::debug(fd); }
425 
426   private:
427     static constexpr uint32_t kDbcDefaultEnvRelCoef = 8353728;
428     static constexpr uint32_t kDbcDefaultRiseHeadroom = 1909602;
429     static constexpr uint32_t kDbcDefaultFallHeadroom = 1909602;
430     static constexpr uint32_t kDbcDefaultTxLvlThreshFs = 2516583;
431     static constexpr uint32_t kDbcDefaultTxLvlHoldOffMs = 0;
432     static constexpr uint32_t kDefaultPmActiveTimeoutMs = 5;
433     static constexpr uint32_t kDbcEnable = 1;
434 
435     std::ofstream mF0;
436     std::ofstream mF0Offset;
437     std::ofstream mRedc;
438     std::ofstream mQ;
439     std::ifstream mEffectCount;
440     std::ifstream mVibeState;
441     std::ifstream mOwtFreeSpace;
442     std::ofstream mF0CompEnable;
443     std::ofstream mRedcCompEnable;
444     std::ofstream mMinOnOffInterval;
445     std::ofstream mInputIoStream;
446     std::ofstream mPcmStream;
447     ::android::base::unique_fd mInputFd;
448 
449     // DBC Parameters
450     std::ofstream mDbcEnvRelCoef;
451     std::ofstream mDbcRiseHeadroom;
452     std::ofstream mDbcFallHeadroom;
453     std::ofstream mDbcTxLvlThreshFs;
454     std::ofstream mDbcTxLvlHoldOffMs;
455     std::ofstream mDbcEnable;
456     std::ofstream mPmActiveTimeoutMs;
457 };
458 
459 class HwCal : public Vibrator::HwCal, private HwCalBase {
460   private:
461     static constexpr char VERSION[] = "version";
462     static constexpr char F0_CONFIG[] = "f0_measured";
463     static constexpr char REDC_CONFIG[] = "redc_measured";
464     static constexpr char Q_CONFIG[] = "q_measured";
465     static constexpr char TICK_VOLTAGES_CONFIG[] = "v_tick";
466     static constexpr char CLICK_VOLTAGES_CONFIG[] = "v_click";
467     static constexpr char LONG_VOLTAGES_CONFIG[] = "v_long";
468 
469     static constexpr uint32_t VERSION_DEFAULT = 2;
470     static constexpr int32_t DEFAULT_FREQUENCY_SHIFT = 0;
471     static constexpr float DEFAULT_DEVICE_MASS = 0.21;
472     static constexpr float DEFAULT_LOC_COEFF = 2.5;
473     static constexpr std::array<uint32_t, 2> V_TICK_DEFAULT = {5, 95};
474     static constexpr std::array<uint32_t, 2> V_CLICK_DEFAULT = {5, 95};
475     static constexpr std::array<uint32_t, 2> V_LONG_DEFAULT = {5, 95};
476 
477   public:
HwCal()478     HwCal() {}
479 
getVersion(uint32_t * value)480     bool getVersion(uint32_t *value) override {
481         if (getPersist(VERSION, value)) {
482             return true;
483         }
484         *value = VERSION_DEFAULT;
485         return true;
486     }
getLongFrequencyShift(int32_t * value)487     bool getLongFrequencyShift(int32_t *value) override {
488         return getProperty("long.frequency.shift", value, DEFAULT_FREQUENCY_SHIFT);
489     }
getDeviceMass(float * value)490     bool getDeviceMass(float *value) override {
491         return getProperty("device.mass", value, DEFAULT_DEVICE_MASS);
492     }
getLocCoeff(float * value)493     bool getLocCoeff(float *value) override {
494         return getProperty("loc.coeff", value, DEFAULT_LOC_COEFF);
495     }
getF0(std::string * value)496     bool getF0(std::string *value) override { return getPersist(F0_CONFIG, value); }
getRedc(std::string * value)497     bool getRedc(std::string *value) override { return getPersist(REDC_CONFIG, value); }
getQ(std::string * value)498     bool getQ(std::string *value) override { return getPersist(Q_CONFIG, value); }
getTickVolLevels(std::array<uint32_t,2> * value)499     bool getTickVolLevels(std::array<uint32_t, 2> *value) override {
500         if (getPersist(TICK_VOLTAGES_CONFIG, value)) {
501             return true;
502         }
503         return getProperty(TICK_VOLTAGES_CONFIG, value, V_TICK_DEFAULT);
504     }
getClickVolLevels(std::array<uint32_t,2> * value)505     bool getClickVolLevels(std::array<uint32_t, 2> *value) override {
506         if (getPersist(CLICK_VOLTAGES_CONFIG, value)) {
507             return true;
508         }
509         return getProperty(CLICK_VOLTAGES_CONFIG, value, V_CLICK_DEFAULT);
510     }
getLongVolLevels(std::array<uint32_t,2> * value)511     bool getLongVolLevels(std::array<uint32_t, 2> *value) override {
512         if (getPersist(LONG_VOLTAGES_CONFIG, value)) {
513             return true;
514         }
515         return getProperty(LONG_VOLTAGES_CONFIG, value, V_LONG_DEFAULT);
516     }
isChirpEnabled()517     bool isChirpEnabled() override {
518         return utils::getProperty("persist.vendor.vibrator.hal.chirp.enabled", false);
519     }
getSupportedPrimitives(uint32_t * value)520     bool getSupportedPrimitives(uint32_t *value) override {
521         return getProperty("supported_primitives", value, (uint32_t)0);
522     }
isF0CompEnabled()523     bool isF0CompEnabled() override {
524         bool value;
525         getProperty("f0.comp.enabled", &value, true);
526         return value;
527     }
isRedcCompEnabled()528     bool isRedcCompEnabled() override {
529         bool value;
530         getProperty("redc.comp.enabled", &value, false);
531         return value;
532     }
debug(int fd)533     void debug(int fd) override { HwCalBase::debug(fd); }
534 };
535 
536 }  // namespace vibrator
537 }  // namespace hardware
538 }  // namespace android
539 }  // namespace aidl
540