blob: b8308ce16f1697f5877a9e64950e639b450ae7c3 [file] [log] [blame]
Vince Leung44efedc2021-02-05 05:57:40 +00001/*
2 * Copyright (C) 2019 The Android Open Source Project *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <stdlib.h>
17
18#include <charconv>
19
20#include "utils.h"
21#include "vibrator.h"
22
23namespace android {
24namespace idlcli {
25
26class CommandVibrator;
27
28namespace vibrator {
29
30using aidl::ActivePwle;
31using aidl::Braking;
32using aidl::BrakingPwle;
33using aidl::PrimitivePwle;
34
35class CommandComposePwle : public Command {
36 std::string getDescription() const override { return "Compose PWLE vibration."; }
37
38 std::string getUsageSummary() const override {
39 return "[options] a <active pwle params> b <braking pwle params> ...";
40 }
41
42 UsageDetails getUsageDetails() const override {
43 UsageDetails details{
44 {"-b", {"Block for duration of vibration."}},
45 {"a <startAmplitude> <startFrequency> <endAmplitude> <endFrequency> <duration>",
46 {"Enter the active PWLE segment parameters"}},
47 {"b <brakingMethod> <duration>", {"Enter the braking PWLE segment parameters"}},
48 {"...", {"May repeat multiple times."}},
49 };
50 return details;
51 }
52
53 int getIntFromString(std::string input, int *output) {
54 int rc = 0;
55 int value;
56 const auto res = std::from_chars(input.data(), input.data() + input.size(), value);
57 if (res.ec == std::errc::invalid_argument) {
58 std::cerr << "Invalid int argument: " << input << std::endl;
59 rc = (int)std::errc::invalid_argument;
60 } else if (res.ec == std::errc::result_out_of_range) {
61 std::cerr << "Result out of range: " << input << std::endl;
62 rc = (int)std::errc::result_out_of_range;
63 }
64 *output = value;
65 return rc;
66 }
67
68 float getFloatFromString(std::string_view input, float *output) {
69 int rc = 0;
70 errno = 0;
71 // from_chars doesn't support conversion to float so we need to first
72 // convert the string_view to string and use the C-string for strtof
73 float value = strtof(std::string(input).c_str(), NULL);
74
75 if (input == "0.0" || input == "0") {
76 return rc;
77 }
78
79 if (value <= 0.0) {
80 std::cerr << "Invalid float argument: " << input << std::endl;
81 rc = EINVAL;
82 } else if (errno == ERANGE) {
83 std::cerr << "Result out of range: " << input << std::endl;
84 rc = errno;
85 } else {
86 *output = value;
87 }
88 return rc;
89 }
90
91 Status doArgs(Args &args) override {
92 while (args.get<std::string>().value_or("").find("-") == 0) {
93 auto opt = *args.pop<std::string>();
94 if (opt == "--") {
95 break;
96 } else if (opt == "-b") {
97 mBlocking = true;
98 } else {
99 std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
100 return USAGE;
101 }
102 }
103 if (args.empty()) {
104 std::cerr << "Missing arguments! Please see usage" << std::endl;
105 return USAGE;
106 }
107 while (!args.empty()) {
108 PrimitivePwle pwle;
109 auto nextArg = args.pop();
110
111 if (*nextArg == "a") {
112 auto startAmplitude = args.pop();
113 float startAmp;
114 if (getFloatFromString(*startAmplitude, &startAmp))
115 return USAGE;
116
117 auto startFrequency = args.pop();
118 float startFreq;
119 if (getFloatFromString(*startFrequency, &startFreq))
120 return USAGE;
121
122 auto endAmplitude = args.pop();
123 float endAmp;
124 if (getFloatFromString(*endAmplitude, &endAmp))
125 return USAGE;
126
127 auto endFrequency = args.pop();
128 float endFreq;
129 if (getFloatFromString(*endFrequency, &endFreq))
130 return USAGE;
131
132 auto duration = args.pop();
133 int dur;
134 if (getIntFromString(*duration, &dur))
135 return USAGE;
136
137 ActivePwle active = {startAmp, startFreq, endAmp, endFreq, dur};
138 pwle = active;
139 } else if (*nextArg == "b") {
140 auto brakingMethod = args.pop();
141 Braking brakingMeth;
142 if (getIntFromString(*brakingMethod, (int *)&brakingMeth))
143 return USAGE;
144
145 auto duration = args.pop();
146 int dur;
147 if (getIntFromString(*duration, &dur))
148 return USAGE;
149
150 BrakingPwle braking = {brakingMeth, dur};
151 pwle = braking;
152 } else {
153 std::cerr << "Invalid arguments! Please see usage" << std::endl;
154 return USAGE;
155 }
156 mCompositePwle.emplace_back(std::move(pwle));
157 }
158 if (!args.empty()) {
159 std::cerr << "Unexpected Arguments!" << std::endl;
160 return USAGE;
161 }
162 return OK;
163 }
164
165 Status doMain(Args && /*args*/) override {
166 auto hal = getHal<aidl::IVibrator>();
167
168 if (!hal) {
169 return UNAVAILABLE;
170 }
171
172 ABinderProcess_setThreadPoolMaxThreadCount(1);
173 ABinderProcess_startThreadPool();
174
175 std::shared_ptr<VibratorCallback> callback;
176
177 if (mBlocking) {
178 callback = ndk::SharedRefBase::make<VibratorCallback>();
179 }
180
181 auto status = hal->call(&aidl::IVibrator::composePwle, mCompositePwle, callback);
182
183 if (status.isOk() && callback) {
184 callback->waitForComplete();
185 }
186
187 std::cout << "Status: " << status.getDescription() << std::endl;
188
189 return status.isOk() ? OK : ERROR;
190 }
191
192 bool mBlocking;
193 std::vector<PrimitivePwle> mCompositePwle;
194};
195
196static const auto Command =
197 CommandRegistry<CommandVibrator>::Register<CommandComposePwle>("composePwle");
198
199} // namespace vibrator
200} // namespace idlcli
201} // namespace android