Как записать с клиентского узла на серверный узел в пользовательскую службу BLE?

ble custom nrf52

Я пытаюсь записать данные с клиентского узла на центральный узел в пользовательскую службу BLE.

Ниже приведен код для центрального узла (клиент)

#include <bluefruit.h>

#define suuid 0x8912
#define cuuid 0x9012

//# определить suuid 0x1256
//#определить cuuid 0x1260

uint16_t gconn_handle;
long int county;

BLEClientService        displays(suuid);
BLEClientCharacteristic displayc(cuuid);

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

  Serial.println("Bluefruit52 Central Custom display Example");
  Serial.println("--------------------------------------\n");

  // Инициализируем Bluefruit с максимальным количеством соединений, как Peripheral = 0, Central = 1
  // Использование SRAM, необходимое для SoftDevice, резко возрастет с увеличением количества подключений
  Bluefruit.begin(0, 1);

  Bluefruit.setName("Bluefruit52 Central");

  // Инициализировать дисплей-клиент
  displays.begin();

  // Инициализировать клиентские характеристики Display.
  // Примечание: клиентский символ будет добавлен к последней службе, которая была запущена методом begin().
  displayc.begin();

  // Увеличить скорость мигания, чтобы он отличался от режима рекламы PrPh
  Bluefruit.setConnLedInterval(250);

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

  /* Start Central Scanning
     - Enable auto scan if disconnected
     - Interval = 100 ms, window = 80 ms
     - Don't use active scan
     - Filter only accept display service
     - Start(timeout) with timeout = 0 will scan forever (until connected)
  */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80); // в единицах 0,625 мс
  Bluefruit.Scanner.filterUuid(displays.uuid);
  Bluefruit.Scanner.useActiveScan(false);
  Bluefruit.Scanner.start(0);                   // // 0 = Не останавливать сканирование через n секунд

  county = 0;
}
uint8_t toggle = 0;
void loop()
{
  // ничего не делать
  if (Bluefruit.connected())
  {
    uint8_t displaydata[5] = { 0x09, 0x10, 0x11, 0x12 };
    displayc.write(displaydata,5);
    //переключить UUID
    /*if (county > 1)
    {
      Bluefruit.disconnect(gconn_handle);
      if (toggle == 0)
      {
        displays.uuid = 0x1256;
        displayc.uuid = 0x1260;
        toggle = 1;
        Serial.println("CONNECTING 0x1256");
      }
      else
      {
        displays.uuid = 0x8912;
        displayc.uuid = 0x9012;
        toggle = 0;

        Serial.println("CONNECTING 0x8912");
      }
      county = 0;
      setup();
    }
    //округ++;
    delay(1000);
    */
  }
}

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

/**
   Callback invoked when an connection is established
   @param conn_handle
*/
void connect_callback(uint16_t conn_handle)
{
  gconn_handle = conn_handle;
  Serial.println("Connected");

  Serial.print("Discovering Display Service ... ");

  // Если дисплей не найден, отключаемся и возвращаемся
  if ( !displays.discover(conn_handle) )
  {
    Serial.println("Found NONE");

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

    return;
  }

  // Как только сервис отображения найден, мы продолжаем обнаруживать его характеристики
  Serial.println("Found it");

  Serial.print("Discovering IMAGE characteristic ... ");
  if ( !displayc.discover() )
  {
    // Измерение chr обязательно, если не найдено (валидно), то отключаем
    Serial.println("not found !!!");
    Serial.println("Measurement characteristic is mandatory but not found");
    Bluefruit.disconnect(conn_handle);
    return;
  }
  Serial.println("Found it");
}

