BLE Nano 2 with HM-10

Hi guys,

I am trying to connect my BLE Nano 2 with HM-10(as a Peripheral device) using Arduino Central_test program.But the problem is it is not pairing with it,but detecting HM-10.How to proceed after this??

  • You need to provide some more details to get some help. an you link to the application you are testing this with? Are you getting any error codes on any of the devices? Are you able to connect? Is it working with other devices (phone, etc.)?

  • We want BLE nano 2 as a central device and HM10 as peripheral device.... want them to communicate using uart profile.... we are working in Arduino IDE and using Central test example.... till now we are able to connect to HM10 as peripheral and NANO 2 as central..... and NANO 2 was able to detect all services and characterstics.... So when we tried to send some "char" to NANO from hm10 using serial moniter..... we are receving that "char" in notify callback event..... but we are not able to find how to send data from NANO 2 to HM10.... Can you please Help on that.

  • Please post a direct link to the code of the example, or upload the code here. Are you trying to send the data over serial or BLE?

  • /* Copyright (c) 2016 RedBear

       Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
       to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
       and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
    
       The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
    
       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
       IN THE SOFTWARE.
    */
    /**
       @brief This example is used to demonstrate central functions.
              Device with this application will try to connect to example "BLE_HRM" or "BLE_simplePeripheral"
              If connecting to "BLE_HRM", will get heart rate
              If connecting to "BLE_simplePeripheral, will discovery all services and characteristics
    */
    #include <nRF5x_BLE_API.h>
    
    BLE           ble;
    String str0 = "";
    String needle1 = "";
    String str1 = "";
    int y = 0;
    int q = 0;
    ////for dangoo bulb
    //static const uint8_t service1_uuid[]       = {0x4A, 0x42, 0x54, 0x53, 0x47, 0x20, 0x4D, 0x65, 0x73, 0x68, 0x20, 0x4C, 0x45, 0x44, 0x19, 0x10};
    //static const uint8_t service1_chars2[]    = {0x4A, 0x42, 0x54, 0x53, 0x47, 0x20, 0x4D, 0x65, 0x73, 0x68, 0x20, 0x4C, 0x45, 0x44, 0x19, 0x11};
    //static const uint8_t service1_chars3[]    = {0x4A, 0x42, 0x54, 0x53, 0x47, 0x20, 0x4D, 0x65, 0x73, 0x68, 0x20, 0x4C, 0x45, 0x44, 0x19, 0x13};
    
    #define TXRX_BUF_LEN                      20
    
    Timeout                                   timeout;
    char s[100] = "";
    
    static uint8_t rx_buf[TXRX_BUF_LEN];
    static uint8_t rx_buf_num;
    static uint8_t rx_state = 0;
    uint8_t tx_value[TXRX_BUF_LEN] = {0,};
    uint8_t rx_value[TXRX_BUF_LEN] = {0,};
    
    
    // for hm10 module
    static const uint8_t service1_uuid[]       = {0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
    static const uint8_t service1_chars2[]    = {0x00, 0x00, 0xFF, 0xE1, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
    static const uint8_t service1_chars3[]    = {0x00, 0x00, 0xFF, 0xE1, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
    static const uint8_t service1_tx_uuid[]    = {0x00, 0x00, 0xFF, 0xE1, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
    static const uint8_t service1_rx_uuid[]    = {0x00, 0x00, 0xFF, 0xE1, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
    
    
    //// FOR DANGOO BULB
    //UUID service_uuid(0x5453);
    //UUID chars_uuid1(0x5453);
    // FOR HM10 MODULE
    UUID service_uuid(0xFFE0);
    UUID chars_uuid1(0xFFE1);
    
    UUID chars_uuid2(service1_chars2);
    UUID chars_uuid3(service1_chars3);
    
    static uint8_t device_is_hrm = 0;
    static uint8_t device_is_simple_peripheral = 0;
    static uint8_t characteristic_is_fond = 0;
    static uint8_t descriptor_is_found = 0;
    GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );
    GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
    GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};
    GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));
    
    static DiscoveredCharacteristic            chars_hrm;
    static DiscoveredCharacteristicDescriptor  desc_of_chars_hrm(NULL, GattAttribute::INVALID_HANDLE, GattAttribute::INVALID_HANDLE, UUID::ShortUUIDBytes_t(0));
    uint8_t valueArray[6] = {0xAE, 0xEE, 0x11, 0x11, 0x1F, 0x56};
    
    static void scanCallBack(const Gap::AdvertisementCallbackParams_t *params);
    static void discoveredServiceCallBack(const DiscoveredService *service);
    static void discoveredCharacteristicCallBack(const DiscoveredCharacteristic *chars);
    static void discoveryTerminationCallBack(Gap::Handle_t connectionHandle);
    static void discoveredCharsDescriptorCallBack(const CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t *params);
    static void discoveredDescTerminationCallBack(const CharacteristicDescriptorDiscovery::TerminationCallbackParams_t *params) ;
    /**
       @brief  Function to decode advertisement or scan response data
    
       @param[in]  type            The data type that you want to get
       @param[in]  advdata_len     The length of advertisement or scan reponse data
       @param[in]  *p_advdata      The pointer of advertisement or scan reponse data
       @param[out] *len            If type exist, this is the length of field data
       @param[out] *p_field_data   If type exist, this is the pointer of field data
    
       @return NRF_SUCCESS or NRF_ERROR_NOT_FOUND
    */
    uint32_t ble_advdata_decode(uint8_t type, uint8_t advdata_len, uint8_t *p_advdata, uint8_t *len, uint8_t *p_field_data) {
      uint8_t index = 0;
      uint8_t field_length, field_type;
    
      while (index < advdata_len) {
        field_length = p_advdata[index];
        field_type   = p_advdata[index + 1];
        if (field_type == type) {
          memcpy(p_field_data, &p_advdata[index + 2], (field_length - 1));
          *len = field_length - 1;
          return NRF_SUCCESS;
        }
        index += field_length + 1;
      }
      return NRF_ERROR_NOT_FOUND;
    }
    void gattServerWriteCallBack(const GattWriteCallbackParams *Handler) {
      uint16_t index;
    
      if (Handler->handle == characteristic1.getValueAttribute().getHandle()) {
        for (index = 0; index < Handler->len; index++) {
          //Serial.write(Handler->data[index]);
          s[index] = Handler->data[index];
        }
        Serial.print ("RX buffer : ");
        Serial.println(s);
    
        if (s[0] == '1')
        {
          digitalWrite(13, HIGH);
          Serial.print ("HIGH");
        }
        else if (s[0] == '0')
        {
          digitalWrite(13, LOW);
          Serial.print ("LOW");
    
        }
        else {
          digitalWrite(13, LOW);
          Serial.print ("Wrong Input !!!");
        }
      }
    }
    
    void m_uart_rx_handle() {
      //update characteristic data
      ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), rx_buf, rx_buf_num);
      memset(rx_buf, 0x00, 20);
      rx_state = 0;
      //Serial.println ("rx_buf");
    }
    
    void uart_handle(uint32_t id, SerialIrq event) {
      // Serial rx IRQ
      if (event == RxIrq) {
        if (rx_state == 0) {
          rx_state = 1;
          timeout.attach_us(m_uart_rx_handle, 100000);
          rx_buf_num = 0;
        }
        while (Serial.available()) {
          if (rx_buf_num < 20) {
            rx_buf[rx_buf_num] = Serial.read();
            rx_buf_num++;
            //Serial.println ("Rx buff");
    
          }
          else
            Serial.read();
        }
    
      }
      //  Serial.println (rx_buf);
    
    }
    
    int find_text(String needle, String haystack) // To find a substring in a string
    {
      String temp = "";
      int x = 0;
      if (haystack.length() < needle.length())
      {
        temp = haystack;
        haystack = needle;
        needle = temp;
        x = 1;
      }
    
      int foundpos = -1;
      for (int i = 0; i <= haystack.length() - needle.length(); i++)
      {
        needle1 = haystack.substring(i, needle.length() + i);
        if (x == 1)
        {
          if (needle1 == haystack)
          {
            foundpos = i;
          }
        }
        else
        {
          if (needle1 == needle)
          {
            foundpos = i;
          }
    
        }
      }
      return foundpos;
    }
    /**
       @brief  Callback handle for scanning device
    
       @param[in]  *params   params->peerAddr            The peer's BLE address
                             params->rssi                The advertisement packet RSSI value
                             params->isScanResponse      Whether this packet is the response to a scan request
                             params->type                The type of advertisement
                                                         (enum from 0 ADV_CONNECTABLE_UNDIRECTED,ADV_CONNECTABLE_DIRECTED,ADV_SCANNABLE_UNDIRECTED,ADV_NON_CONNECTABLE_UNDIRECTED)
                             params->advertisingDataLen  Length of the advertisement data
                             params->advertisingData     Pointer to the advertisement packet's data
    */
    void scanCallBack(const Gap::AdvertisementCallbackParams_t *params) {
      uint8_t index;
      char arr[50] = "";
    
      Serial.println("Scan Device CallBack Handle ");
      Serial.print("  The peerAddr : ");
      for (index = 0; index < 6; index++) {
        Serial.print(params->peerAddr[index], HEX);
        Serial.print(" ");
      }
    
      uint8_t len;
      uint8_t adv_name[31];
      //  Serial.println (NRF_SUCCESS);
      //  Serial.println("chk1");
      //  Serial.println (ble_advdata_decode(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, params->advertisingDataLen, (uint8_t *)params->advertisingData, &len, adv_name));
      //  Serial.println("chk2");
      //  Serial.println (ble_advdata_decode(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, params->advertisingDataLen, (uint8_t *)params->advertisingData, &len, adv_name));
      //  Serial.println("chk3");
    
      if ( NRF_SUCCESS == ble_advdata_decode(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, params->advertisingDataLen, (uint8_t *)params->advertisingData, &len, adv_name) ) {
        Serial.println("inside if");
      }
      else if ( NRF_SUCCESS == ble_advdata_decode(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, params->advertisingDataLen, (uint8_t *)params->advertisingData, &len, adv_name) ) {
        Serial.println("inside else if");
        for (int i = 0; i < 4; i++)
        {
          arr[i] = (char)adv_name[i];
        }
        str0 = (char*)arr;
        //  Serial.println("memcmp");
        //  Serial.println(memcmp("TXRX", arr, 4));
    
        if (memcmp("TXRX", arr, 4) == 0x00)
        {
          Serial.println("Got device, stop scan ");
          ble.stopScan();
          device_is_simple_peripheral = 1;
          ble.connect(params->peerAddr, BLEProtocol::AddressType::PUBLIC, NULL, NULL);
        }
    
    
        if (q == 0)
        {
          str1.concat(str0);
          q++;
        }
        int x = find_text(str0, str1);
        if (x >= 0)
        {
          Serial.println(str1);
          digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
          delay(100);                       // wait for a second
          digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
          delay(100);                       // wait for a second
    
        }
        else if (x == -1)
        {
          str1.concat(",");
          str1.concat(str0);
    
          Serial.println(str1);
          digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
          delay(100);                       // wait for a second
          digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
          delay(100);                       // wait for a second
    
        }
        if (y > 5)
        {
          str1 = "";
          y = 0;
        }
        y++;
        delay(1000);
      }
    
    }
    /** @brief  Connection callback handle
    
        @param[in] *params   params->handle : The ID for this connection
                             params->role : PERIPHERAL  = 0x1, // Peripheral Role
                                            CENTRAL     = 0x2, // Central Role.
                             params->peerAddrType : The peer's BLE address type
                             params->peerAddr : The peer's BLE address
                             params->ownAddrType : This device's BLE address type
                             params->ownAddr : This devices's BLE address
                             params->connectionParams->minConnectionInterval
                             params->connectionParams->maxConnectionInterval
                             params->connectionParams->slaveLatency
                             params->connectionParams->connectionSupervisionTimeout
    */
    void connectionCallBack( const Gap::ConnectionCallbackParams_t *params )
    {
      uint8_t index;
      Serial.println("\r\n----Connection Callback");
      Serial.print("The conn handle : ");
      Serial.println(params->handle, HEX);
      Serial.print("ROLE : ");
      Serial.println(params->role, HEX);
      Serial.print("  The peerAddr : ");
      for (index = 0; index < 6; index++) {
        Serial.print(params->peerAddr[index], HEX);
        Serial.print(" ");
      }
      Serial.println(" ");
      // start to discovery
      startDiscovery(params->handle);
    }
    /** @brief  Disconnect callback handle
    
        @param[in] *params   params->handle : connect handle
                             params->reason : CONNECTION_TIMEOUT                          = 0x08,
                                              REMOTE_USER_TERMINATED_CONNECTION           = 0x13,
                                              REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES = 0x14,  // Remote device terminated connection due to low resources.
                                              REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF     = 0x15,  // Remote device terminated connection due to power off.
                                              LOCAL_HOST_TERMINATED_CONNECTION            = 0x16,
                                              CONN_INTERVAL_UNACCEPTABLE                  = 0x3B,
    */
    void disconnectionCallBack(const Gap::DisconnectionCallbackParams_t *params) {
      Serial.println("Disconnected, start to scanning");
      device_is_simple_peripheral = 0;
      device_is_hrm = 0;
      characteristic_is_fond = 0;
      descriptor_is_found = 0;
      ble.startScan(scanCallBack);
    }
    /**
       @brief Discovered service and characteristics termination callback handle
    */
    static void discoveryTerminationCallBack(Gap::Handle_t connectionHandle) {
      Serial.println("\r\n----discoveryTermination");
      Serial.print("connectionHandle       : ");
      Serial.println(connectionHandle, HEX);
      if (characteristic_is_fond == 1) {
        ble.gattClient().discoverCharacteristicDescriptors(chars_hrm, discoveredCharsDescriptorCallBack, discoveredDescTerminationCallBack);
      }
    }
    /** @brief Discovered descriptor of characteristic termination callback handle
    
        @param[in] *params  params->characteristic  DiscoveredCharacteristic
                            params->status  Status of the discovery operation
    */
    static void discoveredDescTerminationCallBack(const CharacteristicDescriptorDiscovery::TerminationCallbackParams_t *params) {
      Serial.println("\r\n----discovery descriptor Termination");
      if (1) {
        Serial.println("Open HRM notify");
        uint16_t value = 0x0001;
        value =2;
      //  ble.gattClient().write(GattClient::GATT_OP_WRITE_REQ, chars_hrm.getConnectionHandle(), desc_of_chars_hrm.getAttributeHandle(), 2, (uint8_t *)&valueArray);
        ble.gattClient().write(GattClient::GATT_OP_WRITE_REQ, chars_hrm.getConnectionHandle(), 0x11, 6, (uint8_t *)&valueArray); // data
    
      }
    }
    /** @brief Discovered descriptor of characteristic callback handle
    
        @param[in] *params  params->characteristic  DiscoveredCharacteristic
                            params->descriptor  descriptor.getUUID() : The uuid of descriptor atrribute
                                                descriptor.getConnectionHandle()
                                                descriptor.getAttributeHandle() : Arrtibute handle
    */
    static void discoveredCharsDescriptorCallBack(const CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t *params) {
      Serial.println("\r\n----discovered descriptor");
      Serial.print("Desriptor UUID         : ");
      Serial.println(params->descriptor.getUUID().getShortUUID(), HEX);
      if (params->descriptor.getUUID().getShortUUID() == 0xFFE1) {
        // Save characteristic info
        descriptor_is_found = 1;
        desc_of_chars_hrm = params->descriptor;
      }
      Serial.print("connectionHandle       : ");
      Serial.println(params->descriptor.getConnectionHandle(), HEX);
      Serial.print("descriptor Handle      : ");
      Serial.println(params->descriptor.getAttributeHandle(), HEX);
    }
    
    void startDiscovery(uint16_t handle) {
      if (device_is_hrm)
        ble.gattClient().launchServiceDiscovery(handle, discoveredServiceCallBack, discoveredCharacteristicCallBack, service_uuid, chars_uuid1);
      if (device_is_simple_peripheral)
        ble.gattClient().launchServiceDiscovery(handle, discoveredServiceCallBack, discoveredCharacteristicCallBack);
    }
    /** @brief Discovered service callback handle
    
        @param[in] *service  service->getUUID()  The UUID of service
                             service->getStartHandle()
                             service->getEndHandle()
    */
    static void discoveredServiceCallBack(const DiscoveredService *service) {
      Serial.println("\r\n----Service Discovered");
    
      Serial.print("Service UUID type        : ");
      Serial.println(service->getUUID().shortOrLong(), HEX);// 0 16bit_uuid, 1 128bit_uuid
      Serial.print("Service UUID             : ");
      if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
        Serial.println(service->getUUID().getShortUUID(), HEX);
      }
      else {
        uint8_t index;
        const uint8_t *uuid = service->getUUID().getBaseUUID();
        for (index = 0; index < 16; index++) {
          Serial.print(uuid[index], HEX);
          Serial.print(" ");
        }
        Serial.println(" ");
      }
      Serial.print("The service start handle : ");
      Serial.println(service->getStartHandle(), HEX);
      Serial.print("The service end handle   : ");
      Serial.println(service->getEndHandle(), HEX);
    }
    /** @brief Discovered characteristics callback handle
    
        @param[in] *chars  chars->getUUID()        The UUID of service
                           chars->getProperties()  broadcast() : Check if broadcasting is permitted. True is permited.
                                                   read() : Check reading is permitted.
                                                   writeWoResp() : Check if writing with Write Command is permitted
                                                   write() : Check if writing with Write Request is permitted.
                                                   notify() : Check notifications are permitted.
                                                   indicate() : Check if indications are permitted.
                                                   authSignedWrite() : Check if writing with Signed Write Command is permitted.
                           chars->getDeclHandle()  characteristic's declaration attribute handle
                           chars->getValueHandle() characteristic's value attribute handle
                           chars->getLastHandle()  characteristic's last attribute handle
    */
    static void discoveredCharacteristicCallBack(const DiscoveredCharacteristic *chars) {
      Serial.println("\r\n----Characteristic Discovered");
      Serial.print("Chars UUID type        : ");
      Serial.println(chars->getUUID().shortOrLong(), HEX);// 0 16bit_uuid, 1 128bit_uuid
      Serial.print("Chars UUID             : ");
      if (chars->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
        Serial.println(chars->getUUID().getShortUUID(), HEX);
        if (chars->getUUID().getShortUUID() == 0xFFE1) {
          Serial.println("Found HRM characteristic ");
          characteristic_is_fond = 1;
          chars_hrm = *chars;
        }
      }
      else {
        uint8_t index;
        const uint8_t *uuid = chars->getUUID().getBaseUUID();
        for (index = 0; index < 16; index++) {
          Serial.print(uuid[index], HEX);
          Serial.print(" ");
        }
        Serial.println(" ");
      }
    
      Serial.print("properties_read        : ");
      Serial.println(chars->getProperties().read(), DEC);
      Serial.print("properties_writeWoResp : ");
      Serial.println(chars->getProperties().writeWoResp(), DEC);
      Serial.print("properties_write       : ");
      Serial.println(chars->getProperties().write(), DEC);
      Serial.print("properties_notify      : ");
      Serial.println(chars->getProperties().notify(), DEC);
    
      Serial.print("declHandle             : ");
      Serial.println(chars->getDeclHandle(), HEX);
      Serial.print("valueHandle            : ");
      Serial.println(chars->getValueHandle(), HEX);
      Serial.print("lastHandle             : ");
      Serial.println(chars->getLastHandle(), HEX);
    }
    /** @brief  hvx callback handle
    
        @param[in] *params   params->connHandle : The handle of the connection that triggered the event
                             params->handle : Attribute Handle to which the write operation applies
                             params->type : BLE_HVX_NOTIFICATION = 0x01
                                            BLE_HVX_INDICATION   = 0x02
                             params->len : Length (in bytes) of the data to write
                             params->data : Pointer to the data to write
    */
    void hvxCallBack(const GattHVXCallbackParams *params) {
      int s;
      Serial.println("GattClient notify call back ");
      Serial.print("The len : ");
      Serial.println(params->len, DEC);
      Serial.print("The type : ");
      Serial.println(params->type, HEX);
      for (unsigned char index = 0; index < params->len; index++) {
        //Serial.print(params->data[index]);
        s = params->data[index];
      }
      Serial.println((char)s);
      if ((char)s == 'a')
      {
        digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
    
      }
      else if ((char)s == 'b')
      {
        digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
    
      }
      Serial.println("");
    }
    /** @brief  write callback handle
    
        @param[in] *params   params->connHandle : The handle of the connection that triggered the event
                             params->handle : Attribute Handle to which the write operation applies
                             params->writeOp : OP_INVALID               = 0x00,  // Invalid operation.
                                                 OP_WRITE_REQ             = 0x01,  // Write request.
                                                 OP_WRITE_CMD             = 0x02,  // Write command.
                                                 OP_SIGN_WRITE_CMD        = 0x03,  // Signed write command.
                                                 OP_PREP_WRITE_REQ        = 0x04,  // Prepare write request.
                                                 OP_EXEC_WRITE_REQ_CANCEL = 0x05,  // Execute write request: cancel all prepared writes.
                                                 OP_EXEC_WRITE_REQ_NOW    = 0x06,  // Execute write request: immediately execute all prepared writes.
                             params->offset : Offset for the write operation
                             params->len : Length (in bytes) of the data to write
                             params->data : Pointer to the data to write
    */
    void onDataWriteCallBack(const GattWriteCallbackParams *params) {
      Serial.println("GattClient write call back ");
      ble.gattClient().write(GattClient::GATT_OP_WRITE_CMD, chars_hrm.getConnectionHandle(), 0x11, 6, (uint8_t *)&valueArray); // data
      Serial.print("The connhandle : ");
      Serial.println(params->connHandle, HEX);
      Serial.print("The handle : ");
      Serial.println(params->handle, HEX);
      Serial.print("The writeOp : ");
      Serial.println(params->writeOp, HEX);
      Serial.print("The offset : ");
      Serial.println(params->offset, DEC);
      Serial.print("The len : ");
      Serial.println(params->len, DEC);
      Serial.print("The data : ");
      for (uint8_t index = 0; index < params->len; index++) {
        Serial.print( params->data[index], HEX);
      }
      Serial.println("");
    }
    /** @brief  read callback handle
    
        @param[in] *params   params->connHandle : The handle of the connection that triggered the event
                             params->handle : Attribute Handle to which the write operation applies
                             params->offset : Offset for the write operation
                             params->len : Length (in bytes) of the data to write
                             params->data : Pointer to the data to write
    */
    void onDataReadCallBack(const GattReadCallbackParams *params) {
      Serial.println("GattClient read call back ");
      Serial.print("The handle : ");
      Serial.println(params->handle, HEX);
      Serial.print("The offset : ");
      Serial.println(params->offset, DEC);
      Serial.print("The len : ");
      Serial.println(params->len, DEC);
      Serial.print("The data : ");
      for (uint8_t index = 0; index < params->len; index++) {
        Serial.print( params->data[index], HEX);
      }
      Serial.println("");
    }
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200);
      Serial.attach(uart_handle);
    
    
      pinMode(13, OUTPUT);
      Serial.println("Start...");
    
      ble.init();
      ble.onDataWritten(gattServerWriteCallBack);
      ble.onConnection(connectionCallBack);
      ble.onDisconnection(disconnectionCallBack);
      ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallBack);
      ble.gattClient().onHVX(hvxCallBack);
      ble.gattClient().onDataWrite(onDataWriteCallBack);
      ble.gattClient().onDataRead(onDataReadCallBack);
      ble.setScanParams(100, 100, 0, false);
      ble.setActiveScan(true);
      ble.startScan(scanCallBack);
    }
    void loop()
    {
      ble.waitForEvent();
    }
    
  • This is the arduino code we are using and trying to send data between two device (Nano 2 and HM10 in half or full duplex mode) over BLE