rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
esc_json.c File Reference

Read one ESC profile from JSON. More...

#include "esc_json_int.h"
#include "esc_profile.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Data Structures

struct  name_at_t
 A model name and where it stands in the file. More...
struct  dec_t
 State of one decoding pass over the tokens. More...

Macros

#define FAIL(d, ...)
 The first reason stands.
#define COUNT(a)
 Number of entries in a static array.

Functions

static void * take (dec_t *d, size_t n, size_t align)
 Take aligned bytes from the block being filled.
static int64_t member (const dec_t *d, uint32_t obj, const char *key)
 The value of key in the object at token obj, or -1.
static const char * copy_str (dec_t *d, uint32_t ti)
 A string token's text, decoded into the block.
static size_t decoded_len (const dec_t *d, uint32_t ti)
 A string token's length once decoded, in bytes: UTF-8, as the generator measures it.
static const char * get_str (dec_t *d, uint32_t obj, const char *key, const char *where, bool empty_ok, bool null_ok)
 Read a string member.
static bool get_num (dec_t *d, uint32_t obj, const char *key, const char *where, int64_t lo, int64_t hi, bool null_ok, int64_t *out)
 A whole number in lo..hi; *out untouched for null when null_ok.
static bool get_bool (dec_t *d, uint32_t obj, const char *key, const char *where, bool absent_ok)
 Read a boolean member.
static int get_enum (dec_t *d, uint32_t obj, const char *key, const char *where, const char *const *names, int count)
 The index of key's string value in names, or -1 after a FAIL().
static int64_t get_obj (dec_t *d, uint32_t obj, const char *key, const char *where, ttype_t type)
 Read a member that must be an object or an array.
static bool key_ok (const char *k, size_t max, bool dash)
 Check an id or key: 1 to max of a-z, 0-9 and one separator.
static int by_name (const void *a, const void *b)
 Sort comparison of model names, then by position.
static int name_is (const void *key, const void *elem)
 Search comparison of a name with a name_at_t.
static void decode_models (dec_t *d, uint32_t root, esc_profile_t *p)
 Decode the models array of a profile.
static bool has_model (const dec_t *d, const char *name)
 Whether a profile has a model with a name.
static esc_throttle_t moves_from (const esc_profile_t *p)
 Where the stick is when a value's own moves (after_select) begin: the profile's store move, else the move that stores the value; ESC_THR_NONE for a profile with no select move.
static void decode_values (dec_t *d, uint32_t arr, const char *iw, esc_item_t *it, esc_throttle_t before)
 Decode the values array of one item.
static void decode_items (dec_t *d, uint32_t root, esc_profile_t *p)
 Decode the items array of a profile.
static void decode_manual (dec_t *d, uint32_t root, esc_profile_t *p)
 The operator's steps at the ESC: absent or null, none.
static void decode (dec_t *d, esc_profile_t *p)
 Decode a whole profile from the tokens.
bool esc_profile_parse (const char *json, size_t len, esc_profile_t *out, void **block, char *err, size_t err_size)
 Parse one profile file.

Variables

static const char *const k_scheme []
 Allowed values of the enumerated members, as the JSON spells them.
static const char *const k_encoding []
static const char *const k_announce []
static const char *const k_auto [] = { "full", "assisted", "none" }
static const char *const k_throttle [] = { "min", "mid", "max", "none" }
static const char *const k_when []
static const char *const k_changes [] = { "one", "many" }
static const char *const k_manual []
static const char *const k_cells [] = { "lipo", "nimh" }

Detailed Description

Read one ESC profile from JSON.

See esc_profile.h.

Two stages. The text is first cut into tokens: one per value, each with the index one past its last descendant, so a reader skips a subtree in one step and never recurses to find a key. Then the profile is decoded from the tokens twice: once with no block, which only adds up the bytes every string and array will need, and once into a block of exactly that size. One allocation per profile, and free() of it releases everything. The first stage is esc_json_lex.c; esc_json_int.h is what it gives this file.

The rules are tools/gen_esc_profiles.py's. The host suite parses every profile of record and compares it with the generated table, so a rule that differs between the two fails there.

SPDX-License-Identifier: MIT

Macro Definition Documentation

◆ COUNT

