diff --git a/tasmota/include/xsns_62_esp32_mi.h b/tasmota/include/xsns_62_esp32_mi.h index 87cf390ab..9e3f41f36 100644 --- a/tasmota/include/xsns_62_esp32_mi.h +++ b/tasmota/include/xsns_62_esp32_mi.h @@ -252,7 +252,7 @@ struct { void *beConnCB; void *beAdvCB; uint8_t *beAdvBuf; - uint8_t infoMsg = 0; + uint16_t queueDrops = 0; uint8_t role = 0; // bitfield of MI32Role values (concurrently active roles) } MI32; @@ -407,10 +407,6 @@ const uint16_t kMI32DeviceID[MI32_TYPES]={ 0x0098, // Flora const char kMI32DeviceType[] PROGMEM = {"Flora|MJ_HT_V1|LYWSD02|LYWSD03|CGG1|CGD1|NLIGHT|MJYD2S|YLYK01|MHOC401|MHOC303|ATC|MCCGQ02|SJWS01L|PVVX|YLKG08|YLAI003|BTHOME"}; -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|Server characteristic set|Server advertisement set|Server scan response set|Server client did connect|Server client did disconnect| Server client did authenticate"; - const char kMI32_ButtonMsg[] PROGMEM = "Single|Double|Hold"; //mapping: in Tasmota: 1,2,3 ; for HomeKit and Xiaomi 0,1,2 /*********************************************************************************************\ * enumerations @@ -475,22 +471,6 @@ enum MI32Role : uint8_t { MI32_ROLE_ADVERTISER = 0x08, }; -enum MI32_BLEInfoMsg { - MI32_SCAN_ENDED = 1, - MI32_GOT_NOTIFICATION, - MI32_DID_CONNECT, - MI32_DID_DISCONNECT, - MI32_STILL_CONNECTED, - MI32_START_SCANNING_PASSIVE, - MI32_START_SCANNING_ACTIVE, - MI32_SERV_CHARACTERISTIC_ADDED, - MI32_SERV_ADVERTISEMENT_ADDED, - MI32_SERV_SCANRESPONSE_ADDED, - MI32_SERV_CLIENT_CONNECTED, - MI32_SERV_CLIENT_DISCONNECTED, - MI32_SERV_CLIENT_AUTHENTICATED -}; - /*********************************************************************************************\ * extended web gui \*********************************************************************************************/ @@ -509,8 +489,6 @@ const char HTTP_BTN_MENU_MI32[] PROGMEM = "

‌%s" 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 7180cdf9f..5177fc05f 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_MI32.ino @@ -274,10 +274,19 @@ int be_BLE_run(bvm *vm) { int32_t be_BLE_info(struct bvm *vm); int32_t be_BLE_info(struct bvm *vm) { be_newobject(vm, "map"); - char _Role[16]; - GetTextIndexed(_Role, sizeof(_Role), MI32.role, HTTP_MI32_PARENT_BLE_ROLE); - char _role[16]; - LowerCase(_role,_Role); + be_map_insert_int(vm, "role_bits", MI32.role); + char _role[40] = ""; + if(MI32.role == MI32_ROLE_NONE){ + strcpy(_role, "none"); + } else { + const char *roleNames[] = { "scanner", "client", "server", "advertiser" }; + for(uint32_t i = 0; i < 4; i++){ + if(MI32.role & (1 << i)){ + if(_role[0]) strlcat(_role, "+", sizeof(_role)); + strlcat(_role, roleNames[i], sizeof(_role)); + } + } + } be_map_insert_str(vm, "role", _role); be_map_insert_str(vm, "local_addr", NimBLEDevice::toString().c_str()); be_map_insert_int(vm, "power", NimBLEDevice::getPower()); @@ -292,6 +301,20 @@ int be_BLE_run(bvm *vm) { // #else // be_map_insert_nil(vm, "bonds"); // #endif + + be_pushstring(vm, "debug"); + be_newobject(vm, "map"); + be_map_insert_bool(vm, "ready", MI32.ConnTask != nullptr && MI32.mode.readyForNextJob); + be_map_insert_bool(vm, "pending", MI32.mode.triggerNextJob || MI32.mode.triggerBerryConnCB || + MI32.mode.triggerBerryAdvCB || (MI32.ConnTask != nullptr && !MI32.mode.readyForNextJob)); + // The context keeps the most recently staged operation/result until reused. + be_map_insert_int(vm, "operation", MI32.conCtx ? MI32.conCtx->operation : 0); + be_map_insert_int(vm, "error", MI32.conCtx ? MI32.conCtx->error : 0); + be_map_insert_int(vm, "queue_drops", __atomic_load_n(&MI32.queueDrops, __ATOMIC_RELAXED)); + be_pop(vm, 1); + be_data_insert(vm, -3); + be_pop(vm, 2); + NimBLEClient* _serverPeer = MI32.conCtx ? MI32.conCtx->serverPeer : nullptr; if(MI32.mode.connected == 1 || _serverPeer != nullptr){ NimBLEClient* _device = nullptr; diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino index 754c0bff7..6fe4cd9c5 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino @@ -56,6 +56,7 @@ void MI32ConnectionTask(void *pvParameters); static void MI32EnsureServerInstance(NimBLEServer *&pServer); static void MI32RunClientOp(); static bool MI32SetSubscription(NimBLERemoteCharacteristic *pChr, bool subscribe, bool response); +static void MI32QueueSend(const void *item, size_t size, TickType_t wait); std::vector MIBLEsensors; RingbufHandle_t BLERingBufferQueue = nullptr; @@ -64,6 +65,13 @@ static std::atomic MI32ReadingDone{false}; static BLEScan* MI32Scan; static NimBLEClient* MI32Client; +static void MI32QueueSend(const void *item, size_t size, TickType_t wait){ + if(BLERingBufferQueue == nullptr || + xRingbufferSend(BLERingBufferQueue, item, size, wait) != pdTRUE){ + __atomic_add_fetch(&MI32.queueDrops, 1, __ATOMIC_RELAXED); + } +} + /*********************************************************************************************\ * BLE Callback Classes \*********************************************************************************************/ @@ -74,7 +82,6 @@ class MI32SensorCallback : public NimBLEClientCallbacks { MI32.connID = pclient->getConnHandle(); return; } - MI32.infoMsg = MI32_DID_CONNECT; MI32.mode.willConnect = 0; MI32.mode.connected = 1; MI32.connID = pclient->getConnHandle(); @@ -86,7 +93,6 @@ class MI32SensorCallback : public NimBLEClientCallbacks { } MI32.mode.connected = 0; MI32.role &= ~MI32_ROLE_CLIENT; - MI32.infoMsg = MI32_DID_DISCONNECT; MI32.conCtx->error = reason; MI32.conCtx->operation = 5; //set for all disconnects that come from the remote device or connection loss MI32.mode.triggerBerryConnCB = 1; @@ -99,7 +105,6 @@ class MI32SensorCallback : public NimBLEClientCallbacks { class MI32AdvCallbacks: public NimBLEScanCallbacks { void onScanEnd(const NimBLEScanResults &results, int reason) { - MI32.infoMsg = MI32_SCAN_ENDED; MI32.mode.runningScan = 0; MI32.mode.deleteScanTask = 1; // if scan ended dew to a BLE controller error, make sure we stop the task } @@ -167,8 +172,8 @@ class MI32ServerCallbacks: public NimBLEServerCallbacks { item.header.returnCharUUID = 0; item.header.handle = 0; memcpy(item.buffer,connInfo.getAddress().getVal(),6); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + 6 , pdMS_TO_TICKS(1)); - MI32.infoMsg = MI32_SERV_CLIENT_CONNECTED; + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t) + 6, pdMS_TO_TICKS(1)); + MI32.role &= ~MI32_ROLE_ADVERTISER; if(MI32.conCtx == nullptr) return; MI32.conCtx->serverPeer = pServer->getClient(connInfo); // Singleton - do NOT delete via NimBLEDevice::deleteClient. if(MI32.conCtx->itvl_min != 0 && MI32.conCtx->itvl_max != 0){ @@ -183,17 +188,16 @@ class MI32ServerCallbacks: public NimBLEServerCallbacks { item.header.type = BLE_OP_ON_DISCONNECT; item.header.returnCharUUID = 0; item.header.handle = 0; - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); - MI32.infoMsg = MI32_SERV_CLIENT_DISCONNECTED; + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); if(MI32.conCtx == nullptr) return; memset(MI32.conCtx->MAC,0,6); // Reverse-role client cleanup: pServer owns the singleton, just drop our // borrowed pointer. Never call NimBLEDevice::deleteClient on it. MI32.conCtx->serverPeer = nullptr; #ifdef CONFIG_BT_NIMBLE_EXT_ADV - NimBLEDevice::startAdvertising(0); + if(NimBLEDevice::startAdvertising(0)) MI32.role |= MI32_ROLE_ADVERTISER; #else - NimBLEDevice::startAdvertising(); + if(NimBLEDevice::startAdvertising()) MI32.role |= MI32_ROLE_ADVERTISER; #endif }; void onAuthenticationComplete(NimBLEConnInfo& connInfo) { @@ -208,7 +212,6 @@ class MI32ServerCallbacks: public NimBLEServerCallbacks { memset(&peer_security_record, 0, security_record_size); ble_gap_conn_desc connection_desc; if (ble_gap_conn_find(connInfo.getConnHandle(), &connection_desc) != 0) { - MI32.infoMsg = MI32_SERV_CLIENT_AUTHENTICATED; return; } ble_store_key_sec security_key; @@ -222,8 +225,7 @@ class MI32ServerCallbacks: public NimBLEServerCallbacks { item.header.type = BLE_OP_ON_AUTHENTICATED; item.header.returnCharUUID = 0; item.header.handle = 0; - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length, pdMS_TO_TICKS(1)); - MI32.infoMsg = MI32_SERV_CLIENT_AUTHENTICATED; + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length, pdMS_TO_TICKS(1)); } }; @@ -236,7 +238,7 @@ class MI32CharacteristicCallbacks: public NimBLECharacteristicCallbacks { item.header.type = BLE_OP_ON_READ; item.header.returnCharUUID = *reinterpret_cast(pCharacteristic->getUUID().getValue() + 12); item.header.handle = pCharacteristic->getHandle(); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); }; void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) { @@ -253,7 +255,7 @@ class MI32CharacteristicCallbacks: public NimBLECharacteristicCallbacks { item.header.returnCharUUID = *reinterpret_cast(pCharacteristic->getUUID().getValue() + 12); item.header.handle = pCharacteristic->getHandle(); memcpy(item.buffer,pCharacteristic->getValue().data(),valSize); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length , pdMS_TO_TICKS(1)); + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length, pdMS_TO_TICKS(1)); }; /** The status returned in status is defined in NimBLECharacteristic.h. @@ -269,7 +271,7 @@ class MI32CharacteristicCallbacks: public NimBLECharacteristicCallbacks { item.header.returnCharUUID = *reinterpret_cast(pCharacteristic->getUUID().getValue() + 12); item.header.handle = pCharacteristic->getHandle(); memcpy(item.buffer,&code,item.header.length); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length, pdMS_TO_TICKS(1)); + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length, pdMS_TO_TICKS(1)); }; void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue) { @@ -282,7 +284,7 @@ class MI32CharacteristicCallbacks: public NimBLECharacteristicCallbacks { item.header.type = BLE_OP_ON_UNSUBSCRIBE + subValue; item.header.returnCharUUID = *reinterpret_cast(pCharacteristic->getUUID().getValue() + 12); item.header.handle = pCharacteristic->getHandle(); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); }; }; @@ -291,8 +293,6 @@ void MI32notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pD const NimBLEUUID &uuid = pRemoteCharacteristic->getUUID(); const uint8_t *uuidValue = uuid.getValue() + (uuid.bitSize() == BLE_UUID_TYPE_128 ? 12 : 0); const uint16_t uuid16 = *reinterpret_cast(uuidValue); - AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: notifyCB uuid=%04x handle=%u len=%u isNotify=%u"), - uuid16, pRemoteCharacteristic->getHandle(), (unsigned)length, (unsigned)isNotify); struct{ BLERingBufferItem_t header; uint8_t buffer[255]; @@ -303,9 +303,8 @@ void MI32notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pD memcpy(item.buffer,pData,length); item.header.returnCharUUID = uuid16; item.header.handle = pRemoteCharacteristic->getHandle(); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + length , pdMS_TO_TICKS(5)); + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t) + length, pdMS_TO_TICKS(5)); MI32ReadingDone.store(true, std::memory_order_release); - MI32.infoMsg = MI32_GOT_NOTIFICATION; } static bool MI32SetSubscription(NimBLERemoteCharacteristic *pChr, bool subscribe, bool response){ @@ -799,7 +798,6 @@ extern "C" { pAdvertising->stop(); if(MI32.conCtx->addrType > 0){ ble_hs_id_set_rnd(MI32.conCtx->MAC); - AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: set MAC to random")); } NimBLEDevice::setOwnAddrType(MI32.conCtx->addrType); success = true; @@ -812,14 +810,12 @@ extern "C" { pAdvertising->setConnectableMode(MI32.conCtx->buffer[1]); pAdvertising->setMinInterval(MI32.conCtx->itvl_min); pAdvertising->setMaxInterval(MI32.conCtx->itvl_max); - AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: adv params: type: %u, min: %u, max: %u"),MI32.conCtx->buffer[1], (uint16_t)(MI32.conCtx->itvl_min * 0.625), (uint16_t)(MI32.conCtx->itvl_max * 0.625)) ; success = true; } #endif //CONFIG_BT_NIMBLE_EXT_ADV break; case 233: int ret = ble_svc_gap_device_name_set((const char*)MI32.conCtx->buffer + 1); - AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: new gap device name - %s"),(const char*) MI32.conCtx->buffer + 1); success = (ret == 0); break; } @@ -844,7 +840,6 @@ extern "C" { MI32.conCtx->arg1 = arg1; MI32.conCtx->hasArg1 = hasArg1; MI32.conCtx->response = response; - AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: arg1: %u"),MI32.conCtx->arg1); if(operation > 230){ // 231..233: runtime config helpers, executed inline return MI32runBerryConfig(operation); @@ -861,16 +856,10 @@ extern "C" { MI32.conCtx->oneOp = false; } } - AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: Berry op: %d, addrType: %d, oneOp: %u, response: %u"), - MI32.conCtx->operation, MI32.conCtx->addrType, MI32.conCtx->oneOp, MI32.conCtx->response); - if(MI32.ConnTask == nullptr){ AddLog(LOG_LEVEL_ERROR,PSTR("BLE: connection task not running - register conn_cb first")); return false; } - if(MI32.mode.readyForNextJob == 0){ - AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: previous job not finished yet")); - } MI32.mode.triggerNextJob = 1; return true; } @@ -879,14 +868,12 @@ extern "C" { if(function == nullptr || buffer == nullptr){ MI32.beConnCB = nullptr; MI32.mode.deleteConnectionTask = 1; // request task teardown if alive - AddLog(LOG_LEVEL_INFO,PSTR("BLE: Connection callback cleared")); return; } MI32ensureConCtx(buffer); MI32.beConnCB = function; if(MI32.ConnTask != nullptr){ // re-registration: keep the running task, just refresh cb/buffer - AddLog(LOG_LEVEL_INFO,PSTR("BLE: Connection callback re-registered")); return; } if(BLERingBufferQueue == nullptr){ @@ -899,7 +886,7 @@ extern "C" { MI32.mode.readyForNextJob = 0; // task will set to 1 on entry MI32.mode.triggerNextJob = 0; MI32.mode.deleteConnectionTask = 0; - xTaskCreatePinnedToCore( + BaseType_t taskResult = xTaskCreatePinnedToCore( MI32ConnectionTask, /* Function to implement the task */ "MI32ConnectionTask", /* Name of the task */ 8192, /* Stack size in words */ @@ -907,7 +894,10 @@ extern "C" { 2, /* Priority */ &MI32.ConnTask, /* Task handle */ 0); /* Core */ - AddLog(LOG_LEVEL_INFO,PSTR("BLE: Connection task started")); + if(taskResult != pdPASS){ + MI32.ConnTask = nullptr; + AddLog(LOG_LEVEL_ERROR,PSTR("BLE: failed to create connection task")); + } } void MI32setBerryServerCB(void* function, uint8_t *buffer){ //deprecated! @@ -917,7 +907,6 @@ extern "C" { bool MI32setBerryCtxSvc(const char *Svc, bool discoverAttributes){ if(MI32.conCtx != nullptr){ MI32.conCtx->serviceUUID = NimBLEUUID(Svc); - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: SVC: %s"),MI32.conCtx->serviceUUID.toString().c_str()); MI32.mode.discoverAttributes = discoverAttributes; return true; } @@ -927,10 +916,8 @@ extern "C" { bool MI32setBerryCtxChr(const char *Chr){ if(MI32.conCtx != nullptr){ MI32.conCtx->charUUID = NimBLEUUID(Chr).to128(); - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: CHR: %s"),MI32.conCtx->charUUID.toString().c_str()); uint16_t _uuid = *reinterpret_cast(MI32.conCtx->charUUID.getValue() + 12); //if not "notify op" -> present requested characteristic as return UUID MI32.conCtx->returnCharUUID = _uuid; - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: return 16-bit UUID: %04x"),MI32.conCtx->returnCharUUID); return true; } return false; @@ -971,7 +958,6 @@ extern "C" { return false; } } - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: add %s to watchlist of size: %u"),_newAddress.toString().c_str(),NimBLEDevice::getWhiteListCount()); return true; } @@ -1078,28 +1064,36 @@ void MI32loadCfg(){ return; } char * _filebuf = (char*)calloc(_file_size + 1, 1); - if (!_filebuf) { return; } - AddLog(LOG_LEVEL_INFO,PSTR("M32: found config file")); + if (!_filebuf) { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: config allocation failed")); + return; + } if(TfsLoadFile("/mi32cfg",(uint8_t*)_filebuf,_file_size)){ - AddLog(LOG_LEVEL_INFO,PSTR("M32: %s"),_filebuf); JsonParser parser(_filebuf); JsonParserToken root = parser.getRoot(); - if (!root) {AddLog(LOG_LEVEL_INFO,PSTR("M32: invalid root "));} + if (!root) { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: invalid config root")); + free(_filebuf); + return; + } JsonParserArray arr = root.getArray(); - if (!arr) {AddLog(LOG_LEVEL_INFO,PSTR("M32: invalid array object"));; } + if (!arr) { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: config root is not an array")); + free(_filebuf); + return; + } bool _error = true; - int32_t _numberOfDevices = -1; // slot of the last successfully parsed MAC/PID; -1 = none yet + uint32_t _loadedDevices = 0; for (auto _dev : arr) { - AddLog(LOG_LEVEL_INFO,PSTR("M32: found device in config file")); + int32_t _numberOfDevices = -1; JsonParserObject _device = _dev.getObject(); uint8_t _mac[6]; JsonParserToken _val = _device[PSTR("MAC")]; _error = true; if (_val) { char *_macStr = (char *)_val.getStr(); - AddLog(LOG_LEVEL_INFO,PSTR("M32: found MAC: %s"), _macStr); - if(strlen(_macStr)!=12){ - AddLog(LOG_LEVEL_INFO,PSTR("M32: wrong MAC length: %u"), strlen(_macStr)); + if(!_macStr || strlen(_macStr)!=12){ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: invalid config MAC")); break; } MI32HexStringToBytes(_macStr,_mac); @@ -1107,15 +1101,15 @@ void MI32loadCfg(){ if(_val){ uint8_t _pid[2]; char *_pidStr = (char *)_val.getStr(); - AddLog(LOG_LEVEL_INFO,PSTR("M32: found PID: %s"), _pidStr); - if(strlen(_pidStr)!=4){ - AddLog(LOG_LEVEL_INFO,PSTR("M32: wrong PID length: %u"), strlen(_pidStr)); + if(!_pidStr || strlen(_pidStr)!=4){ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: invalid config PID")); break; } MI32HexStringToBytes(_pidStr,_pid); uint16_t _pid16 = _pid[0]*256 + _pid[1]; _numberOfDevices = MIBLEgetSensorSlot(_mac,_pid16,0); if(_numberOfDevices == 0xff){ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: sensor allocation failed")); _error = true; break; } @@ -1123,16 +1117,30 @@ void MI32loadCfg(){ MI32.option.handleEveryDevice = 1; // if in config, we assume to handle it } _error = false; + } else { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: config PID missing")); } + } else { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: config MAC missing")); } // Subsequent fields only valid if MAC+PID parsed successfully above. - if(_numberOfDevices < 0) continue; + if(_numberOfDevices < 0) break; _val = _device[PSTR("key")]; if (_val) { char *_keyStr = (char *)_val.getStr(); + if(!_keyStr){ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: invalid config key")); + _error = true; + break; + } if(strlen(_keyStr)>0){ if(strlen(_keyStr)==32){ uint8_t *_key = (uint8_t*) malloc(16); + if(!_key){ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: key allocation failed")); + _error = true; + break; + } MI32HexStringToBytes(_keyStr,_key); MIBLEsensors[_numberOfDevices].key = _key; if (MIBLEsensors[_numberOfDevices].PID == 0) { // no Xiaomi sensor @@ -1140,6 +1148,7 @@ void MI32loadCfg(){ } } else{ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: invalid config key")); _error = true; break; } @@ -1148,17 +1157,29 @@ void MI32loadCfg(){ _val = _device[PSTR("name")]; if (_val) { char *_name = (char *)_val.getStr(); + if(!_name){ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: invalid config name")); + _error = true; + break; + } MIBLEsensors[_numberOfDevices].name = strdup(_name); - AddLog(LOG_LEVEL_INFO,PSTR("M32: found name: %s"), _name); + if(!MIBLEsensors[_numberOfDevices].name){ + AddLog(LOG_LEVEL_ERROR,PSTR("M32: name allocation failed")); + _error = true; + break; + } } _val = _device[PSTR("feat")]; if (_val) { MIBLEsensors[_numberOfDevices].feature.raw = _val.getUInt(); } + _loadedDevices++; } if(!_error){ - AddLog(LOG_LEVEL_INFO,PSTR("M32: added %u devices from config file"), _numberOfDevices + 1); + AddLog(LOG_LEVEL_INFO,PSTR("M32: loaded %u sensor configurations"), _loadedDevices); } + } else { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: config read failed")); } free(_filebuf); } @@ -1168,7 +1189,10 @@ bool MI32saveConfig(){ const size_t _sensor_count = (MIBLEsensors.size() > MI32_CFG_MAX_SENSORS) ? MI32_CFG_MAX_SENSORS : MIBLEsensors.size(); const size_t _buf_size = 2 + _sensor_count * MI32_CFG_RECORD_SIZE; char * _filebuf = (char*) malloc(_buf_size); - if (!_filebuf) { return false; } + if (!_filebuf) { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: config allocation failed")); + return false; + } _filebuf[0] = '['; size_t _pos = 1; bool _error = false; @@ -1203,10 +1227,11 @@ bool MI32saveConfig(){ if (!_error && _pos>2){ _filebuf[_pos-1] = ']'; _filebuf[_pos] = '\0'; - AddLog(LOG_LEVEL_INFO,PSTR("M32: %s"), _filebuf); _success = TfsSaveFile("/mi32cfg",(uint8_t*)_filebuf,_pos+1); if (_success) { - AddLog(LOG_LEVEL_INFO,PSTR("M32: %u bytes written to config"), _pos+1); + AddLog(LOG_LEVEL_INFO,PSTR("M32: saved %u sensor configurations"), _sensor_count); + } else { + AddLog(LOG_LEVEL_ERROR,PSTR("M32: config save failed")); } } else{ @@ -1279,8 +1304,6 @@ void MI32ScanTask(void *pvParameters){ // MI32Scan->setInterval(30); // MI32Scan->setWindow(25); MI32Scan->start(0, false); // never stop scanning, will pause automatically while connecting - MI32.infoMsg = MI32.option.activeScan?MI32_START_SCANNING_ACTIVE:MI32_START_SCANNING_PASSIVE; - uint32_t timer = 0; for(;;){ vTaskDelay(100/ portTICK_PERIOD_MS); @@ -1294,7 +1317,6 @@ void MI32ScanTask(void *pvParameters){ MI32Scan->setActiveScan(MI32.option.activeScan == 1); MI32Scan->start(0, true); MI32.mode.updateScan = 0; - MI32.infoMsg = MI32.option.activeScan?MI32_START_SCANNING_ACTIVE:MI32_START_SCANNING_PASSIVE; } } MI32.mode.deleteScanTask = 0; @@ -1376,7 +1398,6 @@ static void MI32EnsureServerInstance(NimBLEServer *&pServer){ pServer = NimBLEDevice::createServer(); pServer->setCallbacks(new MI32ServerCallbacks(), true); MI32.role |= MI32_ROLE_SERVER; - AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: server instance created (lazy)")); } /** @@ -1669,6 +1690,7 @@ cleanup: MI32.mode.willConnect = 0; MI32.mode.deleteConnectionTask = 0; MI32.mode.triggerBerryConnCB = 0; + MI32.mode.readyForNextJob = 0; MI32.ConnTask = nullptr; MI32StartTask(MI32_TASK_SCAN); vTaskDelete(NULL); @@ -1756,12 +1778,12 @@ void MI32ServerSetAdv(NimBLEServer *pServer, std::vector& servic pAdvertising->enableScanResponse(true); } #endif //CONFIG_BT_NIMBLE_EXT_ADV + if(MI32.conCtx->operation == BLE_OP_SET_ADV && pAdvertising->isAdvertising()) MI32.role |= MI32_ROLE_ADVERTISER; - MI32.infoMsg = MI32_SERV_SCANRESPONSE_ADDED + (MI32.conCtx->operation - BLE_OP_SET_SCAN_RESP); // .. ADV or SCAN RESPONSE item.header.type = MI32.conCtx->operation; item.header.returnCharUUID = 0; item.header.handle = 0; - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length, pdMS_TO_TICKS(20)); + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t) + item.header.length, pdMS_TO_TICKS(20)); } /** @@ -1803,7 +1825,6 @@ void MI32ServerSetCharacteristic(NimBLEServer *pServer, std::vectorsetCallbacks(&MI32ChrCallback); - MI32.infoMsg = MI32_SERV_CHARACTERISTIC_ADDED; } pCharacteristic->setValue(MI32.conCtx->buffer + 1, MI32.conCtx->buffer[0]); // set value MI32.conCtx->response ? pCharacteristic->indicate() : pCharacteristic->notify(); // use response to select indicate vs notification @@ -1814,7 +1835,7 @@ void MI32ServerSetCharacteristic(NimBLEServer *pServer, std::vector(pCharacteristic->getUUID().getValue() + 12); item.header.handle = pCharacteristic->getHandle(); - xRingbufferSend(BLERingBufferQueue, (const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); + MI32QueueSend((const void*)&item, sizeof(BLERingBufferItem_t), pdMS_TO_TICKS(1)); } /*********************************************************************************************\ @@ -1863,7 +1884,6 @@ if(decryptRet!=0){ // AddLog(LOG_LEVEL_DEBUG,PSTR("%s at slot %u with payload type: %02x"), MI32getDeviceName(_slot),_slot,_payload.type); switch(_payload.type){ case 0x0002: - AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: obj id to pair: %02x"),_payload.objID); // pretty pointless for Tasmota break; case 0x1001: MIBLEsensors[_slot].feature.Btn = 1; @@ -2349,9 +2369,12 @@ void MI32BLELoop() if(MI32.mode.triggerBerryConnCB == 1){ if(MI32.beConnCB != nullptr){ void (*func_ptr)(int, int, int, int) = (void (*)(int, int, int, int))MI32.beConnCB; - char _message[32]; - GetTextIndexed(_message, sizeof(_message), MI32.conCtx->error, kMI32_ConnErrorMsg); - AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: BryCbMsg: %s"),_message); + if(MI32.conCtx->error){ + AddLog(LOG_LEVEL_DEBUG,PSTR("BLE: %s op %u failed %d, uuid %04x, handle %u"), + NimBLEAddress(MI32.conCtx->MAC, MI32.conCtx->addrType).toString().c_str(), + MI32.conCtx->operation, MI32.conCtx->error, + MI32.conCtx->returnCharUUID, MI32.conCtx->handle); + } func_ptr(MI32.conCtx->error, MI32.conCtx->operation , MI32.conCtx->returnCharUUID, MI32.conCtx->handle); } MI32.mode.triggerBerryConnCB = 0; @@ -2380,12 +2403,6 @@ void MI32BLELoop() MI32.mode.triggerBerryConnCB = 1; } } - if(MI32.infoMsg > 0){ - char _message[32]; - GetTextIndexed(_message, sizeof(_message), MI32.infoMsg-1, kMI32_BLEInfoMsg); - AddLog(LOG_LEVEL_DEBUG,PSTR("M32: %s"),_message); - MI32.infoMsg = 0; - } } /** @@ -2433,7 +2450,6 @@ void CmndMi32Key(void) { memmove(keyMAC.buf + 10, keyMAC.buf + 6, 12); const uint8_t _fillbytes[4] = {0x8d,0x3d,0x3c,0x97}; // only valid for YLKG08 and YLKG07 ?? memcpy(keyMAC.buf + 6,_fillbytes,4); - AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*) keyMAC.buf, 16); } MI32AddKey(keyMAC); ResponseCmndDone();