summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/dlt_for_developers.md31
-rw-r--r--include/dlt/dlt_types.h9
-rw-r--r--include/dlt/dlt_user.h2
-rw-r--r--include/dlt/dlt_user_macros.h62
-rw-r--r--src/lib/dlt_user.c9
-rw-r--r--src/system/dlt-system-journal.c28
-rw-r--r--src/system/dlt-system-options.c5
-rw-r--r--src/system/dlt-system.conf3
-rw-r--r--src/system/dlt-system.h1
-rw-r--r--src/tests/dlt-test-user.c86
-rw-r--r--tests/gtest_dlt_user.cpp20
11 files changed, 244 insertions, 12 deletions
diff --git a/doc/dlt_for_developers.md b/doc/dlt_for_developers.md
index a3aa198..651a734 100644
--- a/doc/dlt_for_developers.md
+++ b/doc/dlt_for_developers.md
@@ -535,6 +535,37 @@ DLT_VERBOSE_MODE();
DLT_NONVERBOSE_MODE();
```
+#### Using custom timestamps
+
+The timestamp that is transmitted in the header of a DLT message is usually generated automatically by the library itself right before the message is sent. If you wish to change this, e.g. because you want to indicate when an event occured, rather than when the according message was assembled, you can supply a custom timestamp. Compared to the example above, two macros are defined for convenience:
+
+```
+uint32_t timestamp = 1234567; /* uptime in 0.1 milliseconds */
+if (gflag) {
+ /* Non-verbose mode */
+ DLT_LOG_ID_TS(ctx, DLT_LOG_INFO, 42, timestamp,
+ DLT_INT(num), DLT_STRING(text));
+}
+else {
+ /* Verbose mode */
+ DLT_LOG_TS(ctx, DLT_LOG_INFO, timestamp,
+ DLT_INT(num), DLT_STRING(text));
+}
+```
+
+If you wish to (or have to) use the function interface, you need to set the flag to make use of the user-supplied timestamp manually after calling dlt_user_log_write_start():
+
+
+```
+if (dlt_user_log_write_start(&ctx, &ctxdata, DLT_LOG_INFO) > 0) {
+ ctxdata.use_timestamp = DLT_USER_TIMESTAMP;
+ ctxdata.user_timestamp = (uint32_t) 1234567;
+ dlt_user_log_write_string(&myctxdata, "ID: ");
+ dlt_user_log_write_uint32(&myctxdata, 123);
+ dlt_user_log_write_finish(&myctxdata);
+}
+```
+
### Logging parameters
The following parameter types can be used. Multiple parameters can be added to
diff --git a/include/dlt/dlt_types.h b/include/dlt/dlt_types.h
index f63d046..0047233 100644
--- a/include/dlt/dlt_types.h
+++ b/include/dlt/dlt_types.h
@@ -188,4 +188,13 @@ typedef enum
} DltUserConnectionState;
#endif
+/**
+ * Definition of timestamp types
+ */
+typedef enum
+{
+ DLT_AUTO_TIMESTAMP = 0,
+ DLT_USER_TIMESTAMP
+} DltTimestampType;
+
#endif /* DLT_TYPES_H */
diff --git a/include/dlt/dlt_user.h b/include/dlt/dlt_user.h
index 0804f7e..405d342 100644
--- a/include/dlt/dlt_user.h
+++ b/include/dlt/dlt_user.h
@@ -122,6 +122,8 @@ typedef struct
int32_t trace_status; /**< trace status */
int32_t args_num; /**< number of arguments for extended header*/
char *context_description; /**< description of context */
+ DltTimestampType use_timestamp; /**< whether to use user-supplied timestamps */
+ uint32_t user_timestamp; /**< user-supplied timestamp to use */
} DltContextData;
typedef struct
diff --git a/include/dlt/dlt_user_macros.h b/include/dlt/dlt_user_macros.h
index df9f375..4ad6854 100644
--- a/include/dlt/dlt_user_macros.h
+++ b/include/dlt/dlt_user_macros.h
@@ -69,6 +69,7 @@
#define DLT_USER_MACROS_H
#include "dlt_version.h"
+#include "dlt_types.h"
/**
* \defgroup userapi DLT User API
@@ -217,6 +218,35 @@
#endif
/**
+ * Send log message with variable list of messages (intended for verbose mode)
+ * @param CONTEXT object containing information about one special logging context
+ * @param LOGLEVEL the log level of the log message
+ * @param TS timestamp to be used for log message
+ * @param ARGS variable list of arguments
+ * @note To avoid the MISRA warning "The comma operator has been used outside a for statement"
+ * use a semicolon instead of a comma to separate the ARGS.
+ * Example: DLT_LOG_TS(hContext, DLT_LOG_INFO, timestamp, DLT_STRING("Hello world"); DLT_INT(123));
+ */
+#ifdef _MSC_VER
+/* DLT_LOG_TS is not supported by MS Visual C++ */
+/* use function interface instead */
+#else
+# define DLT_LOG_TS(CONTEXT, LOGLEVEL, TS, ARGS ...) \
+ do { \
+ DltContextData log_local; \
+ int dlt_local; \
+ dlt_local = dlt_user_log_write_start(&CONTEXT, &log_local, LOGLEVEL); \
+ if (dlt_local == DLT_RETURN_TRUE) \
+ { \
+ ARGS; \
+ log_local.use_timestamp = DLT_USER_TIMESTAMP; \
+ log_local.user_timestamp = (uint32_t) TS; \
+ (void)dlt_user_log_write_finish(&log_local); \
+ } \
+ } while (0)
+#endif
+
+/**
* Send log message with variable list of messages (intended for non-verbose mode)
* @param CONTEXT object containing information about one special logging context
* @param LOGLEVEL the log level of the log message
@@ -246,6 +276,38 @@
#endif
/**
+ * Send log message with variable list of messages (intended for non-verbose mode)
+ * @param CONTEXT object containing information about one special logging context
+ * @param LOGLEVEL the log level of the log message
+ * @param MSGID the message id of log message
+ * @param TS timestamp to be used for log message
+ * @param ARGS variable list of arguments:
+ * calls to DLT_STRING(), DLT_BOOL(), DLT_FLOAT32(), DLT_FLOAT64(),
+ * DLT_INT(), DLT_UINT(), DLT_RAW()
+ * @note To avoid the MISRA warning "The comma operator has been used outside a for statement"
+ * use a semicolon instead of a comma to separate the ARGS.
+ * Example: DLT_LOG_ID_TS(hContext, DLT_LOG_INFO, 0x1234, timestamp, DLT_STRING("Hello world"); DLT_INT(123));
+ */
+#ifdef _MSC_VER
+/* DLT_LOG_ID_TS is not supported by MS Visual C++ */
+/* use function interface instead */
+#else
+# define DLT_LOG_ID_TS(CONTEXT, LOGLEVEL, MSGID, TS, ARGS ...) \
+ do { \
+ DltContextData log_local; \
+ int dlt_local; \
+ dlt_local = dlt_user_log_write_start_id(&CONTEXT, &log_local, LOGLEVEL, MSGID); \
+ if (dlt_local == DLT_RETURN_TRUE) \
+ { \
+ ARGS; \
+ log_local.use_timestamp = DLT_USER_TIMESTAMP; \
+ log_local.user_timestamp = (uint32_t) TS; \
+ (void)dlt_user_log_write_finish(&log_local); \
+ } \
+ } while (0)
+#endif
+
+/**
* Add string parameter to the log messsage.
* @param TEXT ASCII string
*/
diff --git a/src/lib/dlt_user.c b/src/lib/dlt_user.c
index 55e57bf..4206dd2 100644
--- a/src/lib/dlt_user.c
+++ b/src/lib/dlt_user.c
@@ -1538,6 +1538,7 @@ DltReturnValue dlt_user_log_write_start_id(DltContext *handle,
log->args_num = 0;
log->log_level = loglevel;
log->size = 0;
+ log->use_timestamp = DLT_AUTO_TIMESTAMP;
/* In non-verbose mode, insert message id */
if (dlt_user.verbose_mode == 0) {
@@ -3584,8 +3585,14 @@ DltReturnValue dlt_user_log_send_log(DltContextData *log, int mtype)
/* Set header extra parameters */
dlt_set_id(msg.headerextra.ecu, dlt_user.ecuID);
+
/*msg.headerextra.seid = 0; */
- msg.headerextra.tmsp = dlt_uptime();
+ if (log->use_timestamp == DLT_AUTO_TIMESTAMP) {
+ msg.headerextra.tmsp = dlt_uptime();
+ }
+ else {
+ msg.headerextra.tmsp = log->user_timestamp;
+ }
if (dlt_message_set_extraparameters(&msg, 0) == DLT_RETURN_ERROR)
return DLT_RETURN_ERROR;
diff --git a/src/system/dlt-system-journal.c b/src/system/dlt-system-journal.c
index 5c10c50..2845406 100644
--- a/src/system/dlt-system-journal.c
+++ b/src/system/dlt-system-journal.c
@@ -202,6 +202,7 @@ void journal_thread(void *v_conf)
sd_journal *j;
char match[DLT_SYSTEM_JOURNAL_BOOT_ID_MAX_LENGTH] = "_BOOT_ID=";
sd_id128_t boot_id;
+ uint32_t ts;
char buffer_process[DLT_SYSTEM_JOURNAL_BUFFER_SIZE] = { 0 },
buffer_priority[DLT_SYSTEM_JOURNAL_BUFFER_SIZE] = { 0 },
@@ -345,13 +346,26 @@ void journal_thread(void *v_conf)
snprintf(buffer_priority, DLT_SYSTEM_JOURNAL_BUFFER_SIZE, "prio_unknown:");
/* write log entry */
- DLT_LOG(journalContext, loglevel,
- DLT_STRING(timestamp.real),
- DLT_STRING(timestamp.monotonic),
- DLT_STRING(buffer_process),
- DLT_STRING(buffer_priority),
- DLT_STRING(buffer_message)
- );
+ if (conf->Journal.UseOriginalTimestamp == 0) {
+ DLT_LOG(journalContext, loglevel,
+ DLT_STRING(timestamp.real),
+ DLT_STRING(timestamp.monotonic),
+ DLT_STRING(buffer_process),
+ DLT_STRING(buffer_priority),
+ DLT_STRING(buffer_message)
+ );
+
+ }
+ else {
+ /* since we are talking about points in time, I'd prefer truncating over arithmetic rounding */
+ ts = (uint32_t)(atof(timestamp.monotonic) * 10000);
+ DLT_LOG_TS(journalContext, loglevel, ts,
+ DLT_STRING(timestamp.real),
+ DLT_STRING(buffer_process),
+ DLT_STRING(buffer_priority),
+ DLT_STRING(buffer_message)
+ );
+ }
}
else {
r = sd_journal_wait(j, 1000000);
diff --git a/src/system/dlt-system-options.c b/src/system/dlt-system-options.c
index 667db9c..5fa31cb 100644
--- a/src/system/dlt-system-options.c
+++ b/src/system/dlt-system-options.c
@@ -148,6 +148,7 @@ void init_configuration(DltSystemConfiguration *config)
config->Journal.CurrentBoot = 1;
config->Journal.Follow = 0;
config->Journal.MapLogLevels = 1;
+ config->Journal.UseOriginalTimestamp = 1;
/* File transfer */
config->Filetransfer.Enable = 0;
@@ -289,6 +290,10 @@ int read_configuration_file(DltSystemConfiguration *config, char *file_name)
{
config->Journal.MapLogLevels = atoi(value);
}
+ else if (strcmp(token, "JournalUseOriginalTimestamp") == 0)
+ {
+ config->Journal.UseOriginalTimestamp = atoi(value);
+ }
/* File transfer */
else if (strcmp(token, "FiletransferEnable") == 0)
diff --git a/src/system/dlt-system.conf b/src/system/dlt-system.conf
index b3677f9..4010b70 100644
--- a/src/system/dlt-system.conf
+++ b/src/system/dlt-system.conf
@@ -74,6 +74,9 @@ JournalFollow = 0
# 7 Debug DLT_LOG_DEBUG
JournalMapLogLevels = 1
+# Use the original timestamp (uptime when the event actually occured) as DLT timestamp (Default: 1)
+JournalUseOriginalTimestamp = 1
+
########################################################################
# Filetransfer Manager
########################################################################
diff --git a/src/system/dlt-system.h b/src/system/dlt-system.h
index ed2b50b..46738b8 100644
--- a/src/system/dlt-system.h
+++ b/src/system/dlt-system.h
@@ -107,6 +107,7 @@ typedef struct {
int CurrentBoot;
int Follow;
int MapLogLevels;
+ int UseOriginalTimestamp;
} JournalOptions;
typedef struct {
diff --git a/src/tests/dlt-test-user.c b/src/tests/dlt-test-user.c
index bc4012e..cd6224f 100644
--- a/src/tests/dlt-test-user.c
+++ b/src/tests/dlt-test-user.c
@@ -74,7 +74,9 @@
#include "dlt.h"
-#define DLT_TEST_NUM_CONTEXT 9
+#define DLT_TEST_NUM_CONTEXT 10
+
+#define DLT_MAX_TIMESTAMP 0xFFFFFFFF
/* LogLevel string representation */
static const char *loglevelstr[DLT_LOG_MAX] = {
@@ -99,6 +101,7 @@ int test6m(void);
int test7m(void);
int test8m(void);
int test9m(void);
+int test10m(void);
/* for function interface */
int test1f(void);
@@ -110,6 +113,7 @@ int test6f(void);
int test7f(void);
int test8f(void);
int test9f(void);
+int test10f(void);
/* Declaration of callback functions */
int test_injection_macro_callback(uint32_t service_id, void *data, uint32_t length);
@@ -154,6 +158,7 @@ void usage()
printf(" 7m: (Macro IF) Test network trace\n");
printf(" 8m: (Macro IF) Test truncated network trace\n");
printf(" 9m: (Macro IF) Test segmented network trace\n");
+ printf(" 10m: (Macro IF) Test user-specified timestamps\n");
printf(" 1f: (Function IF) Test all log levels\n");
printf(" 2f: (Function IF) Test all variable types (verbose) \n");
printf(" 3f: (Function IF) Test all variable types (non-verbose) \n");
@@ -163,6 +168,7 @@ void usage()
printf(" 7f: (Function IF) Test network trace\n");
printf(" 8f: (Function IF) Test truncated network trace\n");
printf(" 9f: (Function IF) Test segmented network trace\n");
+ printf(" 10f: (Function IF) Test user-specified timestamps\n");
}
/**
@@ -177,7 +183,7 @@ int main(int argc, char *argv[])
int c;
int i;
- char ctid[4], ctdesc[255];
+ char ctid[5], ctdesc[255];
int num, maxnum;
@@ -243,7 +249,7 @@ int main(int argc, char *argv[])
DLT_REGISTER_CONTEXT(context_macro_callback, "CBM", "Callback Test context for macro interface");
for (i = 0; i < DLT_TEST_NUM_CONTEXT; i++) {
- snprintf(ctid, 4, "TM%d", i + 1);
+ snprintf(ctid, 5, "TM%02d", i + 1);
snprintf(ctdesc, 255, "Test %d context for macro interface", i + 1);
DLT_REGISTER_CONTEXT(context_macro_test[i], ctid, ctdesc);
}
@@ -252,7 +258,7 @@ int main(int argc, char *argv[])
dlt_register_context(&context_function_callback, "CBF", "Callback Test context for function interface");
for (i = 0; i < DLT_TEST_NUM_CONTEXT; i++) {
- snprintf(ctid, 4, "TF%d", i + 1);
+ snprintf(ctid, 5, "TF%02d", i + 1);
snprintf(ctdesc, 255, "Test %d context for function interface", i + 1);
dlt_register_context(&(context_function_test[i]), ctid, ctdesc);
}
@@ -292,6 +298,7 @@ int main(int argc, char *argv[])
test7m();
test8m();
test9m();
+ test10m();
/* with function interface */
test1f();
@@ -303,6 +310,7 @@ int main(int argc, char *argv[])
test7f();
test8f();
test9f();
+ test10f();
/* wait 1 second before next repeat of tests */
sleep(1);
@@ -643,6 +651,34 @@ int test9m(void)
return 0;
}
+int test10m(void)
+{
+ unsigned long timestamp[] = { 0, 100000, DLT_MAX_TIMESTAMP };
+ /* Test 10: test minimum, regular and maximum timestamp for both verbose and non verbose mode*/
+
+ printf("Test10m: (Macro IF) Test user-supplied time stamps\n");
+ DLT_LOG_STRING(context_info, DLT_LOG_INFO, "Test10: (Macro IF) Test user-supplied timestamps");
+
+ for (int i = 0; i < 3; i++) {
+ char s[12];
+ snprintf(s, 12, "%d.%04d", (int)(timestamp[i] / 10000), (int)(timestamp[i] % 10000));
+
+ DLT_VERBOSE_MODE();
+ DLT_LOG_TS(context_macro_test[9], DLT_LOG_INFO, timestamp[i], DLT_STRING("Tested Timestamp:"), DLT_STRING(s));
+
+ DLT_NONVERBOSE_MODE();
+ DLT_LOG_ID_TS(context_macro_test[9], DLT_LOG_INFO, 16, timestamp[i], DLT_STRING(s));
+ }
+
+ DLT_VERBOSE_MODE();
+
+ /* wait 2 second before next test */
+ sleep(2);
+ DLT_LOG(context_info, DLT_LOG_INFO, DLT_STRING("Test10: (Macro IF) finished"));
+
+ return 0;
+}
+
int test1f(void)
{
/* Test 1: (Function IF) Test all log levels */
@@ -1180,6 +1216,48 @@ int test9f(void)
return 0;
}
+int test10f(void)
+{
+ unsigned long timestamp[] = { 0, 100000, DLT_MAX_TIMESTAMP };
+ /* Test 10: test minimum, regular and maximum timestamp for both verbose and non verbose mode*/
+
+ printf("Test10f: (Function IF) Test user-supplied timestamps\n");
+ if (dlt_user_log_write_start(&context_info, &context_data, DLT_LOG_INFO) > 0) {
+ dlt_user_log_write_string(&context_data, "Test10: (Function IF) Test user-supplied time stamps");
+ dlt_user_log_write_finish(&context_data);
+ }
+
+ for (int i = 0; i < 3; i++) {
+ char s[12];
+ snprintf(s, 12, "%d.%04d", (int)(timestamp[i] / 10000), (int)(timestamp[i] % 10000));
+
+ dlt_verbose_mode();
+ if (dlt_user_log_write_start(&context_function_test[9], &context_data, DLT_LOG_INFO) > 0) {
+ context_data.use_timestamp = DLT_USER_TIMESTAMP;
+ context_data.user_timestamp = (uint32_t) timestamp[i];
+ dlt_user_log_write_string(&context_data, "Tested Timestamp:");
+ dlt_user_log_write_string(&context_data, s);
+ dlt_user_log_write_finish(&context_data);
+ }
+
+ dlt_nonverbose_mode();
+ if (dlt_user_log_write_start_id(&(context_function_test[9]), &context_data, DLT_LOG_INFO, 16) > 0) {
+ context_data.use_timestamp = DLT_USER_TIMESTAMP;
+ context_data.user_timestamp = (uint32_t) timestamp[i];
+ dlt_user_log_write_string(&context_data, s);
+ dlt_user_log_write_finish(&context_data);
+ }
+ }
+
+ dlt_verbose_mode();
+
+ /* wait 2 second before next test */
+ sleep(2);
+ DLT_LOG(context_info, DLT_LOG_INFO, DLT_STRING("Test10: (Macro IF) finished"));
+
+ return 0;
+}
+
int test_injection_macro_callback(uint32_t service_id, void *data, uint32_t length)
{
char text[1024];
diff --git a/tests/gtest_dlt_user.cpp b/tests/gtest_dlt_user.cpp
index 777e459..48be5ef 100644
--- a/tests/gtest_dlt_user.cpp
+++ b/tests/gtest_dlt_user.cpp
@@ -452,6 +452,26 @@ TEST(t_dlt_user_log_write_finish, finish)
}
/*/////////////////////////////////////// */
+/* t_dlt_user_log_write_finish */
+TEST(t_dlt_user_log_write_finish, finish_with_timestamp)
+{
+ DltContext context;
+ DltContextData contextData;
+
+ EXPECT_LE(DLT_RETURN_OK, dlt_register_app("TUSR", "dlt_user.c tests"));
+ EXPECT_LE(DLT_RETURN_OK, dlt_register_context(&context, "TEST", "dlt_user.c t_dlt_user_log_write_finish finish"));
+
+ /* finish with start and initialized context */
+ EXPECT_LE(DLT_RETURN_OK, dlt_user_log_write_start(&context, &contextData, DLT_LOG_DEFAULT));
+ contextData.use_timestamp = DLT_USER_TIMESTAMP;
+ contextData.user_timestamp = UINT32_MAX;
+ EXPECT_LE(DLT_RETURN_OK, dlt_user_log_write_finish(&contextData));
+
+ EXPECT_LE(DLT_RETURN_OK, dlt_unregister_context(&context));
+ EXPECT_LE(DLT_RETURN_OK, dlt_unregister_app());
+}
+
+/*/////////////////////////////////////// */
/* t_dlt_user_log_write_bool */
TEST(t_dlt_user_log_write_bool, normal)
{