nkolban / esp32-snippets

Sample ESP32 snippets and code fragments
https://leanpub.com/kolban-ESP32
Apache License 2.0
2.37k stars 710 forks source link

cache refresh and writing byte array to server. #1001

Closed greatwuu closed 4 years ago

greatwuu commented 4 years ago

I want to write this value to custom UUID then refresh service and characteristic cache to catch new characteristic UUID. But when I try to write I can only write one byte but for this value that has 4 bytes, it has nothing happen. I've looked for some documentation and topics on this repo and esp32 Webboard but still did not understand. several function

  1. esp_err_t esp_ble_gattc_write_char( esp_gatt_if_t gattc_if, uint16_t conn_id, uint16_t handle, uint16_t value_len, uint8_t *value, esp_gatt_write_type_t write_type, esp_gatt_auth_req_t auth_req); For this function I don't know what the parameter I should add to.
  2. esp_ble_gattc_cache_refresh(myDevice->getAddress().toString().c_str()); for this one I can't compile because type of value didn't match Here's my part of code modified from Neil Koban client example.
uint8_t newValue[4] = {0x9f,0xcc,0x01,0x80};
uint8_t accSelfTest = {0x06};
Serial.println(" - Found our characteristic4 : Test Mode Enable");
  // Read the value of the characteristic.
  if (pRemoteCharacteristic->canWrite()) {
    pRemoteCharacteristic->writeValue(newValue,4);
    //esp_ble_gattc_write_char()
    Serial.println("Write Test Mode Enable Complete");
  }
 esp_ble_gattc_cache_refresh(myDevice->getAddress().toString().c_str());
 delay(1500);
  pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID6);
  if (pRemoteCharacteristic == nullptr) {
    Serial.print("Failed to find our characteristic UUID: ");
    Serial.println(charUUID6.toString().c_str());
    pClient->disconnect();
    return false;
  }
Serial.println(" - Found our characteristic4 : ACC. Self Test");
  // Read the value of the characteristic.
  if (pRemoteCharacteristic->canWrite()) {
    pRemoteCharacteristic->writeValue(accSelfTest);
    Serial.println("Write Self Test Complete");
  }
  delay(500);
  if (pRemoteCharacteristic->canRead()) {
    std::string value = pRemoteCharacteristic->readValue();
    int j = value.length();
    Serial.print("Data length = ");
    Serial.println(j);
    for (int i = 0; i < value.length(); i++)
    {
      String stringOne =  String(value[i], DEC);
      Serial.print(stringOne);
    }
    Serial.println("");
  }
  delay(1000);
greatwuu commented 4 years ago

I've researched for bd address and found this solution to convert char from myDevice->getAddress().toString().c_str() into byte array to use with esp_ble_gattc_cache_refresh() ` byte addr[6];

