Skip to content

Commit

Permalink
Merge pull request #2542 from particle-iot/feature/p2_ble_central
Browse files Browse the repository at this point in the history
RTL872x-based platforms: supports BLE GATT client, BLE central role and pairing APIs
  • Loading branch information
avtolstoy authored Sep 29, 2022
2 parents 0945720 + a002f91 commit b64994e
Show file tree
Hide file tree
Showing 15 changed files with 1,635 additions and 290 deletions.
4 changes: 4 additions & 0 deletions hal/inc/hal_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,4 +526,8 @@
#define HAL_PLATFORM_CELLULAR_MODEM_VOLTAGE_TRANSLATOR (1)
#endif // HAL_PLATFORM_CELLULAR_MODEM_VOLTAGE_TRANSLATOR

#ifndef HAL_PLATFORM_BLE_ACTIVE_EVENT
#define HAL_PLATFORM_BLE_ACTIVE_EVENT (0)
#endif // HAL_PLATFORM_BLE_ACTIVE_EVENT

#endif /* HAL_PLATFORM_H */
10 changes: 2 additions & 8 deletions hal/src/nRF52840/ble_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,6 @@ class BleObject::GattClient {
hal_ble_char_t* findDiscoveredCharacteristic(hal_ble_attr_handle_t attrHandle);
int addPublisher(hal_ble_conn_handle_t connHandle, hal_ble_attr_handle_t valueHandle, hal_ble_on_char_evt_cb_t callback, void* context);
int removePublisher(hal_ble_conn_handle_t connHandle, hal_ble_attr_handle_t valueHandle);
int configRemoteCharCCCD(const hal_ble_cccd_config_t* config);
static void processGattClientEvents(const ble_evt_t* event, void* context);
static void onAttMtuExchangeTimerExpired(os_timer_t timer);

Expand Down Expand Up @@ -1806,13 +1805,7 @@ bool BleObject::ConnectionsManager::connecting(const hal_ble_addr_t* address) co

bool BleObject::ConnectionsManager::connected(const hal_ble_addr_t* address) {
if (address == nullptr) {
// Check if local device is connected as BLE Peripheral.
for (const auto& connection : connections_) {
if (connection.info.role == BLE_ROLE_PERIPHERAL) {
return true;
}
}
return false;
return connections_.size() > 0;
}
if (fetchConnection(address)) {
return true;
Expand Down Expand Up @@ -3149,6 +3142,7 @@ int BleObject::GattClient::discoverServices(hal_ble_conn_handle_t connHandle, co
int BleObject::GattClient::discoverCharacteristics(hal_ble_conn_handle_t connHandle, const hal_ble_svc_t* service, hal_ble_on_disc_char_cb_t callback, void* context) {
CHECK_TRUE(BleObject::getInstance().connMgr()->valid(connHandle), SYSTEM_ERROR_NOT_FOUND);
CHECK_FALSE(isDiscovering_, SYSTEM_ERROR_INVALID_STATE);
CHECK_TRUE(service, SYSTEM_ERROR_INVALID_ARGUMENT);
SCOPE_GUARD ({
resetDiscoveryState();
});
Expand Down
1,611 changes: 1,449 additions & 162 deletions hal/src/rtl872x/ble_hal.cpp

Large diffs are not rendered by default.

5 changes: 1 addition & 4 deletions hal/src/rtl872x/freertos/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,7 @@ extern void newlib_impure_ptr_change(struct _reent* r);

/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 2
// #define configTIMER_QUEUE_LENGTH ( 10 + 32 )
// #define configTIMER_TASK_STACK_DEPTH ( 512 )
// #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH ( 64 )
#define configTIMER_TASK_STACK_DEPTH ( ( unsigned short ) (4096 / sizeof( portSTACK_TYPE )) )

Expand Down
2 changes: 2 additions & 0 deletions hal/src/rtl872x/hal_platform_rtl8721x_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,5 @@
#define HAL_PLATFORM_MODULE_SUFFIX_EXTENSIONS (1)

#define HAL_PLATFORM_POWER_MANAGEMENT_STACK_SIZE (1536)

#define HAL_PLATFORM_BLE_ACTIVE_EVENT (1)
1 change: 1 addition & 0 deletions system/src/ble_provisioning_mode_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ int BleProvisioningModeHandler::cacheUserConfigurations() {
preAdvParams_.size = sizeof(hal_ble_adv_params_t);
CHECK(hal_ble_gap_get_advertising_parameters(&preAdvParams_, nullptr));
CHECK(hal_ble_gap_get_tx_power(&preTxPower_, nullptr));
prePpcp_.size = sizeof(hal_ble_conn_params_t);
CHECK(hal_ble_gap_get_ppcp(&prePpcp_, nullptr));
CHECK(hal_ble_gap_get_auto_advertise(&preAutoAdv_, nullptr));

Expand Down
1 change: 1 addition & 0 deletions third_party/ambd_sdk/include.mk
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ INCLUDE_DIRS += $(TARGET_AMBD_SDK_COMMON_PATH)/drivers/usb/device_new/core
INCLUDE_DIRS += $(TARGET_AMBD_SDK_COMMON_PATH)/drivers/usb/common_new

# Hack of the century!
LIBS_EXT_END += -Wl,--wrap=bt_coex_handle_specific_evt
LIBS_EXT_END += $(TARGET_AMBD_SDK_PROJECT_LIB_PATH)/lib_wlan.a
LIBS_EXT_END += $(TARGET_AMBD_SDK_PROJECT_LIB_PATH)/lib_wps.a
ifneq ("$(MODULE)", "user-part")
Expand Down
179 changes: 95 additions & 84 deletions user/tests/wiring/ble_central_peripheral/ble_central/central.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,100 +342,103 @@ const char* ioCapsStr[5] = {

static void pairingTestRoutine(bool request, BlePairingAlgorithm algorithm,
BlePairingIoCaps ours = BlePairingIoCaps::NONE, BlePairingIoCaps theirs = BlePairingIoCaps::NONE) {
peer = BLE.connect(peerAddr, false);
assertTrue(peer.connected());
{
SCOPE_GUARD ({
delay(500);
assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE);
assertFalse(BLE.connected());
delay(500);
});

pairingStatus = -1;
pairingRequested = false;
BLE.onPairingEvent([&](const BlePairingEvent& event) {
if (event.type == BlePairingEventType::REQUEST_RECEIVED) {
Serial.println("Request received");
pairingRequested = true;
} else if (event.type == BlePairingEventType::STATUS_UPDATED) {
pairingStatus = event.payload.status.status;
lesc = event.payload.status.lesc;
Serial.println("status updated");
} else if (event.type == BlePairingEventType::PASSKEY_DISPLAY || event.type == BlePairingEventType::NUMERIC_COMPARISON) {
Serial.print("Passkey display: ");
for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) {
Serial.printf("%c", event.payload.passkey[i]);
}
Serial.println("");
#if !defined(PARTICLE_TEST_RUNNER)
if (event.type == BlePairingEventType::NUMERIC_COMPARISON) {
while (Serial.available()) {
Serial.read();
}
Serial.print("Please confirm if the passkey is identical (y/n): ");
while (!Serial.available());
char c = Serial.read();
Serial.write(c);
Serial.println("");
BLE.setPairingNumericComparison(event.peer, (c == 'y') ? true : false);
}
#else
assertTrue(publishPassKey((const char*)event.payload.passkey, event.payloadLen));
if (event.type == BlePairingEventType::NUMERIC_COMPARISON) {
String peerPassKey;
for (auto t = millis(); millis() - t < 60000;) {
if (getBleTestPasskey(peerPassKey)) {
break;
}
delay(50);
}
assertNotEqual(String(), peerPassKey);
BLE.setPairingNumericComparison(event.peer, peerPassKey == String((const char*)event.payload.passkey, event.payloadLen));
}
#endif // PARTICLE_TEST_RUNNER
} else if (event.type == BlePairingEventType::PASSKEY_INPUT) {
pairingStatus = -1;
pairingRequested = false;
BLE.onPairingEvent([&](const BlePairingEvent& event) {
if (event.type == BlePairingEventType::REQUEST_RECEIVED) {
Serial.println("Request received");
pairingRequested = true;
} else if (event.type == BlePairingEventType::STATUS_UPDATED) {
pairingStatus = event.payload.status.status;
lesc = event.payload.status.lesc;
Serial.printlnf("status updated, %d", event.payload.status.status);
} else if (event.type == BlePairingEventType::PASSKEY_DISPLAY || event.type == BlePairingEventType::NUMERIC_COMPARISON) {
Serial.print("Passkey display: ");
for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) {
Serial.printf("%c", event.payload.passkey[i]);
}
Serial.println("");
#if !defined(PARTICLE_TEST_RUNNER)
if (event.type == BlePairingEventType::NUMERIC_COMPARISON) {
while (Serial.available()) {
Serial.read();
}
Serial.print("Passkey input (must be identical to the peer's): ");
uint8_t i = 0;
uint8_t passkey[BLE_PAIRING_PASSKEY_LEN];
while (i < BLE_PAIRING_PASSKEY_LEN) {
if (Serial.available()) {
passkey[i] = Serial.read();
Serial.write(passkey[i++]);
}
}
Serial.print("Please confirm if the passkey is identical (y/n): ");
while (!Serial.available());
char c = Serial.read();
Serial.write(c);
Serial.println("");
BLE.setPairingPasskey(event.peer, passkey);
BLE.setPairingNumericComparison(event.peer, (c == 'y') ? true : false);
}
#else
Serial.printlnf("passkey input");
assertTrue(publishPassKey((const char*)event.payload.passkey, event.payloadLen));
if (event.type == BlePairingEventType::NUMERIC_COMPARISON) {
String peerPassKey;
// Special case where both ends have KEYBOARD_ONLY capabilities:
// Generate random passkey, the side that is the requester will publish it
if (ours == theirs && ours == BlePairingIoCaps::KEYBOARD_ONLY && request) {
Random rand;
char passkey[BLE_PAIRING_PASSKEY_LEN + 1] = {};
const char dict[] = "0123456789";
rand.genAlpha(passkey, BLE_PAIRING_PASSKEY_LEN, dict, sizeof(dict) - 1);
assertTrue(publishPassKey(passkey, BLE_PAIRING_PASSKEY_LEN));
peerPassKey = String(passkey);
} else {
for (auto t = millis(); millis() - t < 60000;) {
if (getBleTestPasskey(peerPassKey)) {
break;
}
delay(50);
for (auto t = millis(); millis() - t < 60000;) {
if (getBleTestPasskey(peerPassKey)) {
break;
}
delay(50);
}
assertNotEqual(String(), peerPassKey);
BLE.setPairingPasskey(event.peer, (const uint8_t*)peerPassKey.c_str());
BLE.setPairingNumericComparison(event.peer, peerPassKey == String((const char*)event.payload.passkey, event.payloadLen));
}
#endif // PARTICLE_TEST_RUNNER
} else if (event.type == BlePairingEventType::PASSKEY_INPUT) {
#if !defined(PARTICLE_TEST_RUNNER)
while (Serial.available()) {
Serial.read();
}
});
Serial.print("Passkey input (must be identical to the peer's): ");
uint8_t i = 0;
uint8_t passkey[BLE_PAIRING_PASSKEY_LEN];
while (i < BLE_PAIRING_PASSKEY_LEN) {
if (Serial.available()) {
passkey[i] = Serial.read();
Serial.write(passkey[i++]);
}
}
Serial.println("");
BLE.setPairingPasskey(event.peer, passkey);
#else
Serial.printlnf("passkey input");
String peerPassKey;
// Special case where both ends have KEYBOARD_ONLY capabilities:
// Generate random passkey, the side that is the requester will publish it
if (ours == theirs && ours == BlePairingIoCaps::KEYBOARD_ONLY && request) {
Random rand;
char passkey[BLE_PAIRING_PASSKEY_LEN + 1] = {};
const char dict[] = "0123456789";
rand.genAlpha(passkey, BLE_PAIRING_PASSKEY_LEN, dict, sizeof(dict) - 1);
assertTrue(publishPassKey(passkey, BLE_PAIRING_PASSKEY_LEN));
peerPassKey = String(passkey);
} else {
for (auto t = millis(); millis() - t < 60000;) {
if (getBleTestPasskey(peerPassKey)) {
break;
}
delay(50);
}
}
assertNotEqual(String(), peerPassKey);
BLE.setPairingPasskey(event.peer, (const uint8_t*)peerPassKey.c_str());
#endif // PARTICLE_TEST_RUNNER
}
});

// Some platforms may have to restart BT stack to set IO caps, which may fail the connection attempt
delay(1s);

peer = BLE.connect(peerAddr, false);
assertTrue(peer.connected());
{
SCOPE_GUARD ({
delay(500);
assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE);
assertFalse(BLE.connected());
assertFalse(peer.connected());
delay(500);
});
if (request) {
assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE);
} else {
Expand Down Expand Up @@ -473,6 +476,12 @@ test(BLE_28_Pairing_Algorithm_Lesc_Only_Reject_Legacy_Prepare) {
}

test(BLE_29_Pairing_Algorithm_Lesc_Only_Reject_Legacy) {
assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE);
assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LESC_ONLY), (int)SYSTEM_ERROR_NONE);

// Some platforms may have to restart BT stack to set IO caps, which may fail the connection attempt
delay(1s);

peer = BLE.connect(peerAddr, false);
assertTrue(peer.connected());
{
Expand All @@ -491,9 +500,6 @@ test(BLE_29_Pairing_Algorithm_Lesc_Only_Reject_Legacy) {
}
});

assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE);
assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LESC_ONLY), (int)SYSTEM_ERROR_NONE);

assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE);
assertTrue(BLE.isPairing(peer));
assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000));
Expand Down Expand Up @@ -531,6 +537,11 @@ test(BLE_31_Pairing_Receiption_Reject) {
}
});

