# HG changeset patch # User Edouard Tisserant # Date 1727255433 -7200 # Node ID 205d5379b35e21362a4b021849eaa5d87c45ceac # Parent ad2b84071881653eb478e9897312f774e69817fc MQTT: add JSON fixed size 1D array support. WIP. Parsing array still broken. diff -r ad2b84071881 -r 205d5379b35e mqtt/mqtt_client_gen.py --- a/mqtt/mqtt_client_gen.py Fri Sep 20 15:30:22 2024 +0200 +++ b/mqtt/mqtt_client_gen.py Wed Sep 25 11:10:33 2024 +0200 @@ -430,56 +430,84 @@ formatdict["retrieve"] += """ READ_VALUE({c_loc_name}, {C_type})""".format(**locals()) - def recurseJsonTypes(datatype, basetypes): + # collect all used type with their dependencies + basetypes=[] + arrays=set() + structures=set() + already_generated_types = set() + + def recurseJsonTypes(datatype): + # append derivated type first so we can expect the list + # to be sorted with base types in last position basetypes.append(datatype) - # add derivated type first fo we can expect the list to be sorted - # with base types in last position infos = datatype_info_getter(datatype) - for element in infos["elements"]: - field_datatype = element["Type"] - if field_datatype not in MQTT_IEC_types: - recurseJsonTypes(field_datatype, basetypes) - - print(json_types) - - # collect all type dependencies - basetypes=[] # use a list to keep them ordered + print(infos) + element_type = infos["type"] + if element_type == "Structure": + structures.add(datatype) + for element in infos["elements"]: + field_datatype = element["Type"] + if field_datatype not in MQTT_IEC_types: + recurseJsonTypes(field_datatype) + elif element_type == "Array": + arrays.add(datatype) + item_datatype = infos["base_type"] + if item_datatype not in MQTT_IEC_types: + recurseJsonTypes(item_datatype) + def typeCategory(iec_type): + if field_iec_type in arrays: + return "ARRAY" + elif field_iec_type in structures: + return "OBJECT" + return "SIMPLE" + for iec_type,_instances in json_types.items(): - recurseJsonTypes(iec_type, basetypes) - - done_types = set() + recurseJsonTypes(iec_type) + # go backard to get most derivated type definition last # so that CPP can always find base type deinition before for iec_type in reversed(basetypes): # avoid repeating type definition - if iec_type in done_types: + if iec_type in already_generated_types: continue - done_types.add(iec_type) + already_generated_types.add(iec_type) C_type = iec_type.upper() json_decl = "#define TYPE_" + C_type + "(_P, _A) \\\n" infos = datatype_info_getter(iec_type) - elements = infos["elements"] - last = len(elements) - 1 - for idx, element in enumerate(elements): - field_iec_type = element["Type"] + element_type = infos["type"] + if element_type == "Structure": + elements = infos["elements"] + last = len(elements) - 1 + for idx, element in enumerate(elements): + field_iec_type = element["Type"] + if type(field_iec_type) == tuple and field_iec_type[0] == "array": + raise Exception("Inline arrays in structure are not supported. Please use a separate data type for array.") + + field_C_type = field_iec_type.upper() + field_name = element["Name"] + field_C_name = field_name.upper() + decl_type = typeCategory(field_iec_type) + + json_decl += (" _P##_" + decl_type + "(" + + field_C_type + ", " + field_C_name + ", " + field_name + ", _A)" + + ("\n\n" if idx == last else " _P##_separator \\\n")) + + elif element_type == "Array": + dimensions = infos["dimensions"] + if len(dimensions) > 1: + raise Exception("Only 1 dimension arrays are supported") + count = int(dimensions[0][1]) - int(dimensions[0][0]) + 1 + field_iec_type = infos["base_type"] + decl_type = typeCategory(field_iec_type) field_C_type = field_iec_type.upper() - field_name = element["Name"] - field_C_name = field_name.upper() - if field_iec_type in MQTT_IEC_types: - decl_type = "SIMPLE" - else: - decl_type = "OBJECT" - - json_decl += " _P##_"+decl_type+"(" + field_C_type + ", " + field_C_name + ", " + field_name + ", _A)" - if idx != last: - json_decl += " _P##_separator \\" - else: - json_decl += "\n" - json_decl += "\n" - + last = count - 1 + for idx in range(count): + json_decl += (" _P##_ARRAY_" + decl_type + "(" + + field_C_type + ", " + repr(idx) + " , _A)" + + ("\n\n" if idx == last else " _P##_separator \\\n")) formatdict["json_decl"] += json_decl diff -r ad2b84071881 -r 205d5379b35e mqtt/mqtt_template.c --- a/mqtt/mqtt_template.c Fri Sep 20 15:30:22 2024 +0200 +++ b/mqtt/mqtt_template.c Wed Sep 25 11:10:33 2024 +0200 @@ -71,6 +71,9 @@ #define printf_fmt_SIMPLE(C_type, C_name, name, _A) #name " : " printf_fmt_##C_type #define printf_fmt_OBJECT(C_type, C_name, name, _A) #name " : {{ " TYPE_##C_type(printf_fmt, _A) " }}" +#define printf_fmt_ARRAY(C_type, C_name, name, _A) #name " : [ " TYPE_##C_type(printf_fmt, _A) " ]" +#define printf_fmt_ARRAY_SIMPLE(C_type, index, _A) printf_fmt_##C_type +#define printf_fmt_ARRAY_OBJECT(C_type, index, _A) "{{ " TYPE_##C_type(printf_fmt, _A) " }}" #define scanf_fmt_BOOL "%B" #define scanf_fmt_SINT "%hhd" @@ -89,42 +92,51 @@ #define scanf_fmt_SIMPLE(C_type, C_name, name, _A) #name " : " scanf_fmt_##C_type #define scanf_fmt_OBJECT(C_type, C_name, name, _A) #name " : {{ " TYPE_##C_type(scanf_fmt, _A) " }}" - -#define scanf_arg_BOOL(name, data_ptr) &data_ptr->name -#define scanf_arg_SINT(name, data_ptr) &data_ptr->name -#define scanf_arg_USINT(name, data_ptr) &data_ptr->name -#define scanf_arg_INT(name, data_ptr) &data_ptr->name -#define scanf_arg_UINT(name, data_ptr) &data_ptr->name -#define scanf_arg_DINT(name, data_ptr) &data_ptr->name -#define scanf_arg_UDINT(name, data_ptr) &data_ptr->name -#define scanf_arg_LINT(name, data_ptr) &data_ptr->name -#define scanf_arg_ULINT(name, data_ptr) &data_ptr->name -#define scanf_arg_REAL(name, data_ptr) &data_ptr->name -#define scanf_arg_LREAL(name, data_ptr) &data_ptr->name -#define scanf_arg_STRING(name, data_ptr) scan_string, &data_ptr->name +#define scanf_fmt_ARRAY(C_type, C_name, name, _A) #name " : [ " TYPE_##C_type(scanf_fmt, _A) " ]" +#define scanf_fmt_ARRAY_SIMPLE(C_type, index, _A) scanf_fmt_##C_type +#define scanf_fmt_ARRAY_OBJECT(C_type, index, _A) "{{ " TYPE_##C_type(scanf_fmt, _A) " }}" + +#define scanf_arg_BOOL(arg) arg +#define scanf_arg_SINT(arg) arg +#define scanf_arg_USINT(arg) arg +#define scanf_arg_INT(arg) arg +#define scanf_arg_UINT(arg) arg +#define scanf_arg_DINT(arg) arg +#define scanf_arg_UDINT(arg) arg +#define scanf_arg_LINT(arg) arg +#define scanf_arg_ULINT(arg) arg +#define scanf_arg_REAL(arg) arg +#define scanf_arg_LREAL(arg) arg +#define scanf_arg_STRING(arg) scan_string, arg #define scanf_args_separator , -#define scanf_args_SIMPLE(C_type, C_name, name, data_ptr) scanf_arg_##C_type(C_name, data_ptr) +#define scanf_args_SIMPLE(C_type, C_name, name, data_ptr) scanf_arg_##C_type(&data_ptr->C_name) #define scanf_args_OBJECT(C_type, C_name, name, data_ptr) TYPE_##C_type(scanf_args, (&data_ptr->C_name)) - -#define printf_arg_BOOL(name, data_ptr) data_ptr->name -#define printf_arg_SINT(name, data_ptr) data_ptr->name -#define printf_arg_USINT(name, data_ptr) data_ptr->name -#define printf_arg_INT(name, data_ptr) data_ptr->name -#define printf_arg_UINT(name, data_ptr) data_ptr->name -#define printf_arg_DINT(name, data_ptr) data_ptr->name -#define printf_arg_UDINT(name, data_ptr) data_ptr->name -#define printf_arg_LINT(name, data_ptr) data_ptr->name -#define printf_arg_ULINT(name, data_ptr) data_ptr->name -#define printf_arg_REAL(name, data_ptr) data_ptr->name -#define printf_arg_LREAL(name, data_ptr) data_ptr->name -#define printf_arg_STRING(name, data_ptr) data_ptr->name.len, data_ptr->name.body +#define scanf_args_ARRAY(C_type, C_name, name, data_ptr) TYPE_##C_type(scanf_args, data_ptr->C_name.table) +#define scanf_args_ARRAY_SIMPLE(C_type, index, data_ptr) scanf_arg_##C_type(&data_ptr[index]) +#define scanf_args_ARRAY_OBJECT(C_type, index, data_ptr) TYPE_##C_type(scanf_args, (&data_ptr[index])) + +#define printf_arg_BOOL(arg) arg +#define printf_arg_SINT(arg) arg +#define printf_arg_USINT(arg) arg +#define printf_arg_INT(arg) arg +#define printf_arg_UINT(arg) arg +#define printf_arg_DINT(arg) arg +#define printf_arg_UDINT(arg) arg +#define printf_arg_LINT(arg) arg +#define printf_arg_ULINT(arg) arg +#define printf_arg_REAL(arg) arg +#define printf_arg_LREAL(arg) arg +#define printf_arg_STRING(arg) arg.len, arg.body #define printf_args_separator , -#define printf_args_SIMPLE(C_type, C_name, name, data_ptr) printf_arg_##C_type(C_name, data_ptr) +#define printf_args_SIMPLE(C_type, C_name, name, data_ptr) printf_arg_##C_type(data_ptr->C_name) #define printf_args_OBJECT(C_type, C_name, name, data_ptr) TYPE_##C_type(printf_args, (&data_ptr->C_name)) +#define printf_args_ARRAY(C_type, C_name, name, data_ptr) TYPE_##C_type(printf_args, (&data_ptr->C_name.table)) +#define printf_args_ARRAY_SIMPLE(C_type, index, data_ptr) printf_arg_##C_type(data_ptr[index]) +#define printf_args_ARRAY_OBJECT(C_type, index, data_ptr) TYPE_##C_type(printf_args, (data_ptr[index])) static void scan_string(const char *str, int len, void *user_data) {{ IEC_STRING *iecstr = (IEC_STRING*)user_data;