Hello,
I've been investigating an issue with a PAN1326C (contains CC2564C, Firmware v1.1) which spuriously stopped advertising in an automated test setup after a lot of BLE connect/disconnect cycles.
The BT module is still communicating via HCI and it behaves like normal but the advertisements cannot be received anymore.
I was able to track this down to a setup where this state can be reproduced within a few seconds just by
- (A) Initializing the device
- (B) setting up advertisement data and then
- (C) enabling advertisements in a loop (see attached file bttest.c)
- (D) concurrently connect and disconnect from a remote machine:
while true; do sudo hcitool lecc B0:91:22:BC:C2:17; sudo hcitool ledc 3585; done
The remote connect loop (D) starts at
22077 6 11:51:06.708
#include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/prctl.h> #include <unistd.h> #include <time.h> #include <stdbool.h> #include <bluetooth/bluetooth.h> #include <bluetooth/hci.h> #include <bluetooth/hci_lib.h> //#include "utility.h" static volatile int lastSignal = 0; static void signalHandler(int signal) { lastSignal = signal; } int hci_le_set_advertising_data(int dd, uint8_t* data, uint8_t length, int to) { struct hci_request rq; le_set_advertising_data_cp data_cp; uint8_t status; memset(&data_cp, 0, sizeof(data_cp)); data_cp.length = length <= sizeof(data_cp.data) ? length : sizeof(data_cp.data); memcpy(&data_cp.data, data, data_cp.length); memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LE_CTL; rq.ocf = OCF_LE_SET_ADVERTISING_DATA; rq.cparam = &data_cp; rq.clen = LE_SET_ADVERTISING_DATA_CP_SIZE; rq.rparam = &status; rq.rlen = 1; if (hci_send_req(dd, &rq, to) < 0) return -1; if (status) { errno = EIO; return -1; } return 0; } int hci_le_set_scan_response_data(int dd, uint8_t* data, uint8_t length, int to) { struct hci_request rq; le_set_scan_response_data_cp data_cp; uint8_t status; memset(&data_cp, 0, sizeof(data_cp)); data_cp.length = length <= sizeof(data_cp.data) ? length : sizeof(data_cp.data); memcpy(&data_cp.data, data, data_cp.length); memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LE_CTL; rq.ocf = OCF_LE_SET_SCAN_RESPONSE_DATA; rq.cparam = &data_cp; rq.clen = LE_SET_SCAN_RESPONSE_DATA_CP_SIZE; rq.rparam = &status; rq.rlen = 1; if (hci_send_req(dd, &rq, to) < 0) return -1; if (status) { errno = EIO; return -1; } return 0; } // Set advertising interval to 100 ms // Note: 0x00A0 * 0.625ms = 100ms int hci_le_set_advertising_parameters(int dd, int to, int interval) { struct hci_request rq; le_set_advertising_parameters_cp adv_params_cp; uint8_t status; memset(&adv_params_cp, 0, sizeof(adv_params_cp)); adv_params_cp.min_interval = htobs(interval); adv_params_cp.max_interval = htobs(interval); adv_params_cp.chan_map = 7; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_LE_CTL; rq.ocf = OCF_LE_SET_ADVERTISING_PARAMETERS; rq.cparam = &adv_params_cp; rq.clen = LE_SET_ADVERTISING_PARAMETERS_CP_SIZE; rq.rparam = &status; rq.rlen = 1; if (hci_send_req(dd, &rq, to) < 0) return -1; if (status) { errno = EIO; return -1; } return 0; } int main(int argc, const char* argv[]) { char *hciDeviceIdOverride = NULL; int hciDeviceId = 0; int hciSocket; struct hci_dev_info hciDevInfo; char address[18]; int previousAdapterState = -1; int currentAdapterState; const char* adapterState = NULL; fd_set rfds; struct timeval tv; int selectRetval; char stdinBuf[256 * 2 + 1]; char advertisementDataBuf[256]; int advertisementDataLen = 0; char scanDataBuf[256]; int scanDataLen = 0; int len; int i; memset(&hciDevInfo, 0x00, sizeof(hciDevInfo)); hciDeviceIdOverride = getenv("BLENO_HCI_DEVICE_ID"); if (hciDeviceIdOverride != NULL) { hciDeviceId = atoi(hciDeviceIdOverride); } else { // if no env variable given, use the first available device hciDeviceId = hci_get_route(NULL); } if (hciDeviceId < 0) { hciDeviceId = 0; // use device 0, if device id is invalid } // setup HCI socket hciSocket = hci_open_dev(hciDeviceId); hciDevInfo.dev_id = hciDeviceId; if (hciSocket == -1) { printf("adapterState unsupported\n"); return -1; } // setup signal handlers signal(SIGINT, signalHandler); // set scan data hci_le_set_scan_response_data(hciSocket, (uint8_t*)&scanDataBuf, scanDataLen, 1000); // set advertisement data hci_le_set_advertising_data(hciSocket, (uint8_t*)&advertisementDataBuf, advertisementDataLen, 1000); // set advertisement parameters, mostly to set the advertising interval to 100ms hci_le_set_advertising_parameters(hciSocket, 1000, 0xA0); while(lastSignal == 0) { // start advertising hci_le_set_advertise_enable(hciSocket, 1, 1000); usleep (100000); } // stop advertising hci_le_set_advertise_enable(hciSocket, 0, 1000); close(hciSocket); return 0; }