mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
cbor: add tinycbor library and example
This commit is contained in:
parent
f85ba3516f
commit
5a09de8245
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -74,3 +74,7 @@
|
|||||||
[submodule "components/bt/host/nimble/nimble"]
|
[submodule "components/bt/host/nimble/nimble"]
|
||||||
path = components/bt/host/nimble/nimble
|
path = components/bt/host/nimble/nimble
|
||||||
url = ../../espressif/esp-nimble.git
|
url = ../../espressif/esp-nimble.git
|
||||||
|
|
||||||
|
[submodule "components/cbor/tinycbor"]
|
||||||
|
path = components/cbor/tinycbor
|
||||||
|
url = ../../intel/tinycbor.git
|
||||||
|
21
components/cbor/CMakeLists.txt
Normal file
21
components/cbor/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
idf_component_register(SRCS "tinycbor/src/cborencoder_close_container_checked.c"
|
||||||
|
"tinycbor/src/cborencoder.c"
|
||||||
|
"tinycbor/src/cborerrorstrings.c"
|
||||||
|
"tinycbor/src/cborparser_dup_string.c"
|
||||||
|
"tinycbor/src/cborparser.c"
|
||||||
|
"tinycbor/src/cborpretty_stdio.c"
|
||||||
|
"tinycbor/src/cborpretty.c"
|
||||||
|
"tinycbor/src/cbortojson.c"
|
||||||
|
"tinycbor/src/cborvalidation.c"
|
||||||
|
"tinycbor/src/open_memstream.c"
|
||||||
|
INCLUDE_DIRS "port/include"
|
||||||
|
PRIV_INCLUDE_DIRS "tinycbor/src")
|
||||||
|
|
||||||
|
# for open_memstream.c
|
||||||
|
target_compile_definitions(${COMPONENT_LIB} PRIVATE "__GLIBC__")
|
||||||
|
|
||||||
|
# cbortojson.c:378:17: assignment discards 'const' qualifier from pointer target type
|
||||||
|
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-discarded-qualifiers")
|
||||||
|
|
||||||
|
# cborvalidation.c:429:22: 'valf' may be used uninitialized
|
||||||
|
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-maybe-uninitialized")
|
8
components/cbor/component.mk
Normal file
8
components/cbor/component.mk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
COMPONENT_SUBMODULES += tinycbor
|
||||||
|
COMPONENT_ADD_INCLUDEDIRS := port/include
|
||||||
|
COMPONENT_SRCDIRS := tinycbor/src
|
||||||
|
COMPONENT_PRIV_INCLUDEDIRS := tinycbor/src
|
||||||
|
|
||||||
|
tinycbor/src/open_memstream.o: CFLAGS += -D__GLIBC__
|
||||||
|
tinycbor/src/cbortojson.o: CFLAGS += -Wno-discarded-qualifiers
|
||||||
|
tinycbor/src/cborvalidation.o: CFLAGS += -Wno-maybe-uninitialized
|
2
components/cbor/port/include/cbor.h
Normal file
2
components/cbor/port/include/cbor.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "../../tinycbor/src/cbor.h"
|
||||||
|
#include "../../tinycbor/src/cborjson.h"
|
1
components/cbor/tinycbor
Submodule
1
components/cbor/tinycbor
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d2dd95cb8841d88d5a801e3ef9c328fd6200e7bd
|
6
examples/protocols/cbor/CMakeLists.txt
Normal file
6
examples/protocols/cbor/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(cbor)
|
9
examples/protocols/cbor/Makefile
Normal file
9
examples/protocols/cbor/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := cbor
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
56
examples/protocols/cbor/README.md
Normal file
56
examples/protocols/cbor/README.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# CBOR Example
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The [CBOR](https://en.wikipedia.org/wiki/CBOR)(Concise Binary Object Representation) is a binary data serialization format which is similar to JSON but with smaller footprint. This example will illustrate how to encode and decode CBOR data using the APIs provided by [tinycbor](https://github.com/intel/tinycbor).
|
||||||
|
|
||||||
|
For detailed information about how CBOR encoding and decoding works, please refer to [REF7049](https://tools.ietf.org/html/rfc7049) or [cbor.io](http://cbor.io/);
|
||||||
|
|
||||||
|
## How to use example
|
||||||
|
|
||||||
|
### Hardware Required
|
||||||
|
|
||||||
|
This example should be able to run on any commonly available ESP32 development board.
|
||||||
|
|
||||||
|
### Build and Flash
|
||||||
|
|
||||||
|
Run `idf.py -p PORT flash monitor` to build and flash the project.
|
||||||
|
|
||||||
|
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||||
|
|
||||||
|
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
```bash
|
||||||
|
I (320) example: encoded buffer size 67
|
||||||
|
I (320) example: convert CBOR to JSON
|
||||||
|
[{"chip":"esp32","unicore":false,"ip":[192,168,1,100]},3.1400001049041748,"simple(99)","2019-07-10 09:00:00+0000","undefined"]
|
||||||
|
I (340) example: decode CBOR manually
|
||||||
|
Array[
|
||||||
|
Map{
|
||||||
|
chip
|
||||||
|
esp32
|
||||||
|
unicore
|
||||||
|
false
|
||||||
|
ip
|
||||||
|
Array[
|
||||||
|
192
|
||||||
|
168
|
||||||
|
1
|
||||||
|
100
|
||||||
|
]
|
||||||
|
}
|
||||||
|
3.14
|
||||||
|
simple(99)
|
||||||
|
2019-07-10 09:00:00+0000
|
||||||
|
undefined
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
For more API usage, please refer to [tinycbor API](https://intel.github.io/tinycbor/current/).
|
||||||
|
|
||||||
|
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
2
examples/protocols/cbor/main/CMakeLists.txt
Normal file
2
examples/protocols/cbor/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "cbor_example_main.c"
|
||||||
|
INCLUDE_DIRS "")
|
226
examples/protocols/cbor/main/cbor_example_main.c
Normal file
226
examples/protocols/cbor/main/cbor_example_main.c
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/* CBOR Example
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "cbor.h"
|
||||||
|
|
||||||
|
static const char *TAG = "example";
|
||||||
|
|
||||||
|
#define CBOR_CHECK(a, str, goto_tag, ret_value, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if ((a) != CborNoError) \
|
||||||
|
{ \
|
||||||
|
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
ret = ret_value; \
|
||||||
|
goto goto_tag; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void indent(int nestingLevel)
|
||||||
|
{
|
||||||
|
while (nestingLevel--) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dumpbytes(const uint8_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
while (len--) {
|
||||||
|
printf("%02X ", *buf++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode CBOR data manuallly
|
||||||
|
*/
|
||||||
|
static CborError example_dump_cbor_buffer(CborValue *it, int nestingLevel)
|
||||||
|
{
|
||||||
|
CborError ret = CborNoError;
|
||||||
|
while (!cbor_value_at_end(it)) {
|
||||||
|
CborType type = cbor_value_get_type(it);
|
||||||
|
|
||||||
|
indent(nestingLevel);
|
||||||
|
switch (type) {
|
||||||
|
case CborArrayType: {
|
||||||
|
CborValue recursed;
|
||||||
|
assert(cbor_value_is_container(it));
|
||||||
|
puts("Array[");
|
||||||
|
ret = cbor_value_enter_container(it, &recursed);
|
||||||
|
CBOR_CHECK(ret, "enter container failed", err, ret);
|
||||||
|
ret = example_dump_cbor_buffer(&recursed, nestingLevel + 1);
|
||||||
|
CBOR_CHECK(ret, "recursive dump failed", err, ret);
|
||||||
|
ret = cbor_value_leave_container(it, &recursed);
|
||||||
|
CBOR_CHECK(ret, "leave container failed", err, ret);
|
||||||
|
indent(nestingLevel);
|
||||||
|
puts("]");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case CborMapType: {
|
||||||
|
CborValue recursed;
|
||||||
|
assert(cbor_value_is_container(it));
|
||||||
|
puts("Map{");
|
||||||
|
ret = cbor_value_enter_container(it, &recursed);
|
||||||
|
CBOR_CHECK(ret, "enter container failed", err, ret);
|
||||||
|
ret = example_dump_cbor_buffer(&recursed, nestingLevel + 1);
|
||||||
|
CBOR_CHECK(ret, "recursive dump failed", err, ret);
|
||||||
|
ret = cbor_value_leave_container(it, &recursed);
|
||||||
|
CBOR_CHECK(ret, "leave container failed", err, ret);
|
||||||
|
indent(nestingLevel);
|
||||||
|
puts("}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case CborIntegerType: {
|
||||||
|
int64_t val;
|
||||||
|
ret = cbor_value_get_int64(it, &val);
|
||||||
|
CBOR_CHECK(ret, "parse int64 failed", err, ret);
|
||||||
|
printf("%lld\n", (long long)val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CborByteStringType: {
|
||||||
|
uint8_t *buf;
|
||||||
|
size_t n;
|
||||||
|
ret = cbor_value_dup_byte_string(it, &buf, &n, it);
|
||||||
|
CBOR_CHECK(ret, "parse byte string failed", err, ret);
|
||||||
|
dumpbytes(buf, n);
|
||||||
|
puts("");
|
||||||
|
free(buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case CborTextStringType: {
|
||||||
|
char *buf;
|
||||||
|
size_t n;
|
||||||
|
ret = cbor_value_dup_text_string(it, &buf, &n, it);
|
||||||
|
CBOR_CHECK(ret, "parse text string failed", err, ret);
|
||||||
|
puts(buf);
|
||||||
|
free(buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case CborTagType: {
|
||||||
|
CborTag tag;
|
||||||
|
ret = cbor_value_get_tag(it, &tag);
|
||||||
|
CBOR_CHECK(ret, "parse tag failed", err, ret);
|
||||||
|
printf("Tag(%lld)\n", (long long)tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CborSimpleType: {
|
||||||
|
uint8_t type;
|
||||||
|
ret = cbor_value_get_simple_type(it, &type);
|
||||||
|
CBOR_CHECK(ret, "parse simple type failed", err, ret);
|
||||||
|
printf("simple(%u)\n", type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CborNullType:
|
||||||
|
puts("null");
|
||||||
|
break;
|
||||||
|
case CborUndefinedType:
|
||||||
|
puts("undefined");
|
||||||
|
break;
|
||||||
|
case CborBooleanType: {
|
||||||
|
bool val;
|
||||||
|
ret = cbor_value_get_boolean(it, &val);
|
||||||
|
CBOR_CHECK(ret, "parse boolean type failed", err, ret);
|
||||||
|
puts(val ? "true" : "false");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CborHalfFloatType: {
|
||||||
|
uint16_t val;
|
||||||
|
ret = cbor_value_get_half_float(it, &val);
|
||||||
|
CBOR_CHECK(ret, "parse half float type failed", err, ret);
|
||||||
|
printf("__f16(%04x)\n", val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CborFloatType: {
|
||||||
|
float val;
|
||||||
|
ret = cbor_value_get_float(it, &val);
|
||||||
|
CBOR_CHECK(ret, "parse float type failed", err, ret);
|
||||||
|
printf("%g\n", val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CborDoubleType: {
|
||||||
|
double val;
|
||||||
|
ret = cbor_value_get_double(it, &val);
|
||||||
|
CBOR_CHECK(ret, "parse double float type failed", err, ret);
|
||||||
|
printf("%g\n", val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CborInvalidType: {
|
||||||
|
ret = CborErrorUnknownType;
|
||||||
|
CBOR_CHECK(ret, "unknown cbor type", err, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cbor_value_advance_fixed(it);
|
||||||
|
CBOR_CHECK(ret, "fix value failed", err, ret);
|
||||||
|
}
|
||||||
|
return CborNoError;
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
CborEncoder root_encoder;
|
||||||
|
CborParser root_parser;
|
||||||
|
CborValue it;
|
||||||
|
uint8_t buf[100];
|
||||||
|
|
||||||
|
// Initialize the outermost cbor encoder
|
||||||
|
cbor_encoder_init(&root_encoder, buf, sizeof(buf), 0);
|
||||||
|
|
||||||
|
// Create an array containing several items
|
||||||
|
CborEncoder array_encoder;
|
||||||
|
CborEncoder map_encoder;
|
||||||
|
cbor_encoder_create_array(&root_encoder, &array_encoder, 5); // [
|
||||||
|
// 1. Create a map containing several pairs
|
||||||
|
cbor_encoder_create_map(&array_encoder, &map_encoder, 3); // {
|
||||||
|
// chip:esp32
|
||||||
|
cbor_encode_text_stringz(&map_encoder, "chip");
|
||||||
|
cbor_encode_text_stringz(&map_encoder, "esp32");
|
||||||
|
// unicore:false
|
||||||
|
cbor_encode_text_stringz(&map_encoder, "unicore");
|
||||||
|
cbor_encode_boolean(&map_encoder, false);
|
||||||
|
// ip:[192,168,1,100]
|
||||||
|
cbor_encode_text_stringz(&map_encoder, "ip");
|
||||||
|
CborEncoder array2;
|
||||||
|
cbor_encoder_create_array(&map_encoder, &array2, 4); // [
|
||||||
|
// Encode several numbers
|
||||||
|
cbor_encode_uint(&array2, 192);
|
||||||
|
cbor_encode_uint(&array2, 168);
|
||||||
|
cbor_encode_uint(&array2, 1);
|
||||||
|
cbor_encode_uint(&array2, 100);
|
||||||
|
cbor_encoder_close_container(&map_encoder, &array2); // ]
|
||||||
|
cbor_encoder_close_container(&array_encoder, &map_encoder); // }
|
||||||
|
// 2. Encode float number
|
||||||
|
cbor_encode_float(&array_encoder, 3.14);
|
||||||
|
// 3. Encode simple value
|
||||||
|
cbor_encode_simple_value(&array_encoder, 99);
|
||||||
|
// 4. Encode a string
|
||||||
|
cbor_encode_text_stringz(&array_encoder, "2019-07-10 09:00:00+0000");
|
||||||
|
// 5. Encode a undefined value
|
||||||
|
cbor_encode_undefined(&array_encoder);
|
||||||
|
cbor_encoder_close_container(&root_encoder, &array_encoder); // ]
|
||||||
|
|
||||||
|
// If error happend when encoding, then this value should be meaningless
|
||||||
|
ESP_LOGI(TAG, "encoded buffer size %d", cbor_encoder_get_buffer_size(&root_encoder, buf));
|
||||||
|
|
||||||
|
// Initialize the cbor parser and the value iterator
|
||||||
|
cbor_parser_init(buf, sizeof(buf), 0, &root_parser, &it);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "convert CBOR to JSON");
|
||||||
|
// Dump the values in JSON format
|
||||||
|
cbor_value_to_json(stdout, &it, 0);
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "decode CBOR manually");
|
||||||
|
// Decode CBOR data manully
|
||||||
|
example_dump_cbor_buffer(&it, 0);
|
||||||
|
}
|
5
examples/protocols/cbor/main/component.mk
Normal file
5
examples/protocols/cbor/main/component.mk
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||||
|
|
@ -99,7 +99,7 @@ build_example () {
|
|||||||
|
|
||||||
local EXAMPLE_DIR=$(dirname "${MAKE_FILE}")
|
local EXAMPLE_DIR=$(dirname "${MAKE_FILE}")
|
||||||
local EXAMPLE_NAME=$(basename "${EXAMPLE_DIR}")
|
local EXAMPLE_NAME=$(basename "${EXAMPLE_DIR}")
|
||||||
|
|
||||||
# Check if the example needs a different base directory.
|
# Check if the example needs a different base directory.
|
||||||
# Path of the Makefile relative to $IDF_PATH
|
# Path of the Makefile relative to $IDF_PATH
|
||||||
local MAKE_FILE_REL=${MAKE_FILE#"${IDF_PATH}/"}
|
local MAKE_FILE_REL=${MAKE_FILE#"${IDF_PATH}/"}
|
||||||
@ -182,7 +182,8 @@ echo -e "\nFound issues:"
|
|||||||
IGNORE_WARNS="\
|
IGNORE_WARNS="\
|
||||||
library/error\.o\
|
library/error\.o\
|
||||||
\|\ -Werror\
|
\|\ -Werror\
|
||||||
\|error\.d\
|
\|.*error.*\.o\
|
||||||
|
\|.*error.*\.d\
|
||||||
\|reassigning to symbol\
|
\|reassigning to symbol\
|
||||||
\|changes choice state\
|
\|changes choice state\
|
||||||
\|Compiler version is not supported\
|
\|Compiler version is not supported\
|
||||||
|
@ -145,7 +145,7 @@ build_example () {
|
|||||||
cat ${BUILDLOG}
|
cat ${BUILDLOG}
|
||||||
popd
|
popd
|
||||||
|
|
||||||
grep -i "error\|warning" "${BUILDLOG}" 2>&1 | grep -v "error.c.obj" >> "${LOG_SUSPECTED}" || :
|
grep -i "error\|warning" "${BUILDLOG}" 2>&1 >> "${LOG_SUSPECTED}" || :
|
||||||
}
|
}
|
||||||
|
|
||||||
EXAMPLE_NUM=0
|
EXAMPLE_NUM=0
|
||||||
@ -175,6 +175,7 @@ echo -e "\nFound issues:"
|
|||||||
# 'Compiler and toochain versions is not supported' from crosstool_version_check.cmake
|
# 'Compiler and toochain versions is not supported' from crosstool_version_check.cmake
|
||||||
IGNORE_WARNS="\
|
IGNORE_WARNS="\
|
||||||
library/error\.o\
|
library/error\.o\
|
||||||
|
\|.*error.*\.c\.obj\
|
||||||
\|\ -Werror\
|
\|\ -Werror\
|
||||||
\|error\.d\
|
\|error\.d\
|
||||||
\|reassigning to symbol\
|
\|reassigning to symbol\
|
||||||
|
Loading…
Reference in New Issue
Block a user