start working on message
authorLaurent Mazet <mazet@softndesign.org>
Mon, 7 Apr 2025 09:54:33 +0000 (11:54 +0200)
committerLaurent Mazet <mazet@softndesign.org>
Mon, 7 Apr 2025 09:54:33 +0000 (11:54 +0200)
clear_data.c [new file with mode: 0644]
clear_data.h [new file with mode: 0644]
makefile
morep_valid.c
parse.h
raw_data.c [new file with mode: 0644]
raw_data.h [new file with mode: 0644]

diff --git a/clear_data.c b/clear_data.c
new file mode 100644 (file)
index 0000000..148a057
--- /dev/null
@@ -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 <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: */
diff --git a/clear_data.h b/clear_data.h
new file mode 100644 (file)
index 0000000..50ccfda
--- /dev/null
@@ -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 <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: */
index 566e96d300b3ef5cd0364fc5b607630a0de17e4e..a15e1088ba6046fddca53f35d7e78e5839404dc9 100644 (file)
--- 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)
 
index 0c0525b7b8506dfe8f4b56cb8a85fa7fde916e60..674e3141903185d8e64a27bb7f2d943f1db237e8 100644 (file)
@@ -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 <errno.h>
 #include <signal.h>
@@ -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, payloadlen);
+            int seqnum = MOREP_Send (comm->morep, msgtype, payload.data, payload.data_len);
             if (log) {
-                print_message (log, comm->etype, 1, msgtype, seqnum, payloadlen);
+                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 14889818da058f293be0a83b2a4aa4a213e1bc23..4608c7fb9bf2697de7dfa662888ee5c16f68954f 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -6,7 +6,7 @@
   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__ */
 
diff --git a/raw_data.c b/raw_data.c
new file mode 100644 (file)
index 0000000..ee27ec3
--- /dev/null
@@ -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 <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: */
diff --git a/raw_data.h b/raw_data.h
new file mode 100644 (file)
index 0000000..c261cad
--- /dev/null
@@ -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 <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: */