ARMmbed / ble-nrf51822

Nordic stack and drivers for the mbed BLE_API
Other
46 stars 51 forks source link

Cross effect when central and device and unexpected disconnections #46

Open fabiencomte opened 8 years ago

fabiencomte commented 8 years ago

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(), (uint8t)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) { devicehandle = 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
}

}

fabiencomte commented 8 years ago

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 ?

rgrover commented 8 years ago

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.

fabiencomte commented 8 years ago

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" notifications@github.com 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.

rgrover commented 8 years ago

ok. very good. can you please try replacing Nordic SDK APIs with BLE_API in small steps and see where the failure arises?

fabiencomte commented 8 years ago

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.

rgrover commented 8 years ago

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.

rainierwolfcastle commented 8 years ago

ARM Internal Ref: IOTSFW-1026