diff --git a/lib/nvsdump/src/nvsDump.h b/lib/nvsdump/src/nvsDump.h new file mode 100644 index 0000000..4c2f934 --- /dev/null +++ b/lib/nvsdump/src/nvsDump.h @@ -0,0 +1,93 @@ +#include +#include +#include +// Debug buffer size +#define DEBUG_BUFFER_SIZE 130 +#define DEBUG false + +struct nvs_entry { + uint8_t Ns; // Namespace ID + uint8_t Type; // Type of value + uint8_t Span; // Number of entries used for this item + uint8_t Rvs; // Reserved, should be 0xFF + uint32_t CRC; // CRC + char Key[16]; // Key in Ascii + uint64_t Data; // Data in entry +}; + +struct nvs_page { // For nvs entries + uint32_t State; + uint32_t Seqnr; + + uint32_t Unused[5]; + uint32_t CRC; + uint8_t Bitmap[32]; + nvs_entry Entry[126]; +}; + +// Common data +nvs_page buf; + +//************************************************************************************************** +// D B G P R I N T * +//************************************************************************************************** +// Send a line of info to serial output. Works like vsprintf(), but checks the DEBUG flag. * +// Print only if DEBUG flag is true. Always returns the formatted string. * +//************************************************************************************************** +char* dbgprint (const char* format, ...) { + static char sbuf[DEBUG_BUFFER_SIZE]; // For debug lines + va_list varArgs; // For variable number of params + + va_start (varArgs, format); // Prepare parameters + vsnprintf (sbuf, sizeof(sbuf), format, varArgs); // Format the message + va_end (varArgs); // End of using parameters + if (DEBUG) { // DEBUG on? + Serial.print ("D: "); // Yes, print prefix + Serial.println (sbuf); // and the info + } + return sbuf; // Return stored string +} + + +//************************************************************************************************** +// F I N D N S I D * +//************************************************************************************************** +// Find the namespace ID for the namespace passed as parameter. * +//************************************************************************************************** +uint8_t FindNsID (const esp_partition_t* nvs, const char* ns) { + esp_err_t result = ESP_OK; // Result of reading partition + uint32_t offset = 0; // Offset in nvs partition + uint8_t i; // Index in Entry 0..125 + uint8_t bm; // Bitmap for an entry + uint8_t res = 0xFF; // Function result + + + while (offset < nvs->size) { + result = esp_partition_read ( nvs, offset, // Read 1 page in nvs partition + &buf, + sizeof(nvs_page) ); + if (result != ESP_OK) { + dbgprint ("Error reading NVS!"); + break; + } + i=0; + while (i < 126) { + bm = (buf.Bitmap[i/4] >> ((i % 4) * 2)) & 0x03 ; // Get bitmap for this entry + if ((bm == 2) && + (buf.Entry[i].Ns == 0) && + (strcmp (ns, buf.Entry[i].Key) == 0)) { + res = buf.Entry[i].Data & 0xFF; // Return the ID + offset = nvs->size; // Stop outer loop as well + break; + } else { + if (bm == 2) { + i += buf.Entry[i].Span ; // Next entry + } else { + i++; + } + } + } + offset += sizeof(nvs_page); // Prepare to read next page in nvs + } + return res; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 51e9a33..4bcea30 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include #include #include +#include @@ -150,6 +151,11 @@ typedef struct { // Bit field } playProps; playProps playProperties; +typedef struct { + char *nvsKey; + char *nvsEntry; +} nvs_t; + // Configuration of initial values (for the first start) goes here.... // There's no need to change them here as they can be configured via webinterface // Neopixel @@ -311,13 +317,15 @@ static int arrSortHelper(const void* a, const void* b); void callback(const char *topic, const byte *payload, uint32_t length); #endif void buttonHandler(); +void deepSleepManager(void); void doButtonActions(void); void doRfidCardModifications(const uint32_t mod); -void deepSleepManager(void); +bool dumpNvsToSd(char *_namespace, char *_destFile); bool endsWith (const char *str, const char *suf); bool fileValid(const char *_fileItem); void freeMultiCharArray(char **arr, const uint32_t cnt); uint8_t getRepeatMode(void); +bool isNumber(const char *str); void loggerNl(const char *str, const uint8_t logLevel); void logger(const char *str, const uint8_t logLevel); #ifdef MQTT_ENABLE @@ -1039,7 +1047,7 @@ char ** returnPlaylistFromSD(File _fileOrDirectory) { char *token; token = strtok(serializedPlaylist, stringDelimiter); uint32_t pos = 1; - while( token != NULL ) { + while (token != NULL) { files[pos++] = strdup(token); token = strtok(NULL, stringDelimiter); } @@ -2620,19 +2628,23 @@ bool processJsonRequest(char *_serialJson) { if (s.compareTo(rfidString)) { return false; } + dumpNvsToSd("rfidTags", "/backup.txt"); } else if (doc.containsKey("rfidAssign")) { - const char *_rfidIdModId = object["rfidAssign"]["rfidIdMusic"]; + const char *_rfidIdAssinId = object["rfidAssign"]["rfidIdMusic"]; const char *_fileOrUrl = object["rfidAssign"]["fileOrUrl"]; uint8_t _playMode = object["rfidAssign"]["playMode"]; char rfidString[275]; snprintf(rfidString, sizeof(rfidString) / sizeof(rfidString[0]), "%s%s%s0%s%u%s0", stringDelimiter, _fileOrUrl, stringDelimiter, stringDelimiter, _playMode, stringDelimiter); - prefsRfid.putString(_rfidIdModId, rfidString); + prefsRfid.putString(_rfidIdAssinId, rfidString); + Serial.println(_rfidIdAssinId); + Serial.println(rfidString); - String s = prefsRfid.getString(_rfidIdModId, "-1"); + String s = prefsRfid.getString(_rfidIdAssinId, "-1"); if (s.compareTo(rfidString)) { return false; } + dumpNvsToSd("rfidTags", "/backup.txt"); } else if (doc.containsKey("wifiConfig")) { const char *_ssid = object["wifiConfig"]["ssid"]; @@ -2726,6 +2738,90 @@ void onWebsocketEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, Aw } +bool isNumber(const char *str) { + byte i = 0; + + while (*(str + i) != '\0') { + if (!isdigit(*(str + i++))) { + return false; + } + } + + if (i>0) { + return true; + } else { + return false; + } + +} + + +// Dumps all RFID-entries from NVS into a file on SD-card +bool dumpNvsToSd(char *_namespace, char *_destFile) { + esp_partition_iterator_t pi; // Iterator for find + const esp_partition_t* nvs; // Pointer to partition struct + esp_err_t result = ESP_OK; + const char* partname = "nvs"; + uint8_t pagenr = 0; // Page number in NVS + uint8_t i; // Index in Entry 0..125 + uint8_t bm; // Bitmap for an entry + uint32_t offset = 0; // Offset in nvs partition + uint8_t namespace_ID; // Namespace ID found + + pi = esp_partition_find ( ESP_PARTITION_TYPE_DATA, // Get partition iterator for + ESP_PARTITION_SUBTYPE_ANY, // this partition + partname ) ; + if (pi) { + nvs = esp_partition_get(pi); // Get partition struct + esp_partition_iterator_release(pi); // Release the iterator + dbgprint ( "Partition %s found, %d bytes", + partname, + nvs->size ) ; + } else { + Serial.printf("Partition %s not found!", partname) ; + return NULL; + } + namespace_ID = FindNsID (nvs, _namespace) ; // Find ID of our namespace in NVS + + File backupFile = SD.open(_destFile, FILE_WRITE); + if (!backupFile) { + return false; + } + while (offset < nvs->size) { + result = esp_partition_read (nvs, offset, // Read 1 page in nvs partition + &buf, + sizeof(nvs_page)); + if (result != ESP_OK) { + Serial.println(F("Error reading NVS!")); + return false; + } + + i = 0; + + while (i < 126) { + bm = (buf.Bitmap[i/4] >> ((i % 4) * 2 )) & 0x03; // Get bitmap for this entry + if (bm == 2) { + if ((namespace_ID == 0xFF) || // Show all if ID = 0xFF + (buf.Entry[i].Ns == namespace_ID)) { // otherwise just my namespace + if (isNumber(buf.Entry[i].Key)) { + String s = prefsRfid.getString((const char *)buf.Entry[i].Key); + backupFile.printf("%s^%s\n", buf.Entry[i].Key, s.c_str()); + } + } + i += buf.Entry[i].Span; // Next entry + } else { + i++; + } + } + offset += sizeof(nvs_page); // Prepare to read next page in nvs + pagenr++; + } + + backupFile.close(); + return true; +} + + void setup() { Serial.begin(115200); srand(esp_random());