#if HAL_PLATFORM_RTL872X
// We set it to LESC_ONLY before, it will reject the pairing request automatically without generating any event.
assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::AUTO), (int)SYSTEM_ERROR_NONE);
#endif

peer = BLE.connect(peerAddr, false);
assertTrue(peer.connected());
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,6 @@ static void pairingTestRoutine(bool request, BlePairingAlgorithm algorithm,
} else {
assertFalse(lesc);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer,

using namespace particle::test;

// TODO: P2 needs to support BLE central role to perform this test

test(BLE_000_Broacaster_Cloud_Connect) {
subscribeEvents(BLE_ROLE_PERIPHERAL);
Particle.connect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ BleCharacteristic peerCharWriteWoRsp;

using namespace particle::test;

// TODO: P2 needs to support BLE central role to perform this test

test(BLE_000_Scanner_Cloud_Connect) {
subscribeEvents(BLE_ROLE_PERIPHERAL);
Particle.connect();
Expand Down
4 changes: 2 additions & 2 deletions user/tests/wiring/no_fixture_ble/ble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@

#if Wiring_BLE == 1

#if !HAL_PLATFORM_RTL872X // P2 doesn't support setting device address
test(BLE_01_Set_BLE_Device_Address) {
int ret;
BleAddress defaultAddr = BLE.address();
BleAddress getAddr;

#if !HAL_PLATFORM_RTL872X // P2 doesn't support setting public device address
// The most two significant bits should be 0b10.
uint8_t mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x9b};
ret = BLE.setAddress(BleAddress(mac));
Expand Down Expand Up @@ -58,6 +58,7 @@ test(BLE_01_Set_BLE_Device_Address) {
assertEqual(ret, 0);
getAddr = BLE.address();
assertTrue(!strcmp(getAddr.toString().c_str(), "9B:40:33:20:11:00"));
#endif // !HAL_PLATFORM_RTL872X

// The most two significant bits of static address must be 0b11
ret = BLE.setAddress("9b:44:33:22:11:00", BleAddressType::RANDOM_STATIC);
Expand All @@ -74,7 +75,6 @@ test(BLE_01_Set_BLE_Device_Address) {
getAddr = BLE.address();
assertTrue(getAddr == defaultAddr);
}
#endif // !HAL_PLATFORM_RTL872X

test(BLE_02_Set_BLE_Device_Name) {
int ret;
Expand Down
2 changes: 1 addition & 1 deletion wiring/inc/spark_wiring_ble.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ enum class BlePairingIoCaps : uint8_t {
enum class BlePairingAlgorithm : uint8_t {
AUTO = BLE_PAIRING_ALGORITHM_AUTO,
LEGACY_ONLY = BLE_PAIRING_ALGORITHM_LEGACY_ONLY,
LESC_ONLY = BLE_PAIRING_ALGORITHM_LESC_ONLY
LESC_ONLY = BLE_PAIRING_ALGORITHM_LESC_ONLY // nRF52840-based platforms only
};

enum class BlePairingEventType : uint8_t {
Expand Down
Loading

0 comments on commit b64994e

Please sign in to comment.