// #include "storage.h" #include "esp_log.h" #include "esp_vfs.h" #include "esp_vfs_fat.h" #include "jsmn.h" #include "esp_lan.h" static const char *TAG = "storage"; const char *base_path = "/storage"; static wl_handle_t s_wl_handle = WL_INVALID_HANDLE; typedef struct { char *client_config; char *controller_config; } load_config; typedef struct { bool debug; uint16_t log_level; struct network_config *network; } main_config; // allocates memory! free space after use! static char *read_file(char *host_filename) { ESP_LOGI(TAG, "Reading file"); FILE *f; char *fileContent; f = fopen(host_filename, "rb"); if (f == NULL) { ESP_LOGE(TAG, "Failed to open file for reading"); return NULL; } size_t result; fseek(f, 0, SEEK_END); int fileSize = ftell(f); rewind(f); ESP_LOGI(TAG, "fileSize: %i\n", fileSize); fileContent = (char *)malloc(sizeof(char) * fileSize + 1); if (fileContent == NULL) { ESP_LOGE(TAG, "Memory error"); return NULL; } result = fread(fileContent, 1, fileSize, f); if (result != fileSize) { ESP_LOGE(TAG, "Reading error"); free(fileContent); return NULL; } fileContent[fileSize] = '\0'; fclose(f); return fileContent; }; static int jsoneq(const char *json, jsmntok_t *tok, const char *s) { if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start && strncmp(json + tok->start, s, tok->end - tok->start) == 0) { return 0; } return -1; } void parse_trst_config(main_config *cfg, char *fileContent) { int i; int r; jsmn_parser p; jsmntok_t t[256]; /* We expect no more than 128 tokens */ jsmn_init(&p); // should be end at \0 so set max file size to not having to count r = jsmn_parse(&p, fileContent, 8192, t, sizeof(t) / sizeof(t[0])); if (r < 0) { printf("Failed to parse JSON: %d\n", r); return; } /* Assume the top-level element is an object */ if (r < 1 || t[0].type != JSMN_OBJECT) { printf("Object expected\n"); return; } /* Loop over all keys of the root object */ for (i = 1; i < r; i++) { if (jsoneq(fileContent, &t[i], "user") == 0) { /* We may use strndup() to fetch string value */ printf("- User: %.*s\n", t[i + 1].end - t[i + 1].start, fileContent + t[i + 1].start); i++; } else if (jsoneq(fileContent, &t[i], "admin") == 0) { /* We may additionally check if the value is either "true" or "false" */ printf("- Admin: %.*s\n", t[i + 1].end - t[i + 1].start, fileContent + t[i + 1].start); i++; } else if (jsoneq(fileContent, &t[i], "debug") == 0) { /* We may additionally check if the value is either "true" or "false" */ printf("-debug: %.*s\n", t[i + 1].end - t[i + 1].start, fileContent + t[i + 1].start); i++; } else if (jsoneq(fileContent, &t[i], "uid") == 0) { /* We may want to do strtol() here to get numeric value */ printf("- UID: %.*s\n", t[i + 1].end - t[i + 1].start, fileContent + t[i + 1].start); i++; } else if (jsoneq(fileContent, &t[i], "groups") == 0) { int j; printf("- Groups:\n"); if (t[i + 1].type != JSMN_ARRAY) { continue; /* We expect groups to be an array of strings */ } for (j = 0; j < t[i + 1].size; j++) { jsmntok_t *g = &t[i + j + 2]; printf(" * %.*s\n", g->end - g->start, fileContent + g->start); } i += t[i + 1].size + 1; } else { printf("Unexpected key%i: %.*s\n", i, t[i].end - t[i].start, fileContent + t[i].start); } } } char* parse_string(jsmntok_t *token,char* fileContent){ uint16_t size = (token->end - token->start); char* value = malloc(size+1); strncpy(value, fileContent + token->start, size); value[size] = '\0'; return value; } bool parse_bool(jsmntok_t *token,char* fileContent){ if(fileContent[token->start] == 't'){ return true; } else { return false; } } uint16_t parse_int(jsmntok_t *token,char* fileContent){ // uint16_t size = (token.end - token.start); return atoi(fileContent + token->start); } int parse_eth_config(lan_eth_config *cfg,jsmntok_t *token, char *fileContent){ ESP_LOGI(TAG, "t->start:(%d),t->end:(%d),t->size:(%d)", token->start, token->end, token->size); return NULL; } int parse_network_config(network_config *cfg,jsmntok_t *token, char *fileContent){// add pos? ESP_LOGI(TAG, "t->start:(%d),t->end:(%d),t->size:(%d)", token->start, token->end, token->size); int stringPos = token->start; int tokenPos = 1; while(stringPos < token->end){ ESP_LOGI(TAG, "stringPos:(%d),tokenPos:(%d)", stringPos, tokenPos); if (jsoneq(fileContent, &token[tokenPos], "debug") == 0){ stringPos = token[tokenPos].end; tokenPos++; } else { stringPos = token[tokenPos].end; printf("Unexpected nc key%i: %.*s\n", tokenPos, token[tokenPos].end - token[tokenPos].start, fileContent + token[tokenPos].start); tokenPos++; } ESP_LOGI(TAG, "stringPos(%d)",stringPos); }; return tokenPos+1; } void parse_main_config(main_config *cfg, char *fileContent) { int i; int r; jsmn_parser p; jsmntok_t t[256]; /* We expect no more than 256 tokens */ jsmn_init(&p); // should be end at \0 so set max file size to not having to count r = jsmn_parse(&p, fileContent, 8192, t, sizeof(t) / sizeof(t[0])); if (r < 0) { printf("Failed to parse JSON: %d\n", r); return; } /* Assume the top-level element is an object */ if (r < 1 || t[0].type != JSMN_OBJECT) { printf("Object expected\n"); return; } /* Loop over all keys of the root object */ for (i = 1; i < r; i++) { if (jsoneq(fileContent, &t[i], "debug") == 0) { cfg->debug = parse_bool(&t[i + 1],fileContent); i++; } else if (jsoneq(fileContent, &t[i], "log_level") == 0) { cfg->log_level = parse_int(&t[i + 1],fileContent); i++; } else if (jsoneq(fileContent, &t[i], "network") == 0) { if(t[i+1].type == JSMN_OBJECT){ cfg->network = malloc(sizeof(network_config)); int size = parse_network_config(cfg->network, &t[i+1],fileContent); i = i+size; } else { // error } } else { printf("Unexpected key%i: %.*s\n", i, t[i].end - t[i].start, fileContent + t[i].start); } } } void parse_load_config(load_config *cfg, char *fileContent) { int i; int r; jsmn_parser p; jsmntok_t t[32]; /* We expect no more than 128 tokens */ jsmn_init(&p); // should be end at \0 so set max file size to not having to count r = jsmn_parse(&p, fileContent, 8192, t, sizeof(t) / sizeof(t[0])); if (r < 0) { printf("Failed to parse JSON: %d\n", r); return; } /* Assume the top-level element is an object */ if (r < 1 || t[0].type != JSMN_OBJECT) { printf("Object expected\n"); return; } /* Loop over all keys of the root object */ for (i = 1; i < r; i++) { if (jsoneq(fileContent, &t[i], "client_config") == 0) { printf("parse_string client_config\n"); cfg->client_config = parse_string(&t[i+1],fileContent); i++; } else if (jsoneq(fileContent, &t[i], "controller_config") == 0) { cfg->controller_config = parse_string(&t[i+1],fileContent); i++; } else { printf("Unexpected key%i: %.*s\n", i, t[i].end - t[i].start, fileContent + t[i].start); } } } main_config *init_config() { ESP_LOGI(TAG, "init_config:"); // main_config *l_cfg = load_load_config("/storage/load.cfg.json"); ESP_LOGI(TAG, "Mounting FAT filesystem"); // To mount device we need name of device partition, define base_path // and allow format partition in case if it is new one and was not formatted before const esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = 4, .allocation_unit_size = 512, .disk_status_check_enable = false}; esp_err_t err; err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &s_wl_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); return NULL; } char *fileContent = read_file("/storage/load.cfg.json"); load_config *load_cfg = malloc(sizeof(load_config)); parse_load_config(load_cfg, fileContent); free(fileContent); ESP_LOGI(TAG, "controller_config:(%s),client_config:(%s)", load_cfg->controller_config, load_cfg->client_config); fileContent = read_file(load_cfg->controller_config); main_config *main_cfg = malloc(sizeof(main_config)); parse_main_config(main_cfg, fileContent); free(fileContent); ESP_LOGI(TAG, "main_cfg->debug:(%d)", main_cfg->debug); ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, s_wl_handle)); return main_cfg; }