Sending BLE characteristic data from CENTRAL to PERIPHERAL?

Guys:

I have a project that communicates between two Adafruit Feather Express nRF52840 boards via Bluetooth. I'm converting code that I had originally written for two Arduino Nano 33 BLE's (I switched to Adafruit because they have a provision for a 3.7V Lipo battery & charger). Both the Adafruits and the Arduinos run on a Nordic nRF52840.

I figured out how to get the UUID's set up for the service and my seven characteristics and I get the two boards to connect just fine. Six of the characteristics are sensor data posted by the peripheral and read by the central; the last characteristic is a simple on/off bit from the central to the peripheral to tell it to turn on the sensors.

I can send the sensor data to the central and read it, but I'm having a terrible time getting the on/off signal to transmit to the peripheral. With the Arduino, I figured out that it was necessary to read the on/off byte at the peripheral by using:

onoff = RADIO_onoff.value();

Where onoff is the variable that the data is read into and RADIO_onoff represents the characteristic. The key was to use ".value()" instead of "readValue()" on the peripheral end.

With the Adafruit code, the data is written at the central by

RADIO_onoff.write8(switch);

Where "switch" is the variable written into the characteristic. At the peripheral end I have tried

onoff = RADIO_onoff.read8();

But it doesn't work. The Adafruit example program only shows how to transfer data from peripheral to central. Does anyone know the correct syntax to get this value transferred? Thanks for any help you can provide.

Don

No one knows?

eromlignod:
No one knows?

Unfortunately, your post does not include enough information to even give you an educated guess.

Can you provide some more information about your system? e.g. links to the library (for instance on GitHub), a library reference web page, a complete short example ...

OK, I was trying to be concise. The central is an Adafruit Clue nRF52840. Here is the pertinent CENTRAL code I use for the BLE:

#include <bluefruit.h>

float a = 0;                 
float b = 0;
float c = 0;
float d = 0;
float e = 0;
float f = 0;
byte onoff = 0;

BLEClientService UService(0xcba174a9aed54c2f8ea998de50b2bb38);
BLEClientCharacteristic RADIO_a(0x4007f5d26d384249b4b2c48062eaf30a);  
BLEClientCharacteristic RADIO_b(0x6d813cfd2937495dbc1be91aa6742eca);
BLEClientCharacteristic RADIO_c(0xeb00def4f7e94bb4a1d148dd87098f13);
BLEClientCharacteristic RADIO_d(0x143641017d9149edb28d676e39e04cc1);
BLEClientCharacteristic RADIO_e(0xcb27777ba33f42ae841b00fa979077f5);
BLEClientCharacteristic RADIO_f(0xf4b9032407324873a04ebc8b970b567b);
BLEClientCharacteristic RADIO_onoff(0xbe14c89cc6154fc18f892188db954709);

void setup(){
  Bluefruit.begin(0, 1);                                        
  Bluefruit.setName("A central");
  UService.begin();                                            
  RADIO_a.begin();                                         
  RADIO_b.begin();
  RADIO_c.begin();
  RADIO_d.begin();
  RADIO_e.begin();
  RADIO_f.begin();
  RADIO_onoff.begin();

  Bluefruit.setConnLedInterval(250);                            
  Bluefruit.Central.setDisconnectCallback(disconnect_callback);
  Bluefruit.Central.setConnectCallback(connect_callback);
  Bluefruit.Scanner.setRxCallback(scan_callback);                
  Bluefruit.Scanner.restartOnDisconnect(true);                  
  Bluefruit.Scanner.setInterval(160, 80);                        
  Bluefruit.Scanner.filterUuid(UService.uuid);                
  Bluefruit.Scanner.useActiveScan(false);                      
  Bluefruit.Scanner.start(0);  
  
}

void loop() {
  if(Bluefruit.connected()){
    onoff = 1;
    RADIO_onoff.write8(onoff);                                                        
    if(onoff){                                                                            
      a = (float)RADIO_a.read32() / 1000;            
      b = (float)RADIO_b.read32() / 1000;
      c = (float)RADIO_c.read32() / 1000;
      d = (float)RADIO_d.read32() / 1000;
      e = (float)RADIO_e.read32() / 1000;
      f = (float)RADIO_f.read32() / 1000;
    }
  }
}

void disconnect_callback(uint16_t conn_handle, uint8_t reason){
  (void) conn_handle;
  (void) reason;  
}

void connect_callback(uint16_t conn_handle){
}

void scan_callback(ble_gap_evt_adv_report_t* report){
  Bluefruit.Central.connect(report);
}

This reads six numbers, via BLE, from the peripheral. It also attempts to send a "1" to the peripheral to turn on an LED.

The peripheral is an Adafruit Feather Express nRF52840. The PERIPHERAL code looks like this:

#include <bluefruit.h>

BLEService UService = BLEService(0xcba174a9aed54c2f8ea998de50b2bb38);
BLECharacteristic RADIO_a = BLECharacteristic(0x4007f5d26d384249b4b2c48062eaf30a); 
BLECharacteristic RADIO_b = BLECharacteristic(0x6d813cfd2937495dbc1be91aa6742eca);
BLECharacteristic RADIO_c = BLECharacteristic(0xeb00def4f7e94bb4a1d148dd87098f13);
BLECharacteristic RADIO_d = BLECharacteristic(0x143641017d9149edb28d676e39e04cc1);
BLECharacteristic RADIO_e = BLECharacteristic(0xcb27777ba33f42ae841b00fa979077f5);
BLECharacteristic RADIO_f = BLECharacteristic(0xf4b9032407324873a04ebc8b970b567b);
BLECharacteristic RADIO_onoff = BLECharacteristic(0xbe14c89cc6154fc18f892188db954709);
BLEDis bledis;    
BLEBas blebas;    

