--- /dev/null
+/*
+ File name : clear_data.c
+ Projet : MERLIN
+ Date of creation : 2025/04/07
+ Version : 1.0
+ Copyright : Thales SIX
+ Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+ Description : This file contains definition of clear data type
+
+ History :
+ - initial version
+*/
+
+#include <stdint.h>
+
+#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: */
--- /dev/null
+/*
+ File name : clear_data.h
+ Projet : MERLIN
+ Date of creation : 2025/04/07
+ Version : 1.0
+ Copyright : Thales SIX
+ Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+ Description : This file contains definition of clear data type
+
+ History :
+ - initial version
+*/
+
+#ifndef __CLEAR_DATA_H__
+#define __CLEAR_DATA_H__
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__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: */
#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)
/* 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 <errno.h>
#include <signal.h>
#include "morep.h"
#include "parse.h"
+#include "raw_data.h"
#include "verbose.h"
char *progname = NULL;
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);
/* 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;
}
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;
}
/* 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));
print_message (log, comm->etype, 0, rxmsgtype, seqnum, rxpayload, rxlen);
}
}
- free (payload);
}
/* cleaning */
Copyright : Thales SIX
Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
- Description : This file contains parse macros
+ Description : This file contains parse functions and macros
History :
- initial version
#ifndef __PARSE_H__
#define __PARSE_H__
+#include <stdint.h>
#include <string.h>
#include <sys/cdefs.h>
+#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__ */
--- /dev/null
+/*
+ File name : raw_data.c
+ Projet : MERLIN
+ Date of creation : 2025/04/07
+ Version : 1.0
+ Copyright : Thales SIX
+ Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+ Description : This file contains definition of raw data type
+
+ History :
+ - initial version
+*/
+
+#include <stdint.h>
+
+#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: */
--- /dev/null
+/*
+ File name : raw_data.h
+ Projet : MERLIN
+ Date of creation : 2025/04/07
+ Version : 1.0
+ Copyright : Thales SIX
+ Author : Laurent Mazet <laurent.mazet@thalesgroup.com>
+
+ Description : This file contains definition of raw data type
+
+ History :
+ - initial version
+*/
+
+#ifndef __RAW_DATA_H__
+#define __RAW_DATA_H__
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__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: */