Skip to content

Commit 7b562c9

Browse files
committed
samples/pet: add streaming encode example
1 parent a11155c commit 7b562c9

8 files changed

Lines changed: 201 additions & 15 deletions

File tree

samples/pet/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ if (REGENERATE_ZCBOR)
1414
zcbor code # Invoke code generation
1515
--decode --encode # Generate both encoding and decoding code
1616
--short-names # Attempt to make generated symbol names shorter (at the risk of collision)
17+
--stream-encode # Generate streaming encode entrypoints
1718
-c ${CMAKE_CURRENT_LIST_DIR}/../../tests/cases/pet.cddl # Generate code for the data structures in pet.cddl
1819
-t Pet # Create a public API for decoding/encoding the "Pet" type from pet.cddl
1920
--output-cmake ${CMAKE_CURRENT_LIST_DIR}/pet.cmake # The generated cmake file will be placed here

samples/pet/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ structure. The 3 data structures are created in 3 different ways:
77
1. Converted from YAML using the zcbor script (See [CMakeLists.txt](CMakeLists.txt), [pet1.yml](pet1.yml), and pet1.h).
88
2. Encoded using the zcbor C API.
99
3. Encoded using zcbor-generated C code.
10+
4. Encoded using zcbor-generated streaming entrypoints.
1011

1112
The generated code is found in [src](src) and [include](include).
1213
To regenerate the files, invoke the [CMakeLists.txt](CMakeLists.txt) file with `-DREGENERATE_ZCBOR=Y`.
@@ -41,3 +42,7 @@ build/app
4142
> Name: Gary Giraffe
4243
> Birthday: 0x010203040a0b0c0d
4344
> Species: Other
45+
>
46+
> Name: Sammy Streaming
47+
> Birthday: 0xaabbccddeeff1122
48+
> Species: Cat

samples/pet/include/pet_decode.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,32 @@
1515
#include <stdbool.h>
1616
#include <stddef.h>
1717
#include <string.h>
18+
#include "zcbor_encode.h"
19+
#include "zcbor_decode.h"
1820
#include "pet_types.h"
1921

2022
#ifdef __cplusplus
2123
extern "C" {
2224
#endif
2325

24-
#if DEFAULT_MAX_QTY != 3
26+
#if ZCBOR_GENERATED_DEFAULT_MAX_QTY != 3
2527
#error "The type file was generated with a different default_max_qty than this file"
2628
#endif
2729

28-
2930
int cbor_decode_Pet(
3031
const uint8_t *payload, size_t payload_len,
3132
struct Pet *result,
3233
size_t *payload_len_out);
3334

3435

36+
37+
38+
39+
40+
41+
42+
43+
3544
#ifdef __cplusplus
3645
}
3746
#endif

samples/pet/include/pet_encode.h

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,74 @@
1515
#include <stdbool.h>
1616
#include <stddef.h>
1717
#include <string.h>
18+
#include "zcbor_encode.h"
19+
#include "zcbor_decode.h"
1820
#include "pet_types.h"
1921

