|  | @ -72,6 +72,7 @@ | 
		
	
		
			
				|  |  | #include <ArduinoJson.h>
 |  |  | #include <ArduinoJson.h>
 | 
		
	
		
			
				|  |  | #include <nvsDump.h>
 |  |  | #include <nvsDump.h>
 | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | #include "freertos/ringbuf.h"
 | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | // Serial-logging buffer
 |  |  | // Serial-logging buffer
 | 
		
	
	
		
			
				|  | @ -276,6 +277,7 @@ AsyncEventSource events("/events"); | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | TaskHandle_t mp3Play; |  |  | TaskHandle_t mp3Play; | 
		
	
		
			
				|  |  | TaskHandle_t rfid; |  |  | TaskHandle_t rfid; | 
		
	
		
			
				|  |  |  |  |  | TaskHandle_t fileStorageTaskHandle; | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | #ifdef NEOPIXEL_ENABLE
 |  |  | #ifdef NEOPIXEL_ENABLE
 | 
		
	
		
			
				|  |  |     TaskHandle_t LED; |  |  |     TaskHandle_t LED; | 
		
	
	
		
			
				|  | @ -338,6 +340,8 @@ QueueHandle_t trackQueue; | 
		
	
		
			
				|  |  | QueueHandle_t trackControlQueue; |  |  | QueueHandle_t trackControlQueue; | 
		
	
		
			
				|  |  | QueueHandle_t rfidCardQueue; |  |  | QueueHandle_t rfidCardQueue; | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | RingbufHandle_t explorerFileUploadRingBuffer; | 
		
	
		
			
				|  |  |  |  |  | QueueHandle_t explorerFileUploadStatusQueue; | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | // Prototypes
 |  |  | // Prototypes
 | 
		
	
		
			
				|  |  | void accessPointStart(const char *SSID, IPAddress ip, IPAddress netmask); |  |  | void accessPointStart(const char *SSID, IPAddress ip, IPAddress netmask); | 
		
	
	
		
			
				|  | @ -359,6 +363,7 @@ bool getWifiEnableStatusFromNVS(void); | 
		
	
		
			
				|  |  | void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); |  |  | void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); | 
		
	
		
			
				|  |  | void convertUtf8ToAscii(String utf8String, char *asciiString); |  |  | void convertUtf8ToAscii(String utf8String, char *asciiString); | 
		
	
		
			
				|  |  | void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); |  |  | void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); | 
		
	
		
			
				|  |  |  |  |  | void explorerHandleFileStorageTask(void *parameter); | 
		
	
		
			
				|  |  | void explorerHandleListRequest(AsyncWebServerRequest *request); |  |  | void explorerHandleListRequest(AsyncWebServerRequest *request); | 
		
	
		
			
				|  |  | void explorerHandleDeleteRequest(AsyncWebServerRequest *request); |  |  | void explorerHandleDeleteRequest(AsyncWebServerRequest *request); | 
		
	
		
			
				|  |  | void explorerHandleCreateRequest(AsyncWebServerRequest *request); |  |  | void explorerHandleCreateRequest(AsyncWebServerRequest *request); | 
		
	
	
		
			
				|  | @ -3738,32 +3743,99 @@ void convertUtf8ToAscii(String utf8String, char *asciiString) { | 
		
	
		
			
				|  |  | // Handles file upload request from the explorer
 |  |  | // Handles file upload request from the explorer
 | 
		
	
		
			
				|  |  | // requires a GET parameter path, as directory path to the file
 |  |  | // requires a GET parameter path, as directory path to the file
 | 
		
	
		
			
				|  |  | void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { |  |  | void explorerHandleFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     // New File
 | 
		
	
		
			
				|  |  |     if (!index) { |  |  |     if (!index) { | 
		
	
		
			
				|  |  |  |  |  |         String utf8FilePath; | 
		
	
		
			
				|  |  |  |  |  |         static char asciiFilePath[256]; | 
		
	
		
			
				|  |  |         if (request->hasParam("path")) { |  |  |         if (request->hasParam("path")) { | 
		
	
		
			
				|  |  |             AsyncWebParameter *param = request->getParam("path"); |  |  |             AsyncWebParameter *param = request->getParam("path"); | 
		
	
		
			
				|  |  |             String utf8FilePath = param->value() + "/" + filename; |  |  |  | 
		
	
		
			
				|  |  |             char asciiFilePath[256]; |  |  |  | 
		
	
		
			
				|  |  |             convertUtf8ToAscii(utf8FilePath, asciiFilePath); |  |  |  | 
		
	
		
			
				|  |  |             request->_tempFile = FSystem.open( asciiFilePath, "w"); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |             utf8FilePath = param->value() + "/" + filename; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |         } else { |  |  |         } else { | 
		
	
		
			
				|  |  |             request->_tempFile = FSystem.open("/" + filename, "w"); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |             utf8FilePath = "/" + filename; | 
		
	
		
			
				|  |  |         } |  |  |         } | 
		
	
		
			
				|  |  |         snprintf(logBuf, serialLoglength, "%s: %s", (char *) FPSTR(writingFile), filename); |  |  |  | 
		
	
		
			
				|  |  |         loggerNl(logBuf, LOGLEVEL_INFO); |  |  |  | 
		
	
		
			
				|  |  |         // open the file on first call and store the file handle in the request object
 |  |  |  | 
		
	
		
			
				|  |  |  |  |  |         convertUtf8ToAscii(utf8FilePath, asciiFilePath); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         // Create Ringbuffer for upload
 | 
		
	
		
			
				|  |  |  |  |  |         if(explorerFileUploadRingBuffer == NULL) { | 
		
	
		
			
				|  |  |  |  |  |             explorerFileUploadRingBuffer = xRingbufferCreate(4096, RINGBUF_TYPE_BYTEBUF); | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         // Create Queue for receiving a signal from the store task as synchronisation
 | 
		
	
		
			
				|  |  |  |  |  |         if(explorerFileUploadStatusQueue == NULL) { | 
		
	
		
			
				|  |  |  |  |  |             explorerFileUploadStatusQueue = xQueueCreate(1, sizeof(uint8_t)); | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         // Create Task for handling the storage of the data
 | 
		
	
		
			
				|  |  |  |  |  |         xTaskCreate( | 
		
	
		
			
				|  |  |  |  |  |             explorerHandleFileStorageTask, /* Function to implement the task */ | 
		
	
		
			
				|  |  |  |  |  |             "fileStorageTask", /* Name of the task */ | 
		
	
		
			
				|  |  |  |  |  |             4000,  /* Stack size in words */ | 
		
	
		
			
				|  |  |  |  |  |             asciiFilePath,  /* Task input parameter */ | 
		
	
		
			
				|  |  |  |  |  |             2 | portPRIVILEGE_BIT,  /* Priority of the task */ | 
		
	
		
			
				|  |  |  |  |  |             &fileStorageTaskHandle  /* Task handle. */ | 
		
	
		
			
				|  |  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         lastTimeActiveTimestamp = millis(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |     } |  |  |     } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |     if (len) { |  |  |     if (len) { | 
		
	
		
			
				|  |  |         // stream the incoming chunk to the opened file
 |  |  |  | 
		
	
		
			
				|  |  |         request->_tempFile.write(data, len); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |         // stream the incoming chunk to the ringbuffer
 | 
		
	
		
			
				|  |  |  |  |  |         xRingbufferSend(explorerFileUploadRingBuffer, data, len, portTICK_PERIOD_MS * 1000); | 
		
	
		
			
				|  |  |     } |  |  |     } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |     if (final) { |  |  |     if (final) { | 
		
	
		
			
				|  |  |         // close the file handle as the upload is now done
 |  |  |  | 
		
	
		
			
				|  |  |         request->_tempFile.close(); |  |  |  | 
		
	
		
			
				|  |  |  |  |  |         // notify storage task that last data was stored on the ring buffer
 | 
		
	
		
			
				|  |  |  |  |  |         xTaskNotify(fileStorageTaskHandle, 1u, eNoAction); | 
		
	
		
			
				|  |  |  |  |  |         // watit until the storage task is sending the signal to finish
 | 
		
	
		
			
				|  |  |  |  |  |         uint8_t signal; | 
		
	
		
			
				|  |  |  |  |  |         xQueueReceive(explorerFileUploadStatusQueue, &signal, portMAX_DELAY); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         // delete task
 | 
		
	
		
			
				|  |  |  |  |  |         vTaskDelete(fileStorageTaskHandle); | 
		
	
		
			
				|  |  |     } |  |  |     } | 
		
	
		
			
				|  |  | } |  |  | } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  | void explorerHandleFileStorageTask(void *parameter) { | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     File uploadFile; | 
		
	
		
			
				|  |  |  |  |  |     size_t item_size; | 
		
	
		
			
				|  |  |  |  |  |     uint8_t *item; | 
		
	
		
			
				|  |  |  |  |  |     uint8_t value = 0; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     BaseType_t uploadFileNotification; | 
		
	
		
			
				|  |  |  |  |  |     uint32_t uploadFileNotificationValue; | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     uploadFile = FSystem.open((char *)parameter, "w"); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     snprintf(logBuf, serialLoglength, "%s: %s", (char *) FPSTR(writingFile), parameter); | 
		
	
		
			
				|  |  |  |  |  |     loggerNl(logBuf, LOGLEVEL_INFO); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |     for(;;) { | 
		
	
		
			
				|  |  |  |  |  |         esp_task_wdt_reset(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         item = (uint8_t *)xRingbufferReceive(explorerFileUploadRingBuffer, &item_size, portTICK_PERIOD_MS * 100); | 
		
	
		
			
				|  |  |  |  |  |         if (item != NULL) { | 
		
	
		
			
				|  |  |  |  |  |             uploadFile.write(item, item_size); | 
		
	
		
			
				|  |  |  |  |  |             vRingbufferReturnItem(explorerFileUploadRingBuffer, (void *)item); | 
		
	
		
			
				|  |  |  |  |  |         } else { | 
		
	
		
			
				|  |  |  |  |  |             // No data in the buffer, check if all data arrived for the file
 | 
		
	
		
			
				|  |  |  |  |  |             uploadFileNotification = xTaskNotifyWait(0,0,&uploadFileNotificationValue,0); | 
		
	
		
			
				|  |  |  |  |  |             if(uploadFileNotification == pdPASS) { | 
		
	
		
			
				|  |  |  |  |  |                 uploadFile.close(); | 
		
	
		
			
				|  |  |  |  |  |                 // done exit loop to terminate
 | 
		
	
		
			
				|  |  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |  |             vTaskDelay(portTICK_PERIOD_MS * 100); | 
		
	
		
			
				|  |  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  |     // send signal to upload function to terminate
 | 
		
	
		
			
				|  |  |  |  |  |     xQueueSend(explorerFileUploadStatusQueue, &value, 0); | 
		
	
		
			
				|  |  |  |  |  |     vTaskDelete(NULL); | 
		
	
		
			
				|  |  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  | // Sends a list of the content of a directory as JSON file
 |  |  | // Sends a list of the content of a directory as JSON file
 | 
		
	
		
			
				|  |  | // requires a GET parameter path for the directory
 |  |  | // requires a GET parameter path for the directory
 | 
		
	
		
			
				|  |  | void explorerHandleListRequest(AsyncWebServerRequest *request) { |  |  | void explorerHandleListRequest(AsyncWebServerRequest *request) { | 
		
	
	
		
			
				|  | @ -3806,6 +3878,8 @@ void explorerHandleListRequest(AsyncWebServerRequest *request) { | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |         file = root.openNextFile(); |  |  |         file = root.openNextFile(); | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |  |  |  |         esp_task_wdt_reset(); | 
		
	
		
			
				|  |  |  |  |  | 
 | 
		
	
		
			
				|  |  |     } |  |  |     } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  |     serializeJson(obj, serializedJsonString); |  |  |     serializeJson(obj, serializedJsonString); | 
		
	
	
		
			
				|  | @ -3851,6 +3925,7 @@ void explorerHandleDeleteRequest(AsyncWebServerRequest *request) { | 
		
	
		
			
				|  |  |         loggerNl("DELETE: No path variable set", LOGLEVEL_ERROR); |  |  |         loggerNl("DELETE: No path variable set", LOGLEVEL_ERROR); | 
		
	
		
			
				|  |  |     } |  |  |     } | 
		
	
		
			
				|  |  |     request->send(200); |  |  |     request->send(200); | 
		
	
		
			
				|  |  |  |  |  |     esp_task_wdt_reset(); | 
		
	
		
			
				|  |  | } |  |  | } | 
		
	
		
			
				|  |  | 
 |  |  | 
 | 
		
	
		
			
				|  |  | // Handles create request of a directory
 |  |  | // Handles create request of a directory
 | 
		
	
	
		
			
				|  | 
 |