1 /* CBOR Example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 #include <stdio.h>
10 #include "esp_log.h"
11 #include "cbor.h"
12 
13 static const char *TAG = "example";
14 
15 #define CBOR_CHECK(a, str, goto_tag, ret_value, ...)                              \
16     do                                                                            \
17     {                                                                             \
18         if ((a) != CborNoError)                                                   \
19         {                                                                         \
20             ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
21             ret = ret_value;                                                      \
22             goto goto_tag;                                                        \
23         }                                                                         \
24     } while (0)
25 
indent(int nestingLevel)26 static void indent(int nestingLevel)
27 {
28     while (nestingLevel--) {
29         printf("  ");
30     }
31 }
32 
dumpbytes(const uint8_t * buf,size_t len)33 static void dumpbytes(const uint8_t *buf, size_t len)
34 {
35     while (len--) {
36         printf("%02X ", *buf++);
37     }
38 }
39 
40 /**
41  * Decode CBOR data manuallly
42  */
example_dump_cbor_buffer(CborValue * it,int nestingLevel)43 static CborError example_dump_cbor_buffer(CborValue *it, int nestingLevel)
44 {
45     CborError ret = CborNoError;
46     while (!cbor_value_at_end(it)) {
47         CborType type = cbor_value_get_type(it);
48 
49         indent(nestingLevel);
50         switch (type) {
51         case CborArrayType: {
52             CborValue recursed;
53             assert(cbor_value_is_container(it));
54             puts("Array[");
55             ret = cbor_value_enter_container(it, &recursed);
56             CBOR_CHECK(ret, "enter container failed", err, ret);
57             ret = example_dump_cbor_buffer(&recursed, nestingLevel + 1);
58             CBOR_CHECK(ret, "recursive dump failed", err, ret);
59             ret = cbor_value_leave_container(it, &recursed);
60             CBOR_CHECK(ret, "leave container failed", err, ret);
61             indent(nestingLevel);
62             puts("]");
63             continue;
64         }
65         case CborMapType: {
66             CborValue recursed;
67             assert(cbor_value_is_container(it));
68             puts("Map{");
69             ret = cbor_value_enter_container(it, &recursed);
70             CBOR_CHECK(ret, "enter container failed", err, ret);
71             ret = example_dump_cbor_buffer(&recursed, nestingLevel + 1);
72             CBOR_CHECK(ret, "recursive dump failed", err, ret);
73             ret = cbor_value_leave_container(it, &recursed);
74             CBOR_CHECK(ret, "leave container failed", err, ret);
75             indent(nestingLevel);
76             puts("}");
77             continue;
78         }
79         case CborIntegerType: {
80             int64_t val;
81             ret = cbor_value_get_int64(it, &val);
82             CBOR_CHECK(ret, "parse int64 failed", err, ret);
83             printf("%lld\n", (long long)val);
84             break;
85         }
86         case CborByteStringType: {
87             uint8_t *buf;
88             size_t n;
89             ret = cbor_value_dup_byte_string(it, &buf, &n, it);
90             CBOR_CHECK(ret, "parse byte string failed", err, ret);
91             dumpbytes(buf, n);
92             puts("");
93             free(buf);
94             continue;
95         }
96         case CborTextStringType: {
97             char *buf;
98             size_t n;
99             ret = cbor_value_dup_text_string(it, &buf, &n, it);
100             CBOR_CHECK(ret, "parse text string failed", err, ret);
101             puts(buf);
102             free(buf);
103             continue;
104         }
105         case CborTagType: {
106             CborTag tag;
107             ret = cbor_value_get_tag(it, &tag);
108             CBOR_CHECK(ret, "parse tag failed", err, ret);
109             printf("Tag(%lld)\n", (long long)tag);
110             break;
111         }
112         case CborSimpleType: {
113             uint8_t type;
114             ret = cbor_value_get_simple_type(it, &type);
115             CBOR_CHECK(ret, "parse simple type failed", err, ret);
116             printf("simple(%u)\n", type);
117             break;
118         }
119         case CborNullType:
120             puts("null");
121             break;
122         case CborUndefinedType:
123             puts("undefined");
124             break;
125         case CborBooleanType: {
126             bool val;
127             ret = cbor_value_get_boolean(it, &val);
128             CBOR_CHECK(ret, "parse boolean type failed", err, ret);
129             puts(val ? "true" : "false");
130             break;
131         }
132         case CborHalfFloatType: {
133             uint16_t val;
134             ret = cbor_value_get_half_float(it, &val);
135             CBOR_CHECK(ret, "parse half float type failed", err, ret);
136             printf("__f16(%04x)\n", val);
137             break;
138         }
139         case CborFloatType: {
140             float val;
141             ret = cbor_value_get_float(it, &val);
142             CBOR_CHECK(ret, "parse float type failed", err, ret);
143             printf("%g\n", val);
144             break;
145         }
146         case CborDoubleType: {
147             double val;
148             ret = cbor_value_get_double(it, &val);
149             CBOR_CHECK(ret, "parse double float type failed", err, ret);
150             printf("%g\n", val);
151             break;
152         }
153         case CborInvalidType: {
154             ret = CborErrorUnknownType;
155             CBOR_CHECK(ret, "unknown cbor type", err, ret);
156             break;
157         }
158         }
159 
160         ret = cbor_value_advance_fixed(it);
161         CBOR_CHECK(ret, "fix value failed", err, ret);
162     }
163     return CborNoError;
164 err:
165     return ret;
166 }
167 
168 
app_main(void)169 void app_main(void)
170 {
171     CborEncoder root_encoder;
172     CborParser root_parser;
173     CborValue it;
174     uint8_t buf[100];
175 
176     // Initialize the outermost cbor encoder
177     cbor_encoder_init(&root_encoder, buf, sizeof(buf), 0);
178 
179     // Create an array containing several items
180     CborEncoder array_encoder;
181     CborEncoder map_encoder;
182     cbor_encoder_create_array(&root_encoder, &array_encoder, 5); // [
183     // 1. Create a map containing several pairs
184     cbor_encoder_create_map(&array_encoder, &map_encoder, 3); // {
185     // chip:esp32
186     cbor_encode_text_stringz(&map_encoder, "chip");
187     cbor_encode_text_stringz(&map_encoder, "esp32");
188     // unicore:false
189     cbor_encode_text_stringz(&map_encoder, "unicore");
190     cbor_encode_boolean(&map_encoder, false);
191     // ip:[192,168,1,100]
192     cbor_encode_text_stringz(&map_encoder, "ip");
193     CborEncoder array2;
194     cbor_encoder_create_array(&map_encoder, &array2, 4); // [
195     // Encode several numbers
196     cbor_encode_uint(&array2, 192);
197     cbor_encode_uint(&array2, 168);
198     cbor_encode_uint(&array2, 1);
199     cbor_encode_uint(&array2, 100);
200     cbor_encoder_close_container(&map_encoder, &array2);        // ]
201     cbor_encoder_close_container(&array_encoder, &map_encoder); // }
202     // 2. Encode float number
203     cbor_encode_float(&array_encoder, 3.14);
204     // 3. Encode simple value
205     cbor_encode_simple_value(&array_encoder, 99);
206     // 4. Encode a string
207     cbor_encode_text_stringz(&array_encoder, "2019-07-10 09:00:00+0000");
208     // 5. Encode a undefined value
209     cbor_encode_undefined(&array_encoder);
210     cbor_encoder_close_container(&root_encoder, &array_encoder); // ]
211 
212     // If error happend when encoding, then this value should be meaningless
213     ESP_LOGI(TAG, "encoded buffer size %d", cbor_encoder_get_buffer_size(&root_encoder, buf));
214 
215     // Initialize the cbor parser and the value iterator
216     cbor_parser_init(buf, sizeof(buf), 0, &root_parser, &it);
217 
218     ESP_LOGI(TAG, "convert CBOR to JSON");
219     // Dump the values in JSON format
220     cbor_value_to_json(stdout, &it, 0);
221     puts("");
222 
223     ESP_LOGI(TAG, "decode CBOR manually");
224     // Decode CBOR data manully
225     example_dump_cbor_buffer(&it, 0);
226 }
227