• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "controller/scene_controller.h"
16 
17 #include <chrono>
18 #include <cmath>
19 #include <cstddef>
20 #include <optional>
21 
22 #include "controller/device_notify_manager.h"
23 #include "util/log.h"
24 
25 namespace netsim {
26 namespace controller {
27 namespace {
28 constexpr std::chrono::seconds kInactiveLimitToShutdown(300);
29 }
30 
31 /* static */
Singleton()32 SceneController &SceneController::Singleton() {
33   static SceneController *kInstance = new SceneController();
34   return *kInstance;
35 }
36 
Get()37 model::Scene SceneController::Get() {
38   model::Scene scene;
39   for (auto &[_, device] : devices_) {
40     scene.add_devices()->CopyFrom(device->Get());
41   }
42   return scene;
43 }
44 
AddChip(const std::string & guid,const std::string & device_name,common::ChipKind chip_kind,const std::string & chip_name,const std::string & manufacturer,const std::string & product_name)45 std::tuple<uint32_t, uint32_t, uint32_t> SceneController::AddChip(
46     const std::string &guid, const std::string &device_name,
47     common::ChipKind chip_kind, const std::string &chip_name,
48     const std::string &manufacturer, const std::string &product_name) {
49   auto device = GetDevice(guid, device_name);
50   // TODO: catch case of similar name chips
51   auto [chip_id, facade_id] =
52       device->AddChip(chip_kind, chip_name, manufacturer, product_name);
53   inactive_timestamp_.reset();
54   return {device->id, chip_id, facade_id};
55 }
56 
GetDevice(const std::string & guid,const std::string & name)57 std::shared_ptr<Device> SceneController::GetDevice(const std::string &guid,
58                                                    const std::string &name) {
59   std::unique_lock<std::mutex> lock(this->mutex_);
60   for (auto &[_, device] : devices_) {
61     if (device->guid == guid) return device;
62   }
63   static uint32_t identifier = 0;
64   auto device = std::make_shared<Device>(identifier, guid, name);
65   devices_[identifier++] = device;
66   return device;
67 }
68 
RemoveDevice(uint32_t id)69 void SceneController::RemoveDevice(uint32_t id) {
70   if (devices_.find(id) != devices_.end()) {
71     auto device = devices_[id];
72     BtsLog("SceneController::RemoveDevice - removing %s", device->name.c_str());
73     device->Remove();
74     devices_.erase(id);
75   } else {
76     BtsLog("Device not found in remove %d", id);
77   }
78 }
79 
RemoveChip(uint32_t device_id,uint32_t chip_id)80 void SceneController::RemoveChip(uint32_t device_id, uint32_t chip_id) {
81   std::unique_lock<std::mutex> lock(this->mutex_);
82   BtsLog("Scene RemoveChip %d", chip_id);
83   if (devices_.find(device_id) != devices_.end()) {
84     auto device = devices_[device_id];
85     if (device->RemoveChip(chip_id)) {
86       BtsLog("SceneController::RemoveChip device %d, no more chips", device_id);
87       this->RemoveDevice(device_id);
88       if (devices_.empty())
89         inactive_timestamp_.emplace(std::chrono::system_clock::now());
90     }
91   } else {
92     std::cerr << "Trying to remove chip from unknown device" << std::endl;
93   }
94 }
95 
96 // Returns a Device shared_ptr or nullptr
MatchDevice(const std::string & name)97 std::shared_ptr<Device> SceneController::MatchDevice(const std::string &name) {
98   std::shared_ptr<Device> target = nullptr;
99   bool multiple_matches = false;
100   if (name.empty()) {
101     return nullptr;
102   }
103   for (auto &[_, device] : devices_) {
104     // match by device name
105     auto pos = device->name.find(name);
106     if (pos != std::string::npos) {
107       // check for exact match
108       if (device->name == name) return device;
109       // record if multiple ambiguous matches were found
110       if (target != nullptr) multiple_matches = true;
111       target = device;
112     }
113   }
114   // return nullptr if multiple ambiguous matches were found
115   if (multiple_matches) return nullptr;
116   return target;
117 }
118 
119 // UI requesting a change in device info
PatchDevice(const model::Device & request)120 bool SceneController::PatchDevice(const model::Device &request) {
121   std::unique_lock<std::mutex> lock(this->mutex_);
122   if (request.name().empty()) {
123     return false;
124   }
125   auto device = MatchDevice(request.name());
126   if (device == nullptr) return false;
127   device->Patch(request);
128   DeviceNotifyManager::Get().Notify();
129   return true;
130 }
131 
132 // Euclidian distance between two devices.
GetDistance(uint32_t id,uint32_t other_id)133 float SceneController::GetDistance(uint32_t id, uint32_t other_id) {
134   if (devices_.find(id) == devices_.end() ||
135       devices_.find(other_id) == devices_.end()) {
136     BtsLog("Error in GetDistance %d, %d", id, other_id);
137     return 0.0;
138   }
139   auto a = devices_[id]->position;
140   auto b = devices_[other_id]->position;
141   return sqrt(
142       (pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2) + pow(a.z() - b.z(), 2)));
143 }
144 
Reset()145 void SceneController::Reset() {
146   std::unique_lock<std::mutex> lock(this->mutex_);
147   for (auto &[_, device] : devices_) {
148     device->Reset();
149   }
150   DeviceNotifyManager::Get().Notify();
151 }
152 
GetShutdownTime()153 std::optional<std::chrono::seconds> SceneController::GetShutdownTime() {
154   if (!inactive_timestamp_.has_value()) return std::nullopt;
155 
156   auto inactive_seconds = std::chrono::duration_cast<std::chrono::seconds>(
157       std::chrono::system_clock::now() - inactive_timestamp_.value());
158   auto remaining_seconds = kInactiveLimitToShutdown - inactive_seconds;
159   return std::optional<std::chrono::seconds>(remaining_seconds);
160 }
161 }  // namespace controller
162 }  // namespace netsim
163