1 /*
2  * Copyright (C) 2020 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 #include "canbus_config.pb.h"
18 #include "canprototools.h"
19 
20 #include <android-base/logging.h>
21 #include <android/hardware/automotive/can/1.0/ICanController.h>
22 #include <libcanhaltools/libcanhaltools.h>
23 
24 #include <chrono>
25 #include <thread>
26 
27 namespace android::hardware::automotive::can {
28 
29 using ICanController = V1_0::ICanController;
30 
31 /**
32  * Takes output from parsed protobuf config and uses it to configure the CAN HAL.
33  *
34  * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration.
35  * \return boolean status, true on success, false on failure.
36  */
processPbCfg(const config::CanBusConfig & pb_cfg)37 static bool processPbCfg(const config::CanBusConfig& pb_cfg) {
38     for (auto const& bus : pb_cfg.buses()) {
39         if (bus.name().empty()) {
40             LOG(ERROR) << "Invalid config: Bus config must have a valid name field";
41             return false;
42         }
43 
44         LOG(INFO) << "Configure " << bus.name();
45         auto bus_cfg = config::fromPbBus(bus);
46         if (!bus_cfg.has_value()) {
47             return false;
48         }
49 
50         // TODO(149405589): remove this sleep and associated includes.
51         std::this_thread::sleep_for(std::chrono::seconds(1));
52         if (libcanhaltools::configureIface(*bus_cfg) != ICanController::Result::OK) {
53             LOG(ERROR) << "No controller supports " << bus.name() << std::endl;
54             // TODO(149405589): add retry logic in case a bus fails to come up.
55             continue;
56         }
57         LOG(INFO) << bus.name() << " has been successfully configured!";
58     }
59     return true;
60 }
61 
62 /**
63  * This kicks off the CAN HAL configuration process. This starts the following:
64  *     1. Reading the config file
65  *     2. Setting up CAN buses
66  *     3. Handling services
67  * \param filepath is a string specifying the absolute path of the config file
68  * \return boolean status, true on success, false on failure
69  */
configuratorStart(const std::string & filepath)70 static bool configuratorStart(const std::string& filepath) {
71     base::SetDefaultTag("CanConfigurator");
72 
73     LOG(WARNING) << "The HIDL version of CAN HAL has been deprecated, if this tool fails with "
74                  << "SIGABRT, you may need canhalconfigurator-aidl instead.";
75 
76     auto pb_cfg = config::parseConfigFile(filepath);
77     if (!pb_cfg.has_value()) {
78         return false;
79     }
80 
81     // process the rest of the config file data and configure the CAN buses.
82     if (!processPbCfg(*pb_cfg)) {
83         return false;
84     }
85     LOG(INFO) << "CAN HAL has been configured!";
86     return true;
87 }
88 
89 }  // namespace android::hardware::automotive::can
90 
main(int argc,char * argv[])91 int main(int argc, char* argv[]) {
92     std::string config_filepath = "/etc/canbus_config.pb";
93 
94     // allow for CLI specification of a config file.
95     if (argc == 2) {
96         config_filepath = argv[1];
97     } else if (argc > 2) {
98         std::cerr << "usage: " << argv[0] << " [optional config filepath]";
99         return 1;
100     }
101 
102     if (!::android::hardware::automotive::can::configuratorStart(config_filepath)) {
103         return 1;
104     }
105     return 0;
106 }
107