From 81fac808591b3bef0d96514e2cd40f82eec88bc4 Mon Sep 17 00:00:00 2001 From: Christian Baars Date: Tue, 9 Jan 2024 09:10:45 +0100 Subject: [PATCH] MI32 legacy: add optional argument to BLE.run() (#20431) * add optional argument to BLE.run() * set default of scan response to NO --- lib/libesp32/berry_tasmota/src/be_MI32_lib.c | 4 +- .../esp-nimble-cpp/src/NimBLEAdvertising.cpp | 2 +- tasmota/include/xsns_62_esp32_mi.h | 4 +- .../xdrv_52_3_berry_MI32.ino | 14 ++- .../tasmota_xsns_sensor/xsns_62_esp32_mi.ino | 105 +++++++++++++----- 5 files changed, 94 insertions(+), 35 deletions(-) diff --git a/lib/libesp32/berry_tasmota/src/be_MI32_lib.c b/lib/libesp32/berry_tasmota/src/be_MI32_lib.c index e56ad7ae2..3cddb77dc 100644 --- a/lib/libesp32/berry_tasmota/src/be_MI32_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_MI32_lib.c @@ -64,8 +64,8 @@ BE_FUNC_CTYPE_DECLARE(be_BLE_set_MAC, "", "@(bytes)~[i]"); extern void be_BLE_set_characteristic(struct bvm *vm, const char *Chr); BE_FUNC_CTYPE_DECLARE(be_BLE_set_characteristic, "", "@s"); -extern void be_BLE_run(struct bvm *vm, uint8_t operation, bbool response); -BE_FUNC_CTYPE_DECLARE(be_BLE_run, "", "@i[b]"); +extern void be_BLE_run(struct bvm *vm, uint8_t operation, bbool response, int32_t arg1); +BE_FUNC_CTYPE_DECLARE(be_BLE_run, "", "@i[bi]"); extern void be_BLE_set_service(struct bvm *vm, const char *Svc, bbool discoverAttributes); BE_FUNC_CTYPE_DECLARE(be_BLE_set_service, "", "@s[b]"); diff --git a/lib/libesp32_div/esp-nimble-cpp/src/NimBLEAdvertising.cpp b/lib/libesp32_div/esp-nimble-cpp/src/NimBLEAdvertising.cpp index 50a9e8983..283f26493 100644 --- a/lib/libesp32_div/esp-nimble-cpp/src/NimBLEAdvertising.cpp +++ b/lib/libesp32_div/esp-nimble-cpp/src/NimBLEAdvertising.cpp @@ -67,7 +67,7 @@ void NimBLEAdvertising::reset() { m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN; m_customAdvData = false; m_customScanResponseData = false; - m_scanResp = true; + m_scanResp = false; m_advDataSet = false; // Set this to non-zero to prevent auto start if host reset before started by app. m_duration = BLE_HS_FOREVER; diff --git a/tasmota/include/xsns_62_esp32_mi.h b/tasmota/include/xsns_62_esp32_mi.h index 09413a9fa..f707bddaf 100644 --- a/tasmota/include/xsns_62_esp32_mi.h +++ b/tasmota/include/xsns_62_esp32_mi.h @@ -156,11 +156,13 @@ struct MI32connectionContextBerry_t{ NimBLEUUID charUUID; uint16_t returnCharUUID; uint16_t handle; - uint8_t MAC[6]; uint8_t * buffer; + uint8_t MAC[6]; uint8_t operation; uint8_t addrType; int error; + int32_t arg1; + bool hasArg1; bool oneOp; bool response; }; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino index 27a8ed9ba..eab484c2b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino @@ -80,7 +80,7 @@ extern "C" { extern void MI32setBerryAdvCB(void* function, uint8_t *buffer); extern void MI32setBerryConnCB(void* function, uint8_t *buffer); extern void MI32setBerryServerCB(void* function, uint8_t *buffer); - extern bool MI32runBerryConnection(uint8_t operation, bbool response); + extern bool MI32runBerryConnection(uint8_t operation, bbool response, int32_t *arg1); extern bool MI32setBerryCtxSvc(const char *Svc, bbool discoverAttributes); extern bool MI32setBerryCtxChr(const char *Chr); extern bool MI32setBerryCtxMAC(uint8_t *MAC, uint8_t type); @@ -161,13 +161,19 @@ extern "C" { be_raisef(vm, "ble_error", "BLE: could not set characteristic"); } - void be_BLE_run(struct bvm *vm, uint8_t operation, bbool response); - void be_BLE_run(struct bvm *vm, uint8_t operation, bbool response){ + void be_BLE_run(struct bvm *vm, uint8_t operation, bbool response, int32_t arg1); + void be_BLE_run(struct bvm *vm, uint8_t operation, bbool response, int32_t arg1){ + int32_t argc = be_top(vm); // Get the number of arguments bool _response = false; if(response){ _response = response; } - if (MI32runBerryConnection(operation,_response)) return; + int32_t *ptr_arg1 = nullptr; + int32_t _arg1 = arg1; + if(argc == 3){ + ptr_arg1 = &_arg1; + } + if (MI32runBerryConnection(operation, _response, ptr_arg1)) return; be_raisef(vm, "ble_error", "BLE: could not run operation"); } diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino index 415b2b556..4ca91f3b2 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino @@ -93,6 +93,7 @@ class MI32SensorCallback : public NimBLEClientCallbacks { MI32.infoMsg = MI32_DID_CONNECT; MI32.mode.willConnect = 0; MI32.mode.connected = 1; + pclient->updateConnParams(8,11,0,1000); } void onDisconnect(NimBLEClient* pclient) { MI32.mode.connected = 0; @@ -250,7 +251,7 @@ void MI32notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pD memcpy(item.buffer,pData,length); item.header.returnCharUUID = pRemoteCharacteristic->getUUID().getNative()->u16.value; item.header.handle = pRemoteCharacteristic->getHandle(); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + length , pdMS_TO_TICKS(1)); + xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + length , pdMS_TO_TICKS(5)); MI32.mode.readingDone = 1; MI32.infoMsg = MI32_GOT_NOTIFICATION; return; @@ -711,9 +712,8 @@ extern "C" { MI32BLELoop(); } - bool MI32runBerryServer(uint16_t operation, bool response){ + bool MI32runBerryServer(uint16_t operation){ MI32.conCtx->operation = operation; - MI32.conCtx->response = response; AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: Berry server op: %d, response: %u"),MI32.conCtx->operation, MI32.conCtx->response); if(MI32.mode.readyForNextServerJob == 0){ MI32.mode.triggerNextServerJob = 0; @@ -724,14 +724,22 @@ extern "C" { return true; } - bool MI32runBerryConnection(uint8_t operation, bool response){ + bool MI32runBerryConnection(uint8_t operation, bool response, int32_t* arg1){ if(MI32.conCtx != nullptr){ + if(arg1 != nullptr){ + MI32.conCtx->arg1 = *arg1; + MI32.conCtx->hasArg1 = true; + AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: arg1: %u"),MI32.conCtx->arg1); + } + else{ + MI32.conCtx->hasArg1 = false; + } + MI32.conCtx->response = response; if(operation > 200){ - return MI32runBerryServer(operation,response); + return MI32runBerryServer(operation); } MI32.conCtx->oneOp = (operation > 9); MI32.conCtx->operation = operation%10; - MI32.conCtx->response = response; AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: Berry connection op: %d, addrType: %d, oneOp: %u, response: %u"),MI32.conCtx->operation, MI32.conCtx->addrType, MI32.conCtx->oneOp, MI32.conCtx->response); if(MI32.conCtx->oneOp){ MI32StartConnectionTask(); @@ -1214,7 +1222,7 @@ bool MI32StartConnectionTask(){ 2, /* Priority of the task */ &MI32.ConnTask, /* Task handle. */ 0); /* Core where the task should run */ - return true; + return true; } void MI32ConnectionTask(void *pvParameters){ @@ -1240,7 +1248,7 @@ void MI32ConnectionTask(void *pvParameters){ timer++; vTaskDelay(10/ portTICK_PERIOD_MS); } - if(MI32.mode.discoverAttributes){ + if(MI32.mode.discoverAttributes || MI32.conCtx->hasArg1){ // explicit or in the first run with selection by handle MI32Client->discoverAttributes(); // solves connection problems on i.e. yeelight dimmer } NimBLERemoteService* pSvc = nullptr; @@ -1271,7 +1279,12 @@ void MI32ConnectionTask(void *pvParameters){ MI32ConnectionGetServices(); } else{ - pSvc = MI32Client->getService(MI32.conCtx->serviceUUID); + if(MI32.conCtx->hasArg1){ + pSvc = nullptr; // invalidate possible dangling service from last operation + } + else{ + pSvc = MI32Client->getService(MI32.conCtx->serviceUUID); + } } if(pSvc) { @@ -1279,9 +1292,12 @@ void MI32ConnectionTask(void *pvParameters){ MI32ConnectionGetCharacteristics(pSvc); } else{ - pChr = pSvc->getCharacteristic(MI32.conCtx->charUUID); + pChr = pSvc->getCharacteristic(MI32.conCtx->charUUID); } } + else if(MI32.conCtx->hasArg1){ + pChr = MI32Client->getCharacteristic(MI32.conCtx->arg1); // get by handle, overriding svc and chr values + } else{ if(MI32.conCtx->operation != 6){ MI32.conCtx->error = MI32_CONN_NO_SERVICE; @@ -1291,12 +1307,13 @@ void MI32ConnectionTask(void *pvParameters){ switch(MI32.conCtx->operation){ case 1: if(pChr->canRead()) { - NimBLEAttValue _val = pChr->readValue(); - MI32.conCtx->buffer[0] = _val.size(); - memcpy( MI32.conCtx->buffer + 1,_val.data(),MI32.conCtx->buffer[0]); + NimBLEAttValue _val = pChr->readValue(); + MI32.conCtx->buffer[0] = _val.size(); + memcpy( MI32.conCtx->buffer + 1,_val.data(),MI32.conCtx->buffer[0]); + MI32.conCtx->handle = pChr->getHandle(); } else{ - MI32.conCtx->error = MI32_CONN_CAN_NOT_READ; + MI32.conCtx->error = MI32_CONN_CAN_NOT_READ; } break; case 2: @@ -1304,6 +1321,7 @@ void MI32ConnectionTask(void *pvParameters){ uint8_t len = MI32.conCtx->buffer[0]; if(pChr->writeValue(MI32.conCtx->buffer + 1,len,MI32.conCtx->response & !pChr->canWriteNoResponse())) { // falls always back to "no response" if server provides both options // AddLog(LOG_LEVEL_DEBUG,PSTR("M32: write op done")); + MI32.conCtx->handle = pChr->getHandle(); } else{ MI32.conCtx->error = MI32_CONN_DID_NOT_WRITE; @@ -1322,15 +1340,31 @@ void MI32ConnectionTask(void *pvParameters){ break; } } - charvector = pSvc->getCharacteristics(true); // always try to subscribe to all characteristics with the same UUID - for (auto &it: *charvector) { - if (it->getUUID() == MI32.conCtx->charUUID) { - if (it->canNotify()) { - if(!it->subscribe(true, MI32notifyCB, MI32.conCtx->response)) { - MI32.conCtx->error = MI32_CONN_CAN_NOT_NOTIFY; // will return the last result only ATM, maybe check differently + if(MI32.conCtx->hasArg1){ // characteristic selected by handle + if (pChr->canNotify()) { + if(!pChr->subscribe(true, MI32notifyCB, MI32.conCtx->response)) { + MI32.conCtx->error = MI32_CONN_CAN_NOT_NOTIFY; // will return the last result only ATM, maybe check differently + } + } + } + else { // characteristic selected by UUID + charvector = pSvc->getCharacteristics(true); // always try to subscribe to all characteristics with the same UUID + uint32_t position = 1; + for (auto &it: *charvector) { + if (it->getUUID() == MI32.conCtx->charUUID) { + if (it->canNotify()) { + if(!it->subscribe(true, MI32notifyCB, MI32.conCtx->response)) { + MI32.conCtx->error = MI32_CONN_CAN_NOT_NOTIFY; // will return the last result only ATM, maybe check differently + } + else{ + MI32.conCtx->buffer[position++] = it->getHandle() >> 8; + MI32.conCtx->buffer[position++] = it->getHandle() & 0xff; + MI32.conCtx->handle = it->getHandle(); + } } } } + MI32.conCtx->buffer[0] = position - 1; } break; default: @@ -1403,7 +1437,7 @@ bool MI32StartServerTask(){ 2, /* Priority of the task */ &MI32.ServerTask, /* Task handle. */ 0); /* Core where the task should run */ - return true; + return true; } void MI32ServerSetAdv(NimBLEServer *pServer, std::vector& servicesToStart, bool &shallStartServices); @@ -1416,6 +1450,15 @@ void MI32ServerSetAdv(NimBLEServer *pServer, std::vector& servic */ void MI32ServerSetAdv(NimBLEServer *pServer, std::vector& servicesToStart, bool &shallStartServices){ NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); + /** optional argument arg1 + BLE_GAP_CONN_MODE_NON (0) - not connectable advertising + BLE_GAP_CONN_MODE_DIR (1) - directed connectable advertising + BLE_GAP_CONN_MODE_UND (2) - undirected connectable advertising + */ + if(MI32.conCtx->hasArg1){ + pAdvertising->setAdvertisementType(MI32.conCtx->arg1); + // AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: AdvertisementType: %u"),MI32.conCtx->arg1); + } struct{ BLERingBufferItem_t header; uint8_t buffer[255]; @@ -1447,7 +1490,10 @@ void MI32ServerSetAdv(NimBLEServer *pServer, std::vector& servic adv.addData((char *)&MI32.conCtx->buffer[1], MI32.conCtx->buffer[0]); if(MI32.conCtx->operation == BLE_OP_SET_ADV){ pAdvertising->setAdvertisementData(adv); // replace whole advertisement with our custom data from the Berry side - pAdvertising->start(); + if(pAdvertising->isAdvertising() == false && !shallStartServices){ // first advertisement + vTaskDelay(1000/ portTICK_PERIOD_MS); // work around to prevent crash on start + pAdvertising->start(); + } } else { pAdvertising->setScanResponseData(adv); @@ -1486,11 +1532,16 @@ void MI32ServerSetCharacteristic(NimBLEServer *pServer, std::vectorgetCharacteristic(MI32.conCtx->charUUID); // again retrieve ... if(pCharacteristic == nullptr){ uint32_t _writeRSP = MI32.conCtx->response ? NIMBLE_PROPERTY::WRITE : NIMBLE_PROPERTY::WRITE_NR; + uint32_t _property = NIMBLE_PROPERTY::READ | + _writeRSP | + NIMBLE_PROPERTY::NOTIFY | + NIMBLE_PROPERTY::INDICATE; // default to "all" + if(MI32.conCtx->hasArg1){ + _property = MI32.conCtx->arg1; // override with optional argument + // AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: _property: %u"),_property); + } pCharacteristic = pService->createCharacteristic(MI32.conCtx->charUUID, - NIMBLE_PROPERTY::READ | - _writeRSP | - NIMBLE_PROPERTY::NOTIFY | - NIMBLE_PROPERTY::INDICATE); //... or create characteristic. + _property); //... or create characteristic. if(pCharacteristic == nullptr){ MI32.conCtx->error = MI32_CONN_NO_CHARACTERISTIC; return; @@ -1499,7 +1550,7 @@ void MI32ServerSetCharacteristic(NimBLEServer *pServer, std::vectorsetValue(MI32.conCtx->buffer + 1, MI32.conCtx->buffer[0]); // set value - pCharacteristic->notify(true); // always notify .. for now + pCharacteristic->notify(true); // TODO: fallback to indication struct{ BLERingBufferItem_t header; } item;