/**
   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;

  Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}

Ниже код для периферийного устройства (сервер):

#include <bluefruit.h>

#define suuid 0x8912
#define cuuid 0x9012

BLEService        displays = BLEService(suuid);
BLECharacteristic displayc = BLECharacteristic(cuuid);

BLEDis bledis;    // Экземпляр вспомогательного класса DIS (Device Information Service)
BLEBas blebas;    // Экземпляр вспомогательного класса BAS (Battery Service)

uint8_t  bps = 0;

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

  Serial.println("Bluefruit52 Display Example");
  Serial.println("-----------------------\n");

  // Инициализируем модуль Bluefruit
  Serial.println("Initialise the Bluefruit nRF52 module");
  Bluefruit.begin();

  // Установить обработчики обратного вызова подключения/отключения
  Bluefruit.Periph.setConnectCallback(connect_callback);
  Bluefruit.Periph.setDisconnectCallback(disconnect_callback);

  // Настройте и запустите службу информации об устройстве
  Serial.println("Configuring the Device Information Service");
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather52");
  bledis.begin();

  // Запускаем BLE Battery Service и устанавливаем его на 100%
  Serial.println("Configuring the Battery Service");
  blebas.begin();
  blebas.write(100);

  // Настройте службу монитора сердечного ритма, используя
  // Классы BLEService и BLECharacteristic
  Serial.println("Configuring the Heart Rate Monitor Service");
  setupDisplay();

  // Настраиваем рекламный пакет(ы)
  Serial.println("Setting up the advertising payload(s)");
  startAdv();

  Serial.println("Ready Player One!!!");
  Serial.println("\nAdvertising");
}

void startAdv(void)
{
  // Рекламный пакет
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();

  // Включить UUID службы отображения
  Bluefruit.Advertising.addService(displays);

  // Включить имя
  Bluefruit.Advertising.addName();

  /* Start Advertising
     - Enable auto advertising if disconnected
     - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
     - Timeout for fast mode is 30 seconds
     - Start(timeout) with timeout = 0 will advertise forever (until connected)

     For recommended advertising interval
     https://developer.apple.com/library/content/qa/qa1931/_index.html
  */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // в единицах 0,625 мс
  Bluefruit.Advertising.setFastTimeout(30);      // количество секунд в быстром режиме
  Bluefruit.Advertising.start(0);                // 0 = Не останавливать рекламу через n секунд
}

void setupDisplay(void)
{
  displays.begin();
  displayc.setProperties(CHR_PROPS_WRITE);
  displayc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  displayc.setFixedLen(2);
  displayc.setCccdWriteCallback(cccd_callback);  // Опционально захватить обновления CCCD
  displayc.begin();
}

void connect_callback(uint16_t conn_handle)
{
  // Получить ссылку на текущее соединение
  BLEConnection* connection = Bluefruit.Connection(conn_handle);

  char central_name[32] = { 0 };
  connection->getPeerName(central_name, sizeof(central_name));

  Serial.print("Connected to ");
  Serial.println(central_name);
}

/**
   Callback invoked when a connection is dropped
   @param conn_handle connection where this event happens
   @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;

  Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
  Serial.println("Advertising!");
}

void cccd_callback(uint16_t conn_hdl, BLECharacteristic* chr, uint16_t cccd_value)
{
  // Отображаем необработанный пакет запроса
  Serial.print("CCCD Updated: ");
  //Serial.printBuffer(запрос->данные, запрос->длина);
  Serial.print(cccd_value);
  Serial.println("");

  // Проверяем характеристику, с которой связано это обновление CCCD на случай, если
  // этот обработчик используется для нескольких записей CCCD.
  if (chr->uuid == displayc.uuid) {
    if (chr->notifyEnabled(conn_hdl)) {
      Serial.println("Characteristic ID Matched");
    } else {
      Serial.println("Characteristic ID NON-Matched");
    }
  }
}

void loop()
{
  digitalToggle(LED_RED);

  if ( Bluefruit.connected() ) {
      Serial.println(displayc.read8());
  }

  // Отправлять обновление только раз в секунду
  // задержка (1000);
}

Я пытаюсь писать из центрального узла с помощью:

if (Bluefruit.connected())
  {
    uint8_t displaydata[5] = { 0x09, 0x10, 0x11, 0x12 };
    displayc.write(displaydata,5);
  }

И чтение на периферии с помощью :

if ( Bluefruit.connected() ) {
      Serial.println(displayc.read8());
  }

Но на последовательном мониторе отображается 187. Можем ли мы писать с центрального узла (клиента) на периферийный узел (сервер)? Есть ли способ создать функцию обратного вызова RX для узла сервера и узла клиента в пользовательских службах BLE?

Модуль Adafruit Bluefruit nRF52832: здесь Источник Git: здесь Центральный узел HRM Git Источник: здесь Пользовательский узел HRM Источник Git: здесь

, 👍0