1 /*
2  * Copyright 2018 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 "test_command_handler.h"
18 #include "device_boutique.h"
19 #include "phy.h"
20 
21 #include <memory>
22 
23 #include <stdlib.h>
24 
25 #include "base/files/file_util.h"
26 #include "base/json/json_reader.h"
27 #include "base/strings/string_split.h"
28 #include "base/values.h"
29 
30 #include "os/log.h"
31 #include "osi/include/osi.h"
32 
33 using std::vector;
34 
35 namespace test_vendor_lib {
36 
TestCommandHandler(TestModel & test_model)37 TestCommandHandler::TestCommandHandler(TestModel& test_model) : model_(test_model) {
38 #define SET_HANDLER(command_name, method) \
39   active_commands_[command_name] = [this](const vector<std::string>& param) { method(param); };
40   SET_HANDLER("add", Add);
41   SET_HANDLER("add_remote", AddRemote);
42   SET_HANDLER("del", Del);
43   SET_HANDLER("add_phy", AddPhy);
44   SET_HANDLER("del_phy", DelPhy);
45   SET_HANDLER("add_device_to_phy", AddDeviceToPhy);
46   SET_HANDLER("del_device_from_phy", DelDeviceFromPhy);
47   SET_HANDLER("list", List);
48   SET_HANDLER("set_device_address", SetDeviceAddress);
49   SET_HANDLER("set_timer_period", SetTimerPeriod);
50   SET_HANDLER("start_timer", StartTimer);
51   SET_HANDLER("stop_timer", StopTimer);
52   SET_HANDLER("reset", Reset);
53 #undef SET_HANDLER
54 }
55 
AddDefaults()56 void TestCommandHandler::AddDefaults() {
57   // Add a phy for LE and one for BR/EDR
58   AddPhy({"LOW_ENERGY"});
59   AddPhy({"BR_EDR"});
60 
61   // Add the controller to the Phys
62   AddDeviceToPhy({"1", "1"});
63   AddDeviceToPhy({"1", "2"});
64 
65   // Add default test devices and add the devices to the phys
66   // Add({"beacon", "be:ac:10:00:00:01", "1000"});
67   // AddDeviceToPhy({"2", "1"});
68 
69   // Add({"keyboard", "cc:1c:eb:0a:12:d1", "500"});
70   // AddDeviceToPhy({"3", "1"});
71 
72   // Add({"classic", "c1:a5:51:c0:00:01", "22"});
73   // AddDeviceToPhy({"4", "2"});
74 
75   // Add({"car_kit", "ca:12:1c:17:00:01", "238"});
76   // AddDeviceToPhy({"5", "2"});
77 
78   // Add({"sniffer", "ca:12:1c:17:00:01"});
79   // AddDeviceToPhy({"6", "2"});
80 
81   // Add({"sniffer", "3c:5a:b4:04:05:06"});
82   // AddDeviceToPhy({"7", "2"});
83   // Add({"remote_loopback_device", "10:0d:00:ba:c1:06"});
84   // AddDeviceToPhy({"8", "2"});
85   List({});
86 
87   SetTimerPeriod({"10"});
88   StartTimer({});
89 }
90 
HandleCommand(const std::string & name,const vector<std::string> & args)91 void TestCommandHandler::HandleCommand(const std::string& name, const vector<std::string>& args) {
92   if (active_commands_.count(name) == 0) {
93     response_string_ = "Unhandled command: " + name;
94     send_response_(response_string_);
95     return;
96   }
97   active_commands_[name](args);
98 }
99 
FromFile(const std::string & file_name)100 void TestCommandHandler::FromFile(const std::string& file_name) {
101   if (file_name.size() == 0) {
102     return;
103   }
104 
105   std::string commands_raw;
106   if (!base::ReadFileToString(base::FilePath(file_name), &commands_raw)) {
107     LOG_ERROR("Error reading commands from file.");
108     return;
109   }
110 
111   base::StringPairs command_pairs;
112   base::SplitStringIntoKeyValuePairs(commands_raw, ' ', '\n', &command_pairs);
113   for (const std::pair<std::string, std::string>& p : command_pairs) {
114     auto params = base::SplitString(p.second, " ", base::TRIM_WHITESPACE,
115                                     base::SPLIT_WANT_NONEMPTY);
116     HandleCommand(p.first, params);
117   }
118 }
119 
RegisterSendResponse(const std::function<void (const std::string &)> callback)120 void TestCommandHandler::RegisterSendResponse(const std::function<void(const std::string&)> callback) {
121   send_response_ = callback;
122   send_response_("RegisterSendResponse called");
123 }
124 
Add(const vector<std::string> & args)125 void TestCommandHandler::Add(const vector<std::string>& args) {
126   if (args.size() < 1) {
127     response_string_ = "TestCommandHandler 'add' takes an argument";
128     send_response_(response_string_);
129     return;
130   }
131   std::shared_ptr<Device> new_dev = DeviceBoutique::Create(args);
132 
133   if (new_dev == NULL) {
134     response_string_ = "TestCommandHandler 'add' " + args[0] + " failed!";
135     send_response_(response_string_);
136     LOG_WARN("%s", response_string_.c_str());
137     return;
138   }
139 
140   LOG_INFO("Add %s", new_dev->ToString().c_str());
141   size_t dev_index = model_.Add(new_dev);
142   response_string_ = std::to_string(dev_index) + std::string(":") + new_dev->ToString();
143   send_response_(response_string_);
144 }
145 
AddRemote(const vector<std::string> & args)146 void TestCommandHandler::AddRemote(const vector<std::string>& args) {
147   if (args.size() < 3) {
148     response_string_ = "TestCommandHandler usage: add_remote host port phy_type";
149     send_response_(response_string_);
150     return;
151   }
152 
153   size_t port = std::stoi(args[1]);
154   Phy::Type phy_type = Phy::Type::BR_EDR;
155   if ("LOW_ENERGY" == args[2]) {
156     phy_type = Phy::Type::LOW_ENERGY;
157   }
158   if (port == 0 || port > 0xffff || args[0].size() < 2) {
159     response_string_ = "TestCommandHandler bad arguments to 'add_remote': ";
160     response_string_ += args[0];
161     response_string_ += "@";
162     response_string_ += args[1];
163     send_response_(response_string_);
164     return;
165   }
166 
167   model_.AddRemote(args[0], port, phy_type);
168 
169   response_string_ = args[0] + std::string("@") + std::to_string(port);
170   send_response_(response_string_);
171 }
172 
Del(const vector<std::string> & args)173 void TestCommandHandler::Del(const vector<std::string>& args) {
174   size_t dev_index = std::stoi(args[0]);
175 
176   model_.Del(dev_index);
177   response_string_ = "TestCommandHandler 'del' called with device at index " + std::to_string(dev_index);
178   send_response_(response_string_);
179 }
180 
AddPhy(const vector<std::string> & args)181 void TestCommandHandler::AddPhy(const vector<std::string>& args) {
182   if (args[0] == "LOW_ENERGY") {
183     model_.AddPhy(Phy::Type::LOW_ENERGY);
184   } else if (args[0] == "BR_EDR") {
185     model_.AddPhy(Phy::Type::BR_EDR);
186   } else {
187     response_string_ = "TestCommandHandler 'add_phy' with unrecognized type " + args[0];
188     send_response_(response_string_);
189   }
190 }
191 
DelPhy(const vector<std::string> & args)192 void TestCommandHandler::DelPhy(const vector<std::string>& args) {
193   size_t phy_index = std::stoi(args[0]);
194 
195   model_.DelPhy(phy_index);
196   response_string_ = "TestCommandHandler 'del_phy' called with phy at index " + std::to_string(phy_index);
197   send_response_(response_string_);
198 }
199 
AddDeviceToPhy(const vector<std::string> & args)200 void TestCommandHandler::AddDeviceToPhy(const vector<std::string>& args) {
201   if (args.size() != 2) {
202     response_string_ = "TestCommandHandler 'add_device_to_phy' takes two arguments";
203     send_response_(response_string_);
204     return;
205   }
206   size_t dev_index = std::stoi(args[0]);
207   size_t phy_index = std::stoi(args[1]);
208   model_.AddDeviceToPhy(dev_index, phy_index);
209   response_string_ = "TestCommandHandler 'add_device_to_phy' called with device " + std::to_string(dev_index) +
210                      " and phy " + std::to_string(phy_index);
211   send_response_(response_string_);
212   return;
213 }
214 
DelDeviceFromPhy(const vector<std::string> & args)215 void TestCommandHandler::DelDeviceFromPhy(const vector<std::string>& args) {
216   if (args.size() != 2) {
217     response_string_ = "TestCommandHandler 'del_device_from_phy' takes two arguments";
218     send_response_(response_string_);
219     return;
220   }
221   size_t dev_index = std::stoi(args[0]);
222   size_t phy_index = std::stoi(args[1]);
223   model_.DelDeviceFromPhy(dev_index, phy_index);
224   response_string_ = "TestCommandHandler 'del_device_from_phy' called with device " + std::to_string(dev_index) +
225                      " and phy " + std::to_string(phy_index);
226   send_response_(response_string_);
227   return;
228 }
229 
List(const vector<std::string> & args)230 void TestCommandHandler::List(const vector<std::string>& args) {
231   if (args.size() > 0) {
232     LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
233     return;
234   }
235   send_response_(model_.List());
236 }
237 
SetDeviceAddress(const vector<std::string> & args)238 void TestCommandHandler::SetDeviceAddress(const vector<std::string>& args) {
239   if (args.size() != 2) {
240     response_string_ = "TestCommandHandler 'set_device_address' takes two arguments";
241     send_response_(response_string_);
242     return;
243   }
244   size_t device_id = std::stoi(args[0]);
245   Address device_address{};
246   Address::FromString(args[1], device_address);
247   model_.SetDeviceAddress(device_id, device_address);
248   response_string_ = "set_device_address " + args[0];
249   response_string_ += " ";
250   response_string_ += args[1];
251   send_response_(response_string_);
252 }
253 
SetTimerPeriod(const vector<std::string> & args)254 void TestCommandHandler::SetTimerPeriod(const vector<std::string>& args) {
255   if (args.size() != 1) {
256     LOG_INFO("SetTimerPeriod takes 1 argument");
257   }
258   size_t period = std::stoi(args[0]);
259   if (period != 0) {
260     response_string_ = "set timer period to ";
261     response_string_ += args[0];
262     model_.SetTimerPeriod(std::chrono::milliseconds(period));
263   } else {
264     response_string_ = "invalid timer period ";
265     response_string_ += args[0];
266   }
267   send_response_(response_string_);
268 }
269 
StartTimer(const vector<std::string> & args)270 void TestCommandHandler::StartTimer(const vector<std::string>& args) {
271   if (args.size() > 0) {
272     LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
273   }
274   model_.StartTimer();
275   response_string_ = "timer started";
276   send_response_(response_string_);
277 }
278 
StopTimer(const vector<std::string> & args)279 void TestCommandHandler::StopTimer(const vector<std::string>& args) {
280   if (args.size() > 0) {
281     LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
282   }
283   model_.StopTimer();
284   response_string_ = "timer stopped";
285   send_response_(response_string_);
286 }
287 
Reset(const std::vector<std::string> & args)288 void TestCommandHandler::Reset(const std::vector<std::string>& args) {
289   if (args.size() > 0) {
290     LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
291   }
292   model_.Reset();
293   response_string_ = "model reset";
294   send_response_(response_string_);
295 }
296 
297 }  // namespace test_vendor_lib
298