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 
19 #include <stdlib.h>
20 
21 #include <fstream>
22 #include <memory>
23 #include <regex>
24 
25 #include "device_boutique.h"
26 #include "log.h"
27 #include "phy.h"
28 #include "rootcanal/configuration.pb.h"
29 
30 using std::vector;
31 
32 namespace rootcanal {
33 
ParseIntParam(std::string const & in)34 static size_t ParseIntParam(std::string const& in) {
35   return static_cast<size_t>(std::strtoul(in.c_str(), nullptr, 0));
36 }
37 
TestCommandHandler(TestModel & test_model)38 TestCommandHandler::TestCommandHandler(TestModel& test_model)
39     : model_(test_model) {
40 #define SET_HANDLER(command_name, method)                                     \
41   active_commands_[command_name] = [this](const vector<std::string>& param) { \
42     method(param);                                                            \
43   };
44   SET_HANDLER("add", AddDevice);
45   SET_HANDLER("add_remote", AddRemote);
46   SET_HANDLER("del", RemoveDevice);
47   SET_HANDLER("add_phy", AddPhy);
48   SET_HANDLER("del_phy", RemovePhy);
49   SET_HANDLER("add_device_to_phy", AddDeviceToPhy);
50   SET_HANDLER("del_device_from_phy", RemoveDeviceFromPhy);
51   SET_HANDLER("list", List);
52   SET_HANDLER("set_device_address", SetDeviceAddress);
53   SET_HANDLER("set_device_configuration", SetDeviceConfiguration);
54   SET_HANDLER("set_timer_period", SetTimerPeriod);
55   SET_HANDLER("start_timer", StartTimer);
56   SET_HANDLER("stop_timer", StopTimer);
57   SET_HANDLER("reset", Reset);
58 #undef SET_HANDLER
59   send_response_ = [](std::string const&) {};
60 }
61 
AddDefaults()62 void TestCommandHandler::AddDefaults() {
63   // Add a phy for LE and one for BR/EDR
64   AddPhy({"LOW_ENERGY"});
65   AddPhy({"BR_EDR"});
66 
67   // Add the controller to the Phys
68   AddDeviceToPhy({"1", "1"});
69   AddDeviceToPhy({"1", "2"});
70 
71   // Add default test devices and add the devices to the phys
72   //
73   // Add({"beacon", "be:ac:10:00:00:01", "1000"});
74   // AddDeviceToPhy({"2", "1"});
75   //
76   // Add({"sniffer", "ca:12:1c:17:00:01"});
77   // AddDeviceToPhy({"3", "2"});
78   //
79   // Add({"sniffer", "3c:5a:b4:04:05:06"});
80   // AddDeviceToPhy({"4", "2"});
81 
82   List({});
83 
84   SetTimerPeriod({"10"});
85   StartTimer({});
86 }
87 
HandleCommand(const std::string & name,const vector<std::string> & args)88 void TestCommandHandler::HandleCommand(const std::string& name,
89                                        const vector<std::string>& args) {
90   if (active_commands_.count(name) == 0) {
91     response_string_ = "Unhandled command: " + name;
92     send_response_(response_string_);
93     return;
94   }
95   active_commands_[name](args);
96 }
97 
RegisterSendResponse(const std::function<void (const std::string &)> callback)98 void TestCommandHandler::RegisterSendResponse(
99     const std::function<void(const std::string&)> callback) {
100   send_response_ = callback;
101   send_response_("RegisterSendResponse called");
102 }
103 
AddDevice(const vector<std::string> & args)104 void TestCommandHandler::AddDevice(const vector<std::string>& args) {
105   if (args.empty()) {
106     response_string_ = "TestCommandHandler 'add' takes an argument";
107     send_response_(response_string_);
108     return;
109   }
110   std::shared_ptr<Device> new_dev = DeviceBoutique::Create(args);
111 
112   if (new_dev == NULL) {
113     response_string_ = "TestCommandHandler 'add' " + args[0] + " failed!";
114     send_response_(response_string_);
115     WARNING("{}", response_string_);
116     return;
117   }
118 
119   INFO("Add {}", new_dev->ToString());
120   size_t dev_index = model_.AddDevice(new_dev);
121   response_string_ =
122       std::to_string(dev_index) + std::string(":") + new_dev->ToString();
123   send_response_(response_string_);
124 }
125 
AddRemote(const vector<std::string> & args)126 void TestCommandHandler::AddRemote(const vector<std::string>& args) {
127   if (args.size() < 3) {
128     response_string_ =
129         "TestCommandHandler usage: add_remote host port phy_type";
130     send_response_(response_string_);
131     return;
132   }
133 
134   size_t port = ParseIntParam(args[1]);
135   Phy::Type phy_type = Phy::Type::BR_EDR;
136   if ("LOW_ENERGY" == args[2]) {
137     phy_type = Phy::Type::LOW_ENERGY;
138   }
139   if (port == 0 || port > 0xffff || args[0].size() < 2) {
140     response_string_ = "TestCommandHandler bad arguments to 'add_remote': ";
141     response_string_ += args[0];
142     response_string_ += "@";
143     response_string_ += args[1];
144     send_response_(response_string_);
145     return;
146   }
147 
148   model_.AddRemote(args[0], port, phy_type);
149 
150   response_string_ = args[0] + std::string("@") + std::to_string(port);
151   send_response_(response_string_);
152 }
153 
RemoveDevice(const vector<std::string> & args)154 void TestCommandHandler::RemoveDevice(const vector<std::string>& args) {
155   size_t dev_index = ParseIntParam(args[0]);
156 
157   model_.RemoveDevice(dev_index);
158   response_string_ = "TestCommandHandler 'del' called with device at index " +
159                      std::to_string(dev_index);
160   send_response_(response_string_);
161 }
162 
AddPhy(const vector<std::string> & args)163 void TestCommandHandler::AddPhy(const vector<std::string>& args) {
164   if (args.size() != 1) {
165     response_string_ = "TestCommandHandler 'add_phy' takes one argument";
166   } else if (args[0] == "LOW_ENERGY") {
167     model_.AddPhy(Phy::Type::LOW_ENERGY);
168     response_string_ = "TestCommandHandler 'add_phy' called with LOW_ENERGY";
169   } else if (args[0] == "BR_EDR") {
170     model_.AddPhy(Phy::Type::BR_EDR);
171     response_string_ = "TestCommandHandler 'add_phy' called with BR_EDR";
172   } else {
173     response_string_ =
174         "TestCommandHandler 'add_phy' with unrecognized type " + args[0];
175   }
176   send_response_(response_string_);
177 }
178 
RemovePhy(const vector<std::string> & args)179 void TestCommandHandler::RemovePhy(const vector<std::string>& args) {
180   size_t phy_index = ParseIntParam(args[0]);
181 
182   model_.RemovePhy(phy_index);
183   response_string_ = "TestCommandHandler 'del_phy' called with phy at index " +
184                      std::to_string(phy_index);
185   send_response_(response_string_);
186 }
187 
AddDeviceToPhy(const vector<std::string> & args)188 void TestCommandHandler::AddDeviceToPhy(const vector<std::string>& args) {
189   if (args.size() != 2) {
190     response_string_ =
191         "TestCommandHandler 'add_device_to_phy' takes two arguments";
192     send_response_(response_string_);
193     return;
194   }
195   size_t dev_index = ParseIntParam(args[0]);
196   size_t phy_index = ParseIntParam(args[1]);
197   model_.AddDeviceToPhy(dev_index, phy_index);
198   response_string_ =
199       "TestCommandHandler 'add_device_to_phy' called with device " +
200       std::to_string(dev_index) + " and phy " + std::to_string(phy_index);
201   send_response_(response_string_);
202 }
203 
RemoveDeviceFromPhy(const vector<std::string> & args)204 void TestCommandHandler::RemoveDeviceFromPhy(const vector<std::string>& args) {
205   if (args.size() != 2) {
206     response_string_ =
207         "TestCommandHandler 'del_device_from_phy' takes two arguments";
208     send_response_(response_string_);
209     return;
210   }
211   size_t dev_index = ParseIntParam(args[0]);
212   size_t phy_index = ParseIntParam(args[1]);
213   model_.RemoveDeviceFromPhy(dev_index, phy_index);
214   response_string_ =
215       "TestCommandHandler 'del_device_from_phy' called with device " +
216       std::to_string(dev_index) + " and phy " + std::to_string(phy_index);
217   send_response_(response_string_);
218 }
219 
List(const vector<std::string> & args)220 void TestCommandHandler::List(const vector<std::string>& args) {
221   if (!args.empty()) {
222     INFO("Unused args: arg[0] = {}", args[0]);
223     return;
224   }
225   send_response_(model_.List());
226 }
227 
SetDeviceAddress(const vector<std::string> & args)228 void TestCommandHandler::SetDeviceAddress(const vector<std::string>& args) {
229   if (args.size() != 2) {
230     response_string_ =
231         "TestCommandHandler 'set_device_address' takes two arguments";
232     send_response_(response_string_);
233     return;
234   }
235   size_t device_id = ParseIntParam(args[0]);
236   Address device_address{};
237   Address::FromString(args[1], device_address);
238   model_.SetDeviceAddress(device_id, device_address);
239   response_string_ = "set_device_address " + args[0];
240   response_string_ += " ";
241   response_string_ += args[1];
242   send_response_(response_string_);
243 }
244 
SetDeviceConfiguration(const vector<std::string> & args)245 void TestCommandHandler::SetDeviceConfiguration(const vector<std::string>& args) {
246   if (args.size() != 2) {
247     response_string_ =
248         "TestCommandHandler 'set_device_configuration' takes two arguments";
249     send_response_(response_string_);
250     return;
251   }
252   size_t device_id = ParseIntParam(args[0]);
253   rootcanal::configuration::ControllerPreset preset =
254       rootcanal::configuration::ControllerPreset::DEFAULT;
255 
256   if (args[1] == "default") {
257     preset = rootcanal::configuration::ControllerPreset::DEFAULT;
258   } else if (args[1] == "laird_bl654") {
259     preset = rootcanal::configuration::ControllerPreset::LAIRD_BL654;
260   } else if (args[1] == "csr_rck_pts_dongle") {
261     preset = rootcanal::configuration::ControllerPreset::CSR_RCK_PTS_DONGLE;
262   } else {
263     response_string_ =
264         "TestCommandHandler 'set_device_configuration' invalid configuration preset";
265     send_response_(response_string_);
266     return;
267   }
268 
269   rootcanal::configuration::Controller configuration;
270   configuration.set_preset(preset);
271   model_.SetDeviceConfiguration(device_id, configuration);
272   response_string_ = "set_device_configuration " + args[0];
273   response_string_ += " ";
274   response_string_ += args[1];
275   send_response_(response_string_);
276 }
277 
SetTimerPeriod(const vector<std::string> & args)278 void TestCommandHandler::SetTimerPeriod(const vector<std::string>& args) {
279   if (args.size() != 1) {
280     INFO("SetTimerPeriod takes 1 argument");
281   }
282   size_t period = ParseIntParam(args[0]);
283   if (period != 0) {
284     response_string_ = "set timer period to ";
285     response_string_ += args[0];
286     model_.SetTimerPeriod(std::chrono::milliseconds(period));
287   } else {
288     response_string_ = "invalid timer period ";
289     response_string_ += args[0];
290   }
291   send_response_(response_string_);
292 }
293 
StartTimer(const vector<std::string> & args)294 void TestCommandHandler::StartTimer(const vector<std::string>& args) {
295   if (!args.empty()) {
296     INFO("Unused args: arg[0] = {}", args[0]);
297   }
298   model_.StartTimer();
299   response_string_ = "timer started";
300   send_response_(response_string_);
301 }
302 
StopTimer(const vector<std::string> & args)303 void TestCommandHandler::StopTimer(const vector<std::string>& args) {
304   if (!args.empty()) {
305     INFO("Unused args: arg[0] = {}", args[0]);
306   }
307   model_.StopTimer();
308   response_string_ = "timer stopped";
309   send_response_(response_string_);
310 }
311 
Reset(const std::vector<std::string> & args)312 void TestCommandHandler::Reset(const std::vector<std::string>& args) {
313   if (!args.empty()) {
314     INFO("Unused args: arg[0] = {}", args[0]);
315   }
316   model_.Reset();
317   response_string_ = "model reset";
318   send_response_(response_string_);
319 }
320 
321 }  // namespace rootcanal
322