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 <optional>
25 #include <type_traits> // for remove_extent_t
26 #include <utility> // for move
27
28 #include "include/phy.h" // for Phy, Phy::Type
29 #include "log.h" // for LOG_WARN, LOG_INFO
30 #include "phy_layer.h"
31
32 namespace rootcanal {
33
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)34 TestModel::TestModel(
35 std::function<AsyncUserId()> get_user_id,
36 std::function<AsyncTaskId(AsyncUserId, std::chrono::milliseconds,
37 const TaskCallback&)>
38 event_scheduler,
39
40 std::function<AsyncTaskId(AsyncUserId, std::chrono::milliseconds,
41 std::chrono::milliseconds, const TaskCallback&)>
42 periodic_event_scheduler,
43
44 std::function<void(AsyncUserId)> cancel_tasks_from_user,
45 std::function<void(AsyncTaskId)> cancel,
46 std::function<std::shared_ptr<Device>(const std::string&, int, Phy::Type)>
47 connect_to_remote,
48 std::array<uint8_t, 5> bluetooth_address_prefix)
49 : bluetooth_address_prefix_(std::move(bluetooth_address_prefix)),
50 get_user_id_(std::move(get_user_id)),
51 schedule_task_(std::move(event_scheduler)),
52 schedule_periodic_task_(std::move(periodic_event_scheduler)),
53 cancel_task_(std::move(cancel)),
54 cancel_tasks_from_user_(std::move(cancel_tasks_from_user)),
55 connect_to_remote_(std::move(connect_to_remote)) {
56 model_user_id_ = get_user_id_();
57 }
58
~TestModel()59 TestModel::~TestModel() {
60 StopTimer();
61 }
62
SetTimerPeriod(std::chrono::milliseconds new_period)63 void TestModel::SetTimerPeriod(std::chrono::milliseconds new_period) {
64 timer_period_ = new_period;
65
66 if (timer_tick_task_ == kInvalidTaskId) {
67 return;
68 }
69
70 // Restart the timer with the new period
71 StopTimer();
72 StartTimer();
73 }
74
StartTimer()75 void TestModel::StartTimer() {
76 LOG_INFO("StartTimer()");
77 timer_tick_task_ =
78 schedule_periodic_task_(model_user_id_, std::chrono::milliseconds(0),
79 timer_period_, [this]() { TestModel::Tick(); });
80 }
81
StopTimer()82 void TestModel::StopTimer() {
83 LOG_INFO("StopTimer()");
84 cancel_task_(timer_tick_task_);
85 timer_tick_task_ = kInvalidTaskId;
86 }
87
CreatePhyLayer(PhyLayer::Identifier id,Phy::Type type)88 std::unique_ptr<PhyLayer> TestModel::CreatePhyLayer(PhyLayer::Identifier id,
89 Phy::Type type) {
90 return std::make_unique<PhyLayer>(id, type);
91 }
92
CreatePhyDevice(PhyDevice::Identifier id,std::string type,std::shared_ptr<Device> device)93 std::shared_ptr<PhyDevice> TestModel::CreatePhyDevice(
94 PhyDevice::Identifier id, std::string type,
95 std::shared_ptr<Device> device) {
96 return std::make_shared<PhyDevice>(id, std::move(type), std::move(device));
97 }
98
99 // Add a device to the test model.
AddDevice(std::shared_ptr<Device> device)100 PhyDevice::Identifier TestModel::AddDevice(std::shared_ptr<Device> device) {
101 std::optional<PhyDevice::Identifier> device_id{};
102 if (reuse_device_ids_) {
103 // Find the first unused identifier.
104 // The identifier is used to generate the bluetooth address,
105 // and reusing the first unused identifier lets a re-connecting
106 // get the same identifier and address.
107 for (PhyDevice::Identifier id = 0; id < next_device_id_; id++) {
108 if (phy_devices_.count(id) == 0) {
109 device_id = id;
110 break;
111 }
112 }
113 }
114
115 if (!device_id.has_value()) {
116 device_id = next_device_id_++;
117 }
118
119 std::string device_type = device->GetTypeString();
120 std::shared_ptr<PhyDevice> phy_device =
121 CreatePhyDevice(device_id.value(), device_type, std::move(device));
122 phy_devices_[phy_device->id] = phy_device;
123 return phy_device->id;
124 }
125
126 // Remove a device from the test model.
RemoveDevice(PhyDevice::Identifier device_id)127 void TestModel::RemoveDevice(PhyDevice::Identifier device_id) {
128 for (auto& [_, phy_layer] : phy_layers_) {
129 phy_layer->Unregister(device_id);
130 }
131 phy_devices_.erase(device_id);
132 }
133
134 // Add a phy to the test model.
AddPhy(Phy::Type type)135 PhyLayer::Identifier TestModel::AddPhy(Phy::Type type) {
136 static PhyLayer::Identifier next_id = 0;
137 std::shared_ptr<PhyLayer> phy_layer = CreatePhyLayer(next_id++, type);
138 phy_layers_[phy_layer->id] = phy_layer;
139 return phy_layer->id;
140 }
141
142 // Remove a phy from the test model.
RemovePhy(PhyLayer::Identifier phy_id)143 void TestModel::RemovePhy(PhyLayer::Identifier phy_id) {
144 if (phy_layers_.find(phy_id) != phy_layers_.end()) {
145 phy_layers_[phy_id]->UnregisterAll();
146 phy_layers_.erase(phy_id);
147 }
148 }
149
150 // Add the selected device to the selected phy.
AddDeviceToPhy(PhyDevice::Identifier device_id,PhyLayer::Identifier phy_id)151 void TestModel::AddDeviceToPhy(PhyDevice::Identifier device_id,
152 PhyLayer::Identifier phy_id) {
153 if (phy_layers_.find(phy_id) != phy_layers_.end() &&
154 phy_devices_.find(device_id) != phy_devices_.end()) {
155 phy_layers_[phy_id]->Register(phy_devices_[device_id]);
156 }
157 }
158
159 // Remove the selected device from the selected phy.
RemoveDeviceFromPhy(PhyDevice::Identifier device_id,PhyLayer::Identifier phy_id)160 void TestModel::RemoveDeviceFromPhy(PhyDevice::Identifier device_id,
161 PhyLayer::Identifier phy_id) {
162 if (phy_layers_.find(phy_id) != phy_layers_.end()) {
163 phy_layers_[phy_id]->Unregister(device_id);
164 }
165 }
166
AddLinkLayerConnection(std::shared_ptr<Device> device,Phy::Type type)167 void TestModel::AddLinkLayerConnection(std::shared_ptr<Device> device,
168 Phy::Type type) {
169 LOG_INFO("Adding a new link layer connection of type: %s",
170 type == Phy::Type::BR_EDR ? "BR_EDR" : "LOW_ENERGY");
171
172 PhyDevice::Identifier device_id = AddDevice(device);
173
174 for (auto& [_, phy_layer] : phy_layers_) {
175 if (phy_layer->type == type) {
176 phy_layer->Register(phy_devices_[device_id]);
177 }
178 }
179
180 AsyncUserId user_id = get_user_id_();
181 device->RegisterCloseCallback([this, device_id, user_id] {
182 schedule_task_(user_id, std::chrono::milliseconds(0),
183 [this, device_id, user_id]() {
184 OnConnectionClosed(device_id, user_id);
185 });
186 });
187 }
188
AddRemote(const std::string & server,int port,Phy::Type type)189 void TestModel::AddRemote(const std::string& server, int port, Phy::Type type) {
190 auto device = connect_to_remote_(server, port, type);
191 if (device == nullptr) {
192 return;
193 }
194 AddLinkLayerConnection(device, type);
195 }
196
AddHciConnection(std::shared_ptr<HciDevice> device)197 PhyDevice::Identifier TestModel::AddHciConnection(
198 std::shared_ptr<HciDevice> device) {
199 PhyDevice::Identifier device_id =
200 AddDevice(std::static_pointer_cast<Device>(device));
201 auto bluetooth_address = Address{{
202 uint8_t(device_id),
203 bluetooth_address_prefix_[4],
204 bluetooth_address_prefix_[3],
205 bluetooth_address_prefix_[2],
206 bluetooth_address_prefix_[1],
207 bluetooth_address_prefix_[0],
208 }};
209 device->SetAddress(bluetooth_address);
210
211 LOG_INFO("Initialized device with address %s",
212 bluetooth_address.ToString().c_str());
213
214 for (auto& [_, phy_layer] : phy_layers_) {
215 phy_layer->Register(phy_devices_[device_id]);
216 }
217
218 AsyncUserId user_id = get_user_id_();
219 device->RegisterCloseCallback([this, device_id, user_id] {
220 schedule_task_(user_id, std::chrono::milliseconds(0),
221 [this, device_id, user_id]() {
222 OnConnectionClosed(device_id, user_id);
223 });
224 });
225 return device_id;
226 }
227
OnConnectionClosed(PhyDevice::Identifier device_id,AsyncUserId user_id)228 void TestModel::OnConnectionClosed(PhyDevice::Identifier device_id,
229 AsyncUserId user_id) {
230 if (phy_devices_.find(device_id) != phy_devices_.end()) {
231 cancel_tasks_from_user_(user_id);
232 RemoveDevice(device_id);
233 }
234 }
235
SetDeviceAddress(PhyDevice::Identifier device_id,Address address)236 void TestModel::SetDeviceAddress(PhyDevice::Identifier device_id,
237 Address address) {
238 if (phy_devices_.find(device_id) != phy_devices_.end()) {
239 phy_devices_[device_id]->SetAddress(std::move(address));
240 }
241 }
242
List()243 const std::string& TestModel::List() {
244 list_string_.clear();
245 list_string_ += " Devices: \r\n";
246
247 for (auto const& [device_id, device] : phy_devices_) {
248 list_string_ += " " + std::to_string(device_id) + ":";
249 list_string_ += device->ToString() + " \r\n";
250 }
251
252 list_string_ += " Phys: \r\n";
253
254 for (auto const& [phy_id, phy] : phy_layers_) {
255 list_string_ += " " + std::to_string(phy_id) + ":";
256 list_string_ += phy->ToString() + " \r\n";
257 }
258
259 return list_string_;
260 }
261
Tick()262 void TestModel::Tick() {
263 for (auto& [_, device] : phy_devices_) {
264 device->Tick();
265 }
266 }
267
Reset()268 void TestModel::Reset() {
269 StopTimer();
270 schedule_task_(model_user_id_, std::chrono::milliseconds(0), [this]() {
271 LOG_INFO("Running Reset task");
272 for (auto& [_, phy_layer] : phy_layers_) {
273 phy_layer->UnregisterAll();
274 }
275 phy_devices_.clear();
276 next_device_id_ = 0;
277 });
278 }
279
280 } // namespace rootcanal
281