diff --git a/lib/libesp32/berry_tasmota/src/be_MI32_lib.c b/lib/libesp32/berry_tasmota/src/be_MI32_lib.c index 89f2757fa..22c0a0bc6 100644 --- a/lib/libesp32/berry_tasmota/src/be_MI32_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_MI32_lib.c @@ -44,12 +44,17 @@ module MI32 (scope: global) { * To use: `import BLE` *******************************************************************/ +extern int be_BLE_init(bvm *vm); + extern void be_BLE_reg_conn_cb(void* function, uint8_t *buffer); BE_FUNC_CTYPE_DECLARE(be_BLE_reg_conn_cb, "", "cc"); extern void be_BLE_reg_adv_cb(void* function, uint8_t *buffer); BE_FUNC_CTYPE_DECLARE(be_BLE_reg_adv_cb, "", "c[c]"); +extern void be_BLE_reg_server_cb(void* function, uint8_t *buffer); +BE_FUNC_CTYPE_DECLARE(be_BLE_reg_server_cb, "", "c[c]"); + extern void be_BLE_set_MAC(struct bvm *vm, uint8_t *buf, size_t size, uint8_t type); BE_FUNC_CTYPE_DECLARE(be_BLE_set_MAC, "", "@(bytes)~[i]"); @@ -73,6 +78,7 @@ BE_FUNC_CTYPE_DECLARE(be_BLE_adv_block, "", "@(bytes)~[i]"); /* @const_object_info_begin module BLE (scope: global) { + init, func(be_BLE_init) conn_cb, ctype_func(be_BLE_reg_conn_cb) set_svc, ctype_func(be_BLE_set_service) run, ctype_func(be_BLE_run) @@ -81,6 +87,7 @@ module BLE (scope: global) { set_MAC, ctype_func(be_BLE_set_MAC) adv_watch, ctype_func(be_BLE_adv_watch) adv_block, ctype_func(be_BLE_adv_block) + serv_cb, ctype_func(be_BLE_reg_server_cb) } @const_object_info_end */ diff --git a/tasmota/include/xsns_62_esp32_mi.h b/tasmota/include/xsns_62_esp32_mi.h index 8418554df..52e221d1f 100644 --- a/tasmota/include/xsns_62_esp32_mi.h +++ b/tasmota/include/xsns_62_esp32_mi.h @@ -148,6 +148,7 @@ struct MI32connectionContextBerry_t{ NimBLEUUID serviceUUID; NimBLEUUID charUUID; uint16_t returnCharUUID; + uint16_t handle; uint8_t MAC[6]; uint8_t * buffer; uint8_t operation; @@ -162,17 +163,29 @@ struct MI32notificationBuffer_t{ uint16_t returnCharUUID; }; +struct BLEqueueBuffer_t{ + union{ + uint8_t *buffer; + int32_t value; + }; + size_t length; + uint16_t returnCharUUID; + uint16_t handle; + uint16_t type; +}; + struct { // uint32_t period; // set manually in addition to TELE-period, is set to TELE-period after start TaskHandle_t ScanTask = nullptr; TaskHandle_t ConnTask = nullptr; + TaskHandle_t ServerTask = nullptr; MI32connectionContextBerry_t *conCtx = nullptr; union { struct { uint32_t init:1; uint32_t connected:1; uint32_t autoScan:1; - uint32_t canScan:1; + // uint32_t canScan:1; uint32_t runningScan:1; uint32_t updateScan:1; uint32_t deleteScanTask:1; @@ -191,6 +204,11 @@ struct { uint32_t triggerNextConnJob:1; uint32_t readyForNextConnJob:1; uint32_t discoverAttributes:1; + + uint32_t triggerNextServerJob:1; + uint32_t readyForNextServerJob:1; + uint32_t triggerBerryServerCB:1; + uint32_t deleteServerTask:1; }; uint32_t all = 0; } mode; @@ -218,8 +236,9 @@ struct { uint8_t HKinfoMsg = 0; char hk_setup_code[11]; #endif //USE_MI_HOMEKIT - void *beConnCB; + void *beConnCB; void *beAdvCB; + void *beServerCB; uint8_t *beAdvBuf; uint8_t infoMsg = 0; } MI32; @@ -379,7 +398,7 @@ const char kMI32DeviceType[] PROGMEM = {"Flora|MJ_HT_V1|LYWSD02|LYWSD03|CGG1|CGD const char kMI32_ConnErrorMsg[] PROGMEM = "no Error|could not connect|did disconnect|got no service|got no characteristic|can not read|can not notify|can not write|did not write|notify time out"; -const char kMI32_BLEInfoMsg[] PROGMEM = "Scan ended|Got Notification|Did connect|Did disconnect|Still connected|Start passive scanning|Start active scanning"; +const char kMI32_BLEInfoMsg[] PROGMEM = "Scan ended|Got Notification|Did connect|Did disconnect|Still connected|Start passive scanning|Start active scanning|Server characteristic set|Server advertisement set|Server scan response set|Server client did connect|Server client did disconnect"; const char kMI32_HKInfoMsg[] PROGMEM = "HAP core started|HAP core did not start!!|HAP controller disconnected|HAP controller connected|HAP outlet added"; @@ -397,6 +416,33 @@ enum MI32_Commands { // commands useable in console or rules enum MI32_TASK { MI32_TASK_SCAN = 0, MI32_TASK_CONN = 1, + MI32_TASK_SERV = 2, +}; + +enum BLE_CLIENT_OP { +BLE_OP_READ = 1, +BLE_OP_WRITE, +BLE_OP_SUBSCRIBE, +BLE_OP_UNSUBSCRIBE, //maybe used later +BLE_OP_DISCONNECT, +BLE_OP_GET_NOTIFICATION = 103, +}; + +enum BLE_SERVER_OP { +//commands +BLE_OP_SET_ADV = 201, +BLE_OP_SET_SCAN_RESP, +BLE_OP_SET_CHARACTERISTIC = 211, +//response +BLE_OP_ON_READ = 221, +BLE_OP_ON_WRITE, +BLE_OP_ON_UNSUBSCRIBE, +BLE_OP_ON_SUBSCRIBE_TO_NOTIFICATIONS, +BLE_OP_ON_SUBSCRIBE_TO_INDICATIONS, +BLE_OP_ON_SUBSCRIBE_TO_NOTIFICATIONS_AND_INDICATIONS, +BLE_OP_ON_CONNECT, +BLE_OP_ON_DISCONNECT, +BLE_OP_ON_STATUS, }; enum MI32_ConnErrorMsg { @@ -419,7 +465,12 @@ enum MI32_BLEInfoMsg { MI32_DID_DISCONNECT, MI32_STILL_CONNECTED, MI32_START_SCANNING_PASSIVE, - MI32_START_SCANNING_ACTIVE + MI32_START_SCANNING_ACTIVE, + MI32_SERV_CHARACTERISTIC_ADDED, + MI32_SERV_ADVERTISEMENT_ADDED, + MI32_SERV_SCANRESPONSE_ADDED, + MI32_SERV_CLIENT_CONNECTED, + MI32_SERV_CLIENT_DISCONNECTED }; enum MI32_HKInfoMsg { 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 52f9c02e0..eb5e9ed33 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino @@ -74,9 +74,11 @@ extern "C" { /******************************************************************** ** BLE - generic BLE functions -********************************************************************/ +********************************************************************/ + extern bool MI32checkBLEinitialization(); 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 MI32setBerryCtxSvc(const char *Svc, bbool discoverAttributes); extern bool MI32setBerryCtxChr(const char *Chr); @@ -84,12 +86,25 @@ extern "C" { extern bool MI32addMACtoBlockList(uint8_t *MAC, uint8_t type); extern bool MI32addMACtoWatchList(uint8_t *MAC, uint8_t type); + int be_BLE_init(bvm *vm); + int be_BLE_init(bvm *vm) { + if (MI32checkBLEinitialization() == true){ + be_return(vm); + } + be_raise(vm, "ble_error", "BLE: device not initialized"); + be_return_nil(vm); + } void be_BLE_reg_conn_cb(void* function, uint8_t *buffer); void be_BLE_reg_conn_cb(void* function, uint8_t *buffer){ MI32setBerryConnCB(function,buffer); } + void be_BLE_reg_server_cb(void* function, uint8_t *buffer); + void be_BLE_reg_server_cb(void* function, uint8_t *buffer){ + MI32setBerryServerCB(function,buffer); + } + void be_BLE_reg_adv_cb(void* function, uint8_t *buffer); void be_BLE_reg_adv_cb(void* function, uint8_t *buffer){ if(function == 0){ @@ -193,7 +208,9 @@ BLE.set_chr BLE.set_MAC BLE.run(op, optional: bool response) + be_BLE_op: +# client 1 read 2 write 3 subscribe @@ -205,8 +222,28 @@ be_BLE_op: 13 subscribe once, then disconnect 14 unsubscribe once, then disconnect - maybe later +#server +__commands +201 add/set advertisement +202 add/set scan response + +211 add/set characteristic + +__response +221 onRead +222 onWrite +223 unsubscribed +224 subscribed to notifications +225 subscribed to indications +226 subscribed to notifications and indications +227 onConnect +228 onDisconnect +229 onStatus + + BLE.conn_cb(cb,buffer) BLE.adv_cb(cb,buffer) +BLE.serv_cb(cb,buffer) BLE.adv_watch(MAC) BLE.adv_block(MAC) diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino index b57503b2c..4e188e0b9 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino @@ -163,9 +163,77 @@ class MI32AdvCallbacks: public NimBLEAdvertisedDeviceCallbacks { }; }; +static std::queue BLEmessageQueue; + +class MI32ServerCallbacks: public NimBLEServerCallbacks { + void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { + BLEqueueBuffer_t q; + q.length = 6; + q.type = BLE_OP_ON_CONNECT; + q.buffer = new uint8_t[q.length]; + memcpy(q.buffer,desc->peer_ota_addr.val,6); + BLEmessageQueue.push(q); + MI32.infoMsg = MI32_SERV_CLIENT_CONNECTED; + }; + void onDisconnect(NimBLEServer* pServer) { + BLEqueueBuffer_t q; + q.length = 0; + q.type = BLE_OP_ON_DISCONNECT; + memset(MI32.conCtx->MAC,0,6); + BLEmessageQueue.push(q); + MI32.infoMsg = MI32_SERV_CLIENT_DISCONNECTED; + NimBLEDevice::startAdvertising(); + }; +}; + +class MI32CharacteristicCallbacks: public NimBLECharacteristicCallbacks { + void onRead(NimBLECharacteristic* pCharacteristic){ + BLEqueueBuffer_t q; + q.length = 0; + q.type = BLE_OP_ON_READ; + q.returnCharUUID = pCharacteristic->getUUID().getNative()->u16.value; + q.handle = pCharacteristic->getHandle(); + BLEmessageQueue.push(q); + }; + + void onWrite(NimBLECharacteristic* pCharacteristic) { + BLEqueueBuffer_t q; + q.type = BLE_OP_ON_WRITE; + q.returnCharUUID = pCharacteristic->getUUID().getNative()->u16.value; + q.handle = pCharacteristic->getHandle(); + q.length = pCharacteristic->getDataLength(); + q.buffer = new uint8_t[q.length]; + memcpy(q.buffer,pCharacteristic->getValue(),pCharacteristic->getDataLength()); + BLEmessageQueue.push(q); + }; + + /** The status returned in status is defined in NimBLECharacteristic.h. + * The value returned in code is the NimBLE host return code. + */ + void onStatus(NimBLECharacteristic* pCharacteristic, Status status, int code) { + BLEqueueBuffer_t q; + q.length = 0; + q.type = BLE_OP_ON_STATUS; + q.returnCharUUID = pCharacteristic->getUUID().getNative()->u16.value; + q.handle = pCharacteristic->getHandle(); + q.value = code; + BLEmessageQueue.push(q); + }; + + void onSubscribe(NimBLECharacteristic* pCharacteristic, ble_gap_conn_desc* desc, uint16_t subValue) { + BLEqueueBuffer_t q; + q.length = 0; + q.type = BLE_OP_ON_UNSUBSCRIBE + subValue; + q.returnCharUUID = pCharacteristic->getUUID().getNative()->u16.value; + q.handle = pCharacteristic->getHandle(); + BLEmessageQueue.push(q); + }; +}; + static MI32AdvCallbacks MI32ScanCallbacks; static MI32SensorCallback MI32SensorCB; +static MI32CharacteristicCallbacks MI32ChrCallback; static NimBLEClient* MI32Client; static std::queue MI32NotificationQueue; @@ -653,8 +721,9 @@ void MI32Init(void) { if (!MI32.mode.init) { NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE); NimBLEDevice::setScanDuplicateCacheSize(40); // will not be perfect for every situation (few vs many BLE devices nearby) - NimBLEDevice::init(""); - AddLog(LOG_LEVEL_INFO,PSTR("M32: Init BLE device")); + const std::string name(TasmotaGlobal.hostname); + NimBLEDevice::init(name); + AddLog(LOG_LEVEL_INFO,PSTR("M32: Init BLE device: %s"),TasmotaGlobal.hostname); MI32.mode.init = 1; MI32.mode.readyForNextConnJob = 1; MI32StartTask(MI32_TASK_SCAN); // Let's get started !! @@ -672,21 +741,41 @@ void MI32Init(void) { \*********************************************************************************************/ extern "C" { + bool MI32checkBLEinitialization(){ + return (MI32.mode.init && Settings->flag5.mi32_enable); + } + + bool MI32runBerryServer(uint16_t operation, bool response){ + 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; + AddLog(LOG_LEVEL_DEBUG,PSTR("M32: old server job not finished yet!!")); + return false; + } + MI32.mode.triggerNextServerJob = 1; + return true; + } + bool MI32runBerryConnection(uint8_t operation, bool response){ if(MI32.conCtx != nullptr){ + if(operation > 200){ + return MI32runBerryServer(operation,response); + } MI32.conCtx->oneOp = (operation > 9); MI32.conCtx->operation = operation%10; MI32.conCtx->response = response; - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Berry connection op: %d, addrType: %d, oneOp: %u, response: %u"),MI32.conCtx->operation, MI32.conCtx->addrType, MI32.conCtx->oneOp, MI32.conCtx->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(); } else{ if(MI32.mode.connected){ - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: continue connection job")); + AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: continue connection job")); MI32.mode.triggerNextConnJob = 1; if(!MI32.mode.readyForNextConnJob){ - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: old connection job not finished yet!!")); + AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: old connection job not finished yet!!")); } } else{ @@ -704,7 +793,24 @@ extern "C" { } MI32.conCtx->buffer = buffer; MI32.beConnCB = function; - AddLog(LOG_LEVEL_INFO,PSTR("M32: Connection Ctx created")); + AddLog(LOG_LEVEL_INFO,PSTR("BLE: Connection Ctx created")); + } + + void MI32setBerryServerCB(void* function, uint8_t *buffer){ + if(function == nullptr || buffer == nullptr) + { + MI32.mode.deleteServerTask = 1; + MI32.beServerCB = nullptr; + AddLog(LOG_LEVEL_INFO,PSTR("BLE: Server session stopping")); + return; + } + if(MI32.conCtx == nullptr){ + MI32.conCtx = new MI32connectionContextBerry_t; + } + MI32.conCtx->buffer = buffer; + MI32.beServerCB = function; + MI32StartTask(MI32_TASK_SERV); + AddLog(LOG_LEVEL_INFO,PSTR("BLE: Server Ctx created")); } bool MI32setBerryCtxSvc(const char *Svc, bool discoverAttributes){ @@ -723,7 +829,7 @@ extern "C" { AddLog(LOG_LEVEL_DEBUG,PSTR("M32: CHR: %s"),MI32.conCtx->charUUID.toString().c_str()); uint16_t _uuid = MI32.conCtx->charUUID.getNative()->u16.value; //if not "notify op" -> present requested characteristic as return UUID MI32.conCtx->returnCharUUID = _uuid; - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: return UUID: %04x"),MI32.conCtx->returnCharUUID); + AddLog(LOG_LEVEL_DEBUG,PSTR("M32: return 16-bit UUID: %04x"),MI32.conCtx->returnCharUUID); return true; } return false; @@ -846,7 +952,7 @@ extern "C" { case 5: //HAP_EVENT_PAIRING_STARTED MI32suspendScanTask(); default: - vTaskResume(MI32.ScanTask); + MI32resumeScanTask(); } if(event==4){ MI32.HKinfoMsg = MI32_HAP_CONTROLLER_DISCONNECTED; @@ -1042,7 +1148,11 @@ void MI32saveConfig(){ \*********************************************************************************************/ void MI32suspendScanTask(void){ - if (MI32.ScanTask != nullptr) vTaskSuspend(MI32.ScanTask); + if (MI32.ScanTask != nullptr && MI32.mode.runningScan == 1) vTaskSuspend(MI32.ScanTask); +} + +void MI32resumeScanTask(void){ + if (MI32.ScanTask != nullptr && MI32.mode.runningScan == 1) vTaskResume(MI32.ScanTask); } void MI32StartTask(uint32_t task){ @@ -1057,15 +1167,22 @@ void MI32StartTask(uint32_t task){ MI32.mode.deleteScanTask = 1; MI32StartConnectionTask(); break; + case MI32_TASK_SERV: + MI32.mode.deleteScanTask = 1; + MI32StartServerTask(); + break; default: break; } } +// Scan task section + void MI32StartScanTask(){ - if (MI32.mode.connected) return; + if (MI32.mode.connected == 1) return; if(MI32.ScanTask!=nullptr) vTaskDelete(MI32.ScanTask); MI32.mode.runningScan = 1; + MI32.mode.deleteScanTask = 0; xTaskCreatePinnedToCore( MI32ScanTask, /* Function to implement the task */ "MI32ScanTask", /* Name of the task */ @@ -1098,13 +1215,14 @@ void MI32ScanTask(void *pvParameters){ uint32_t timer = 0; for(;;){ - vTaskDelay(1000/ portTICK_PERIOD_MS); - if(MI32.mode.deleteScanTask){ + vTaskDelay(100/ portTICK_PERIOD_MS); + if(MI32.mode.deleteScanTask == 1){ MI32Scan->stop(); MI32.mode.runningScan = 0; + MI32.ScanTask = nullptr; break; } - if(MI32.mode.updateScan){ + if(MI32.mode.updateScan == 1){ MI32Scan->stop(); MI32Scan->setActiveScan(MI32.option.activeScan == 1); MI32Scan->start(0,true); @@ -1115,6 +1233,8 @@ void MI32ScanTask(void *pvParameters){ vTaskDelete( NULL ); } +// connection task section + bool MI32ConnectActiveSensor(){ // only use inside a task !! if(MI32.conCtx->operation == 5) { return false; @@ -1307,6 +1427,144 @@ void MI32ConnectionTask(void *pvParameters){ vTaskDelete( NULL ); } +// server task section + +bool MI32StartServerTask(){ + AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: Server task ... start")); + MI32NotificationQueue = {}; + xTaskCreatePinnedToCore( + MI32ServerTask, /* Function to implement the task */ + "MI32ServerTask", /* Name of the task */ + 8192, /* Stack size in words */ + NULL, /* Task input parameter */ + 2, /* Priority of the task */ + &MI32.ServerTask, /* Task handle. */ + 0); /* Core where the task should run */ + return true; +} + +void MI32ServerSetAdv(NimBLEServer *pServer, std::vector& servicesToStart, bool &shallStartServices); +void MI32ServerSetAdv(NimBLEServer *pServer, std::vector& servicesToStart, bool &shallStartServices){ + NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); + BLEqueueBuffer_t q; + q.length = 0; + if(shallStartServices && MI32.conCtx->operation == BLE_OP_SET_ADV){ + q.buffer = new uint8_t[256]; + for (auto & pService : servicesToStart) { + pService->start(); + } + shallStartServices = false; // only do this at the first run + if(servicesToStart.size() != 0){ + pServer->start(); // only start server when svc and chr do exist + uint32_t idx = 0; + for (auto & pService : servicesToStart) { + std::vector characteristics = pService->getCharacteristics(); + for (auto & pCharacteristic : characteristics) { + uint16_t handle = pCharacteristic->getHandle(); // now we have handles, so pass them to Berry + q.buffer[idx] = (uint8_t)handle>>8; + q.buffer[idx+1] = (uint8_t)handle&0xff; + if (idx > 254) break; // limit to 127 characteristics + idx += 2; + } + } + q.length = idx; + } + servicesToStart.clear(); // release vector + } + NimBLEAdvertisementData adv; + 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(); + } else + { + pAdvertising->setScanResponseData(adv); + pAdvertising->setScanResponse(true); + } + + MI32.infoMsg = MI32_SERV_SCANRESPONSE_ADDED + (MI32.conCtx->operation - BLE_OP_SET_SCAN_RESP); // .. ADV or SCAN RESPONSE + q.type = MI32.conCtx->operation; + q.returnCharUUID = 0; // does not matter + q.handle = 0; //dito + BLEmessageQueue.push(q); +} + +void MI32ServerSetCharacteristic(NimBLEServer *pServer, std::vector& servicesToStart, bool &shallStartServices); +void MI32ServerSetCharacteristic(NimBLEServer *pServer, std::vector& servicesToStart, bool &shallStartServices){ + MI32.conCtx->error = MI32_CONN_NO_ERROR; + NimBLEService *pService = pServer->getServiceByUUID(MI32.conCtx->serviceUUID); // retrieve ... + if(pService == nullptr){ + pService = pServer->createService(MI32.conCtx->serviceUUID); //... or create service. + if(pService == nullptr){ + MI32.conCtx->error = MI32_CONN_NO_SERVICE; + return; + } + + if(shallStartServices){ + servicesToStart.push_back(pService); + } + } + NimBLECharacteristic *pCharacteristic = pService->getCharacteristic(MI32.conCtx->charUUID); // again retrieve ... + if(pCharacteristic == nullptr){ + uint32_t _writeRSP = MI32.conCtx->response ? NIMBLE_PROPERTY::WRITE : NIMBLE_PROPERTY::WRITE_NR; + pCharacteristic = pService->createCharacteristic(MI32.conCtx->charUUID, + NIMBLE_PROPERTY::READ | + _writeRSP | + NIMBLE_PROPERTY::NOTIFY | + NIMBLE_PROPERTY::INDICATE); //... or create characteristic. + if(pCharacteristic == nullptr){ + MI32.conCtx->error = MI32_CONN_NO_CHARACTERISTIC; + return; + } + pCharacteristic->setCallbacks(&MI32ChrCallback); + MI32.infoMsg = MI32_SERV_CHARACTERISTIC_ADDED; + } + pCharacteristic->setValue(MI32.conCtx->buffer + 1, MI32.conCtx->buffer[0]); // set value + pCharacteristic->notify(true); // always notify .. for now + BLEqueueBuffer_t q; + q.length = 0; + q.type = BLE_OP_SET_CHARACTERISTIC; + q.returnCharUUID = pCharacteristic->getUUID().getNative()->u16.value; + q.handle = pCharacteristic->getHandle(); // this returns "-1", no valid handle yet :( + BLEmessageQueue.push(q); +} + +void MI32ServerTask(void *pvParameters){ + MI32.conCtx->error = MI32_CONN_NO_ERROR; + NimBLEServer *pServer = NimBLEDevice::createServer(); + pServer->setCallbacks(new MI32ServerCallbacks()); + MI32.mode.readyForNextServerJob = 1; + MI32.mode.deleteServerTask = 0; + std::vector servicesToStart; + bool shallStartServices = true; //will start service at the first call MI32ServerSetAdv() + + for(;;){ + while(MI32.mode.triggerNextServerJob == 0){ + if(MI32.mode.deleteServerTask == 1){ + delete MI32.conCtx; + MI32.conCtx = nullptr; + pServer->stopAdvertising(); + MI32StartTask(MI32_TASK_SCAN); + vTaskDelete( NULL ); + } + vTaskDelay(50/ portTICK_PERIOD_MS); + } + MI32.mode.readyForNextServerJob = 0; + switch(MI32.conCtx->operation){ + case BLE_OP_SET_ADV: case BLE_OP_SET_SCAN_RESP: + MI32ServerSetAdv(pServer, servicesToStart, shallStartServices); + break; + case BLE_OP_SET_CHARACTERISTIC: + MI32ServerSetCharacteristic(pServer, servicesToStart, shallStartServices); + break; + } + + MI32.mode.triggerNextServerJob = 0; + MI32.mode.readyForNextServerJob = 1; + MI32.mode.triggerBerryServerCB = 1; + } +} + /*********************************************************************************************\ * parse the response from advertisements \*********************************************************************************************/ @@ -1720,6 +1978,28 @@ void MI32Every50mSecond(){ } MI32.mode.triggerBerryConnCB = 0; } + + if(!BLEmessageQueue.empty()){ + BLEqueueBuffer_t q = BLEmessageQueue.front(); + BLEmessageQueue.pop(); + MI32.conCtx->returnCharUUID = q.returnCharUUID; + MI32.conCtx->handle = q.handle; + MI32.conCtx->operation = q.type; + MI32.conCtx->error = 0; + if(q.length != 0){ + MI32.conCtx->buffer[0] = q.length; + memcpy(MI32.conCtx->buffer + 1,q.buffer,q.length); + delete q.buffer; + } + if(MI32.beServerCB != nullptr){ + void (*func_ptr)(int, int, int, int) = (void (*)(int, int, int, int))MI32.beServerCB; + char _message[32]; + GetTextIndexed(_message, sizeof(_message), MI32.conCtx->error, kMI32_ConnErrorMsg); + AddLog(LOG_LEVEL_DEBUG,PSTR("M32: BryCbMsg: %s"),_message); + func_ptr(MI32.conCtx->error, MI32.conCtx->operation , MI32.conCtx->returnCharUUID, MI32.conCtx->handle); + } + } + if(MI32.infoMsg > 0){ char _message[32]; GetTextIndexed(_message, sizeof(_message), MI32.infoMsg-1, kMI32_BLEInfoMsg); @@ -2057,7 +2337,7 @@ void MI32InitGUI(void){ WSContentSend_P(PSTR("")); WSContentSpaceButton(BUTTON_MAIN); WSContentStop(); - vTaskResume(MI32.ScanTask); + MI32resumeScanTask(); } void MI32HandleWebGUI(void){ @@ -2246,7 +2526,7 @@ void MI32Show(bool json) MI32addHistory(MI32.energy_history,Energy->active_power[0],100); //TODO: which value?? #endif //USE_MI_ESP32_ENERGY #endif //USE_MI_EXT_GUI - vTaskResume(MI32.ScanTask); + MI32resumeScanTask(); #ifdef USE_WEBSERVER } else { MI32suspendScanTask(); @@ -2309,7 +2589,7 @@ void MI32Show(bool json) #endif //USE_MI_EXT_GUI #endif // USE_WEBSERVER } - vTaskResume(MI32.ScanTask); + MI32resumeScanTask(); } int ExtStopBLE(){