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