blob: 4e01340558503fb896d2e9659bef3a8ca1ff7934 [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* 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 "blecent.h"
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/ESP32/ChipDeviceScanner.h>
#define CHIPoBLE_SERVICE_UUID 0xFFF6
namespace chip {
namespace DeviceLayer {
namespace Internal {
namespace {
/// Retrieve CHIP device identification info from the device advertising data
bool NimbleGetChipDeviceInfo(const ble_hs_adv_fields & fields, chip::Ble::ChipBLEDeviceIdentificationInfo & deviceInfo)
{
// Check for CHIP Service UUID
if (fields.svc_data_uuid16 != NULL)
{
if (fields.svc_data_uuid16_len > 8 && fields.svc_data_uuid16[0] == 0xf6 && fields.svc_data_uuid16[1] == 0xff)
{
deviceInfo.OpCode = fields.svc_data_uuid16[2];
deviceInfo.DeviceDiscriminatorAndAdvVersion[0] = fields.svc_data_uuid16[3];
deviceInfo.DeviceDiscriminatorAndAdvVersion[1] = fields.svc_data_uuid16[4];
// vendor and product Id from adv
deviceInfo.DeviceVendorId[0] = fields.svc_data_uuid16[5];
deviceInfo.DeviceVendorId[1] = fields.svc_data_uuid16[6];
deviceInfo.DeviceProductId[0] = fields.svc_data_uuid16[7];
deviceInfo.DeviceProductId[1] = fields.svc_data_uuid16[8];
deviceInfo.AdditionalDataFlag = fields.svc_data_uuid16[9];
return true;
}
}
return false;
}
} // namespace
void ChipDeviceScanner::ReportDevice(const struct ble_hs_adv_fields & fields, const ble_addr_t & addr)
{
chip::Ble::ChipBLEDeviceIdentificationInfo deviceInfo;
if (NimbleGetChipDeviceInfo(fields, deviceInfo) == false)
{
ChipLogDetail(Ble, "Device %s does not look like a CHIP device", addr_str(addr.val));
return;
}
mDelegate->OnDeviceScanned(fields, addr, deviceInfo);
}
void ChipDeviceScanner::RemoveDevice()
{
// TODO
}
int ChipDeviceScanner::OnBleCentralEvent(struct ble_gap_event * event, void * arg)
{
ChipDeviceScanner * scanner = (ChipDeviceScanner *) arg;
switch (event->type)
{
case BLE_GAP_EVENT_DISC_COMPLETE: {
scanner->mIsScanning = false;
return 0;
}
case BLE_GAP_EVENT_DISC: {
/* Try to connect to the advertiser if it looks interesting. */
struct ble_hs_adv_fields fields;
ble_hs_adv_parse_fields(&fields, event->disc.data, event->disc.length_data);
scanner->ReportDevice(fields, event->disc.addr);
return 0;
}
}
return 0;
}
CHIP_ERROR ChipDeviceScanner::StartScan(uint16_t timeout)
{
ReturnErrorCodeIf(mIsScanning, CHIP_ERROR_INCORRECT_STATE);
uint8_t ownAddrType;
struct ble_gap_disc_params discParams;
int rc;
/* Figure out address to use while advertising. */
rc = ble_hs_id_infer_auto(0, &ownAddrType);
if (rc != 0)
{
ChipLogError(DeviceLayer, "ble_hs_id_infer_auto failed: %d", rc);
return CHIP_ERROR_INTERNAL;
}
/* Set up discovery parameters. */
memset(&discParams, 0, sizeof(discParams));
/* Tell the controller to filter the duplicates. */
discParams.filter_duplicates = 1;
/* Perform passive scanning. */
discParams.passive = 1;
/* Use defaults for the rest of the parameters. */
discParams.itvl = 0;
discParams.window = 0;
discParams.filter_policy = 0;
discParams.limited = 0;
/* Start the discovery process. */
rc = ble_gap_disc(ownAddrType, (timeout * 1000), &discParams, OnBleCentralEvent, this);
if (rc != 0)
{
ChipLogError(DeviceLayer, "ble_gap_disc failed: %d", rc);
return CHIP_ERROR_INTERNAL;
}
mIsScanning = true;
return CHIP_NO_ERROR;
}
CHIP_ERROR ChipDeviceScanner::StopScan()
{
ReturnErrorCodeIf(!mIsScanning, CHIP_NO_ERROR);
int rc = ble_gap_disc_cancel();
if (rc != 0)
{
ChipLogError(DeviceLayer, "ble_gap_disc_cancel failed: %d", rc);
return CHIP_ERROR_INTERNAL;
}
mIsScanning = false;
mDelegate->OnScanComplete();
return CHIP_NO_ERROR;
}
} // namespace Internal
} // namespace DeviceLayer
} // namespace chip