From cc8e8da0347ec93b6d47a7f016c6880ac57378fe Mon Sep 17 00:00:00 2001 From: Drasko DRASKOVIC Date: Wed, 4 May 2016 22:43:02 +0200 Subject: [PATCH] Add JSON support This commits adds JSON support by adding Jsmn (http://zserge.com/jsmn.html), a minimalistic JSON parser. Signed-off-by: Drasko DRASKOVIC --- .gitmodules | 3 + examples/json_jsmn_simple/Makefile | 4 + examples/json_jsmn_simple/json_jsmn_simple.c | 112 +++++++++++++++++++ extras/jsmn/component.mk | 10 ++ extras/jsmn/jsmn | 1 + 5 files changed, 130 insertions(+) create mode 100644 examples/json_jsmn_simple/Makefile create mode 100644 examples/json_jsmn_simple/json_jsmn_simple.c create mode 100644 extras/jsmn/component.mk create mode 160000 extras/jsmn/jsmn diff --git a/.gitmodules b/.gitmodules index 8dc737e..52708f8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "extras/mbedtls/mbedtls"] path = extras/mbedtls/mbedtls url = https://github.com/ARMmbed/mbedtls.git +[submodule "extras/jsmn/jsmn"] + path = extras/jsmn/jsmn + url = https://github.com/zserge/jsmn.git diff --git a/examples/json_jsmn_simple/Makefile b/examples/json_jsmn_simple/Makefile new file mode 100644 index 0000000..89e6ba7 --- /dev/null +++ b/examples/json_jsmn_simple/Makefile @@ -0,0 +1,4 @@ +# Simple makefile for simple example +PROGRAM=json_jsmn_simple +EXTRA_COMPONENTS = extras/jsmn +include ../../common.mk diff --git a/examples/json_jsmn_simple/json_jsmn_simple.c b/examples/json_jsmn_simple/json_jsmn_simple.c new file mode 100644 index 0000000..3a65ddf --- /dev/null +++ b/examples/json_jsmn_simple/json_jsmn_simple.c @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2010 Serge A. Zaitsev and + * 2016 Drasko DRASKOVIC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include +#include +#include +#include "jsmn.h" + +/** + * A small example of jsmn parsing when JSON structure is known and number of + * tokens is predictable. + */ + +const char *JSON_STRING = + "{\"user\": \"johndoe\", \"admin\": false, \"uid\": 1000,\n " + "\"groups\": [\"users\", \"wheel\", \"audio\", \"video\"]}"; + +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 json_test(void *pvParameters) +{ + int i; + int r; + jsmn_parser p; + jsmntok_t t[128]; /* We expect no more than 128 tokens */ + + jsmn_init(&p); + r = jsmn_parse(&p, JSON_STRING, strlen(JSON_STRING), t, sizeof(t)/sizeof(t[0])); + if (r < 0) { + printf("Failed to parse JSON: %d\n", r); + } + + /* Assume the top-level element is an object */ + if (r < 1 || t[0].type != JSMN_OBJECT) { + printf("Object expected\n"); + } + + /* Loop over all keys of the root object */ + for (i = 1; i < r; i++) { + if (jsoneq(JSON_STRING, &t[i], "user") == 0) { + /* We may use strndup() to fetch string value */ + printf("- User: %.*s\n", t[i+1].end-t[i+1].start, + JSON_STRING + t[i+1].start); + i++; + } else if (jsoneq(JSON_STRING, &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, + JSON_STRING + t[i+1].start); + i++; + } else if (jsoneq(JSON_STRING, &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, + JSON_STRING + t[i+1].start); + i++; + } else if (jsoneq(JSON_STRING, &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, JSON_STRING + g->start); + } + i += t[i+1].size + 1; + } else { + printf("Unexpected key: %.*s\n", t[i].end-t[i].start, + JSON_STRING + t[i].start); + } + } + + while (1) + ; +} + + +void user_init(void) +{ + uart_set_baud(0, 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + xTaskCreate(json_test, (signed char *)"jsont", 1024, NULL, 2, NULL); +} diff --git a/extras/jsmn/component.mk b/extras/jsmn/component.mk new file mode 100644 index 0000000..13beac4 --- /dev/null +++ b/extras/jsmn/component.mk @@ -0,0 +1,10 @@ +# Component makefile for extras/jsmn + +# expected anyone using jsmn json component includes it as 'jsmn/jsmn.h' +INC_DIRS += $(jsmn_ROOT)jsmn + +# args for passing into compile rule generation +jsmn_INC_DIR = +jsmn_SRC_DIR = $(jsmn_ROOT)jsmn + +$(eval $(call component_compile_rules,jsmn)) diff --git a/extras/jsmn/jsmn b/extras/jsmn/jsmn new file mode 160000 index 0000000..bbc6755 --- /dev/null +++ b/extras/jsmn/jsmn @@ -0,0 +1 @@ +Subproject commit bbc6755fce14c713f9bb4ba47c688d15efc1394b