ble-nrf51822
ble-nrf51822 copied to clipboard
Cross effect when central and device and unexpected disconnections
This code to a test triangle with 3 boards.
link 1: board A is central, board B is device link 2: board B is central, board C is device link 3: board C is central, board A is device
every time a char is received on serial port of a board, it's reported to the serial ports of the 2 other boards connected.
It works not so bad but depending on connections order, some half links are not working.
For the boards that did first connection as central and second as device, both TX are working. For the boards that did first connection as device and second as central, half TX are working.
After 20 to 30 s, unexpected disconnections are reported.
include "mbed.h"
include "BLE.h"
include "UARTService.h"
include "ble/DiscoveredCharacteristic.h"
include "ble/DiscoveredService.h"
include "UARTService.h"
define SOFT_DEVICE_FATHER_HANDLE 3
define BOARDS_COUNT 3
const Gap::Address_t mac_board_0 = {0xb8, 0xac, 0x4e, 0x8d, 0x8b, 0xeb}; const Gap::Address_t mac_board_1 = {0x9c, 0x43, 0x62, 0x30, 0xaf, 0xd2}; const Gap::Address_t mac_board_2 = {0x5f, 0x1a, 0x9e, 0x6a, 0x63, 0xdd};
// tiny ble board
define LED_GREEN p21
define LED_RED p22
define LED_BLUE p23
define BUTTON_PIN p17
define BATTERY_PIN p1
define MPU6050_SDA p12
define MPU6050_SCL p13
define UART_TX p9
define UART_RX p11
define UART_CTS p8
define UART_RTS p10
DigitalOut led(LED_RED); DigitalOut alivenessLED(LED_GREEN); InterruptIn button(BUTTON_PIN); AnalogIn battery(BATTERY_PIN); Serial pc(UART_TX, UART_RX);
bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2) { #if 0 if (mac_1[0] != mac_2[0]) { return false; } if (mac_1[1] != mac_2[1]) { return false; } if (mac_1[2] != mac_2[2]) { return false; } if (mac_1[3] != mac_2[3]) { return false; } if (mac_1[4] != mac_2[4]) { return false; } if (mac_1[5] != mac_2[5]) { return false; } #else for (int i = 0; i < 6; i++) { if (mac_1[i] != mac_2[i]) { //pc.printf("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i); return false; } else { //pc.printf("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i); } } #endif return true; }
int get_board_index(const Gap::Address_t mac) { if (mac_equals(mac, mac_board_0)) { return 0; } if (mac_equals(mac, mac_board_1)) { return 1; } if (mac_equals(mac, mac_board_2)) { return 2; }
return -1;
}
void periodicCallback(void) { alivenessLED = !alivenessLED; /* do blinky on alivenessLED while we're waiting for BLE events */ }
// Mixed role **************************************************** BLE ble; Gap::Address_t my_mac; int my_board_index = -1;
// Device role **************************************************** UARTService * uartServicePtr = NULL; const static char DEVICE_NAME[] = "ChangeMe!!"; // change this static const uint16_t uuid16_list[] = {UARTServiceShortUUID}; volatile int central_handle = -1;
// Central role **************************************************** Gap::Handle_t connectionHandle = 0xFFFF; DiscoveredCharacteristic uartTXCharacteristic; DiscoveredCharacteristic uartRXCharacteristic; bool foundUartRXCharacteristic = false; volatile int device_handle = -1;
// Device role **************************************************** void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params) { if (uartServicePtr != NULL) { if ((params->handle == uartServicePtr->getTXCharacteristicHandle()) && (params->len >= 1)) { if (params->data[0] != '0') { led = 1; } else { led = 0; }
for(int i = 0; i < params->len; i++)
{
pc.printf("%c", params->data[i]);
}
pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle);
}
}
}
// Central role **************************************************** void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) { // do connections like a triangle int peer_board_index = get_board_index(params->peerAddr);
int next_board_index = my_board_index + 1;
if (next_board_index >= BOARDS_COUNT)
{
next_board_index = 0;
}
//pc.printf("adv %d, %d, %d\r\n", peer_board_index, my_board_index, next_board_index);
if (peer_board_index == next_board_index)
{
//pc.printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
// params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
// params->rssi, params->isScanResponse, params->type);
ble.gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
}
}
void serviceDiscoveryCallback(const DiscoveredService *service) { if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { //pc.printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); } else { //pc.printf("S UUID-"); const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { //pc.printf("%02x", longUUIDBytes[i]); } //pc.printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); } }
void characteristicDiscoveryCallback(const DiscoveredCharacteristic characteristicP) { //pc.printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast()); if (characteristicP->getUUID().getShortUUID() == UARTServiceTXCharacteristicShortUUID) { //pc.printf("fit TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID); / !ALERT! Alter this filter to suit your device. / uartTXCharacteristic = *characteristicP; } else if (characteristicP->getUUID().getShortUUID() == UARTServiceRXCharacteristicShortUUID) { //pc.printf("fit RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID); / !ALERT! Alter this filter to suit your device. */ uartRXCharacteristic = *characteristicP; foundUartRXCharacteristic = true; } }
void discoveryTerminationCallback(Gap::Handle_t connectionHandle) { pc.printf("terminated SD for handle %u\r\n", connectionHandle); }
void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params) { //pc.printf("received HVX callback for handle %u; type %s\r\r\n", params->handle, (params->type == BLE_HVX_NOTIFICATION) ? "notification" : "indication"); if (params->type == BLE_HVX_NOTIFICATION) { if ((params->handle == uartRXCharacteristic.getValueHandle()) && (params->len > 0)) { for (int i = 0; i < params->len; i++) { pc.printf("%c", params->data[i]); }
pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle);
}
}
else
{
pc.printf("%d\r\n", params->type);
}
}
// Mixed role **************************************************** void connectionCallback(const Gap::ConnectionCallbackParams_t params) { if (params->role == Gap::CENTRAL) { device_handle = params->handle; pc.printf("connected as central (handle = %d)\r\n\r", params->handle); connectionHandle = params->handle; ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback); ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback/, 0xa000, 0xa001*/); } else { central_handle = params->handle; pc.printf("connected as device (handle = %d)\r\n\r", params->handle);
//pc.printf("Conn. params => min=%d, max=%d, slave=%d, supervision=%d\r\n", params->connectionParams->minConnectionInterval, params->connectionParams->maxConnectionInterval, params->connectionParams->slaveLatency, params->connectionParams->connectionSupervisionTimeout);
Gap::ConnectionParams_t connectionParams;
connectionParams.minConnectionInterval = 6;
connectionParams.maxConnectionInterval = 12;
connectionParams.slaveLatency = 40;
connectionParams.connectionSupervisionTimeout = 500;
if (ble.updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE)
{
pc.printf("failed to update connection parameter\r\n");
}
}
pc.printf("own %02x:%02x:%02x:%02x:%02x:%02x (%s), peer %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n", params->ownAddr[5], params->ownAddr[4], params->ownAddr[3], params->ownAddr[2], params->ownAddr[1], params->ownAddr[0], (params->ownAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random", params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0], (params->peerAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random");
}
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) { pc.printf("disconnected (handle = %d)\r\n", handle);
if (handle == SOFT_DEVICE_FATHER_HANDLE)
{
central_handle = -1;
// restart advertising
ble.startAdvertising();
}
else
{
device_handle = -1;
// restart scan
ble.gap().startScan(advertisementCallback);
}
}
void serialTxCallback() {
}
int rx_char = -1;
void serialRxCallback()
{
if (rx_char != -1)
{
pc.printf("overflow\r\n");
}
//computer.putc(computer.getc());
rx_char = pc.getc();
}
/* volatile bool gatt_server_is_busy = false;
void gattServerOnDataSent(unsigned count) { gatt_server_is_busy = false; } */
int main(void) { alivenessLED = 0;
pc.baud(115200);
//pc.attach(&serialTxCallback, Serial::TxIrq);
pc.attach(&serialRxCallback, Serial::RxIrq);
// clear terminal output
for (int k = 0; k < 32; k++)
{
pc.printf("\r\n");
}
pc.printf("Central and device\r\n");
Ticker ticker;
ticker.attach(periodicCallback, 1);
// Mixed role ****************************************************
ble.init();
Gap::AddressType_t my_mac_type;
ble.gap().getAddress(&my_mac_type, my_mac);
my_board_index = get_board_index(my_mac);
pc.printf("me %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n", my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0], (my_mac_type == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random");
// try to speed up but looks like if it was ignored
Gap::ConnectionParams_t fast;
if (ble.getPreferredConnectionParams(&fast) != BLE_ERROR_NONE)
{
pc.printf("getPreferredConnectionParams failed\r\n");
}
else
{
fast.minConnectionInterval = 16; // 20 ms
fast.maxConnectionInterval = 32; // 40 ms
fast.slaveLatency = 0;
if (ble.gap().setPreferredConnectionParams(&fast) != BLE_ERROR_NONE)
{
pc.printf("setPreferredConnectionParams failed\r\n");
}
}
ble.gap().onConnection(connectionCallback);
ble.gap().onDisconnection(disconnectionCallback);
// Device role ****************************************************
ble.gattServer().onDataWritten(onReceivedDataFromCentralCallback);
//ble.gattServer().onDataSent(gattServerOnDataSent);
UARTService uartService(ble);
uartServicePtr = &uartService;
// setup advertising
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); // BLE only, no classic BT
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); // add name
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // UUID's broadcast in advertising packet
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // advertising type
ble.setAdvertisingInterval(100);
// Central role ****************************************************
ble.gattClient().onHVX(onReceivedDataFromDeviceCallback);
ble.gap().setScanParams(500, 450);
// start advertising and scan
ble.startAdvertising();
ble.gap().startScan(advertisementCallback);
while (true)
{
// allow notifications from device
if (foundUartRXCharacteristic && !ble.gattClient().isServiceDiscoveryActive())
{
foundUartRXCharacteristic = false; /* need to do the following only once */
uint16_t value = BLE_HVX_NOTIFICATION;
ble.gattClient().write(GattClient::GATT_OP_WRITE_REQ,
connectionHandle,
uartRXCharacteristic.getValueHandle() + 1, /* HACK Alert. We're assuming that CCCD descriptor immediately follows the value attribute. */
sizeof(uint16_t), /* HACK Alert! size should be made into a BLE_API constant. */
reinterpret_cast<const uint8_t *>(&value));
}
// while a new char from computer is available
while (rx_char != -1)
{
uint8_t temp[20];
int length = 1;
uint8_t command = rx_char;
rx_char = -1;
// if special char to test a 20 bytes frame
/*
if (command == '*')
{
pc.printf("20 chars\r\n");
int c = 0;
for (c = 0; c < 20; c++)
{
temp[c] = 'a' + c;
}
length = 20;
}
else
{
temp[0] = command;
}
*/
temp[0] = command;
// to central
if (command == '1')
{
if (central_handle != -1)
{
// device to central
while (1)
{
if (central_handle == -1)
{
pc.printf("\r\ndisconnected 1 (to central)\r\n");
break;
}
if (!ble.gap().getState().connected)
{
pc.printf("\r\ndisconnected 2 (to central)\r\n");
break;
}
int ret = ble.gattServer().write(/*central_handle, */uartServicePtr->getRXCharacteristicHandle(), temp, length);
if (ret == BLE_ERROR_NONE)
{
//gatt_server_is_busy = true;
break;
}
else if (ret == BLE_STACK_BUSY) // write return busy for all errors...
{
pc.printf("\r\nbusy (to central)\r\n");
//break;
}
else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED)
{
pc.printf("\r\nnot permitted (to central)\r\n");
break;
}
else if (ret == BLE_ERROR_INVALID_STATE)
{
pc.printf("\r\ninvalid state (to central)\r\n");
break;
}
else
{
pc.printf("\r\ncode %d (to central)\r\n", ret);
}
//ble.waitForEvent();
}
}
else
{
pc.printf("\r\nnot connected with central\r\n");
}
}
// to device
if (command == '2')
{
if (device_handle != -1)
{
// central to device
while (1)
{
if (device_handle == -1)
{
pc.printf("\r\ndisconnected (to device)\r\n");
break;
}
int ret = uartTXCharacteristic.write(length, temp);
if (ret == BLE_ERROR_NONE)
{
break;
}
else if (ret == BLE_STACK_BUSY)
{
pc.printf("\r\nbusy (to device)\r\n");
break;
}
else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED)
{
pc.printf("\r\nnot permitted (to device)\r\n");
break;
}
else if (ret == BLE_ERROR_INVALID_STATE)
{
pc.printf("\r\ninvalid state (to device)\r\n");
break;
}
else
{
pc.printf("\r\ncode %d (to device)\r\n", ret);
}
//ble.waitForEvent();
}
}
else
{
pc.printf("\r\nnot connected with device\r\n");
}
}
/*
while (gatt_server_is_busy)
{
}
*/
}
ble.waitForEvent(); // save power
}
}
please see this post.
https://devzone.nordicsemi.com/question/49705/s130-potential-unstability-case/
I'm not totally sure that is due to S130. Does anyone have an idea ?
thanks for pointing us to this discussion. I'm afraid your application is a bit too large for me to review it carefully. Raise this again if no resolution comes about in a few days and I'll try to review.
I rewritten a pure nordic sdk test application and it works... So there s130 looks correct and the bug is probably in mbed lib side.
Envoyé depuis Yahoo Mail pour Android
De:"Rohit Grover" [email protected] Date:mar. j sept. PM à 14:12 Objet:Re: [ble-nrf51822] Cross effect when central and device and unexpected disconnections (#46)
thanks for pointing us to this discussion. I'm afraid your application is a bit too large for me to review it carefully. Raise this again if no resolution comes about in a few days and I'll try to review.
— Reply to this email directly or view it on GitHub.
ok. very good. can you please try replacing Nordic SDK APIs with BLE_API in small steps and see where the failure arises?
Hello, i'm late on my project so i will try to do that in... few weeks. I'm moving to Nordic SDK to be on schedule.
That's a pity. The BLE_API is a thin wrapper around the Nordic SDK and should not result in loss of capability. I hope you find time to uncover the particular issue with BLE_API (if any) which prevented you from developing your application--that would be a very helpful contribution to the rest of the community. We look forward to supporting you in your development.
ARM Internal Ref: IOTSFW-1026