2022
#ifdef __cplusplus
2123
extern "C" {
2224
#endif
2325

24-
#if DEFAULT_MAX_QTY != 3
26+
#if ZCBOR_GENERATED_DEFAULT_MAX_QTY != 3
2527
#error "The type file was generated with a different default_max_qty than this file"
2628
#endif
2729

28-
2930
int cbor_encode_Pet(
3031
uint8_t *payload, size_t payload_len,
3132
const struct Pet *input,
3233
size_t *payload_len_out);
3334

35+
/* Streaming encode helpers */
36+
struct zcbor_stream_iter_io {
37+
void *ctx;
38+
zcbor_stream_iter next;
39+
};
40+
#ifndef ZCBOR_CHUNK_OUT_DEFINED
41+
#define ZCBOR_CHUNK_OUT_DEFINED
42+
struct zcbor_chunk_out {
43+
void *ctx;
44+
zcbor_stream_chunk_out call;
45+
};
46+
#endif
47+
#ifndef ZCBOR_CHUNK_IN_DEFINED
48+
#define ZCBOR_CHUNK_IN_DEFINED
49+
struct zcbor_chunk_in {
50+
void *ctx;
51+
zcbor_stream_chunk_in call;
52+
};
53+
#endif
54+
55+
#ifndef CBOR_STREAM_IO_PET_DEFINED
56+
#define CBOR_STREAM_IO_PET_DEFINED
57+
struct cbor_stream_io_Pet {
58+
/* Repeated fields (iterator) */
59+
struct zcbor_stream_iter_io Pet_name_names;
60+
61+
/* Text string fields (chunk_out) */
62+
/* no tstr chunk_out io */
63+
64+
/* Byte string fields (chunk_out) */
65+
struct zcbor_chunk_out chunks_out_Timestamp;
66+
67+
/* Text string fields (chunk_in) */
68+
/* no tstr chunk_in io */
69+
70+
/* Byte string fields (chunk_in) */
71+
struct zcbor_chunk_in chunks_in_Timestamp;
72+
};
73+
#endif
74+
typedef struct cbor_stream_io_Pet cbor_stream_io_Pet;
75+
76+
int cbor_stream_encode_Pet(
77+
zcbor_stream_write_fn stream_write, void *stream_user_data,
78+
const struct Pet *input,
79+
const cbor_stream_io_Pet *io,
80+
size_t *bytes_written_out);
81+
82+
83+
84+
85+
3486

3587
#ifdef __cplusplus
3688
}

samples/pet/include/pet_types.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,17 @@ extern "C" {
2727
*
2828
* See `zcbor --help` for more information about --default-max-qty
2929
*/
30-
#define DEFAULT_MAX_QTY 3
30+
#define ZCBOR_GENERATED_DEFAULT_MAX_QTY 3
31+
32+
/* Allow build-system override. */
33+
#ifndef DEFAULT_MAX_QTY
34+
#define DEFAULT_MAX_QTY ZCBOR_GENERATED_DEFAULT_MAX_QTY
35+
#endif
36+
37+
/* Allow build-system override for streaming state array size. */
38+
#ifndef ZCBOR_STREAM_STATE_ARRAY_SIZE
39+
#define ZCBOR_STREAM_STATE_ARRAY_SIZE 8
40+
#endif
3141

3242
struct Pet {
3343
struct zcbor_string names[3];

samples/pet/src/main.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,33 @@
66

77
#include <zcbor_encode.h>
88
#include <stdio.h>
9+
#include <string.h>
910
#include <pet_decode.h>
1011
#include <pet_encode.h>
1112
#include <pet1.h>
1213

14+
struct stream_ctx {
15+
uint8_t *buf;
16+
size_t size;
17+
size_t pos;
18+
};
19+
20+
static size_t stream_write(void *user_data, const uint8_t *data, size_t len)
21+
{
22+
struct stream_ctx *ctx = (struct stream_ctx *)user_data;
23+
24+
if (!ctx || !data || len == 0) {
25+
return 0;
26+
}
27+
if (ctx->pos + len > ctx->size) {
28+
return 0;
29+
}
30+
31+
memcpy(&ctx->buf[ctx->pos], data, len);
32+
ctx->pos += len;
33+
return len;
34+
}
35+
1336
static void print_pet(const struct Pet *pet)
1437
{
1538
printf("Name:");
@@ -120,10 +143,52 @@ static void get_pet3(void)
120143
print_pet(&decoded_pet);
121144
}
122145

146+
/** Fourth pet - encoded with zcbor-generated streaming entrypoint. */
147+
static void get_pet4_streaming(void)
148+
{
149+
struct Pet decoded_pet;
150+
struct Pet encoded_pet;
151+
int err;
152+
uint8_t pet4[30];
153+
size_t out_len = 0;
154+
struct stream_ctx ctx = {
155+
.buf = pet4,
156+
.size = sizeof(pet4),
157+
.pos = 0,
158+
};
159+
const uint8_t first_name[] = "Sammy";
160+
const uint8_t last_name[] = "Streaming";
161+
const uint8_t timestamp4[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22 };
162+
163+
encoded_pet.names[0].value = first_name;
164+
encoded_pet.names[0].len = sizeof(first_name) - 1;
165+
encoded_pet.names[1].value = last_name;
166+
encoded_pet.names[1].len = sizeof(last_name) - 1;
167+
encoded_pet.names_count = 2;
168+
encoded_pet.birthday.value = timestamp4;
169+
encoded_pet.birthday.len = sizeof(timestamp4);
170+
encoded_pet.species_choice = Pet_species_cat_c;
171+
172+
err = cbor_stream_encode_Pet(stream_write, &ctx, &encoded_pet, NULL, &out_len);
173+
if (err != ZCBOR_SUCCESS || out_len != ctx.pos) {
174+
printf("Streaming encode failed for pet4: %d\r\n", err);
175+
return;
176+
}
177+
178+
err = cbor_decode_Pet(pet4, out_len, &decoded_pet, NULL);
179+
if (err != ZCBOR_SUCCESS) {
180+
printf("Decoding failed for pet4: %d\r\n", err);
181+
return;
182+
}
183+
184+
print_pet(&decoded_pet);
185+
}
186+
123187
int main(void)
124188
{
125189
get_pet1();
126190
get_pet2();
127191
get_pet3();
192+
get_pet4_streaming();
128193
return 0;
129194
}

samples/pet/src/pet_decode.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "pet_decode.h"
1717
#include "zcbor_print.h"
1818

19-
#if DEFAULT_MAX_QTY != 3
19+
#if ZCBOR_GENERATED_DEFAULT_MAX_QTY != 3
2020
#error "The type file was generated with a different default_max_qty than this file"
2121
#endif
2222

@@ -29,6 +29,8 @@
2929
} \
3030
} while(0)
3131

