1 /*
2  * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
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 
16 #include "power_device.h"
17 #include <cstring>
18 #include <memory>
19 #include <mutex>
20 #include "btm.h"
21 #include "log.h"
22 #include "message.h"
23 #include "power_state_machine.h"
24 #include "securec.h"
25 
26 namespace OHOS {
27 namespace bluetooth {
28 struct PowerDevice::impl {
29 public:
implOHOS::bluetooth::PowerDevice::impl30     impl(const RawAddress rawAddr, utility::Dispatcher &dispatcher):rawAddr_(rawAddr), dispatcher_(dispatcher){};
~implOHOS::bluetooth::PowerDevice::impl31     ~impl(){};
32     const RawAddress rawAddr_;
33     utility::Dispatcher &dispatcher_;
34     std::map<std::string, RequestStatus> requestPower_ {};
35     std::unique_ptr<PowerStateMachine> psm_ = nullptr;
36     std::pair<PowerSsrLevel, PowerModeLevel> requestPowerLevel_ =
37         std::pair<PowerSsrLevel, PowerModeLevel>(PowerSsrLevel::NO_ACTION, PowerModeLevel::NO_ACTION);
38     std::pair<PowerSsrLevel, PowerModeLevel> controlPowerLevel_ =
39         std::pair<PowerSsrLevel, PowerModeLevel>(PowerSsrLevel::NO_ACTION, PowerModeLevel::NO_ACTION);
40     int controlPowerMode_ {};
41     int controlInterval_ {};
42     std::unique_ptr<PowerTimer> sniffDelayTimer_ = nullptr;
43     std::mutex mutex_ {};
44 
45     BT_DISALLOW_COPY_AND_ASSIGN(impl);
46 };
47 
PowerDevice(const RawAddress rawAddr,utility::Dispatcher & dispatcher)48 PowerDevice::PowerDevice(const RawAddress rawAddr, utility::Dispatcher &dispatcher)
49     : pimpl(std::make_unique<PowerDevice::impl>(rawAddr, dispatcher))
50 {
51     pimpl->psm_ = std::make_unique<PowerStateMachine>();
52     pimpl->psm_->Init(*this);
53 
54     pimpl->sniffDelayTimer_ = std::make_unique<PowerTimer>(std::bind(
55         [&]()->void {
56             std::weak_ptr<PowerDevice> weakDevice = shared_from_this();
57             pimpl->dispatcher_.PostTask(std::bind(&bluetooth::PowerDevice::DelayTimeoutCallback, weakDevice));
58         }
59     ));
60 }
61 
~PowerDevice()62 PowerDevice::~PowerDevice()
63 {
64     pimpl->sniffDelayTimer_->Stop();
65 }
66 
67 /// update request power function
SetRequestPower(const std::string & profileName,const RequestStatus status) const68 void PowerDevice::SetRequestPower(const std::string &profileName, const RequestStatus status) const
69 {
70     pimpl->requestPower_[profileName] = status;
71 }
72 
DeleteRequestPower(const std::string & profileName) const73 void PowerDevice::DeleteRequestPower(const std::string &profileName) const
74 {
75     pimpl->requestPower_.erase(profileName);
76 }
77 
SetPowerMode()78 void PowerDevice::SetPowerMode()
79 {
80     PowerInfo maxPower = CalcMaxPower();
81     if (maxPower.powerMode_ == PowerModeLevel::NO_ACTION) {
82         return;
83     }
84     if (maxPower.powerMode_ == PowerModeLevel::LEVEL_ACTIVE) {
85         SetActiveMode();
86     } else {
87         SetSniffMode(maxPower);
88     }
89 }
90 
91 /// set power mode interface, use by SetPowerMode() / DelayTimeoutCallback()
SetActiveMode()92 void PowerDevice::SetActiveMode()
93 {
94     LOG_DEBUG("PM_: SetActiveMode");
95     StopDelayTimer();  // Stop Sniff Delay Timer.
96     utility::Message msg(PowerStateMachine::MSG_PM_SET_ACTIVE);
97     pimpl->psm_->ProcessMessage(msg);
98 }
99 
SetSniffMode(PowerInfo requestPower)100 void PowerDevice::SetSniffMode(PowerInfo requestPower)
101 {
102     LOG_DEBUG("PM_: SetSniffMode");
103     // Because the hardware does not support resetting the sniff parameter in the sniff state,
104     // it exits the sniff first, and then delays to enter the sniff.
105     PowerModeLevel controlPowerMode = GetControlPowerLevel().second;
106     if (requestPower.powerMode_ != controlPowerMode &&
107         (controlPowerMode == PowerModeLevel::LEVEL_LOW ||
108         controlPowerMode == PowerModeLevel::LEVEL_MID ||
109         controlPowerMode == PowerModeLevel::LEVEL_HIG)) {
110         LOG_DEBUG("PM_:::SetSniffMode() contorl is in sniff state, to reset the sniff parameter, you need to exit "
111                   "sniff state first\n");
112         SetActiveMode();
113     }
114 
115     if (GetDelayTimerRemainMs() <= static_cast<uint64_t>(requestPower.timeout_)) {
116         LOG_DEBUG("PM_: Reset Timer: timeoutMs: %{public}d\n", requestPower.timeout_);
117         StopDelayTimer();
118         StartDelayTimer(static_cast<uint64_t>(requestPower.timeout_));
119     }
120 }
121 
GetPowerMode() const122 BTPowerMode PowerDevice::GetPowerMode() const
123 {
124     PowerModeLevel powerLevel = GetControlPowerLevel().second;
125     BTPowerMode powerMode = BTPowerMode::MODE_ACTIVE;
126     if (powerLevel == PowerModeLevel::LEVEL_ACTIVE) {
127         powerMode = BTPowerMode::MODE_ACTIVE;
128     } else if (powerLevel == PowerModeLevel::LEVEL_HIG) {
129         powerMode = BTPowerMode::MODE_SNIFF_LEVEL_HIG;
130     } else if (powerLevel == PowerModeLevel::LEVEL_MID) {
131         powerMode = BTPowerMode::MODE_SNIFF_LEVEL_MID;
132     } else if (powerLevel == PowerModeLevel::LEVEL_LOW) {
133         powerMode = BTPowerMode::MODE_SNIFF_LEVEL_LOW;
134     }
135     return powerMode;
136 }
137 
ModeChangeCallBack(uint8_t status,uint8_t currentMode,uint16_t interval)138 void PowerDevice::ModeChangeCallBack(uint8_t status, uint8_t currentMode, uint16_t interval)
139 {
140     if (status == 0) {
141         LOG_DEBUG("PM_: %{public}s, status: %{public}d, currentMode: %{public}d, interval: %{public}d\n", __FUNCTION__, status, currentMode, interval);
142         /// update state
143         if (currentMode == BTM_PM_ACTIVE_MODE) {  // current Mode Active
144             UpdateControlSniffSubrating(PowerSsrLevel::NO_ACTION);
145             UpdatecontrolPowerLevel(PowerModeLevel::LEVEL_ACTIVE);
146             utility::Message msg(PowerStateMachine::MSG_PM_MODE_CHANGE_ACTIVE);
147             pimpl->psm_->ProcessMessage(msg);
148         } else if (currentMode == BTM_PM_SNIFF_MODE) {  // current Mode Sniff
149             if (interval <= SNIFF_LEVEL_LOW_MAX_INTERVAL && interval >= SNIFF_LEVEL_LOW_MIN_INTERVAL) {
150                 UpdatecontrolPowerLevel(PowerModeLevel::LEVEL_LOW);
151             } else if (interval <= SNIFF_LEVEL_MID_MAX_INTERVAL && interval >= SNIFF_LEVEL_MID_MIN_INTERVAL) {
152                 UpdatecontrolPowerLevel(PowerModeLevel::LEVEL_MID);
153             } else if (interval <= SNIFF_LEVEL_HIG_MAX_INTERVAL && interval >= SNIFF_LEVEL_HIG_MIN_INTERVAL) {
154                 UpdatecontrolPowerLevel(PowerModeLevel::LEVEL_HIG);
155             }
156             utility::Message msg(PowerStateMachine::MSG_PM_MODE_CHANGE_SNIFF);
157             pimpl->psm_->ProcessMessage(msg);
158         }
159     } else {  /// hci status error
160         LOG_DEBUG("PM_: %{public}s, hci status error: %{public}d\n", __FUNCTION__, status);
161     }
162 }
163 
SniffSubratingCompleteCallback(uint8_t status) const164 void PowerDevice::SniffSubratingCompleteCallback(uint8_t status) const
165 {
166     LOG_DEBUG("PM_: %{public}s, line: %{public}d\n", __FUNCTION__, __LINE__);
167     if (status == 0) {
168         UpdateControlSniffSubrating(GetRequestPowerLevel().first);
169         utility::Message msg(PowerStateMachine::MSG_PM_SET_SUBRATING_COMPLETE);
170         pimpl->psm_->ProcessMessage(msg);
171     }
172 }
173 
174 /// calc power level and ssr level
CalcMaxPower() const175 PowerInfo PowerDevice::CalcMaxPower() const
176 {
177     PowerInfo maxPower = PowerInfo(PowerModeLevel::NO_ACTION, 0);
178     for (auto &its : pimpl->requestPower_) {
179         PowerInfo itSpec = PowerSpec::GetPowerSpec(its.first, its.second);
180         if (itSpec.powerMode_ > maxPower.powerMode_) {
181             maxPower = itSpec;
182         }
183     }
184     return maxPower;
185 }
186 
CalcLowestSsrLevel() const187 PowerSsrLevel PowerDevice::CalcLowestSsrLevel() const
188 {
189     PowerSsrLevel lowestLevel = PowerSsrLevel::NO_ACTION;
190     for (auto &its : pimpl->requestPower_) {
191         PowerSsrLevel level = PowerSpec::GetPowerSsrLevel(its.first, its.second);
192         if ((level != PowerSsrLevel::NO_ACTION) && (level < lowestLevel)) {
193             lowestLevel = level;
194         }
195     }
196     return lowestLevel;
197 }
198 
199 /// btm power interface
BtmSetSniffSubrating(const PowerSsrParam & ssrParam) const200 int PowerDevice::BtmSetSniffSubrating(const PowerSsrParam &ssrParam) const
201 {
202     LOG_DEBUG("PM_: %{public}s start, line: %{public}d\n", __FUNCTION__, __LINE__);
203     BtAddr btAddr;
204     (void)memset_s(&btAddr, sizeof(btAddr), 0, sizeof(btAddr));
205     pimpl->rawAddr_.ConvertToUint8(btAddr.addr);
206 
207     BtmSniffSubrating btmSsrParam;
208     btmSsrParam.maximumLatency = ssrParam.maxLat_;
209     btmSsrParam.minimumLocalTimeout = ssrParam.minLocTo_;
210     btmSsrParam.minimumRemoteTimeout = ssrParam.minRmtTo_;
211 
212     return BTM_SetSniffSubrating(&btAddr, &btmSsrParam);
213 }
214 
BtmExitSniffMode() const215 int PowerDevice::BtmExitSniffMode() const
216 {
217     LOG_DEBUG("PM_: %{public}s start, line: %{public}d\n", __FUNCTION__, __LINE__);
218     BtAddr btAddr;
219     (void)memset_s(&btAddr, sizeof(btAddr), 0, sizeof(btAddr));
220     pimpl->rawAddr_.ConvertToUint8(btAddr.addr);
221     return BTM_ExitSniffMode(&btAddr);
222 }
223 
BtmEnterSniffMode(const PowerParam & param) const224 int PowerDevice::BtmEnterSniffMode(const PowerParam &param) const
225 {
226     LOG_DEBUG("PM_: %{public}s start, line: %{public}d\n", __FUNCTION__, __LINE__);
227     BtAddr btAddr;
228     BtmSniffParam btmSniffParam;
229 
230     (void)memset_s(&btAddr, sizeof(btAddr), 0, sizeof(btAddr));
231     pimpl->rawAddr_.ConvertToUint8(btAddr.addr);
232     btmSniffParam.attempt = param.attempt_;
233     btmSniffParam.maxInterval = param.maxInterval_;
234     btmSniffParam.minInterval = param.minInterval_;
235     btmSniffParam.timeout = param.timeout_;
236 
237     return BTM_EnterSniffMode(&btAddr, &btmSniffParam);
238 }
239 
GetRequestPowerLevel() const240 const std::pair<PowerSsrLevel, PowerModeLevel> &PowerDevice::GetRequestPowerLevel() const
241 {
242     return pimpl->requestPowerLevel_;
243 }
244 
SetRequestPowerLevel(const PowerSsrLevel ssr,const PowerModeLevel power) const245 void PowerDevice::SetRequestPowerLevel(const PowerSsrLevel ssr, const PowerModeLevel power) const
246 {
247     pimpl->requestPowerLevel_ = std::pair<PowerSsrLevel, PowerModeLevel>(ssr, power);
248 }
249 
GetControlPowerLevel() const250 const std::pair<PowerSsrLevel, PowerModeLevel> &PowerDevice::GetControlPowerLevel() const
251 {
252     std::unique_lock<std::mutex> lock(pimpl->mutex_);
253     return pimpl->controlPowerLevel_;
254 }
255 
UpdateControlSniffSubrating(const PowerSsrLevel ssr) const256 void PowerDevice::UpdateControlSniffSubrating(const PowerSsrLevel ssr) const
257 {
258     std::unique_lock<std::mutex> lock(pimpl->mutex_);
259     pimpl->controlPowerLevel_.first = ssr;
260 }
261 
UpdatecontrolPowerLevel(const PowerModeLevel powerLevel) const262 void PowerDevice::UpdatecontrolPowerLevel(const PowerModeLevel powerLevel) const
263 {
264     std::unique_lock<std::mutex> lock(pimpl->mutex_);
265     pimpl->controlPowerLevel_.second = powerLevel;
266 }
267 
DelayTimeoutCallback(const std::weak_ptr<PowerDevice> & weakDevice)268 void PowerDevice::DelayTimeoutCallback(const std::weak_ptr<PowerDevice>& weakDevice)
269 {
270     std::shared_ptr<PowerDevice> sharedDevice = weakDevice.lock();
271     if (sharedDevice != nullptr) {
272         LOG_DEBUG("PM_: %{public}s start, line: %{public}d\n", __FUNCTION__, __LINE__);
273         PowerInfo maxPowerInfo = sharedDevice->CalcMaxPower();
274         LOG_DEBUG("PM_: %{public}s, maxPowerInfo: %{public}d\n", __FUNCTION__, static_cast<int>(maxPowerInfo.powerMode_));
275         if (maxPowerInfo.powerMode_ == PowerModeLevel::LEVEL_ACTIVE) {
276             sharedDevice->SetActiveMode();
277         } else if (maxPowerInfo.powerMode_ == PowerModeLevel::NO_ACTION) {
278             return;
279         } else {
280             PowerSsrLevel lowestSsrLevel = sharedDevice->CalcLowestSsrLevel();
281             sharedDevice->SetRequestPowerLevel(lowestSsrLevel, maxPowerInfo.powerMode_);
282             utility::Message msg(PowerStateMachine::MSG_PM_SET_SNIFF);
283             sharedDevice->pimpl->psm_->ProcessMessage(msg);
284         }
285     } else {
286         LOG_DEBUG("PowerDevice::DelayTimeoutCallback sharedDevice == nullptr");
287     }
288 }
289 
290 /// delay timer function
StartDelayTimer(int ms) const291 void PowerDevice::StartDelayTimer(int ms) const
292 {
293     LOG_DEBUG("PM_: %{public}s start, line: %{public}d\n", __FUNCTION__, __LINE__);
294     pimpl->sniffDelayTimer_->Start(ms);
295 }
296 
StopDelayTimer() const297 void PowerDevice::StopDelayTimer() const
298 {
299     LOG_DEBUG("PM_: %{public}s start, line: %{public}d\n", __FUNCTION__, __LINE__);
300     pimpl->sniffDelayTimer_->Stop();
301 }
302 
GetDelayTimerRemainMs() const303 uint64_t PowerDevice::GetDelayTimerRemainMs() const
304 {
305     return pimpl->sniffDelayTimer_->GetRemainMs();
306 }
307 
Start(int ms,bool isPeriodic)308 bool PowerDevice::PowerTimer::Start(int ms, bool isPeriodic)
309 {
310     bool ret = utility::Timer::Start(ms, isPeriodic);
311     struct timespec ts = {};
312     clock_gettime(CLOCK_BOOTTIME, &ts);
313     deadLineMs_ = ts.tv_sec * MS_PER_SECOND + ts.tv_nsec / NS_PER_MS + ms;
314     return ret;
315 }
316 
Stop()317 bool PowerDevice::PowerTimer::Stop()
318 {
319     deadLineMs_ = 0;
320     return utility::Timer::Stop();
321 }
322 
GetRemainMs()323 uint64_t PowerDevice::PowerTimer::GetRemainMs()
324 {
325     struct timespec ts = {};
326     clock_gettime(CLOCK_BOOTTIME, &ts);
327     uint64_t presentMs = ts.tv_sec * MS_PER_SECOND + ts.tv_nsec / NS_PER_MS;
328     if (deadLineMs_ > presentMs) {
329         return deadLineMs_ - presentMs;
330     } else {
331         deadLineMs_ = 0;
332         return 0;
333     }
334 }
335 }  // namespace bluetooth
336 }  // namespace OHOS