1 /*
2 * Copyright (C) 2021 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 "chre/core/ble_request_manager.h"
18
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/fatal_error.h"
21 #include "chre/platform/log.h"
22 #include "chre/util/nested_data_ptr.h"
23 #include "chre/util/system/event_callbacks.h"
24
25 namespace chre {
26
init()27 void BleRequestManager::init() {
28 mPlatformBle.init();
29 }
30
getCapabilities()31 uint32_t BleRequestManager::getCapabilities() {
32 return mPlatformBle.getCapabilities();
33 }
34
getFilterCapabilities()35 uint32_t BleRequestManager::getFilterCapabilities() {
36 return mPlatformBle.getFilterCapabilities();
37 }
38
handleExistingRequest(uint16_t instanceId,bool * hasExistingRequest,size_t * requestIndex)39 void BleRequestManager::handleExistingRequest(uint16_t instanceId,
40 bool *hasExistingRequest,
41 size_t *requestIndex) {
42 const BleRequest *foundRequest =
43 mRequests.findRequest(instanceId, requestIndex);
44 *hasExistingRequest = (foundRequest != nullptr);
45 if (foundRequest != nullptr &&
46 foundRequest->getRequestStatus() != RequestStatus::APPLIED) {
47 handleAsyncResult(instanceId, foundRequest->isEnabled(),
48 false /* success */, CHRE_ERROR_OBSOLETE_REQUEST,
49 true /* forceUnregister */);
50 }
51 }
52
compliesWithBleSetting(uint16_t instanceId,bool enabled,bool hasExistingRequest,size_t requestIndex)53 bool BleRequestManager::compliesWithBleSetting(uint16_t instanceId,
54 bool enabled,
55 bool hasExistingRequest,
56 size_t requestIndex) {
57 bool success = true;
58 if (enabled && !bleSettingEnabled()) {
59 success = false;
60 handleAsyncResult(instanceId, enabled, false /* success */,
61 CHRE_ERROR_FUNCTION_DISABLED);
62 if (hasExistingRequest) {
63 bool requestChanged = false;
64 mRequests.removeRequest(requestIndex, &requestChanged);
65 }
66 }
67 return success;
68 }
69
updateRequests(BleRequest && request,bool hasExistingRequest,bool * requestChanged,size_t * requestIndex)70 bool BleRequestManager::updateRequests(BleRequest &&request,
71 bool hasExistingRequest,
72 bool *requestChanged,
73 size_t *requestIndex) {
74 bool success = true;
75 if (hasExistingRequest) {
76 mRequests.updateRequest(*requestIndex, std::move(request), requestChanged);
77 } else if (request.isEnabled()) {
78 success =
79 mRequests.addRequest(std::move(request), requestIndex, requestChanged);
80 } else {
81 // Already disabled requests shouldn't result in work for the PAL.
82 *requestChanged = false;
83 *requestIndex = mRequests.getRequests().size();
84 }
85 return success;
86 }
87
startScanAsync(Nanoapp * nanoapp,chreBleScanMode mode,uint32_t reportDelayMs,const struct chreBleScanFilter * filter)88 bool BleRequestManager::startScanAsync(Nanoapp *nanoapp, chreBleScanMode mode,
89 uint32_t reportDelayMs,
90 const struct chreBleScanFilter *filter) {
91 CHRE_ASSERT(nanoapp);
92 BleRequest request(nanoapp->getInstanceId(), true, mode, reportDelayMs,
93 filter);
94 return configure(std::move(request));
95 }
96
stopScanAsync(Nanoapp * nanoapp)97 bool BleRequestManager::stopScanAsync(Nanoapp *nanoapp) {
98 CHRE_ASSERT(nanoapp);
99 BleRequest request(nanoapp->getInstanceId(), false /* enable */);
100 return configure(std::move(request));
101 }
102
disableActiveScan(const Nanoapp * nanoapp)103 uint32_t BleRequestManager::disableActiveScan(const Nanoapp *nanoapp) {
104 CHRE_ASSERT(nanoapp);
105
106 size_t requestIndex;
107 const BleRequest *foundRequest =
108 mRequests.findRequest(nanoapp->getInstanceId(), &requestIndex);
109
110 if (foundRequest == nullptr || !foundRequest->isEnabled()) {
111 // No active request found.
112 return 0;
113 }
114
115 BleRequest request(nanoapp->getInstanceId(), false /* enable */);
116 configure(std::move(request));
117 return 1;
118 }
119
120 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
readRssiAsync(Nanoapp * nanoapp,uint16_t connectionHandle,const void * cookie)121 bool BleRequestManager::readRssiAsync(Nanoapp *nanoapp,
122 uint16_t connectionHandle,
123 const void *cookie) {
124 CHRE_ASSERT(nanoapp);
125 if (mPendingRssiRequests.full()) {
126 LOG_OOM();
127 return false;
128 }
129 if (mPendingRssiRequests.empty()) {
130 // no previous request existed, so issue this one immediately to get
131 // an early exit if we get a failure
132 auto status = readRssi(connectionHandle);
133 if (status != CHRE_ERROR_NONE) {
134 return false;
135 }
136 }
137 // it's pending, so report the result asynchronously
138 mPendingRssiRequests.push(
139 BleReadRssiRequest{nanoapp->getInstanceId(), connectionHandle, cookie});
140 return true;
141 }
142 #endif
143
addBleRequestLog(uint32_t instanceId,bool enabled,size_t requestIndex,bool compliesWithBleSetting)144 void BleRequestManager::addBleRequestLog(uint32_t instanceId, bool enabled,
145 size_t requestIndex,
146 bool compliesWithBleSetting) {
147 BleRequestLog log(SystemTime::getMonotonicTime(), instanceId, enabled,
148 compliesWithBleSetting);
149 if (enabled) {
150 if (instanceId == CHRE_INSTANCE_ID) {
151 log.populateRequestData(mRequests.getCurrentMaximalRequest());
152 } else if (compliesWithBleSetting) {
153 log.populateRequestData(mRequests.getRequests()[requestIndex]);
154 }
155 }
156 mBleRequestLogs.kick_push(log);
157 }
158
configure(BleRequest && request)159 bool BleRequestManager::configure(BleRequest &&request) {
160 bool success = validateParams(request);
161 if (success) {
162 bool requestChanged = false;
163 size_t requestIndex = 0;
164 bool hasExistingRequest = false;
165 uint16_t instanceId = request.getInstanceId();
166 uint8_t enabled = request.isEnabled();
167 handleExistingRequest(instanceId, &hasExistingRequest, &requestIndex);
168 bool compliant = compliesWithBleSetting(instanceId, enabled,
169 hasExistingRequest, requestIndex);
170 if (compliant) {
171 success = updateRequests(std::move(request), hasExistingRequest,
172 &requestChanged, &requestIndex);
173 if (success) {
174 if (!mPlatformRequestInProgress) {
175 if (!requestChanged) {
176 handleAsyncResult(instanceId, enabled, true /* success */,
177 CHRE_ERROR_NONE);
178 if (requestIndex < mRequests.getRequests().size()) {
179 mRequests.getMutableRequests()[requestIndex].setRequestStatus(
180 RequestStatus::APPLIED);
181 }
182 } else {
183 success = controlPlatform();
184 if (!success) {
185 handleNanoappEventRegistration(instanceId, enabled,
186 false /* success */,
187 true /* forceUnregister */);
188 mRequests.removeRequest(requestIndex, &requestChanged);
189 }
190 }
191 }
192 }
193 }
194 if (success) {
195 addBleRequestLog(instanceId, enabled, requestIndex, compliant);
196 }
197 }
198 return success;
199 }
200
controlPlatform()201 bool BleRequestManager::controlPlatform() {
202 bool success = false;
203 const BleRequest &maxRequest = mRequests.getCurrentMaximalRequest();
204 bool enable = bleSettingEnabled() && maxRequest.isEnabled();
205 if (enable) {
206 chreBleScanFilter filter = maxRequest.getScanFilter();
207 success = mPlatformBle.startScanAsync(
208 maxRequest.getMode(), maxRequest.getReportDelayMs(), &filter);
209 mPendingPlatformRequest =
210 BleRequest(0, enable, maxRequest.getMode(),
211 maxRequest.getReportDelayMs(), &filter);
212 } else {
213 success = mPlatformBle.stopScanAsync();
214 mPendingPlatformRequest = BleRequest(0, enable);
215 }
216 if (success) {
217 for (BleRequest &req : mRequests.getMutableRequests()) {
218 if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
219 req.setRequestStatus(RequestStatus::PENDING_RESP);
220 }
221 }
222 mPlatformRequestInProgress = true;
223 }
224
225 return success;
226 }
227
handleFreeAdvertisingEvent(struct chreBleAdvertisementEvent * event)228 void BleRequestManager::handleFreeAdvertisingEvent(
229 struct chreBleAdvertisementEvent *event) {
230 mPlatformBle.releaseAdvertisingEvent(event);
231 }
232
freeAdvertisingEventCallback(uint16_t,void * eventData)233 void BleRequestManager::freeAdvertisingEventCallback(uint16_t /* eventType */,
234 void *eventData) {
235 auto event = static_cast<chreBleAdvertisementEvent *>(eventData);
236 EventLoopManagerSingleton::get()
237 ->getBleRequestManager()
238 .handleFreeAdvertisingEvent(event);
239 }
240
handleAdvertisementEvent(struct chreBleAdvertisementEvent * event)241 void BleRequestManager::handleAdvertisementEvent(
242 struct chreBleAdvertisementEvent *event) {
243 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
244 CHRE_EVENT_BLE_ADVERTISEMENT, event, freeAdvertisingEventCallback);
245 }
246
handlePlatformChange(bool enable,uint8_t errorCode)247 void BleRequestManager::handlePlatformChange(bool enable, uint8_t errorCode) {
248 auto callback = [](uint16_t /*type*/, void *data, void *extraData) {
249 bool enable = NestedDataPtr<bool>(data);
250 uint8_t errorCode = NestedDataPtr<uint8_t>(extraData);
251 EventLoopManagerSingleton::get()
252 ->getBleRequestManager()
253 .handlePlatformChangeSync(enable, errorCode);
254 };
255
256 EventLoopManagerSingleton::get()->deferCallback(
257 SystemCallbackType::BleScanResponse, NestedDataPtr<bool>(enable),
258 callback, NestedDataPtr<uint8_t>(errorCode));
259 }
260
handlePlatformChangeSync(bool enable,uint8_t errorCode)261 void BleRequestManager::handlePlatformChangeSync(bool enable,
262 uint8_t errorCode) {
263 bool success = (errorCode == CHRE_ERROR_NONE);
264 // Requests to disable BLE scans should always succeed
265 if (!mPendingPlatformRequest.isEnabled() && enable) {
266 errorCode = CHRE_ERROR;
267 success = false;
268 CHRE_ASSERT_LOG(false, "Unable to stop BLE scan");
269 }
270
271 mPlatformRequestInProgress = false;
272 for (BleRequest &req : mRequests.getMutableRequests()) {
273 if (req.getRequestStatus() == RequestStatus::PENDING_RESP) {
274 handleAsyncResult(req.getInstanceId(), req.isEnabled(), success,
275 errorCode);
276 if (success) {
277 req.setRequestStatus(RequestStatus::APPLIED);
278 }
279 }
280 }
281
282 if (!success) {
283 mRequests.removeRequests(RequestStatus::PENDING_RESP);
284 } else {
285 // No need to waste memory for requests that have no effect on the overall
286 // maximal request.
287 mRequests.removeDisabledRequests();
288 mActivePlatformRequest = std::move(mPendingPlatformRequest);
289 }
290
291 dispatchPendingRequests();
292
293 // Only clear mResyncPending if the request succeeded or after all pending
294 // requests are dispatched and a resync request can be issued with only the
295 // requests that were previously applied.
296 if (mResyncPending) {
297 if (success) {
298 mResyncPending = false;
299 } else if (!success && !mPlatformRequestInProgress) {
300 mResyncPending = false;
301 updatePlatformRequest(true /* forceUpdate */);
302 }
303 }
304 // Finish dispatching pending requests before processing the setting change
305 // request to ensure nanoapps receive CHRE_ERROR_FUNCTION_DISABLED responses.
306 // If both a resync and a setting change are pending, prioritize the resync.
307 // If the resync successfully completes, the PAL will be in the correct state
308 // and updatePlatformRequest will not begin a new request.
309 if (mSettingChangePending && !mPlatformRequestInProgress) {
310 updatePlatformRequest();
311 mSettingChangePending = false;
312 }
313 }
314
dispatchPendingRequests()315 void BleRequestManager::dispatchPendingRequests() {
316 if (mRequests.hasRequests(RequestStatus::PENDING_REQ)) {
317 uint8_t errorCode = CHRE_ERROR_NONE;
318 if (!bleSettingEnabled() && mRequests.isMaximalRequestEnabled()) {
319 errorCode = CHRE_ERROR_FUNCTION_DISABLED;
320 } else if (!controlPlatform()) {
321 errorCode = CHRE_ERROR;
322 }
323 if (errorCode != CHRE_ERROR_NONE) {
324 for (const BleRequest &req : mRequests.getRequests()) {
325 if (req.getRequestStatus() == RequestStatus::PENDING_REQ) {
326 handleAsyncResult(req.getInstanceId(), req.isEnabled(),
327 false /* success */, errorCode);
328 }
329 }
330 mRequests.removeRequests(RequestStatus::PENDING_REQ);
331 }
332 }
333 }
334
handleAsyncResult(uint16_t instanceId,bool enabled,bool success,uint8_t errorCode,bool forceUnregister)335 void BleRequestManager::handleAsyncResult(uint16_t instanceId, bool enabled,
336 bool success, uint8_t errorCode,
337 bool forceUnregister) {
338 uint8_t requestType = enabled ? CHRE_BLE_REQUEST_TYPE_START_SCAN
339 : CHRE_BLE_REQUEST_TYPE_STOP_SCAN;
340 postAsyncResultEventFatal(instanceId, requestType, success, errorCode);
341 handleNanoappEventRegistration(instanceId, enabled, success, forceUnregister);
342 }
343
handleNanoappEventRegistration(uint16_t instanceId,bool enabled,bool success,bool forceUnregister)344 void BleRequestManager::handleNanoappEventRegistration(uint16_t instanceId,
345 bool enabled,
346 bool success,
347 bool forceUnregister) {
348 Nanoapp *nanoapp =
349 EventLoopManagerSingleton::get()->getEventLoop().findNanoappByInstanceId(
350 instanceId);
351 if (nanoapp != nullptr) {
352 if (success && enabled) {
353 nanoapp->registerForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
354 } else if (!enabled || forceUnregister) {
355 nanoapp->unregisterForBroadcastEvent(CHRE_EVENT_BLE_ADVERTISEMENT);
356 }
357 }
358 }
359
handleRequestStateResyncCallback()360 void BleRequestManager::handleRequestStateResyncCallback() {
361 auto callback = [](uint16_t /* eventType */, void * /* eventData */,
362 void * /* extraData */) {
363 EventLoopManagerSingleton::get()
364 ->getBleRequestManager()
365 .handleRequestStateResyncCallbackSync();
366 };
367 EventLoopManagerSingleton::get()->deferCallback(
368 SystemCallbackType::BleRequestResyncEvent, nullptr /* data */, callback);
369 }
370
handleRequestStateResyncCallbackSync()371 void BleRequestManager::handleRequestStateResyncCallbackSync() {
372 if (mPlatformRequestInProgress) {
373 mResyncPending = true;
374 } else {
375 updatePlatformRequest(true /* forceUpdate */);
376 }
377 }
378
379 #ifdef CHRE_BLE_READ_RSSI_SUPPORT_ENABLED
handleReadRssi(uint8_t errorCode,uint16_t connectionHandle,int8_t rssi)380 void BleRequestManager::handleReadRssi(uint8_t errorCode,
381 uint16_t connectionHandle, int8_t rssi) {
382 struct readRssiResponse {
383 uint8_t errorCode;
384 int8_t rssi;
385 uint16_t connectionHandle;
386 };
387
388 auto callback = [](uint16_t /* eventType */, void *eventData,
389 void * /* extraData */) {
390 readRssiResponse response = NestedDataPtr<readRssiResponse>(eventData);
391 EventLoopManagerSingleton::get()->getBleRequestManager().handleReadRssiSync(
392 response.errorCode, response.connectionHandle, response.rssi);
393 };
394
395 EventLoopManagerSingleton::get()->deferCallback(
396 SystemCallbackType::BleReadRssiEvent,
397 NestedDataPtr<readRssiResponse>(
398 readRssiResponse{errorCode, rssi, connectionHandle}),
399 callback);
400 }
401
handleReadRssiSync(uint8_t errorCode,uint16_t connectionHandle,int8_t rssi)402 void BleRequestManager::handleReadRssiSync(uint8_t errorCode,
403 uint16_t connectionHandle,
404 int8_t rssi) {
405 if (mPendingRssiRequests.empty()) {
406 FATAL_ERROR(
407 "Got unexpected handleReadRssi event without outstanding request");
408 }
409
410 if (mPendingRssiRequests.front().connectionHandle != connectionHandle) {
411 FATAL_ERROR(
412 "Got readRssi event for mismatched connection handle (%d != %d)",
413 mPendingRssiRequests.front().connectionHandle, connectionHandle);
414 }
415
416 resolvePendingRssiRequest(errorCode, rssi);
417 dispatchNextRssiRequestIfAny();
418 }
419
resolvePendingRssiRequest(uint8_t errorCode,int8_t rssi)420 void BleRequestManager::resolvePendingRssiRequest(uint8_t errorCode,
421 int8_t rssi) {
422 auto event = memoryAlloc<chreBleReadRssiEvent>();
423 if (event == nullptr) {
424 FATAL_ERROR("Failed to alloc BLE async result");
425 }
426
427 event->result.cookie = mPendingRssiRequests.front().cookie;
428 event->result.success = (errorCode == CHRE_ERROR_NONE);
429 event->result.requestType = CHRE_BLE_REQUEST_TYPE_READ_RSSI;
430 event->result.errorCode = errorCode;
431 event->result.reserved = 0;
432 event->connectionHandle = mPendingRssiRequests.front().connectionHandle;
433 event->rssi = rssi;
434
435 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
436 CHRE_EVENT_BLE_RSSI_READ, event, freeEventDataCallback,
437 mPendingRssiRequests.front().instanceId);
438
439 mPendingRssiRequests.pop();
440 }
441
dispatchNextRssiRequestIfAny()442 void BleRequestManager::dispatchNextRssiRequestIfAny() {
443 while (!mPendingRssiRequests.empty()) {
444 auto req = mPendingRssiRequests.front();
445 auto status = readRssi(req.connectionHandle);
446 if (status == CHRE_ERROR_NONE) {
447 // control flow resumes in the handleReadRssi() callback, on completion
448 return;
449 }
450 resolvePendingRssiRequest(status, 0x7F /* failure RSSI from BT spec */);
451 }
452 }
453
readRssi(uint16_t connectionHandle)454 uint8_t BleRequestManager::readRssi(uint16_t connectionHandle) {
455 if (!bleSettingEnabled()) {
456 return CHRE_ERROR_FUNCTION_DISABLED;
457 }
458 auto success = mPlatformBle.readRssiAsync(connectionHandle);
459 if (success) {
460 return CHRE_ERROR_NONE;
461 } else {
462 return CHRE_ERROR;
463 }
464 }
465 #endif
466
getScanStatus(struct chreBleScanStatus *)467 bool BleRequestManager::getScanStatus(struct chreBleScanStatus * /* status */) {
468 // TODO(b/266820139): Implement this
469 return false;
470 }
471
onSettingChanged(Setting setting,bool)472 void BleRequestManager::onSettingChanged(Setting setting, bool /* state */) {
473 if (setting == Setting::BLE_AVAILABLE) {
474 if (mPlatformRequestInProgress) {
475 mSettingChangePending = true;
476 } else {
477 updatePlatformRequest();
478 }
479 }
480 }
481
updatePlatformRequest(bool forceUpdate)482 void BleRequestManager::updatePlatformRequest(bool forceUpdate) {
483 bool desiredPlatformState =
484 bleSettingEnabled() && mRequests.isMaximalRequestEnabled();
485 bool updatePlatform = (forceUpdate || (desiredPlatformState !=
486 mActivePlatformRequest.isEnabled()));
487
488 if (updatePlatform) {
489 if (controlPlatform()) {
490 addBleRequestLog(CHRE_INSTANCE_ID, desiredPlatformState,
491 mRequests.getRequests().size(),
492 true /* compliesWithBleSetting */);
493 } else {
494 FATAL_ERROR("Failed to send update BLE platform request");
495 }
496 }
497 }
498
499 // TODO(b/290860901): require data & ~mask == 0
validateParams(const BleRequest & request)500 bool BleRequestManager::validateParams(const BleRequest &request) {
501 bool valid = true;
502 if (request.isEnabled()) {
503 for (const chreBleGenericFilter &filter : request.getGenericFilters()) {
504 if (!isValidAdType(filter.type)) {
505 valid = false;
506 break;
507 }
508 if (filter.len == 0 || filter.len > CHRE_BLE_DATA_LEN_MAX) {
509 valid = false;
510 break;
511 }
512 }
513 }
514 return valid;
515 }
516
postAsyncResultEventFatal(uint16_t instanceId,uint8_t requestType,bool success,uint8_t errorCode)517 void BleRequestManager::postAsyncResultEventFatal(uint16_t instanceId,
518 uint8_t requestType,
519 bool success,
520 uint8_t errorCode) {
521 chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
522 if (event == nullptr) {
523 FATAL_ERROR("Failed to alloc BLE async result");
524 } else {
525 event->requestType = requestType;
526 event->success = success;
527 event->errorCode = errorCode;
528 event->reserved = 0;
529
530 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
531 CHRE_EVENT_BLE_ASYNC_RESULT, event, freeEventDataCallback, instanceId);
532 }
533 }
534
isValidAdType(uint8_t adType)535 bool BleRequestManager::isValidAdType(uint8_t adType) {
536 return adType == CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16_LE;
537 }
538
bleSettingEnabled()539 bool BleRequestManager::bleSettingEnabled() {
540 return EventLoopManagerSingleton::get()
541 ->getSettingManager()
542 .getSettingEnabled(Setting::BLE_AVAILABLE);
543 }
544
logStateToBuffer(DebugDumpWrapper & debugDump) const545 void BleRequestManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
546 debugDump.print("\nBLE:\n");
547 debugDump.print(" Active Platform Request:\n");
548 mActivePlatformRequest.logStateToBuffer(debugDump,
549 true /* isPlatformRequest */);
550 if (mPlatformRequestInProgress) {
551 debugDump.print(" Pending Platform Request:\n");
552 mPendingPlatformRequest.logStateToBuffer(debugDump,
553 true /* isPlatformRequest */);
554 }
555 debugDump.print(" Request Multiplexer:\n");
556 for (const BleRequest &req : mRequests.getRequests()) {
557 req.logStateToBuffer(debugDump);
558 }
559 debugDump.print(" Last %zu valid BLE requests:\n", mBleRequestLogs.size());
560 static_assert(kNumBleRequestLogs <= INT8_MAX,
561 "kNumBleRequestLogs must be less than INT8_MAX.");
562 for (int8_t i = static_cast<int8_t>(mBleRequestLogs.size()) - 1; i >= 0;
563 i--) {
564 const auto &log = mBleRequestLogs[static_cast<size_t>(i)];
565 debugDump.print(" ts=%" PRIu64 " instanceId=%" PRIu32 " %s",
566 log.timestamp.toRawNanoseconds(), log.instanceId,
567 log.enable ? "enable" : "disable\n");
568 if (log.enable && log.compliesWithBleSetting) {
569 debugDump.print(" mode=%" PRIu8 " reportDelayMs=%" PRIu32
570 " rssiThreshold=%" PRId8 " scanCount=%" PRIu8 "\n",
571 static_cast<uint8_t>(log.mode), log.reportDelayMs,
572 log.rssiThreshold, log.scanFilterCount);
573 } else if (log.enable) {
574 debugDump.print(" request did not comply with BLE setting\n");
575 }
576 }
577 }
578
579 } // namespace chre
580