diff --git a/src/ESPUIclient.cpp b/src/ESPUIclient.cpp index 0becacf..a6bf8b9 100644 --- a/src/ESPUIclient.cpp +++ b/src/ESPUIclient.cpp @@ -79,7 +79,7 @@ void ESPUIclient::FillInHeader(JsonDocument& document) document[F("type")] = UI_EXTEND_GUI; document[F("sliderContinuous")] = ESPUI.sliderContinuous; document[F("startindex")] = 0; - document[F("totalcontrols")] = ESPUI.controlCount; + document[F("totalcontrols")] = ESPUIcontrolMgr.GetControlCount(); JsonArray items = AllocateJsonArray(document, F("controls")); JsonObject titleItem = AllocateJsonObject(items); titleItem[F("type")] = (int)UI_TITLE; @@ -253,213 +253,6 @@ bool ESPUIclient::onWsEvent(AwsEventType type, void* arg, uint8_t* data, size_t return Response; } -/* -Prepare a chunk of elements as a single JSON string. If the allowed number of elements is greater than the total -number this will represent the entire UI. More likely, it will represent a small section of the UI to be sent. The -client will acknowledge receipt by requesting the next chunk. - */ -uint32_t ESPUIclient::prepareJSONChunk(uint16_t startindex, - JsonDocument & rootDoc, - bool InUpdateMode, - String FragmentRequestString) -{ -#ifdef ESP32 - xSemaphoreTake(ESPUI.ControlsSemaphore, portMAX_DELAY); -#endif // def ESP32 - - // Serial.println(String("prepareJSONChunk: Start. InUpdateMode: ") + String(InUpdateMode)); - // Serial.println(String("prepareJSONChunk: Start. startindex: ") + String(startindex)); - // Serial.println(String("prepareJSONChunk: Start. FragmentRequestString: '") + FragmentRequestString + "'"); - int elementcount = 0; - uint32_t MaxMarshaledJsonSize = (!InUpdateMode) ? ESPUI.jsonInitialDocumentSize: ESPUI.jsonUpdateDocumentSize; - uint32_t EstimatedUsedMarshaledJsonSize = 0; - - do // once - { - // Follow the list until control points to the startindex'th node - Control* control = ESPUI.controls; - uint32_t currentIndex = 0; - uint32_t DataOffset = 0; - JsonArray items = rootDoc[F("controls")]; - bool SingleControl = false; - - if(!emptyString.equals(FragmentRequestString)) - { - // Serial.println(F("prepareJSONChunk:Fragmentation:Got Header (1)")); - // Serial.println(String("prepareJSONChunk:startindex: ") + String(startindex)); - // Serial.println(String("prepareJSONChunk:currentIndex: ") + String(currentIndex)); - // Serial.println(String("prepareJSONChunk:FragmentRequestString: '") + FragmentRequestString + "'"); - - // this is actually a fragment or directed update request - // parse the string we got from the UI and try to update that specific - // control. - AllocateJsonDocument(FragmentRequest, FragmentRequestString.length() * 3); -/* - ArduinoJson::detail::sizeofObject(N); - if(0 >= FragmentRequest.capacity()) - { - Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Could not allocate memory for a fragmentation request. Skipping Response")); - break; - } -*/ - size_t FragmentRequestStartOffset = FragmentRequestString.indexOf("{"); - DeserializationError error = deserializeJson(FragmentRequest, FragmentRequestString.substring(FragmentRequestStartOffset)); - if(DeserializationError::Ok != error) - { - Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Could not extract json from the fragment request")); - break; - } - - if(!FragmentRequest.containsKey(F("id"))) - { - Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Request does not contain a control ID")); - break; - } - uint16_t ControlId = uint16_t(FragmentRequest[F("id")]); - - if(!FragmentRequest.containsKey(F("offset"))) - { - Serial.println(F("ERROR:prepareJSONChunk:Fragmentation:Request does not contain a starting offset")); - break; - } - DataOffset = uint16_t(FragmentRequest[F("offset")]); - control = ESPUI.getControlNoLock(ControlId); - if(nullptr == control) - { - Serial.println(String(F("ERROR:prepareJSONChunk:Fragmentation:Requested control: ")) + String(ControlId) + F(" does not exist")); - break; - } - - // Serial.println(F("prepareJSONChunk:Fragmentation:disable the control search operation")); - currentIndex = 1; - startindex = 0; - SingleControl = true; - } - - // find a control to send - while ((startindex > currentIndex) && (nullptr != control)) - { - // only count active controls - if (!control->ToBeDeleted()) - { - if(InUpdateMode) - { - // In update mode we only count the controls that have been updated. - if(control->NeedsSync(CurrentSyncID)) - { - ++currentIndex; - } - } - else - { - // not in update mode. Count all active controls - ++currentIndex; - } - } - control = control->next; - } - - // any controls left to be processed? - if(nullptr == control) - { - // Serial.println("prepareJSONChunk: No controls to process"); - break; - } - - // keep track of the number of elements we have serialised into this - // message. Overflow is detected and handled later in this loop - // and needs an index to the last item added. - while (nullptr != control) - { - // skip deleted controls or controls that have not been updated - if (control->ToBeDeleted() && !SingleControl) - { - // Serial.println(String("prepareJSONChunk: Ignoring Deleted control: ") + String(control->id)); - control = control->next; - continue; - } - - if(InUpdateMode && !SingleControl) - { - if(control->NeedsSync(CurrentSyncID)) - { - // dont skip this control - } - else - { - // control has not been updated. Skip it - control = control->next; - continue; - } - } - - // Serial.println(String(F("prepareJSONChunk: MaxMarshaledJsonSize: ")) + String(MaxMarshaledJsonSize)); - // Serial.println(String(F("prepareJSONChunk: Cur EstimatedUsedMarshaledJsonSize: ")) + String(EstimatedUsedMarshaledJsonSize)); - - JsonObject item = AllocateJsonObject(items); - elementcount++; - uint32_t RemainingSpace = (MaxMarshaledJsonSize - EstimatedUsedMarshaledJsonSize) - 100; - // Serial.println(String(F("prepareJSONChunk: RemainingSpace: ")) + String(RemainingSpace)); - uint32_t SpaceUsedByMarshaledControl = 0; - bool ControlIsFragmented = control->MarshalControl(item, - InUpdateMode, - DataOffset, - RemainingSpace, - SpaceUsedByMarshaledControl); - // Serial.println(String(F("prepareJSONChunk: SpaceUsedByMarshaledControl: ")) + String(SpaceUsedByMarshaledControl)); - EstimatedUsedMarshaledJsonSize += SpaceUsedByMarshaledControl; - // Serial.println(String(F("prepareJSONChunk: New EstimatedUsedMarshaledJsonSize: ")) + String(EstimatedUsedMarshaledJsonSize)); - // Serial.println(String(F("prepareJSONChunk: ControlIsFragmented: ")) + String(ControlIsFragmented)); - - // did the control get added to the doc? - if (0 == SpaceUsedByMarshaledControl || - (ESPUI.jsonChunkNumberMax > 0 && (elementcount % ESPUI.jsonChunkNumberMax) == 0)) - { - // Serial.println( String("prepareJSONChunk: too much data in the message. Remove the last entry")); - if (1 == elementcount) - { - // Serial.println(String(F("prepareJSONChunk: Control ")) + String(control->id) + F(" is too large to be sent to the browser.")); - // Serial.println(String(F("ERROR: prepareJSONChunk: value: ")) + control->value); - rootDoc.clear(); - item = AllocateJsonObject(items); - control->MarshalErrorMessage(item); - elementcount = 0; - } - else - { - // Serial.println(String("prepareJSONChunk: Defering control: ") + String(control->id)); - // Serial.println(String("prepareJSONChunk: elementcount: ") + String(elementcount)); - - items.remove(elementcount); - --elementcount; - } - // exit the loop - control = nullptr; - } - else if ((SingleControl) || - (ControlIsFragmented) || - (MaxMarshaledJsonSize < (EstimatedUsedMarshaledJsonSize + 100))) - { - // Serial.println("prepareJSONChunk: Doc is Full, Fragmented Control or Single Control. exit loop"); - control = nullptr; - } - else - { - // Serial.println("prepareJSONChunk: Next Control"); - control = control->next; - } - } // end while (control != nullptr) - - } while (false); - -#ifdef ESP32 - xSemaphoreGive(ESPUI.ControlsSemaphore); -#endif // def ESP32 - - // Serial.println(String("prepareJSONChunk: END: elementcount: ") + String(elementcount)); - return elementcount; -} - /* Convert & Transfer Arduino elements to JSON elements. This function sends a chunk of JSON describing the controls of the UI, starting from the control at index startidx. @@ -492,7 +285,7 @@ bool ESPUIclient::SendControlsToClient(uint16_t startidx, ClientUpdateType_t Tra break; } - else if ((startidx >= ESPUI.controlCount) && (emptyString.equals(FragmentRequest))) + else if ((startidx >= ESPUIcontrolMgr.GetControlCount()) && (emptyString.equals(FragmentRequest))) { // Serial.println(F("ERROR:ESPUIclient:SendControlsToClient: No more controls to send.")); Response = true; @@ -514,7 +307,7 @@ bool ESPUIclient::SendControlsToClient(uint16_t startidx, ClientUpdateType_t Tra // Serial.println(String("ESPUIclient:SendControlsToClient:type: ") + String((uint32_t)document["type"])); // Serial.println("ESPUIclient:SendControlsToClient: Build Controls."); - if(prepareJSONChunk(startidx, document, ClientUpdateType_t::UpdateNeeded == TransferMode, FragmentRequest)) + if(ESPUIcontrolMgr.prepareJSONChunk(startidx, document, ClientUpdateType_t::UpdateNeeded == TransferMode, FragmentRequest, CurrentSyncID)) { #if defined(DEBUG_ESPUI) if (ESPUI.verbosity >= Verbosity::VerboseJSON) diff --git a/src/ESPUIclient.h b/src/ESPUIclient.h index b013f5e..34deb14 100644 --- a/src/ESPUIclient.h +++ b/src/ESPUIclient.h @@ -44,7 +44,6 @@ protected: bool CanSend(); void FillInHeader(ArduinoJson::JsonDocument& document); - uint32_t prepareJSONChunk(uint16_t startindex, JsonDocument& rootDoc, bool InUpdateMode, String value); bool SendControlsToClient(uint16_t startidx, ClientUpdateType_t TransferMode, String FragmentRequest); bool SendClientNotification(ClientUpdateType_t value);