nRF52832 BLE «conn_handle» для отключения текущих подключенных устройств

Я работаю над модулем Adafruit nRF52832 Bluefruit . Я хочу, чтобы соединение BLE отключалось с помощью функции и могло вызываться при необходимости. Но проблема в том, что для функции отключения требуется "conn_handle" для отключения от текущего подключенного Клиента.

Может ли кто-нибудь помочь мне найти, где я могу получить "conn_handle" подключенного клиента?

/**
 * Обратный вызов вызывается при разрыве соединения
 * @param conn_handle
 * @param reason is a BLE_HCI_STATUS_CODE который можно найти в ble_hci.h.
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;

  connection_num--;

  // Пометить идентификатор как недействительный
  int id  = findConnHandle(conn_handle);

  // Несуществующее соединение, что-то пошло не так, DBG !!!
  if ( id < 0 ) return;

  // Пометить дескриптор подключения как недействительный
  prphs[id].conn_handle = BLE_CONN_HANDLE_INVALID;

  Serial.print(prphs[id].name);
  Serial.println(" disconnected!");
}

Приведенный ниже полный код предназначен для "Central Bleuart Multi"-

/*************************************************** ****************************

Это пример для наших модулей Bluefruit LE на базе nRF52.

Возьмите один сегодня в магазине Adafruit!

Adafruit вкладывает время и ресурсы, предоставляя этот открытый исходный код,
пожалуйста, поддержите Adafruit и оборудование с открытым исходным кодом, купив
продукты от Adafruit!

Лицензия MIT, см. ЛИЦЕНЗИЯ для получения дополнительной информации
Весь текст выше и экран-заставка ниже должны быть включены в
любое перераспределение
************************************* ************* *******************/

/* Этот скетч демонстрирует центральный API(), который позволяет вам подключаться
* к нескольким периферийным платам (Bluefruit nRF52 в периферийном режиме или
* любые платы Bluefruit nRF51).
*
* Одна или несколько плат Bluefruit, сконфигурированных как периферийные устройства с
* Для этой демонстрации требуется запущенный сервис bleuart.
*
* Этот скетч будет:
* - Чтение данных из последовательного порта HW (обычно последовательный порт USB, доступный
* например, через Serial Monitor) и отправлять любые входящие данные на
* все остальные периферийные устройства, подключенные к центральному устройству.
* - Пересылать любые входящие сообщения bleuart с периферийного устройства на все
* другие подключенные устройства.
*
* Рекомендуется давать каждой периферийной плате отдельное имя, чтобы
* чтобы легче различать отдельные устройства.
*
* Объяснение дескриптора подключения
* -----------------------------
* Общее количество подключений BLE_MAX_CONNECTION (20)
*
* «Дескриптор соединения» — это целое число, присвоенное SoftDevice.
* (собственный стек BLE Nordic). Каждое соединение получит свое
* числовой дескриптор, начинающийся от 0 до BLE_MAX_CONNECTION-1, в зависимости от порядка
* соединения(й).
*
* - Например, если наша центральная плата сначала подключается к мобильному телефону (работает как периферийное устройство),
* затем подключается к другой плате Bluefruit, работающей в периферийном режиме, затем
* дескриптор подключения мобильного телефона равен 0, а дескриптор Bluefruit
* плата равна 1 и так далее.
*/

/* ШАБЛОНЫ СВЕТОДИОДОВ
* ------------
* LED_RED — изменение шаблона мигания в зависимости от количества подключений.
* LED_BLUE - постоянно мигает при сканировании
*/

#include <bluefruit.h>

// Структура, содержащая информацию о периферии
typedef struct
{
  char name[16+1];

  uint16_t conn_handle;

  // Каждому prph нужна собственная клиентская служба bleuart
  BLEClientUart bleuart;
} prph_info_t;

/* Peripheral info array (one per peripheral device)
 * 
 * There are 'BLE_MAX_CONNECTION' central connections, but the
 * the connection handle can be numerically larger (for example if
 * the peripheral role is also used, such as connecting to a mobile
 * device). As such, we need to convert connection handles <-> the array
 * index where appropriate to prevent out of array accesses.
 * 
 * Note: One can simply declares the array with BLE_MAX_CONNECTION and use connection
 * handle as index directly with the expense of SRAM.
 */
prph_info_t prphs[BLE_MAX_CONNECTION];