32+
33+
3234
static bool decode_Pet(zcbor_state_t *state, struct Pet *result);
3335

3436

@@ -55,14 +57,12 @@ static bool decode_Pet(
5557
return res;
5658
}
5759

58-
59-
6060
int cbor_decode_Pet(
6161
const uint8_t *payload, size_t payload_len,
6262
struct Pet *result,
6363
size_t *payload_len_out)
6464
{
65-
zcbor_state_t states[4];
65+
zcbor_state_t states[3 + ZCBOR_CONST_STATE_SLOTS];
6666

6767
return zcbor_entry_function(payload, payload_len, (void *)result, payload_len_out, states,
6868
(zcbor_decoder_t *)decode_Pet, sizeof(states) / sizeof(zcbor_state_t), 1);

samples/pet/src/pet_encode.c

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "pet_encode.h"
1717
#include "zcbor_print.h"
1818

19-
#if DEFAULT_MAX_QTY != 3
19+
#if ZCBOR_GENERATED_DEFAULT_MAX_QTY != 3
2020
#error "The type file was generated with a different default_max_qty than this file"
2121
#endif
2222

@@ -29,6 +29,24 @@
2929
} \
3030
} while(0)
3131

32+
/* Streaming io struct (internal, schema-wide). */
33+
struct cbor_stream_io {
34+
/* Repeated fields (iterator) */
35+
struct zcbor_stream_iter_io Pet_name_names;
36+
37+
/* Text string fields (chunk_out) */
38+
/* no tstr chunk_out io */
39+
40+
/* Byte string fields (chunk_out) */
41+
struct zcbor_chunk_out chunks_out_Timestamp;
42+
43+
/* Text string fields (chunk_in) */
44+
/* no tstr chunk_in io */
45+
46+
/* Byte string fields (chunk_in) */
47+
struct zcbor_chunk_in chunks_in_Timestamp;
48+
};
49+
3250
static bool encode_Pet(zcbor_state_t *state, const struct Pet *input);
3351

3452

