h2zero / NimBLE-Arduino

A fork of the NimBLE library structured for compilation with Arduino, for use with ESP32, nRF5x.
https://h2zero.github.io/NimBLE-Arduino/
Apache License 2.0
667 stars 138 forks source link

NimBLEClient issue on TRANSPARENT UART: receiving only one callback from ble server after writing #637

Closed giorgioinfo13 closed 5 months ago

giorgioinfo13 commented 5 months ago

Hi everyone, I have a problem using the Bluetooth library NimBLEDevice.h for Espressif ESP32-WROVER-E I describe the problem: I have to initialize a NimBLEClient (master) on ESP32, this must connect to one of my server devices (slave).

I use a communication protocol called Transparent UART, I attach a link to help you understand what it is

https://microchipdeveloper.com/xwiki/bin/view/applications/ble/android-development-for-bm70rn4870/transparent-uart-service-for-bm70rn4870/

Long story short, when I write a value on the server's RX characteristic (which has WRITE properties), I receive a response callback (as I rightly expect because I have previously registered the TX callback which has NOTIFY properties). If I then sequentially write a second value on the RX characteristic, I do not receive a second callback from the server.

Why?

I wrote the bluetooth firmware of the server device and I am sure that it is sending the second callback correctly. When I connect to this server via a smartphone app everything works correctly, whereas if I use the NimBLEClient library from ESP32 I do not receive this callback. I attach a test code that shows the problem (maybe it helps to make you understand better) and also the output I receive. I expect that after sending the second command "Data sent." will be printed on the screen. exactly as happens with the first, but this doesn't happen. Is it possible that after calling the ->writeValue() function a second time, the memory is full?

Thank you in advance!


Output:

Starting BLE Client... Connected! writing first command on RX Server

Writing command: [8 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0] Data sent. Callback from TX server: [5 5 0 4C 2B E6 45 56 F7 FD 11 89 95 6C 3F 3D 53 AA] writing second command on RX Server

Writing command: [8 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0]

Code:

#include <Arduino.h>
#include <NimBLEDevice.h>

static BLEUUID serviceUUID_UART("49535343-FE7D-4AE5-8FA9-9FAFD205E455");
static BLEUUID characteristicUUIDTX_UART("49535343-1E4D-4BD9-BA61-23C647249616");  // INDICATE/NOTIFY/WRITE/WRITE NO RESPONSE
static BLEUUID characteristicUUIDRX_UART("49535343-8841-43F4-A8D4-ECBE34729BB3");  // WRITE/WRITE NO RESPONSE

static NimBLEAddress serverAddress("60:8A:10:2F:XX:XX");

NimBLEClient *pClient = nullptr;

NimBLERemoteCharacteristic *pTXCharacteristic = nullptr;
NimBLERemoteCharacteristic *pRXCharacteristic = nullptr;

void disconnectFromServer()
{
  if (pClient != nullptr && pClient->isConnected())
  {
    pClient->disconnect();
  }
}

void writeToUARTRXCharacteristic(const uint8_t *data, size_t length) //writing on RX Server
{
  if (pClient->isConnected() && pRXCharacteristic != nullptr && pRXCharacteristic->canWrite())
  {
    Serial.print("\nWriting command: [");
    for (int i = 0; i < length; i++)
    {
      if (i > 0)
      {
        Serial.print(" ");
      }
      Serial.print(data[i], HEX);
    }
    Serial.println("]");
    delay(100);
    pRXCharacteristic->writeValue(data, 18, true); // the program stops HERE after sending the second command
    Serial.println("Data sent.");
  }
  else
  {
    Serial.println("RXCharacteristic error.");
  }
}

void sendSecondCommand()
{
  Serial.println("writing second command on RX Server");
  byte secondCommand[18] = {0x08, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00};
  writeToUARTRXCharacteristic(secondCommand, 18);
}

void sendFirstCommand()
{
  Serial.println("writing first command on RX Server");
  byte firstCommand[18] = {0x08, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00};
  writeToUARTRXCharacteristic(firstCommand, 18);
}

void notifyCallbackClientTX(NimBLERemoteCharacteristic *pCharacteristic, uint8_t *pData, size_t length, bool isNotify)
{
  Serial.print("Callback from server: [");
  for (int i = 0; i < length; i++)
  {
    if (i > 0)
    {
      Serial.print(" ");
    }
    Serial.print(pData[i], HEX);
  }
  Serial.println("]");
  delay(100);
  sendSecondCommand();
}

void connectToServer(NimBLEClient *pClient, NimBLEAddress serverAddress)
{
  Serial.println("Starting BLE Client...");

  if (pClient->connect(serverAddress))
  {
    Serial.println("Connected!");
    NimBLERemoteService *pRemoteService = pClient->getService(serviceUUID_UART);
    if (pRemoteService == nullptr)
    {
      Serial.println("Service not found.");
      pClient->disconnect();
      return;
    }

    pTXCharacteristic = pRemoteService->getCharacteristic(characteristicUUIDTX_UART);
    if (pTXCharacteristic != nullptr && pTXCharacteristic->canNotify())
    {
      pTXCharacteristic->subscribe(true, notifyCallbackClientTX); //subscribing for server callbacks

    }
    else
    {
      Serial.println("TX not found.");
    }

    pRXCharacteristic = pRemoteService->getCharacteristic(characteristicUUIDRX_UART);
    if (pRXCharacteristic != nullptr && pRXCharacteristic->canWrite())
    {
      sendFirstCommand(); //writing on RX Server
    }
    else
    {
      Serial.println("RX not found.");
    }

  }
  else
  {
    Serial.println("Connection failed!");
    pClient->disconnect();
  }
}

void setup()
{
  Serial.begin(115200);

  NimBLEDevice::init("");
  NimBLEDevice::setPower(ESP_PWR_LVL_P9);
  Serial.println(serverAddress.toString().c_str());
  pClient = NimBLEDevice::createClient();
  connectToServer(pClient, serverAddress);
}

void loop()
{
  //not used
}
giorgioinfo13 commented 5 months ago

Solution found! The "problem" was here

pRXCharacteristic->writeValue(data, 18, true);

I changed with

pRXCharacteristic->writeValue(data, 18, false);

And all is working

h2zero commented 4 months ago

Glad you found it, yes you need to check if the write mode you are using is supported.