volatile float sensor[6] = {1,2,3,4,5,6};
byte onoff = 0;
uint8_t  bps = 0;

void setup(){
  pinMode(LED_RED, OUTPUT);

  Bluefruit.begin();                                             
  Bluefruit.setName("A peripheral");                             
  Bluefruit.Periph.setConnectCallback(connect_callback);           
  Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
  bledis.setManufacturer("DGD");                             
  bledis.setModel("Bluefruit Feather Express nRF52840");
  bledis.begin();
  blebas.begin();                                                 
  blebas.write(100);
  
  setupParameters();
  startAdvertising();
}

void loop(){
  if (Bluefruit.connected()){                                     
          onoff = RADIO_onoff.read8();                           
          if(onoff){
            if(!digitalRead(LED_RED))                               
              digitalWrite(LED_RED, HIGH);           
          }
          else               
            digitalWrite(LED_RED, LOW);                                       
          RADIO_a.write32((uint32_t)(1000 * sensor[0]));     
          RADIO_b.write32((uint32_t)(1000 * sensor[1]));                     
          RADIO_c.write32((uint32_t)(1000 * sensor[2]));                     
          RADIO_d.write32((uint32_t)(1000 * sensor[3]));                     
          RADIO_e.write32((uint32_t)(1000 * sensor[4]));                     
          RADIO_f.write32((uint32_t)(1000 * sensor[5]));
  }
}

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));
}

void disconnect_callback(uint16_t conn_handle, uint8_t reason){
  (void) conn_handle;
  (void) reason;
}

void startAdvertising(void){  
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);    // Advertising packet
  Bluefruit.Advertising.addTxPower();  
  Bluefruit.Advertising.addService(UService);                    
  Bluefruit.Advertising.addName();                                
  Bluefruit.Advertising.restartOnDisconnect(true);                
  Bluefruit.Advertising.setInterval(32, 244);                     
  Bluefruit.Advertising.setFastTimeout(30);                       
  Bluefruit.Advertising.start(0);                                 
}

void setupParameters(void){
  UService.begin();

  RADIO_a.setProperties(CHR_PROPS_READ);
  RADIO_a.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  RADIO_a.setFixedLen(4);
  RADIO_a.begin();

  RADIO_b.setProperties(CHR_PROPS_READ);
  RADIO_b.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  RADIO_b.setFixedLen(4);
  RADIO_b.begin();

  RADIO_c.setProperties(CHR_PROPS_READ);
  RADIO_c.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  RADIO_c.setFixedLen(4);
  RADIO_c.begin();

  RADIO_d.setProperties(CHR_PROPS_READ);
  RADIO_d.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  RADIO_d.setFixedLen(4);
  RADIO_d.begin();

  RADIO_e.setProperties(CHR_PROPS_READ);
  RADIO_e.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  RADIO_e.setFixedLen(4);
  RADIO_e.begin();

  RADIO_f.setProperties(CHR_PROPS_READ);
  RADIO_f.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  RADIO_f.setFixedLen(4);
  RADIO_f.begin();

  RADIO_onoff.setProperties(CHR_PROPS_WRITE);
  RADIO_onoff.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  RADIO_onoff.setFixedLen(1);
  RADIO_onoff.begin();
  RADIO_onoff.write8(1);                                            
}

This takes six values in the array sensor[6] and sends them to the central, via BLE. I also attempts to read the value of "onoff" and control an LED with it.

The BLE connects and I get all the sensor data just fine. But I can't get the onoff data to send back the other way. I also have checked the value of onoff, which never becomes "1", so I know it doesn't have anything to do with the LED. I have a feeling it's the nomenclature I'm using, but I can't seem to find any information or examples to set me straight.

Does this help?

Don

eromlignod:
Does this help?

I will let you be the judge of that. :slight_smile:

I found the following example:

Bluefruit52Lib nrf_blinky.ino

In line 100 to 120 two characteristics are declared one with read and one with read/write access.

Looking into the following file

Bluefruit52Lib src BLECharacteristic.h

Line 98 confirms the second parameter is the write permission.

void setPermission(BleSecurityMode read_perm, BleSecurityMode write_perm);

You set this to SECMODE_NO_ACCESS. You need to change that to SECMODE_OPEN.

RADIO_onoff.setProperties(CHR_PROPS_WRITE);
RADIO_onoff.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);

I suspect, you should also set the first line to setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE);. Otherwise when you set the property you cannot confirm from your central. A write only property is usually not used. Maybe you have a special case.

RADIO_onoff.setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE);
RADIO_onoff.setPermission(SECMODE_OPEN, SECMODE_OPEN);

I have not looked at all the code. Let us see how far this gets you. :slight_smile:

Just a note. It might be useful to use different names for your variables e.g. temperatureCharacteristic. Would make your code easier to read.

Klaus:

THAT DID IT! Those two little changes were all it took. Thank you so much (again)! I was going insane trying to find an example.

I had discovered the read|write mistake this evening, but I never thought about the SECMODE_OPEN change. I do have more descriptive variable names; I simplified them because the project is proprietary.

I really appreciate your extra work to help me with this.

Don