189 lines
6.1 KiB
C++
189 lines
6.1 KiB
C++
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <cinttypes>
|
|
|
|
#include "chre.h"
|
|
#include "chre/util/macros.h"
|
|
#include "chre/util/memory.h"
|
|
#include "chre/util/nanoapp/log.h"
|
|
#include "chre/util/time.h"
|
|
#include "chre/util/unique_ptr.h"
|
|
|
|
#ifdef CHRE_NANOAPP_INTERNAL
|
|
namespace chre {
|
|
namespace {
|
|
#endif // CHRE_NANOAPP_INTERNAL
|
|
|
|
bool gAsyncResultReceived = false;
|
|
uint32_t gTimerHandle = 0;
|
|
|
|
//! A fake/unused cookie to pass into the session async and timer request.
|
|
const uint32_t kBleCookie = 0x1337;
|
|
//! The interval in seconds between updates.
|
|
const chreBleScanMode kScanModes[] = {CHRE_BLE_SCAN_MODE_BACKGROUND,
|
|
CHRE_BLE_SCAN_MODE_FOREGROUND,
|
|
CHRE_BLE_SCAN_MODE_AGGRESSIVE};
|
|
|
|
enum ScanRequestType {
|
|
NO_FILTER = 0,
|
|
SERVICE_DATA_16 = 1,
|
|
STOP_SCAN = 2,
|
|
};
|
|
|
|
chreBleScanFilter *getBleScanFilter(ScanRequestType &scanRequestType) {
|
|
chre::UniquePtr<chreBleScanFilter> filter =
|
|
chre::MakeUniqueZeroFill<chreBleScanFilter>();
|
|
filter->rssiThreshold = CHRE_BLE_RSSI_THRESHOLD_NONE;
|
|
filter->scanFilterCount = 1;
|
|
chre::UniquePtr<chreBleGenericFilter> scanFilter =
|
|
chre::MakeUniqueZeroFill<chreBleGenericFilter>();
|
|
switch (scanRequestType) {
|
|
case NO_FILTER:
|
|
filter = nullptr;
|
|
scanRequestType = SERVICE_DATA_16;
|
|
break;
|
|
case SERVICE_DATA_16:
|
|
scanFilter->type = CHRE_BLE_AD_TYPE_SERVICE_DATA_WITH_UUID_16;
|
|
scanFilter->len = 2;
|
|
filter->scanFilters = scanFilter.release();
|
|
scanRequestType = STOP_SCAN;
|
|
break;
|
|
case STOP_SCAN:
|
|
break;
|
|
}
|
|
return filter.release();
|
|
}
|
|
|
|
void makeBleScanRequest() {
|
|
static uint8_t scanModeIndex = 0;
|
|
static ScanRequestType scanRequestType = NO_FILTER;
|
|
if (scanRequestType != STOP_SCAN) {
|
|
chreBleScanMode mode = kScanModes[scanModeIndex];
|
|
uint32_t reportDelayMs = 0;
|
|
chreBleScanFilter *filter = getBleScanFilter(scanRequestType);
|
|
LOGI("Sending BLE start scan request to PAL with parameters:");
|
|
LOGI(" mode=%" PRIu8, kScanModes[scanModeIndex]);
|
|
LOGI(" reportDelayMs=%" PRIu32, reportDelayMs);
|
|
if (filter != nullptr) {
|
|
LOGI(" rssiThreshold=%" PRIu32, filter->rssiThreshold);
|
|
LOGI(" scanFilterType=%" PRIx8, filter->scanFilters[0].type);
|
|
LOGI(" scanFilterLen=%" PRIu8, filter->scanFilters[0].len);
|
|
LOGI(" scanFilterData=%s", filter->scanFilters[0].data);
|
|
LOGI(" scanFilterDataMask=%s", filter->scanFilters[0].dataMask);
|
|
}
|
|
if (chreBleStartScanAsync(mode, 0, nullptr)) {
|
|
LOGI("BLE start scan request sent to PAL");
|
|
} else {
|
|
LOGE("Error sending BLE start scan request sent to PAL");
|
|
}
|
|
if (filter != nullptr) {
|
|
if (filter->scanFilters != nullptr) {
|
|
chre::memoryFree(
|
|
const_cast<chreBleGenericFilter *>(filter->scanFilters));
|
|
}
|
|
chre::memoryFree(filter);
|
|
}
|
|
} else {
|
|
if (chreBleStopScanAsync()) {
|
|
LOGI("BLE stop scan request sent to PAL");
|
|
} else {
|
|
LOGE("Error sending BLE stop scan request sent to PAL");
|
|
}
|
|
scanRequestType = NO_FILTER;
|
|
scanModeIndex = (scanModeIndex + 1) % ARRAY_SIZE(kScanModes);
|
|
}
|
|
gTimerHandle = chreTimerSet(CHRE_ASYNC_RESULT_TIMEOUT_NS, /* 5 sec */
|
|
&kBleCookie, true /* oneShot */);
|
|
}
|
|
|
|
void handleAdvertismentEvent(const chreBleAdvertisementEvent *event) {
|
|
for (uint8_t i = 0; i < event->numReports; i++) {
|
|
LOGI("BLE Report %" PRIu8, i + 1);
|
|
LOGI("Scan data:");
|
|
const uint8_t *data = event->reports[i].data;
|
|
for (uint8_t j = 0; j < event->reports[i].dataLength; j++) {
|
|
LOGI(" %" PRIx8, data[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void handleAsyncResultEvent(const chreAsyncResult *result) {
|
|
gAsyncResultReceived = true;
|
|
const char *requestType =
|
|
result->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN ? "start"
|
|
: "stop";
|
|
if (result->success) {
|
|
LOGI("BLE %s scan success", requestType);
|
|
} else {
|
|
LOGE("BLE %s scan failure: %" PRIu8, requestType, result->errorCode);
|
|
}
|
|
}
|
|
|
|
void handleTimerEvent(const void *eventData) {
|
|
static uint32_t timerCount = 1;
|
|
if (eventData == &kBleCookie) {
|
|
LOGI("BLE timer event received, count %" PRIu32, timerCount++);
|
|
if (!gAsyncResultReceived) {
|
|
LOGE("BLE async result not received");
|
|
}
|
|
gAsyncResultReceived = false;
|
|
makeBleScanRequest();
|
|
} else {
|
|
LOGE("Invalid timer cookie");
|
|
}
|
|
}
|
|
|
|
bool nanoappStart(void) {
|
|
LOGI("nanoapp started");
|
|
makeBleScanRequest();
|
|
return true;
|
|
}
|
|
|
|
void nanoappEnd(void) {
|
|
if (!chreBleStopScanAsync()) {
|
|
LOGE("Error sending BLE stop scan request sent to PAL");
|
|
}
|
|
if (!chreTimerCancel(gTimerHandle)) {
|
|
LOGE("Error canceling timer");
|
|
}
|
|
LOGI("nanoapp stopped");
|
|
}
|
|
|
|
void nanoappHandleEvent(uint32_t /* sender_instance_id */, uint16_t event_type,
|
|
const void *event_data) {
|
|
if (event_type == CHRE_EVENT_BLE_ADVERTISEMENT) {
|
|
handleAdvertismentEvent(
|
|
static_cast<const chreBleAdvertisementEvent *>(event_data));
|
|
} else if (event_type == CHRE_EVENT_BLE_ASYNC_RESULT) {
|
|
handleAsyncResultEvent(static_cast<const chreAsyncResult *>(event_data));
|
|
} else if (event_type == CHRE_EVENT_TIMER) {
|
|
handleTimerEvent(event_data);
|
|
}
|
|
}
|
|
|
|
#ifdef CHRE_NANOAPP_INTERNAL
|
|
} // anonymous namespace
|
|
} // namespace chre
|
|
|
|
#include "chre/platform/static_nanoapp_init.h"
|
|
#include "chre/util/nanoapp/app_id.h"
|
|
#include "chre/util/system/napp_permissions.h"
|
|
|
|
CHRE_STATIC_NANOAPP_INIT(BleWorld, kBleWorldAppId, 0,
|
|
NanoappPermissions::CHRE_PERMS_BLE);
|
|
#endif // CHRE_NANOAPP_INTERNAL
|