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