/* * Copyright (C) 2022 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 "canbus_config.pb.h" #include "canprototools.h" #include #include #include #include #include namespace android::hardware::automotive::can { using namespace std::string_literals; using ::aidl::android::hardware::automotive::can::ICanController; static constexpr std::string_view kDefaultConfigPath = "/etc/canbus_config.pb"; /** * Takes output from parsed protobuf config and uses it to configure the CAN HAL. * * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration. * \return boolean status, true on success, false on failure. */ static bool processPbCfg(const config::CanBusConfig& pb_cfg) { for (auto const& bus : pb_cfg.buses()) { if (bus.name().empty()) { LOG(ERROR) << "Invalid config: Bus config must have a valid name field"; return false; } auto busCfgMaybe = config::fromPbBus(bus); if (!busCfgMaybe.has_value()) { return false; } auto busCfg = *busCfgMaybe; const auto instance = ICanController::descriptor + "/default"s; const auto service = ICanController::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str()))); if (service == nullptr) { LOG(FATAL) << "Can't find CAN HAL! (has it started yet?)"; return false; } LOG(VERBOSE) << "Bringing up a " << busCfg.name << " @ " << busCfg.bitrate; std::string ifaceName; const auto status = service->upBus(busCfg, &ifaceName); if (!status.isOk() && status.getExceptionCode() != EX_SERVICE_SPECIFIC) { LOG(FATAL) << "Binder transaction failed!" << status.getStatus(); return false; } else if (!status.isOk()) { LOG(ERROR) << "upBus failed: " << config::resultStringFromStatus(status) << ": " << status.getMessage(); continue; } LOG(INFO) << bus.name() << " has been successfully configured on " << ifaceName; } return true; } /** * This kicks off the CAN HAL configuration process. This starts the following: * 1. Reading the config file * 2. Setting up CAN buses * 3. Handling services * \param filepath is a string specifying the absolute path of the config file * \return boolean status, true on success, false on failure */ static bool configuratorStart(const std::string& filepath) { base::SetDefaultTag("CanConfigurator"); auto pbCfg = config::parseConfigFile(filepath); if (!pbCfg.has_value()) { return false; } // process the rest of the config file data and configure the CAN buses. if (!processPbCfg(*pbCfg)) { return false; } LOG(INFO) << "CAN HAL has been configured!"; return true; } extern "C" int main(int argc, char* argv[]) { std::string configFilepath = static_cast(kDefaultConfigPath); // allow for CLI specification of a config file. if (argc == 2) { configFilepath = argv[1]; } else if (argc > 2) { std::cerr << "usage: " << argv[0] << " [optional config filepath]"; return 1; } if (!configuratorStart(configFilepath)) { return 1; } return 0; } } // namespace android::hardware::automotive::can