Home | History | Annotate | Download | only in vibrator
      1 /*
      2  * Copyright (C) 2017 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 
     17 #define LOG_TAG "VibratorService"
     18 
     19 #include <log/log.h>
     20 
     21 #include <hardware/hardware.h>
     22 #include <hardware/vibrator.h>
     23 #include <cutils/properties.h>
     24 
     25 #include "Vibrator.h"
     26 
     27 #include <cinttypes>
     28 #include <cmath>
     29 #include <iostream>
     30 #include <fstream>
     31 
     32 
     33 namespace android {
     34 namespace hardware {
     35 namespace vibrator {
     36 namespace V1_2 {
     37 namespace implementation {
     38 
     39 static constexpr int8_t MAX_RTP_INPUT = 127;
     40 static constexpr int8_t MIN_RTP_INPUT = 0;
     41 
     42 static constexpr char RTP_MODE[] = "rtp";
     43 static constexpr char WAVEFORM_MODE[] = "waveform";
     44 
     45 // Use effect #1 in the waveform library for CLICK effect
     46 static constexpr char WAVEFORM_CLICK_EFFECT_SEQ[] = "1 0";
     47 static constexpr int32_t WAVEFORM_CLICK_EFFECT_MS = 6;
     48 
     49 // Use effect #2 in the waveform library for TICK effect
     50 static constexpr char WAVEFORM_TICK_EFFECT_SEQ[] = "2 0";
     51 static constexpr int32_t WAVEFORM_TICK_EFFECT_MS = 2;
     52 
     53 // Use effect #3 in the waveform library for DOUBLE_CLICK effect
     54 static constexpr char WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ[] = "3 0";
     55 static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_EFFECT_MS = 135;
     56 
     57 // Use effect #4 in the waveform library for HEAVY_CLICK effect
     58 static constexpr char WAVEFORM_HEAVY_CLICK_EFFECT_SEQ[] = "4 0";
     59 static constexpr uint32_t WAVEFORM_HEAVY_CLICK_EFFECT_MS = 8;
     60 
     61 // Timeout threshold for selecting open or closed loop mode
     62 static constexpr int8_t LOOP_MODE_THRESHOLD_MS = 20;
     63 
     64 using Status = ::android::hardware::vibrator::V1_0::Status;
     65 using EffectStrength = ::android::hardware::vibrator::V1_0::EffectStrength;
     66 
     67 Vibrator::Vibrator(std::ofstream&& activate, std::ofstream&& duration,
     68         std::ofstream&& state, std::ofstream&& rtpinput,
     69         std::ofstream&& mode, std::ofstream&& sequencer,
     70         std::ofstream&& scale, std::ofstream&& ctrlloop, std::ofstream&& lptrigger) :
     71     mActivate(std::move(activate)),
     72     mDuration(std::move(duration)),
     73     mState(std::move(state)),
     74     mRtpInput(std::move(rtpinput)),
     75     mMode(std::move(mode)),
     76     mSequencer(std::move(sequencer)),
     77     mScale(std::move(scale)),
     78     mCtrlLoop(std::move(ctrlloop)),
     79     mLpTriggerEffect(std::move(lptrigger)) {
     80 
     81     mClickDuration = property_get_int32("ro.vibrator.hal.click.duration", WAVEFORM_CLICK_EFFECT_MS);
     82     mTickDuration = property_get_int32("ro.vibrator.hal.tick.duration", WAVEFORM_TICK_EFFECT_MS);
     83     mHeavyClickDuration = property_get_int32(
     84         "ro.vibrator.hal.heavyclick.duration", WAVEFORM_HEAVY_CLICK_EFFECT_MS);
     85 
     86     // This enables effect #1 from the waveform library to be triggered by SLPI
     87     // while the AP is in suspend mode
     88     mLpTriggerEffect << 1 << std::endl;
     89     if (!mLpTriggerEffect) {
     90         ALOGW("Failed to set LP trigger mode (%d): %s", errno, strerror(errno));
     91     }
     92 }
     93 
     94 Return<Status> Vibrator::on(uint32_t timeoutMs, bool forceOpenLoop, bool isWaveform) {
     95     uint32_t loopMode = 1;
     96 
     97     // Open-loop mode is used for short click for over-drive
     98     // Close-loop mode is used for long notification for stability
     99     if (!forceOpenLoop && timeoutMs > LOOP_MODE_THRESHOLD_MS) {
    100         loopMode = 0;
    101     }
    102 
    103     mCtrlLoop << loopMode << std::endl;
    104     mDuration << timeoutMs << std::endl;
    105     if (!mDuration) {
    106         ALOGE("Failed to set duration (%d): %s", errno, strerror(errno));
    107         return Status::UNKNOWN_ERROR;
    108     }
    109 
    110     if (isWaveform) {
    111         mMode << WAVEFORM_MODE << std::endl;
    112     } else {
    113         mMode << RTP_MODE << std::endl;
    114     }
    115 
    116     mActivate << 1 << std::endl;
    117     if (!mActivate) {
    118         ALOGE("Failed to activate (%d): %s", errno, strerror(errno));
    119         return Status::UNKNOWN_ERROR;
    120     }
    121 
    122    return Status::OK;
    123 }
    124 
    125 // Methods from ::android::hardware::vibrator::V1_2::IVibrator follow.
    126 Return<Status> Vibrator::on(uint32_t timeoutMs) {
    127     return on(timeoutMs, false /* forceOpenLoop */, false /* isWaveform */);
    128 }
    129 
    130 Return<Status> Vibrator::off()  {
    131     mActivate << 0 << std::endl;
    132     if (!mActivate) {
    133         ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
    134         return Status::UNKNOWN_ERROR;
    135     }
    136     return Status::OK;
    137 }
    138 
    139 Return<bool> Vibrator::supportsAmplitudeControl()  {
    140     return (mRtpInput ? true : false);
    141 }
    142 
    143 Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
    144 
    145     if (amplitude == 0) {
    146         return Status::BAD_VALUE;
    147     }
    148 
    149     int32_t rtp_input =
    150             std::round((amplitude - 1) / 254.0 * (MAX_RTP_INPUT - MIN_RTP_INPUT) +
    151             MIN_RTP_INPUT);
    152 
    153     mRtpInput << rtp_input << std::endl;
    154     if (!mRtpInput) {
    155         ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));
    156         return Status::UNKNOWN_ERROR;
    157     }
    158 
    159     return Status::OK;
    160 }
    161 
    162 static uint8_t convertEffectStrength(EffectStrength strength) {
    163     uint8_t scale;
    164 
    165     switch (strength) {
    166     case EffectStrength::LIGHT:
    167         scale = 2; // 50%
    168         break;
    169     case EffectStrength::MEDIUM:
    170     case EffectStrength::STRONG:
    171         scale = 0; // 100%
    172         break;
    173     }
    174 
    175     return scale;
    176 }
    177 
    178 Return<void> Vibrator::perform(V1_0::Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
    179     return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
    180 }
    181 
    182 Return<void> Vibrator::perform_1_1(V1_1::Effect_1_1 effect, EffectStrength strength,
    183         perform_cb _hidl_cb) {
    184     return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
    185 }
    186 
    187 Return<void> Vibrator::perform_1_2(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
    188     return performEffect(static_cast<Effect>(effect), strength, _hidl_cb);
    189 }
    190 
    191 Return<void> Vibrator::performEffect(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
    192     Status status = Status::OK;
    193     uint32_t timeMS;
    194 
    195     switch (effect) {
    196     case Effect::CLICK:
    197         mSequencer << WAVEFORM_CLICK_EFFECT_SEQ << std::endl;
    198         timeMS = mClickDuration;
    199         break;
    200     case Effect::DOUBLE_CLICK:
    201         mSequencer << WAVEFORM_DOUBLE_CLICK_EFFECT_SEQ << std::endl;
    202         timeMS = WAVEFORM_DOUBLE_CLICK_EFFECT_MS;
    203         break;
    204     case Effect::TICK:
    205         mSequencer << WAVEFORM_TICK_EFFECT_SEQ << std::endl;
    206         timeMS = mTickDuration;
    207         break;
    208     case Effect::HEAVY_CLICK:
    209         mSequencer << WAVEFORM_HEAVY_CLICK_EFFECT_SEQ << std::endl;
    210         timeMS = mHeavyClickDuration;
    211         break;
    212     default:
    213         _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
    214         return Void();
    215     }
    216     mScale << convertEffectStrength(strength) << std::endl;
    217     on(timeMS, true /* forceOpenLoop */, true /* isWaveform */);
    218     _hidl_cb(status, timeMS);
    219     return Void();
    220 }
    221 
    222 
    223 } // namespace implementation
    224 }  // namespace V1_2
    225 }  // namespace vibrator
    226 }  // namespace hardware
    227 }  // namespace android
    228