• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
23 namespace android {
24 namespace idlcli {
25 
26 class CommandVibrator;
27 
28 namespace vibrator {
29 
30 using aidl::ActivePwle;
31 using aidl::Braking;
32 using aidl::BrakingPwle;
33 using aidl::PrimitivePwle;
34 
35 class CommandComposePwle : public Command {
getDescription() const36     std::string getDescription() const override { return "Compose PWLE vibration."; }
37 
getUsageSummary() const38     std::string getUsageSummary() const override {
39         return "[options] a <active pwle params> b <braking pwle params> ...";
40     }
41 
getUsageDetails() const42     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 
getIntFromString(std::string input,int * output)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 
getFloatFromString(std::string_view input,float * output)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 
doArgs(Args & args)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 
doMain(Args &&)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 
196 static const auto Command =
197     CommandRegistry<CommandVibrator>::Register<CommandComposePwle>("composePwle");
198 
199 }  // namespace vibrator
200 }  // namespace idlcli
201 }  // namespace android
202