#define COUNT ( a)
Value:
((int)(sizeof(a) / sizeof((a)[0])))

Number of entries in a static array.

Parameters
aThe array.

◆ FAIL

#define FAIL ( d,
... )
Value:
do { \
if (!(d)->failed) { \
(d)->failed = true; \
if ((d)->err != NULL && (d)->err_size > 0u) { \
(void)snprintf((d)->err, (d)->err_size, __VA_ARGS__); \
} \
} \
} while (0)

The first reason stands.

A macro rather than a variadic function: the arguments go straight to snprintf(), and there is no va_list to get wrong.

Function Documentation

◆ by_name()

int by_name ( const void * a,
const void * b )
static

Sort comparison of model names, then by position.

Parameters
aPointer to a name_at_t.
bPointer to a name_at_t.
Returns
Negative, zero or positive as a sorts before, with or after b.

◆ copy_str()

const char * copy_str ( dec_t * d,
uint32_t ti )
static

A string token's text, decoded into the block.

Never longer than the text it came from: no escape decodes to more bytes than it is written in.

Parameters
dThe decoding state.
tiIndex of the string token.
Returns
The decoded, NUL-terminated text in the block, or NULL while sizing.

◆ decode()

void decode ( dec_t * d,
esc_profile_t * p )
static

Decode a whole profile from the tokens.

Run once to size the block and once to fill it.

Parameters
dThe decoding state.
pReceives the profile.

◆ decode_items()

void decode_items ( dec_t * d,
uint32_t root,
esc_profile_t * p )
static

Decode the items array of a profile.

Parameters
dThe decoding state.
rootIndex of the root object token.
pReceives the items.

◆ decode_manual()

void decode_manual ( dec_t * d,
uint32_t root,
esc_profile_t * p )
static

The operator's steps at the ESC: absent or null, none.

Only an assisted profile has them, 1 to ESC_MANUAL_MAX, in the order a run meets them.

Parameters
dThe decoding state.
rootIndex of the root object token.
pReceives the steps.

◆ decode_models()

void decode_models ( dec_t * d,
uint32_t root,
esc_profile_t * p )
static

Decode the models array of a profile.

Model names must be unique within the profile.

Parameters
dThe decoding state.
rootIndex of the root object token.
pReceives the models.

◆ decode_values()

void decode_values ( dec_t * d,
uint32_t arr,
const char * iw,
esc_item_t * it,
esc_throttle_t before )
static

Decode the values array of one item.

Parameters
dThe decoding state.
arrIndex of the values array token.
iwPath of the item, for the reason text.
itThe item that receives the values.
beforeStick position before the item's first value move.

◆ decoded_len()

size_t decoded_len ( const dec_t * d,
uint32_t ti )
static

A string token's length once decoded, in bytes: UTF-8, as the generator measures it.

The sizing pass has no copy to measure.

Parameters
dThe decoding state.
tiIndex of the string token.
Returns
The decoded length, bytes.

◆ esc_profile_parse()

bool esc_profile_parse ( const char * json,
size_t len,
esc_profile_t * out,
void ** block,
char * err,
size_t err_size )

Parse one profile file.

Everything the profile points at – strings, models, items, values – is placed in one block from malloc(); *block receives it and free(*block) releases the lot. On failure nothing is allocated and err (when not NULL) holds a line for the operator, e.g. "items[2].values: empty".

Parameters
jsonThe file's bytes.
lenLength of json in bytes.
outReceives the parsed profile.
blockReceives the malloc() block that holds the profile.
errMessage for the operator, or NULL.
err_sizeSize of err in bytes.
Returns
true when out is a usable profile

◆ get_bool()

bool get_bool ( dec_t * d,
uint32_t obj,
const char * key,
const char * where,
bool absent_ok )
static

Read a boolean member.

Parameters
dThe decoding state.
objIndex of the object token.
keyThe member name.
wherePath of the object, for the reason text.
absent_oktrue when an absent member reads as false.
Returns
The value; false when absent and absent_ok is set.

◆ get_enum()

int get_enum ( dec_t * d,
uint32_t obj,
const char * key,
const char * where,
const char *const * names,
int count )
static

The index of key's string value in names, or -1 after a FAIL().