void parseBytes(const char str, char sep, byte bytes, int maxBytes, int base) { for (int i = 0; i < maxBytes; i++) { bytes[i] = strtoul(str, NULL, base); // Convert byte str = strchr(str, sep); // Find next separator if (str == NULL || *str == '\0') { break; // No more separators, exit } str++; // Point to next character after separator } }

//in other functions. const char* devAddr = myDevice->getAddress().toString().c_str(); parseBytes(devAddr, ':', addr, 6, 16); for(int i =0 ; i<5 ; i++){Serial.println(addr[i], HEX);} ` I only try to print into serial monitor and esp_ble_gattc_cache_refresh() but can't see any different cause I have no LOG show when running on esp32 but everything seems okay. need to try again when able to write byte array into the server to activate hidden characteristics.

chegewara commented 4 years ago

esp_ble_gattc_cache_refresh(esp_bd_addr_t remote_bda) You have BLEAddress->native()

greatwuu commented 4 years ago

esp_ble_gattc_cache_refresh(esp_bd_addr_t remote_bda) You have BLEAddress->native()

Dear Chegewara,

Sorry for a nonsense question because I’m new to this BLE but what do you mean about BLEAddress->native() I did not understand it do I have to call this class to activate refresh function and now I’m still stuck with writing byte array to server characteristic. But when I’m write a byte array with nRF Connect everything work fine. If I can write with esp32 I’m also can test the refresh service function. Anyway thanks for your support.

greatwuu commented 4 years ago

Update!!!

Now I can write byte array to my device by using pRemoteCharacteristic->writeValue(newValue,4, true);

Just add TRUE at the end of the command and it can be used!!!

I've read this issue https://github.com/nkolban/esp32-snippets/issues/382 Big thanks to chegewara and vcmorini.

Next I'll try to refresh a service by using esp_ble_gattc_cache_refresh(esp_bd_addr_t remote_bda)

chegewara commented 4 years ago

There is class BLEAddress. In that class you have function that will return value or pointer to value you need: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEAddress.h#L26

greatwuu commented 4 years ago

BLE_client:216:52: error: cannot convert 'uint8_t ()[6] {aka unsigned char ()[6]}' to 'uint8_t {aka unsigned char}' for argument '1' to 'esp_err_t esp_ble_gattc_cache_refresh(uint8_t*)'

esp_ble_gattc_cache_refresh(myAddress->getNative());

Hi, I edit my code then got this error message. When edit to *myAddress->getNative() Got this error 10:33:07.942 -> Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. 10:33:07.942 -> Core 1 register dump: 10:33:07.942 -> PC : 0x4000c310 PS : 0x00060130 A0 : 0x800fc2b5 A1 : 0x3ffc8650 10:33:07.942 -> A2 : 0x3ffc8670 A3 : 0x00000000 A4 : 0x00000006 A5 : 0x3ffc8670 10:33:07.942 -> A6 : 0x3ffbedb0 A7 : 0x00000000 A8 : 0x00000000 A9 : 0x3ffc8650 10:33:07.942 -> A10 : 0x00000002 A11 : 0x3f4020ef A12 : 0x0000001f A13 : 0x0000ff00 10:33:07.942 -> A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000004 EXCCAUSE: 0x0000001c 10:33:07.975 -> EXCVADDR: 0x00000000 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff

chegewara commented 4 years ago

esp_ble_gattc_cache_refresh((uint8_t*)myAddress->getNative()); or esp_ble_gattc_cache_refresh((uint8_t*)&myAddress->getNative()[0]);

greatwuu commented 4 years ago

After trying code with your suggestion the same error occurs 0x400d2454: connectToServer() at D:\BLE_client/BLE_client.ino line 216 0x400d2f12: loop() at D:\BLE_client/BLE_client.ino line 440 0x400d8635: loopTask(void*) at C:\Users\parin\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\cores\esp32\main.cpp line 19 0x4008e089: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143 PC: 0x4000c310 EXCVADDR: 0x00000000

I'm using a decoder to traceback the error and found this. Now I'm trying to find a solution

greatwuu commented 4 years ago

I'd do some research and found that my result from exception decoder is LoadProhibited from address 0x00000000

Which describe in

But I don't know where to look for. By the way, I declared a BLEAddress class as static BLEAddress* myAddress; And use as

esp_ble_gattc_cache_refresh((uint8_t*)myAddress->getNative()); or esp_ble_gattc_cache_refresh((uint8_t*)&myAddress->getNative()[0]);

Is they have anything to do with this exception?

chegewara commented 4 years ago

static BLEAddress* myAddress;

This in NULL, try that: bleClient->getPeerAddress().getNative()

greatwuu commented 4 years ago

Thanks for your advice. Now it's looking good can compile and run but it seems to have no service refresh at all.

But now I'm stuck at refresh UUID. Can I use any other method to refresh server UUID? Anyways thanks you so much for your support.

greatwuu commented 4 years ago

Hey!, I read reference from https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/esp_gattc.html#_CPPv424esp_ble_gattc_cb_param_t I have a question, Did esp_bd_addr_tserver_bda and esp_bd_addr_tremote_bda is the same value because in BLERemoteCharacteristic class esp_ble_gattc_register_for_notify can use esp_bd_addr_tserver_bda as *m_pRemoteService->getClient()->getPeerAddress().getNative() but when I try to use the same method nothing happen. esp_ble_gattc_cache_refresh((uint8_t*)pRemoteService->getClient()->getPeerAddress().getNative());

chegewara commented 4 years ago

Yes, its the same address.

https://github.com/espressif/esp-idf/issues/3198

greatwuu commented 4 years ago

Yes, its the same address.

espressif/esp-idf#3198

Did a GATTC API different version or older version than the one on https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/esp_gattc.html

greatwuu commented 4 years ago

Now, I add a bool BLEClient::serviceRefresh() { esp_err_t errRc = esp_ble_gattc_cache_refresh(*getPeerAddress().getNative()); if (errRc != ESP_OK) { log_e("esp_ble_gattc_cache_refresh: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return false; } else return true; }

and call this in main program. `if (pClient->serviceRefresh()){ pRemoteService = pClient->getService(serviceUUID2); if (pRemoteService == nullptr) { Serial.print("Failed to find our service UUID: "); Serial.println(serviceUUID.toString().c_str()); pClient->disconnect(); return false; }

pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID6); if (pRemoteCharacteristic == nullptr) { Serial.print("Failed to find our characteristic UUID: "); Serial.println(charUUID6.toString().c_str()); pClient->disconnect(); return false; }`

It seems that refresh function return TRUE after execute but still can not get characteristic UUID before resetting a device

Soth-Eng commented 2 years ago

@greatwuu How did you solve this issue

greatwuu commented 2 years ago

@greatwuu How did you solve this issue

Hi Soth,

Now I have no device to review my previous code. I will review and get back to you later.

greatwuu commented 2 years ago

Sorry for late reply, I have checked my code and found that the server that I have connected to will updated the Services and Char UUID automatically and if it is not updated software will try to reconnect it. `bool connectToServer() { Serial.print("Forming a connection to "); strAddr = myDevice->getAddress().toString().c_str(); Serial.println(strAddr); BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM); pClient = BLEDevice::createClient(); Serial.println(" - Created client"); pClient->setClientCallbacks(new MyClientCallback());

pClient->connect(myDevice); Serial.println(" - Connected to server"); Serial.print(devName); Serial.print(" RSSI = "); Serial.println(RSSIvalue);

pRemoteService = pClient->getService(serviceUUID); if (pRemoteService == nullptr) { Serial.print("ERROR : Failed to find GENERIC ACCESS UUID: "); Serial.println(serviceUUID.toString().c_str()); pClient->disconnect(); return false; }

pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); if (pRemoteCharacteristic == nullptr) { Serial.print("ERROR : Failed to find DEVICE NAME UUID: "); Serial.println(charUUID.toString().c_str()); pClient->disconnect(); return false; } Serial.println(" - Device name"); // Read the value of the characteristic. if (pRemoteCharacteristic->canRead()) { std::string value = pRemoteCharacteristic->readValue(); devName = value.c_str(); Serial.println(value.c_str()); }

pRemoteService = pClient->getService(serviceUUID2); if (pRemoteService == nullptr) { Serial.print("ERROR : Failed to find CUSTOM SERVICE UUID: "); Serial.println(serviceUUID.toString().c_str()); pClient->disconnect(); return false; } pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID5); if (pRemoteCharacteristic == nullptr) { Serial.print("Failed to find our CUSTOM CHAR. UUID: "); Serial.println(charUUID5.toString().c_str()); pClient->disconnect(); return false; } Serial.println(" - Test Mode Enable"); if (pRemoteCharacteristic->canWrite()) { pRemoteCharacteristic->writeValue(newValue, 4, true); Serial.println("**Write Test Mode Enable Complete**"); } delay(500); pRemoteService = pClient->getService(serviceUUID2); if (pRemoteService == nullptr) { Serial.print("ERROR : Failed to find CUSTOM service UUID: "); Serial.println(serviceUUID.toString().c_str()); pClient->disconnect(); } pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID6); if (pRemoteCharacteristic == nullptr) { Serial.print("ERROR : Reseting Device "); Serial.println(charUUID6.toString().c_str()); pClient->disconnect(); } connected = true; return true; }`