android13/system/chre/apps/ble_world/ble_world.cc

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