/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "utils.h" #include "vibrator.h" namespace android { namespace idlcli { class CommandVibrator; namespace vibrator { using aidl::ActivePwle; using aidl::Braking; using aidl::BrakingPwle; using aidl::PrimitivePwle; class CommandComposePwle : public Command { std::string getDescription() const override { return "Compose PWLE vibration."; } std::string getUsageSummary() const override { return "[options] a b ..."; } UsageDetails getUsageDetails() const override { UsageDetails details{ {"-b", {"Block for duration of vibration."}}, {"a ", {"Enter the active PWLE segment parameters"}}, {"b ", {"Enter the braking PWLE segment parameters"}}, {"...", {"May repeat multiple times."}}, }; return details; } int getIntFromString(std::string input, int *output) { int rc = 0; int value; const auto res = std::from_chars(input.data(), input.data() + input.size(), value); if (res.ec == std::errc::invalid_argument) { std::cerr << "Invalid int argument: " << input << std::endl; rc = (int)std::errc::invalid_argument; } else if (res.ec == std::errc::result_out_of_range) { std::cerr << "Result out of range: " << input << std::endl; rc = (int)std::errc::result_out_of_range; } *output = value; return rc; } float getFloatFromString(std::string_view input, float *output) { int rc = 0; errno = 0; // from_chars doesn't support conversion to float so we need to first // convert the string_view to string and use the C-string for strtof float value = strtof(std::string(input).c_str(), NULL); if (input == "0.0" || input == "0") { return rc; } if (value <= 0.0) { std::cerr << "Invalid float argument: " << input << std::endl; rc = EINVAL; } else if (errno == ERANGE) { std::cerr << "Result out of range: " << input << std::endl; rc = errno; } else { *output = value; } return rc; } Status doArgs(Args &args) override { while (args.get().value_or("").find("-") == 0) { auto opt = *args.pop(); if (opt == "--") { break; } else if (opt == "-b") { mBlocking = true; } else { std::cerr << "Invalid Option '" << opt << "'!" << std::endl; return USAGE; } } if (args.empty()) { std::cerr << "Missing arguments! Please see usage" << std::endl; return USAGE; } while (!args.empty()) { PrimitivePwle pwle; auto nextArg = args.pop(); if (*nextArg == "a") { auto startAmplitude = args.pop(); float startAmp; if (getFloatFromString(*startAmplitude, &startAmp)) return USAGE; auto startFrequency = args.pop(); float startFreq; if (getFloatFromString(*startFrequency, &startFreq)) return USAGE; auto endAmplitude = args.pop(); float endAmp; if (getFloatFromString(*endAmplitude, &endAmp)) return USAGE; auto endFrequency = args.pop(); float endFreq; if (getFloatFromString(*endFrequency, &endFreq)) return USAGE; auto duration = args.pop(); int dur; if (getIntFromString(*duration, &dur)) return USAGE; ActivePwle active = {startAmp, startFreq, endAmp, endFreq, dur}; pwle = active; } else if (*nextArg == "b") { auto brakingMethod = args.pop(); Braking brakingMeth; if (getIntFromString(*brakingMethod, (int *)&brakingMeth)) return USAGE; auto duration = args.pop(); int dur; if (getIntFromString(*duration, &dur)) return USAGE; BrakingPwle braking = {brakingMeth, dur}; pwle = braking; } else { std::cerr << "Invalid arguments! Please see usage" << std::endl; return USAGE; } mCompositePwle.emplace_back(std::move(pwle)); } if (!args.empty()) { std::cerr << "Unexpected Arguments!" << std::endl; return USAGE; } return OK; } Status doMain(Args && /*args*/) override { auto hal = getHal(); if (!hal) { return UNAVAILABLE; } ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); std::shared_ptr callback; if (mBlocking) { callback = ndk::SharedRefBase::make(); } auto status = hal->call(&aidl::IVibrator::composePwle, mCompositePwle, callback); if (status.isOk() && callback) { callback->waitForComplete(); } std::cout << "Status: " << status.getDescription() << std::endl; return status.isOk() ? OK : ERROR; } bool mBlocking; std::vector mCompositePwle; }; static const auto Command = CommandRegistry::Register("composePwle"); } // namespace vibrator } // namespace idlcli } // namespace android