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