From: Laurent Mazet Date: Mon, 7 Apr 2025 09:54:33 +0000 (+0200) Subject: start working on message X-Git-Tag: v1.0~69 X-Git-Url: https://secure.softndesign.org/git/?a=commitdiff_plain;h=3a544ca6660652d3ef388c88be32e73db7c313c4;p=morep.git start working on message --- diff --git a/clear_data.c b/clear_data.c new file mode 100644 index 0000000..148a057 --- /dev/null +++ b/clear_data.c @@ -0,0 +1,39 @@ +/* + File name : clear_data.c + Projet : MERLIN + Date of creation : 2025/04/07 + Version : 1.0 + Copyright : Thales SIX + Author : Laurent Mazet + + Description : This file contains definition of clear data type + + History : + - initial version +*/ + +#include + +#include "parse.h" + +#include "clear_data.h" + +int parse_clear_data (char *line, CLEAR_DATA_t *out) +{ + BEGIN_PARSE (line) + PARSE ("CHANNEL", out->channel_id) + PARSE ("BYPASS", out->bypass) + PARSEA ("DATA", out->data) + END_PARSE () +} + +int format_clear_data (CLEAR_DATA_t *in, char *buffer, int maxlen) +{ + BEGIN_FORMAT (buffer, maxlen); + FORMAT ("CHANNEL", out->channel_id) + FORMAT ("BYPASS", out->bypass) + FORMATA ("DATA", out->data) + END_FORMAT () +} + +/* vim: set ts=4 sw=4 si et: */ diff --git a/clear_data.h b/clear_data.h new file mode 100644 index 0000000..50ccfda --- /dev/null +++ b/clear_data.h @@ -0,0 +1,61 @@ +/* + File name : clear_data.h + Projet : MERLIN + Date of creation : 2025/04/07 + Version : 1.0 + Copyright : Thales SIX + Author : Laurent Mazet + + Description : This file contains definition of clear data type + + History : + - initial version +*/ + +#ifndef __CLEAR_DATA_H__ +#define __CLEAR_DATA_H__ + +#include +#include + +__BEGIN_DECLS + +/** + @ingroup MESSAGES + + Clear data type +*/ +typedef struct { + uint8_t channelid; /**< channel index */ + uint8_t bypass_len; /**< attached bypass message length */ + uint8_t bypass[255]; /**< attached bypass message */ + uint8_t data_len; /**< data length (must be aligned to 16 bytes) */ + uint8_t data[1472]; /**< data message */ +} CLEAR_DATA_t; + +/** + @ingroup MESSAGES + + Parse a string containing some clear data type fields + + @param line string to analyse + @param out output structure +*/ +int parse_clear_data (char *line, CLEAR_DATA_t *out); + +/** + @ingroup MESSAGES + + Format clear data type fields into a string + + @param in input structure + @param buffer output string + @param maxlen buffer limit +*/ +int format_clear_data (CLEAR_DATA_t *in, char *buffer, int maxlen); + +__END_DECLS + +#endif /* __CLEAR_DATA_H__ */ + +/* vim: set ts=4 sw=4 si et: */ diff --git a/makefile b/makefile index 566e96d..a15e108 100644 --- a/makefile +++ b/makefile @@ -13,6 +13,7 @@ OFLAGS = -O4 -Os #OFLAGS += -malign-double CFLAGS += -W -Wall -Wextra -g #CFLAGS += -std=c99 -D_XOPEN_SOURCE=500 +CFLAGS += -std=c11 -D_XOPEN_SOURCE=500 CFLAGS += $(OFLAGS) $(INCLUDES) $(OPTIONS) LDFLAGS += -g $(LDOPTS) $(OPTIONS) diff --git a/morep_valid.c b/morep_valid.c index 0c0525b..674e314 100644 --- a/morep_valid.c +++ b/morep_valid.c @@ -14,8 +14,8 @@ /* depend: */ /* cflags: */ -/* linker: morep.o */ -/* winlnk: morep.o */ +/* linker: morep.o parse.o raw_data.o */ +/* winlnk: morep.o parse.o raw_data.o */ #include #include @@ -27,6 +27,7 @@ #include "morep.h" #include "parse.h" +#include "raw_data.h" #include "verbose.h" char *progname = NULL; @@ -82,125 +83,6 @@ char *read_stream (FILE *sd, int *plen) return buffer; } -uint8_t *parse_payload (char *value, int *plen) -{ - int slen = strlen (value); - uint8_t *buffer = NULL; - int length = 0; - - /* string payload: "..." (no space, tab or =) */ - if ((*value == '"') && (slen > 1)) { - if (value[slen - 1] == '"') { - length = slen - 2; - buffer = (uint8_t *) calloc (length + 1, 1); - memcpy (buffer, value + 1, length); - } else { - VERBOSE (morep, ERROR, PRINTF ("incomplet string '%s'\n", value)); - } - } - - /* file payload: @filename */ - else if (*value == '@') { - FILE *fid = fopen (value + 1, "r"); - if (fid != NULL) { - buffer = (uint8_t *) read_stream (fid, &length); - fclose (fid); - } else { - VERBOSE (morep, ERROR, PRINTF ("can't open file '%s'\n", value)); - } - } - - /* hexa payload: xxxxxx [0-9a-fA-F] */ - else if (slen % 2 == 0) { - length = slen / 2; - buffer = (uint8_t *) calloc (length, 1); - int i; - for (i = 0; i < length; i++) { - char digit[3] = {0}; - char *ptr = NULL; - digit[0] = value[2 * i]; - digit[1] = value[2 * i + 1]; - buffer[i] = strtol (digit, &ptr, 16); - if (*ptr != '\0') { - VERBOSE (morep, ERROR, PRINTF ("unrecognize hexa-string (%d) '%s'\n", 2 * i, value)); - free (buffer); - buffer = NULL; - break; - } - } - } - - /* unrecognize format */ - else { - VERBOSE (morep, WARNING, PRINTF ("can't parse buffer '%s'\n", value)); - } - - if (plen) { - *plen = length; - } - - return buffer; -} - - -uint8_t *parse_line (char *line, uint8_t *msgtype, int *plen) -{ - uint8_t *payload = NULL; - int length = -1; - *msgtype = -1; - - /* trim line */ - while ((*line == ' ') || (*line == '\t')) { - line++; - } - - /* segment line as var=val */ - char *delim = " =\t"; - char *str = strdup (line); - char *save_ptr; - char *ptr = str; - while (1) { - char *var = strtok_r (ptr, delim, &save_ptr); - ptr = NULL; - if (!var) break; - char *val = strtok_r (NULL, delim, &save_ptr); - if (!var) break; - - /* switch on string */ - STR_SWITCH (var) - - /* case message type */ - CASE ("MSG") { - *msgtype = strtol (val, NULL, 0); - if (length < 0 ) { - length = 0; - } - } - - /* case payload */ - CASE ("PAYLOAD") { - payload = parse_payload (val, &length); - } - - /* default */ - DEFAULT { - VERBOSE (morep, WARNING, PRINTF ("unknown word '%s'\n", var)); - } - - /* end switch */ - END_SWITCH (var) - - } - /* end of segmentation */ - free (str); - - if (plen) { - *plen = length; - } - - return payload; -} - void print_message (FILE *fd, char *etype, int mode, uint8_t msg, int seqnum, uint8_t *payload, int len) { fprintf (fd ? fd : stdout, "%c%s SEG=%d MSG=%d LEN=%d", mode ? 'T' : 'R', etype, seqnum, msg, len); @@ -359,19 +241,11 @@ int main (int argc, char **argv) /* read line */ char *line = ptr; - do { - if ((*ptr == '\n') || (*ptr == '\r')) { - *ptr = 0; - } - } while (*ptr++ != '\0'); + TEST_CHARS (ptr, "\n\r", 1); + *ptr++ = '\0'; /* clean line */ - while ((*line == ' ') || (*line == '\t')) { - if (*line == '\0') { - break; - } - line++; - } + TEST_CHARS (line, " \t", 0); if ((*line == '\0') || (*line == '#')) { continue; } @@ -413,19 +287,31 @@ int main (int argc, char **argv) VERBOSE (morep, DEBUG, PRINTF ("work with %c[%s]\n", comm->mode ? 'T' : 'R', comm->etype)); /* get values */ - uint8_t msgtype = 0; - int len = 0; - uint8_t *payload = parse_line (line + offset, &msgtype, &len); - if (len < 0) { + char *tmp = line; + TEST_CHARS (tmp, " \t", 0); + TEST_CHARS (tmp, " \t=", 1); + if (strncmp (tmp, "MSG", 3) != 0) { + VERBOSE (morep, WARNING, PRINTF ("can't parse line '%s'\n", line)); + continue; + } + TEST_CHARS (tmp, " \t=", 0); + uint8_t msgtype = strtol (tmp, &tmp, 0); + if ((*tmp != ' ') && (*tmp != '\t')) { + VERBOSE (morep, WARNING, PRINTF ("can't parse line '%s'\n", line)); + continue; + } + + RAW_DATA_t payload = {0}; + if (parse_raw_data (tmp, &payload) != 0) { VERBOSE (morep, WARNING, PRINTF ("can't parse line '%s'\n", line)); continue; } /* transmit */ if (mode == 1) { - int seqnum = MOREP_Send (comm->morep, msgtype, payload, len); + int seqnum = MOREP_Send (comm->morep, msgtype, payload.data, payload.data_len); if (log) { - print_message (log, comm->etype, 1, msgtype, seqnum, payload, len); + print_message (log, comm->etype, 1, msgtype, seqnum, payload.data, payload.data_len); } } else { /* receive */ uint8_t rxmsgtype = 0; @@ -439,10 +325,10 @@ int main (int argc, char **argv) } /* check payload */ else { - int ok = (rxlen == len); + int ok = (rxlen == payload.data_len); i = -1; for (i = 0; ok && (i < rxlen); i++) { - ok = (rxpayload[i] == payload[i]); + ok = (rxpayload[i] == payload.data[i]); } if (!ok) { VERBOSE (morep, WARNING, PRINTF ("R%04x SEQ=%d MSG=%d: payloads differed at %d/%d\n", rxmsgtype, seqnum, rxmsgtype, i, rxlen)); @@ -452,7 +338,6 @@ int main (int argc, char **argv) print_message (log, comm->etype, 0, rxmsgtype, seqnum, rxpayload, rxlen); } } - free (payload); } /* cleaning */ diff --git a/parse.h b/parse.h index 1488981..4608c7f 100644 --- a/parse.h +++ b/parse.h @@ -6,7 +6,7 @@ Copyright : Thales SIX Author : Laurent Mazet - Description : This file contains parse macros + Description : This file contains parse functions and macros History : - initial version @@ -15,93 +15,165 @@ #ifndef __PARSE_H__ #define __PARSE_H__ +#include #include #include +#include "verbose.h" + __BEGIN_DECLS /** - Begin of switch/case on a string + @ingroup MESSAGES + + Test if a string contains only some characters or excludes them - @param str string + @param str string to be parsed + @param delim list of characters to test + @param test 0 for "contain only", 1 for "exclude" */ -#define STR_SWITCH(str) \ - { char *str_var = str; if (0) {} +#define TEST_CHARS(str, delim, test) \ + while (*str != '\0') { \ + int i, stat = 0; \ + for (i = 0; (delim[i] != '\0') && (!stat); i++) { \ + if (*str == delim[i]) { \ + stat = 1; \ + } \ + } \ + if (stat == test) { \ + break; \ + } \ + str++; \ + } /** - Case of a switch/case on a string + @ingroup MESSAGES - @param value string value -*/ -#define CASE(value) \ - else if (strcasecmp (str_var, value) == 0) -/** - Case of a switch/case on a string + Init parsing macro - @param value string value - @param assign statement + @param line string to be parsed */ -#define CASE_MAP(value, assign) \ - else if (strcasecmp (str_var, value) == 0) { assign; } +#define BEGIN_PARSE(line) \ +{ \ + int rc = 0; \ + char *pt = (line); \ + while (1) { \ + /* find variable */ \ + TEST_CHARS (pt, " \t", 0); \ + char *var = pt; \ + TEST_CHARS (pt, " \t=", 1); \ + if (*var == '\0') { \ + break; \ + } \ + TEST_CHARS (pt, " \t=", 0); \ + /* find value */ \ + char *val = pt; \ + while (*pt != '\0') { \ + if ((*pt == ' ') && (*(pt - 1) != '\\')) { \ + break; \ + } \ + pt++; \ + } \ + if (*val == '\0') { \ + rc = 1; \ + break; \ + } /** - Default of a switch/case on a string -*/ -#define DEFAULT else + @ingroup MESSAGES -/** - End of a switch/case on a string + Parsing macro + + @param name field name + @param buf preallocated storage */ -#define END_SWITCH(str) } +#define PARSE(name, buf) \ + else if (strcmp (var, name) == 0) { \ + _Generic ((buf), \ + uint8_t: buf = parse_int (val), \ + int8_t: buf = parse_int (val), \ + uint16_t: buf = parse_int (val), \ + int16_t: buf = parse_int (val), \ + uint32_t: buf = parse_int (val), \ + float: buf = parse_double (val), \ + double: buf = parse_double (val))i; \ + } + +#define PARSEA(name, buf) \ + else if (strcmp (var, name) == 0) { \ + buf##_len = parse_array (val, buf, sizeof (buf)); \ + } /** - Init parsing macro + @ingroup MESSAGES - @param delim delimitator characters (usualy "=\t\n\r") + End of parsing macro */ -#define INIT_BIG_SWITCH(_delim) \ - const char *delim = _delim; \ - char *save_ptr; \ - char *str = strdup (c_buf); \ - char *ascii_type = strtok_r (str, delim, &save_ptr); \ - STR_SWITCH(ascii_type) +#define END_PARSE() \ + else { \ + VERBOSE (morep, WARNING, PRINTF ("can understand '%s'\n", var)); \ + rc = 1; \ + break; \ + } \ + } \ + return rc; \ +} /** - Begin of parsing macro + @ingroup MESSAGES - @param T message type + Initialize format section + + @param buffer output buffer + @maxlen buffer limit */ -#define PARSE(T) \ - T *e = (T *) msg; \ - memset (msg, 0, sizeof(*e)); \ - while (1) { \ - char *var = strtok_r (NULL, delim, &save_ptr); \ - if (!var) break; \ - char *val = strtok_r (NULL, delim, &save_ptr); \ - if (!val) break; \ - STR_SWITCH(var) +#define BEGIN_FORMAT(buffer, maxlen) \ + char *_buffer = (buffer); \ + int _maxlen = (maxlen); \ + int len = 0; /** - End of parsing macro + @ingroup MESSAGES + + Format a field + + @param name field name + @param field data from structure */ -#define END_PARSE() \ - DEFAULT { \ - fprintf(stderr, "ERROR : %s message : %s field unknown\n", \ - ascii_type, var); \ - rc = -1; \ - break; \ - } \ - END_SWITCH(var) \ -} +#define FORMAT(name, field) \ + _Generic (typeof (field), \ + uint8_t: len += snprintf (_buffer, _maxlen - len, "%d", field), \ + int8_t: len += snprintf (_buffer, _maxlen - len, "%d", field), \ + uint16_t: len += snprintf (_buffer, _maxlen - len, "%d", field), \ + int16_t: len += snprintf (_buffer, _maxlen - len, "%d", field), \ + uint8_t: len += snprintf (_buffer, _maxlen - len, "%d", field)); \ + if (len == _maxlen) { \ + VERBOSE (morep, WARNING, PRINTF ("field '%s' too large\n", #field)); \ + } + +#define FORMATA(name, field) \ + len += snprint_array (_buffer, _maxlen - len, field, field##_len); \ + if (len == _maxlen) { \ + VERBOSE (morep, WARNING, PRINTF ("field '%s' too large\n", #field)); \ + } /** - End parsing macro + @ingroup MESSAGES + + End of format section */ -#define END_BIG_SWITCH() \ - END_SWITCH(ascii_type) \ - free (str); +#define END_FORMAT() \ + return (len >= _maxlen); + +/* private function (do not use outside) */ + +int parse_int (char *val); + +double parse_double (char *val); + +int parse_array (char *val, uint8_t *buffer, int maxlen); -__END_DECLS +int snprint_array (char *buffer, int size, uint8_t *data, int nb); #endif /* __PARSE_H__ */ diff --git a/raw_data.c b/raw_data.c new file mode 100644 index 0000000..ee27ec3 --- /dev/null +++ b/raw_data.c @@ -0,0 +1,35 @@ +/* + File name : raw_data.c + Projet : MERLIN + Date of creation : 2025/04/07 + Version : 1.0 + Copyright : Thales SIX + Author : Laurent Mazet + + Description : This file contains definition of raw data type + + History : + - initial version +*/ + +#include + +#include "parse.h" + +#include "raw_data.h" + +int parse_raw_data (char *line, RAW_DATA_t *out) +{ + BEGIN_PARSE (line) + PARSEA ("DATA", out->data) + END_PARSE () +} + +int format_raw_data (RAW_DATA_t *in, char *buffer, int maxlen) +{ + BEGIN_FORMAT (buffer, maxlen) + FORMATA ("DATA", in->data) + END_FORMAT () +} + +/* vim: set ts=4 sw=4 si et: */ diff --git a/raw_data.h b/raw_data.h new file mode 100644 index 0000000..c261cad --- /dev/null +++ b/raw_data.h @@ -0,0 +1,58 @@ +/* + File name : raw_data.h + Projet : MERLIN + Date of creation : 2025/04/07 + Version : 1.0 + Copyright : Thales SIX + Author : Laurent Mazet + + Description : This file contains definition of raw data type + + History : + - initial version +*/ + +#ifndef __RAW_DATA_H__ +#define __RAW_DATA_H__ + +#include +#include + +__BEGIN_DECLS + +/** + @ingroup MESSAGES + + Raw data type +*/ +typedef struct { + uint8_t data_len; /**< data length*/ + uint8_t data[1496 * 16 - 1]; /**< data message */ +} RAW_DATA_t; + +/** + @ingroup MESSAGES + + Parse a string containing some raw data type fields + + @param line string to analyse + @param out output structure +*/ +int parse_raw_data (char *line, RAW_DATA_t *out); + +/** + @ingroup MESSAGES + + Format raw data type fields into a string + + @param in input structure + @param buffer output string + @param maxlen buffer limit +*/ +int format_raw_data (RAW_DATA_t *in, char *buffer, int maxlen); + +__END_DECLS + +#endif /* __RAW_DATA_H__ */ + +/* vim: set ts=4 sw=4 si et: */