@@ -37,27 +55,53 @@ static bool encode_Pet(
3755
{
3856
zcbor_log("%s\r\n", __func__);
3957

40-
bool res = (((zcbor_list_start_encode(state, 3) && ((((zcbor_list_start_encode(state, 3) && ((zcbor_multi_encode_minmax(1, 3, &(*input).names_count, (zcbor_encoder_t *)zcbor_tstr_encode, state, (*&(*input).names), sizeof(struct zcbor_string))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, 3)))
58+
bool res = (((zcbor_list_start_encode(state, ZCBOR_VALUE_IS_INDEFINITE_LENGTH) && ((((zcbor_list_start_encode(state, ZCBOR_VALUE_IS_INDEFINITE_LENGTH) && ((((((const struct cbor_stream_io *)zcbor_get_stream_io(state)) && ((const struct cbor_stream_io *)zcbor_get_stream_io(state))->Pet_name_names.next) ? (zcbor_multi_encode_iter_minmax(1, DEFAULT_MAX_QTY, (zcbor_encoder_t *)zcbor_tstr_encode, state, ((const struct cbor_stream_io *)zcbor_get_stream_io(state))->Pet_name_names.next, ((const struct cbor_stream_io *)zcbor_get_stream_io(state))->Pet_name_names.ctx)) : (zcbor_multi_encode_minmax(1, DEFAULT_MAX_QTY, &(*input).names_count, (zcbor_encoder_t *)zcbor_tstr_encode, state, (*&(*input).names), sizeof(struct zcbor_string))))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)))
4159
&& (((((((*input).birthday.len == 8)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))
4260
&& (zcbor_bstr_encode(state, (&(*input).birthday))))
4361
&& ((((*input).species_choice == Pet_species_cat_c) ? ((zcbor_uint32_put(state, (1))))
4462
: (((*input).species_choice == Pet_species_dog_c) ? ((zcbor_uint32_put(state, (2))))
4563
: (((*input).species_choice == Pet_species_other_c) ? ((zcbor_uint32_put(state, (3))))
46-
: false))))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, 3))));
64+
: false))))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, ZCBOR_VALUE_IS_INDEFINITE_LENGTH))));
4765

4866
log_result(state, res, __func__);
4967
return res;
5068
}
5169

52-
53-
5470
int cbor_encode_Pet(
5571
uint8_t *payload, size_t payload_len,
5672
const struct Pet *input,
5773
size_t *payload_len_out)
5874
{
59-
zcbor_state_t states[4];
75+
zcbor_state_t states[3 + ZCBOR_CONST_STATE_SLOTS];
6076

6177
return zcbor_entry_function(payload, payload_len, (void *)input, payload_len_out, states,
6278
(zcbor_decoder_t *)encode_Pet, sizeof(states) / sizeof(zcbor_state_t), 1);
6379
}
80+
81+
int cbor_stream_encode_Pet(
82+
zcbor_stream_write_fn stream_write, void *stream_user_data,
83+
const struct Pet *input,
84+
const cbor_stream_io_Pet *io,
85+
size_t *bytes_written_out)
86+
{
87+
zcbor_state_t states[ZCBOR_STREAM_STATE_ARRAY_SIZE];
88+
zcbor_new_encode_state_streaming(states, sizeof(states) / sizeof(states[0]),
89+
stream_write, stream_user_data, 1);
90+
struct cbor_stream_io io_local = {0};
91+
if (io) {
92+
io_local.Pet_name_names = io->Pet_name_names;
93+
io_local.chunks_out_Timestamp = io->chunks_out_Timestamp;
94+
zcbor_set_stream_io(&states[0], &io_local);
95+
} else {
96+
zcbor_set_stream_io(&states[0], NULL);
97+
}
98+
bool ok = encode_Pet(&states[0], input);
99+
if (!ok) {
100+
int err = zcbor_pop_error(&states[0]);
101+
return (err == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : err;
102+
}
103+
if (bytes_written_out) {
104+
*bytes_written_out = zcbor_stream_bytes_written(&states[0]);
105+
}
106+
return ZCBOR_SUCCESS;
107+
}

0 commit comments

Comments
 (0)