// Программный таймер для мигания КРАСНОГО светодиода
SoftwareTimer blinkTimer;
uint8_t connection_num = 0; // для моргания

void setup() 
{
  Serial.begin(115200);
  while ( !Serial ) delay(10);   // для nrf52840 с родным usb

  // Инициализируем blinkTimer на 100 мс и запускаем его
  blinkTimer.begin(100, blink_timer_callback);
  blinkTimer.start();

  Serial.println("Bluefruit52 Central Multi BLEUART Example");
  Serial.println("-----------------------------------------\n");
  
  // Инициализируем Bluefruit с максимальным числом одновременных подключений: Peripheral = 0, Central = 4
  // Использование SRAM, требуемое SoftDevice, будет увеличиваться с увеличением количества подключений
  Bluefruit.begin(0, 4);

  // Имя набора
  Bluefruit.setName("Bluefruit52 Central");
  
  // Запускаем периферийный пул
  for (uint8_t idx=0; idx<BLE_MAX_CONNECTION; idx++)
  {
    // Недействительный дескриптор соединения
    prphs[idx].conn_handle = BLE_CONN_HANDLE_INVALID;
    
    // Все услуги BLE Central Uart
    prphs[idx].bleuart.begin();
    prphs[idx].bleuart.setRxCallback(bleuart_rx_callback);
  }

  // Обратные вызовы для Central
  Bluefruit.Central.setConnectCallback(connect_callback);
  Bluefruit.Central.setDisconnectCallback(disconnect_callback);

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Filter only accept bleuart service in advertising
   * - Don't use active scan (used to retrieve the optional scan response adv packet)
   * - Start(0) = will scan forever since no timeout is given
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80);       // в единицах 0,625 мс
  Bluefruit.Scanner.filterUuid(BLEUART_UUID_SERVICE);
  Bluefruit.Scanner.useActiveScan(false);       // Не запрашивать данные ответа сканирования
  Bluefruit.Scanner.start(0);                   // 0 = Не останавливать сканирование через n секунд
}

/**
 * Callback invoked when scanner picks up an advertising packet
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  // Поскольку мы настраиваем сканер с помощью filterUuid()
  // Обратный вызов сканирования вызывается только для устройства с объявленным сервисом bleuart
  // Подключаемся к устройству с сервисом bleuart в рекламном пакете
  Bluefruit.Central.connect(report);
}

/**
 * Callback invoked when an connection is established
 * @param conn_handle
 */
void connect_callback(uint16_t conn_handle)
{
  // Находим доступный идентификатор для использования
  int id  = findConnHandle(BLE_CONN_HANDLE_INVALID);

  // Eeek: Превышено количество подключений!!!
  if ( id < 0 ) return;
  
  prph_info_t* peer = &prphs[id];
  peer->conn_handle = conn_handle;
  
  Bluefruit.Connection(conn_handle)->getPeerName(peer->name, sizeof(peer->name)-1);

  Serial.print("Connected to ");
  Serial.println(peer->name);

  Serial.print("Discovering BLE UART service ... ");

  if ( peer->bleuart.discover(conn_handle) )
  {
    Serial.println("Found it");
    Serial.println("Enabling TXD characteristic's CCCD notify bit");
    peer->bleuart.enableTXD();

    Serial.println("Continue scanning for more peripherals");
    Bluefruit.Scanner.start(0);

    Serial.println("Enter some text in the Serial Monitor to send it to all connected peripherals:");
  } else
  {
    Serial.println("Found ... NOTHING!");

    // отключаемся, так как не можем найти сервис bleuart
    Bluefruit.disconnect(conn_handle);
  }  

  connection_num++;
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;

  connection_num--;

  // Пометить идентификатор как недействительный
  int id  = findConnHandle(conn_handle);

  // Несуществующее соединение, что-то пошло не так, DBG !!!
  if ( id < 0 ) return;

  // Пометить дескриптор подключения как недействительный
  prphs[id].conn_handle = BLE_CONN_HANDLE_INVALID;

  Serial.print(prphs[id].name);
  Serial.println(" disconnected!");
}

/**
 * Callback invoked when BLE UART data is received
 * @param uart_svc Reference object to the service where the data 
 * arrived.
 */
