• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_model.h"
18 
19 #include <stdlib.h>  // for size_t
20 
21 #include <iomanip>      // for operator<<, setfill
22 #include <iostream>     // for basic_ostream
23 #include <memory>       // for shared_ptr, make...
24 #include <type_traits>  // for remove_extent_t
25 #include <utility>      // for move
26 
27 #include "include/phy.h"  // for Phy, Phy::Type
28 #include "log.h"          // for LOG_WARN, LOG_INFO
29 
30 namespace rootcanal {
31 
TestModel(std::function<AsyncUserId ()> get_user_id,std::function<AsyncTaskId (AsyncUserId,std::chrono::milliseconds,const TaskCallback &)> event_scheduler,std::function<AsyncTaskId (AsyncUserId,std::chrono::milliseconds,std::chrono::milliseconds,const TaskCallback &)> periodic_event_scheduler,std::function<void (AsyncUserId)> cancel_tasks_from_user,std::function<void (AsyncTaskId)> cancel,std::function<std::shared_ptr<Device> (const std::string &,int,Phy::Type)> connect_to_remote,std::array<uint8_t,5> bluetooth_address_prefix)32 TestModel::TestModel(
33     std::function<AsyncUserId()> get_user_id,
34     std::function<AsyncTaskId(AsyncUserId, std::chrono::milliseconds,
35                               const TaskCallback&)>
36         event_scheduler,
37 
38     std::function<AsyncTaskId(AsyncUserId, std::chrono::milliseconds,
39                               std::chrono::milliseconds, const TaskCallback&)>
40         periodic_event_scheduler,
41 
42     std::function<void(AsyncUserId)> cancel_tasks_from_user,
43     std::function<void(AsyncTaskId)> cancel,
44     std::function<std::shared_ptr<Device>(const std::string&, int, Phy::Type)>
45         connect_to_remote,
46     std::array<uint8_t, 5> bluetooth_address_prefix)
47     : bluetooth_address_prefix_(std::move(bluetooth_address_prefix)),
48       get_user_id_(std::move(get_user_id)),
49       schedule_task_(std::move(event_scheduler)),
50       schedule_periodic_task_(std::move(periodic_event_scheduler)),
51       cancel_task_(std::move(cancel)),
52       cancel_tasks_from_user_(std::move(cancel_tasks_from_user)),
53       connect_to_remote_(std::move(connect_to_remote)) {
54   model_user_id_ = get_user_id_();
55 }
56 
~TestModel()57 TestModel::~TestModel() {
58   StopTimer();
59 }
60 
SetTimerPeriod(std::chrono::milliseconds new_period)61 void TestModel::SetTimerPeriod(std::chrono::milliseconds new_period) {
62   timer_period_ = new_period;
63 
64   if (timer_tick_task_ == kInvalidTaskId) return;
65 
66   // Restart the timer with the new period
67   StopTimer();
68   StartTimer();
69 }
70 
StartTimer()71 void TestModel::StartTimer() {
72   LOG_INFO("StartTimer()");
73   timer_tick_task_ = schedule_periodic_task_(
74       model_user_id_, std::chrono::milliseconds(0), timer_period_,
75       [this]() { TestModel::TimerTick(); });
76 }
77 
StopTimer()78 void TestModel::StopTimer() {
79   LOG_INFO("StopTimer()");
80   cancel_task_(timer_tick_task_);
81   timer_tick_task_ = kInvalidTaskId;
82 }
83 
Add(std::shared_ptr<Device> new_dev)84 size_t TestModel::Add(std::shared_ptr<Device> new_dev) {
85   devices_.push_back(std::move(new_dev));
86   return devices_.size() - 1;
87 }
88 
Del(size_t dev_index)89 void TestModel::Del(size_t dev_index) {
90   if (dev_index >= devices_.size() || devices_[dev_index] == nullptr) {
91     LOG_WARN("Unknown device %zu", dev_index);
92     return;
93   }
94   schedule_task_(model_user_id_, std::chrono::milliseconds(0),
95                  [this, dev_index]() {
96                    devices_[dev_index]->UnregisterPhyLayers();
97                    devices_[dev_index] = nullptr;
98                  });
99 }
100 
AddPhy(Phy::Type phy_type)101 size_t TestModel::AddPhy(Phy::Type phy_type) {
102   size_t factory_id = phys_.size();
103   phys_.push_back(std::move(CreatePhy(phy_type, factory_id)));
104   return factory_id;
105 }
106 
CreatePhy(Phy::Type phy_type,size_t factory_id)107 std::unique_ptr<PhyLayerFactory> TestModel::CreatePhy(Phy::Type phy_type, size_t factory_id) {
108   return std::make_unique<PhyLayerFactory>(phy_type, factory_id);
109 }
110 
DelPhy(size_t phy_index)111 void TestModel::DelPhy(size_t phy_index) {
112   if (phy_index >= phys_.size()) {
113     LOG_WARN("Unknown phy at index %zu", phy_index);
114     return;
115   }
116   schedule_task_(
117       model_user_id_, std::chrono::milliseconds(0),
118       [this, phy_index]() { phys_[phy_index]->UnregisterAllPhyLayers(); });
119 }
120 
AddDeviceToPhy(size_t dev_index,size_t phy_index)121 void TestModel::AddDeviceToPhy(size_t dev_index, size_t phy_index) {
122   if (dev_index >= devices_.size() || devices_[dev_index] == nullptr) {
123     LOG_WARN("Unknown device %zu", dev_index);
124     return;
125   }
126   if (phy_index >= phys_.size()) {
127     LOG_WARN("Can't find phy %zu", phy_index);
128     return;
129   }
130   auto dev = devices_[dev_index];
131   dev->RegisterPhyLayer(phys_[phy_index]->GetPhyLayer(
132       [dev](model::packets::LinkLayerPacketView packet) {
133         dev->IncomingPacket(std::move(packet));
134       },
135       dev_index));
136 }
137 
DelDeviceFromPhy(size_t dev_index,size_t phy_index)138 void TestModel::DelDeviceFromPhy(size_t dev_index, size_t phy_index) {
139   if (dev_index >= devices_.size() || devices_[dev_index] == nullptr) {
140     LOG_WARN("Unknown device %zu", dev_index);
141     return;
142   }
143   if (phy_index >= phys_.size()) {
144     LOG_WARN("Can't find phy %zu", phy_index);
145     return;
146   }
147   schedule_task_(model_user_id_, std::chrono::milliseconds(0),
148                  [this, dev_index, phy_index]() {
149                    devices_[dev_index]->UnregisterPhyLayer(
150                        phys_[phy_index]->GetType(),
151                        phys_[phy_index]->GetFactoryId());
152                  });
153 }
154 
AddLinkLayerConnection(std::shared_ptr<Device> dev,Phy::Type phy_type)155 void TestModel::AddLinkLayerConnection(std::shared_ptr<Device> dev,
156                                        Phy::Type phy_type) {
157   LOG_INFO("Adding a new link layer connection of type: %s",
158            phy_type == Phy::Type::BR_EDR ? "BR_EDR" : "LOW_ENERGY");
159   int index = Add(dev);
160   AsyncUserId user_id = get_user_id_();
161 
162   for (size_t i = 0; i < phys_.size(); i++) {
163     if (phy_type == phys_[i]->GetType()) {
164       AddDeviceToPhy(index, i);
165     }
166   }
167 
168   dev->RegisterCloseCallback([this, index, user_id] {
169     schedule_task_(
170         user_id, std::chrono::milliseconds(0),
171         [this, index, user_id]() { OnConnectionClosed(index, user_id); });
172   });
173 }
174 
AddRemote(const std::string & server,int port,Phy::Type phy_type)175 void TestModel::AddRemote(const std::string& server, int port,
176                           Phy::Type phy_type) {
177   auto dev = connect_to_remote_(server, port, phy_type);
178   if (dev == nullptr) {
179     return;
180   }
181   AddLinkLayerConnection(dev, phy_type);
182 }
183 
AddHciConnection(std::shared_ptr<HciDevice> dev)184 size_t TestModel::AddHciConnection(std::shared_ptr<HciDevice> dev) {
185   size_t index = Add(std::static_pointer_cast<Device>(dev));
186   auto bluetooth_address = Address{{
187       uint8_t(index),
188       bluetooth_address_prefix_[4],
189       bluetooth_address_prefix_[3],
190       bluetooth_address_prefix_[2],
191       bluetooth_address_prefix_[1],
192       bluetooth_address_prefix_[0],
193   }};
194   dev->SetAddress(bluetooth_address);
195 
196   LOG_INFO("Initialized device with address %s",
197            bluetooth_address.ToString().c_str());
198 
199   for (size_t i = 0; i < phys_.size(); i++) {
200     AddDeviceToPhy(index, i);
201   }
202 
203   AsyncUserId user_id = get_user_id_();
204   dev->RegisterTaskScheduler([user_id, this](std::chrono::milliseconds delay,
205                                              TaskCallback task_callback) {
206     return schedule_task_(user_id, delay, std::move(task_callback));
207   });
208   dev->RegisterTaskCancel(cancel_task_);
209   dev->RegisterCloseCallback([this, index, user_id] {
210     schedule_task_(
211         user_id, std::chrono::milliseconds(0),
212         [this, index, user_id]() { OnConnectionClosed(index, user_id); });
213   });
214   return index;
215 }
216 
OnConnectionClosed(size_t index,AsyncUserId user_id)217 void TestModel::OnConnectionClosed(size_t index, AsyncUserId user_id) {
218   if (index >= devices_.size() || devices_[index] == nullptr) {
219     LOG_WARN("Unknown device %zu", index);
220     return;
221   }
222 
223   cancel_tasks_from_user_(user_id);
224   devices_[index]->UnregisterPhyLayers();
225   devices_[index] = nullptr;
226 }
227 
SetDeviceAddress(size_t index,Address address)228 void TestModel::SetDeviceAddress(size_t index, Address address) {
229   if (index >= devices_.size() || devices_[index] == nullptr) {
230     LOG_WARN("Can't find device %zu", index);
231     return;
232   }
233   devices_[index]->SetAddress(std::move(address));
234 }
235 
List()236 const std::string& TestModel::List() {
237   list_string_ = "";
238   list_string_ += " Devices: \r\n";
239   for (size_t i = 0; i < devices_.size(); i++) {
240     list_string_ += "  " + std::to_string(i) + ":";
241     if (devices_[i] == nullptr) {
242       list_string_ += " deleted \r\n";
243     } else {
244       list_string_ += devices_[i]->ToString() + " \r\n";
245     }
246   }
247   list_string_ += " Phys: \r\n";
248   for (size_t i = 0; i < phys_.size(); i++) {
249     list_string_ += "  " + std::to_string(i) + ":";
250     list_string_ += phys_[i]->ToString() + " \r\n";
251   }
252   return list_string_;
253 }
254 
TimerTick()255 void TestModel::TimerTick() {
256   for (size_t i = 0; i < devices_.size(); i++) {
257     if (devices_[i] != nullptr) {
258       devices_[i]->TimerTick();
259     }
260   }
261 }
262 
Reset()263 void TestModel::Reset() {
264   StopTimer();
265   schedule_task_(model_user_id_, std::chrono::milliseconds(0), [this]() {
266     LOG_INFO("Running Reset task");
267     for (size_t i = 0; i < devices_.size(); i++) {
268       if (devices_[i] != nullptr) {
269         devices_[i]->UnregisterPhyLayers();
270       }
271     }
272     devices_.clear();
273   });
274 }
275 
276 }  // namespace rootcanal
277