Parameters
dThe decoding state.
objIndex of the object token.
keyThe member name.
wherePath of the object, for the reason text.
namesThe allowed values.
countNumber of entries in names.
Returns
The index into names, or -1 after a FAIL().

◆ get_num()

bool get_num ( dec_t * d,
uint32_t obj,
const char * key,
const char * where,
int64_t lo,
int64_t hi,
bool null_ok,
int64_t * out )
static

A whole number in lo..hi; *out untouched for null when null_ok.

Parameters
dThe decoding state.
objIndex of the object token.
keyThe member name.
wherePath of the object, for the reason text.
loSmallest allowed value.
hiLargest allowed value.
null_oktrue when a missing or null member is allowed.
outReceives the value.
Returns
true when a value was read into out.

◆ get_obj()

int64_t get_obj ( dec_t * d,
uint32_t obj,
const char * key,
const char * where,
ttype_t type )
static

Read a member that must be an object or an array.

Parameters
dThe decoding state.
objIndex of the object token.
keyThe member name.
wherePath of the object, for the reason text.
typeT_OBJ or T_ARR.
Returns
Index of the member token, or -1 after a FAIL().

◆ get_str()

const char * get_str ( dec_t * d,
uint32_t obj,
const char * key,
const char * where,
bool empty_ok,
bool null_ok )
static

Read a string member.

Fails when the member is absent or not a string, or is empty while empty_ok is false. A null member is "" when null_ok is set.

Parameters
dThe decoding state.
objIndex of the object token.
keyThe member name.
wherePath of the object, for the reason text.
empty_oktrue when an empty string is allowed.
null_oktrue when a missing or null member is allowed.
Returns
The decoded text, "" or NULL as described above.

◆ has_model()

bool has_model ( const dec_t * d,
const char * name )
static

Whether a profile has a model with a name.

Parameters
dThe decoding state, with the sorted model names.
nameThe model name.
Returns
true when a model has the name.

◆ key_ok()

bool key_ok ( const char * k,
size_t max,
bool dash )
static

Check an id or key: 1 to max of a-z, 0-9 and one separator.

Parameters
kThe text to check.
maxLongest allowed length, characters.
dashtrue for "-" as the separator, false for "_".
Returns
true when the text is allowed.

◆ member()

int64_t member ( const dec_t * d,
uint32_t obj,
const char * key )
static

The value of key in the object at token obj, or -1.

Parameters
dThe decoding state.
objIndex of the object token.
keyThe key to find.
Returns
Index of the value token, or -1 when the key is absent.

◆ moves_from()

esc_throttle_t moves_from ( const esc_profile_t * p)
static

Where the stick is when a value's own moves (after_select) begin: the profile's store move, else the move that stores the value; ESC_THR_NONE for a profile with no select move.

Parameters
pThe profile.
Returns
The position the moves start from.

◆ name_is()

int name_is ( const void * key,
const void * elem )
static

Search comparison of a name with a name_at_t.

Parameters
keyThe name searched for, a const char *.
elemA name_at_t.
Returns
Negative, zero or positive as key sorts before, with or after.

◆ take()

void * take ( dec_t * d,
size_t n,
size_t align )
static

Take aligned bytes from the block being filled.

While sizing, only the used count moves; while filling, the bytes are handed out from the block.

Parameters
dThe decoding state.
nBytes wanted.
alignAlignment of the returned pointer, bytes.
Returns
The pointer into the block, or NULL while sizing.

Variable Documentation

◆ k_announce

const char* const k_announce[]
static
Initial value:
= { "item", "value",
"item_then_value" }

◆ k_encoding

const char* const k_encoding[]
static
Initial value:
= { "count", "short_long", "melody",
"yes_no" }

◆ k_manual

const char* const k_manual[]
static
Initial value:
= { "before_power", "at_power_up",
"before_menu", "during_menu", "before_power_off", "after_programming" }

◆ k_scheme

const char* const k_scheme[]
static
Initial value:
= { "count", "short_long",
"melody_groups", "yes_no", "stick_position", "other" }

Allowed values of the enumerated members, as the JSON spells them.

◆ k_when

const char* const k_when[]
static
Initial value:
= { "before_power_on",
"after_power_on" }