void bleuart_rx_callback(BLEClientUart& uart_svc)
{
  // uart_svc — это prphs[conn_handle].bleuart
  uint16_t conn_handle = uart_svc.connHandle();

  int id = findConnHandle(conn_handle);
  prph_info_t* peer = &prphs[id];
  
  // Печать имени отправителя
  Serial.printf("[From %s]: ", peer->name);

  // Чтение и передача на все периферийные устройства
  while ( uart_svc.available() )
  {
    // MTU по умолчанию с дополнительным байтом для конца строки
    char buf[20+1] = { 0 };
    
    if ( uart_svc.read(buf,sizeof(buf)-1) )
    {
      Serial.println(buf);
      sendAll(buf);
    }
  }
}

/**
 * Helper function to send a string to all connected peripherals
 */
void sendAll(const char* str)
{
  Serial.print("[Send to All]: ");
  Serial.println(str);
  
  for(uint8_t id=0; id < BLE_MAX_CONNECTION; id++)
  {
    prph_info_t* peer = &prphs[id];

    if ( peer->bleuart.discovered() )
    {
      peer->bleuart.print(str);
    }
  }
}

void loop()
{
  // Сначала проверяем, подключены ли мы к какой-либо периферии
  if ( Bluefruit.Central.connected() )
  {
    // MTU по умолчанию с дополнительным байтом для конца строки
    char buf[20+1] = { 0 };
    
    // Чтение из HW Serial (обычно USB Serial) и отправка на все периферийные устройства
    if ( Serial.readBytes(buf, sizeof(buf)-1) )
    {
      sendAll(buf);
    }
  }
}

/**
 * Find the connection handle in the peripheral array
 * @param conn_handle Connection handle
 * @return array index if found, otherwise -1
 */
int findConnHandle(uint16_t conn_handle)
{
  for(int id=0; id<BLE_MAX_CONNECTION; id++)
  {
    if (conn_handle == prphs[id].conn_handle)
    {
      return id;
    }
  }

  return -1;  
}

/**
 * Software Timer callback is invoked via a built-in FreeRTOS thread with
 * minimal stack size. Therefore it should be as simple as possible. If
 * a periodically heavy task is needed, please use Scheduler.startLoop() to
 * create a dedicated task for it.
 * 
 * More information http://www.freertos.org/RTOS-software-timer.html
 */
void blink_timer_callback(TimerHandle_t xTimerID)
{
  (void) xTimerID;

  // Период последовательности 10 раз (1 секунда).
  // КРАСНЫЙ светодиод будет переключаться первые 2*n раз (вкл./выкл.) и останется выключенным до конца периода
  // Где n = номер соединения
  static uint8_t count = 0;

  if ( count < 2*connection_num ) digitalToggle(LED_RED);
  if ( count % 2 && digitalRead(LED_RED)) digitalWrite(LED_RED, LOW); // выпуск №98

  count++;
  if (count >= 10) count = 0;
}

Исходный код GitHub

Я хочу вызвать эту функцию отключения, но не знаю, где взять conn_handle. Если у кого-то есть какие-либо идеи, пожалуйста, помогите мне.

Я уже пробовал заходить в библиотеки; лучшее, что он показывает, это просто определение функции обратного вызова:

1: Bluefruit.Central.setDisconnectCallback(disconnect_callback);

2: void BLECentral::setDisconnectCallback( ble_disconnect_callback_t fp )
   {
     _disconnect_cb = fp;
   }

3: class BLECentral
   {
     ...
     private:
       ble_disconnect_callback_t _disconnect_cb;
   }

4: typedef void (*ble_disconnect_callback_t ) (uint16_t conn_hdl, uint8_t reason);

Это все, что я получил об этой функции отключения в разных библиотеках в соответствии с определением, но ничего не связанного с conn_handle.

, 👍1


1 ответ


Лучший ответ:

0

Не знаю, правильно это или нет, но это работает.

Когда установлено новое соединение, "connect" отзывается с помощью "conn_handle" как его аргумент. Если кто-то знает, расскажите, пожалуйста, как эта функция отзывает себя.

Но я создал глобальную переменную uint16_t conn_handle

uint16_t g_conn_handle;    
void connect_callback(uint16_t conn_handle)
    {
      g_conn_handle=conn_handle;
      // Находим доступный идентификатор для использования
      int id  = findConnHandle(BLE_CONN_HANDLE_INVALID);
    
      // Иек: Exc
      ...

Теперь я могу вызвать функцию Disconnect с этой глобальной переменной g_conn_handle.

,