libelosdlt

This library aims to implement the Diagnostic Log and Trace (DLT) protocol. The implementation is tested using the https://github.com/COVESA/dlt-daemon.

Currently it supports :

  • (un-)register a application

  • (un-)register a context

  • sending a log message

The following communication channels are implemented:

  • Pipe

  • TCP-Socket

  • Unix Domain Socket

However logging is currently only possible using a pipe connection. This is the default if using libelosDlt.c::elosDltConnect.

Example

In src/demos/elosDlt.c you can find an example program using libelosDlt to send a DLT log message.

// SPDX-License-Identifier: MIT

#include <elos/libelosdlt/libelosdlt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    int ret = -1;
    elosDltConnection_t dlt = {0};

    if (argc < 2) {
        printf("usage :\n %s </path/socket|/path/pipe>\n", argv[0]);
    } else {
        printf("try to connect\n");
#if 0
    dlt.socketPath = argv[1];
    if (elosDltConnectUnix(&dlt) < 0) {
      printf("Failed to connect to %s\n", dlt.socketPath);
    } else {
      const char *logMessage = "hugo hat husten";
      ret = elosDltSendControlMessage(&dlt, logMessage, strlen(logMessage));
      close(dlt.socketFd);
    }
#elif 0
        dlt.host = "::1";
        dlt.port = 3490;
        if (elosDltConnectTcp(&dlt) < 0) {
            printf("Failed to connect to %s : %d\n", dlt.host, dlt.port);
        } else {
            const char *logMessage = "hugo hat husten";
            ret = elosDltSendControlMessage(&dlt, logMessage, strlen(logMessage));
            close(dlt.socketFd);
        }
#else
        dlt.pipePath = argv[1];
        ret = elosDltConnectPipe(&dlt);
        if (ret < 0) {
            printf("Failed to connect to %s\n", dlt.pipePath);
        } else {
            ret = elosDltRegisterContext(&dlt);
            if (ret < 0) {
                printf("Failed to register app context\n");
            } else {
                ret = elosDltSendUserLog(&dlt, "hugo hat husten");
                if (ret < 0) {
                    printf("Failed to send log message\n");
                }

                ret = elosDltUnregisterContext(&dlt);
                if (ret < 0) {
                    printf("Failed to unregister app context\n");
                }
            }
        }

#endif
    }

    return ret != -1 ? EXIT_SUCCESS : EXIT_SUCCESS;
}

API

The API description can be found here /src/libelosdlt/public/elos/libelosdlt/libelosdlt.h

// SPDX-License-Identifier: MIT
#pragma once

#include <safu/result.h>

#include "elos/libelosdlt/types.h"

__BEGIN_DECLS

/*******************************************************************
 * Connect to DLT daemon using connection info defined in `param`.
 * Lookup order is :
 * 1. param.pipePath
 * 2. param.socketPath
 * 3. param.connectionString
 *
 * Note: Currently only `pipe` connection mode is known to work for logging.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to be connected.
 *       param: structure containing the connection parameter.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltConnect(elosDltConnection_t *dlt, elosDltConnectionParam_t *param);
/*******************************************************************
 * Connect to DLT daemon, the `elosDltConnection_t` must have set `port` and
 * `host`.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to be connected.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltConnectTcp(elosDltConnection_t *dlt);

/*******************************************************************
 * Connect to DLT daemon, the `elosDltConnection_t` must have set `socketPath`.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to be connected.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltConnectUnix(elosDltConnection_t *dlt);

/*******************************************************************
 * Connect to DLT daemon, the `elosDltConnection_t` must have set `pipePath`.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to be connected.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltConnectPipe(elosDltConnection_t *dlt);

/*******************************************************************
 * Disconnect from DLT daemon by closing the connection. No session management
 * is done, means unregister any created application or session contexts must be
 * done in advance.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to be disconnected.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltDisconnect(elosDltConnection_t *dlt);

/*******************************************************************
 * Create an application and session context if not already existing.
 * For the application and session context the Ids specified in `dlt.appId` and
 * `dlt.contextId` are used.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to holding the Ids
 *            to be registered.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltRegisterContext(elosDltConnection_t *dlt);

/*******************************************************************
 * Unregister an application and session context if not already done.
 * For the application and session context the Ids specified in `dlt.appId` and
 * `dlt.contextId` are used.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to holding the Ids
 *            to be unregistered.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltUnregisterContext(elosDltConnection_t *dlt);

/*******************************************************************
 * Send a log message as `user message` to DLT daemon.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to send send a
 *            log message to DLT daemon.
 *       payload: The string to be logged, must be a `\0`-terminated c-string.
 *                The string must be less then 128 bytes.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltSendUserLog(elosDltConnection_t *dlt, char *payload);

/*******************************************************************
 * Send a log message as `control message` to DLT daemon.
 *
 * Parameters:
 *       dlt: pointer to an instance of `elosDltConnection_t` to send send a
 *            log message to DLT daemon.
 *       payload: The data to be logged.
 *       payloadLength: length of the payload, must be less the 128 byte.
 *
 * Returns:
 *      - `SAFU_RESULT_OK` on success
 *      - `SAFU_RESULT_FAILED` on failure
 ******************************************************************/
safuResultE_t elosDltSendControlMessage(elosDltConnection_t *dlt, const char *payload, size_t payloadLength);

__END_DECLS

The protocol definition and the types can be found here /src/libelosdlt/interface/elos/libelosdlt/types.h:

// SPDX-License-Identifier: MIT
#pragma once

#include <stdint.h>
#include <sys/cdefs.h>
#include <time.h>

#define DLT_ID_SIZE 4

__BEGIN_DECLS

/*******************************************************************
 * The header fragment of an DLT message.
 *
 * Note: This assumes to always use the extended header
 *
 * Members:
 *     headerTyp: Bit field to define the anatomy of the header
 *     messageCount: sequence number of messages
 *     length: overall length of a message starting and including this header
 *     ecuId: used as ECU id in DLT log
 *     sessionId: the process id of the process sending this messages
 *     monotonicTimestamp: time in nano sec since system start
 *     messageInfo: Bit field to define kind of a message (Request/Response,
 *                  message type, verbose)
 *     argCount: Number of arguments attached to this message
 *     appId: used as application id in DLT log
 *     contextId: used as context id in DLT log
 ******************************************************************/
typedef struct elosDltMessage {
    struct {
        uint8_t useExtendedHeader : 1;
        uint8_t msbFirst : 1;
        uint8_t withEcuId : 1;
        uint8_t withSessionID : 1;
        uint8_t withTimestamp : 1;
        uint8_t protocolVersion1 : 1;
        uint8_t reserved : 2;
    } headerTyp;
    uint8_t messageCount;
    uint16_t length;
    char ecuId[DLT_ID_SIZE];
    uint32_t sessionId;
    uint32_t monotonicTimestamp;
    uint8_t messageInfo;
    uint8_t argCount;
    char appId[DLT_ID_SIZE];
    char contextId[DLT_ID_SIZE];
} __attribute__((aligned(1), packed)) elosDltMessage_t;

/*******************************************************************
 * Types of DLT user messages currently supported.
 *
 ******************************************************************/
typedef enum elosDltUserMessageTypeE {
    ELOS_USER_MESSAGE_TYPE_UNDEFINED = 0,
    ELOS_USER_MESSAGE_TYPE_LOG = 1,
    ELOS_USER_MESSAGE_TYPE_REGISTER_APPLICATION = 2,
    ELOS_USER_MESSAGE_TYPE_UNREGISTER_APPLICATION = 3,
    ELOS_USER_MESSAGE_TYPE_REGISTER_CONTEXT = 4,
    ELOS_USER_MESSAGE_TYPE_UNREGISTER_CONTEXT = 5,
} elosDltUserMessageTypeE_t;

/*******************************************************************
 * The protocol fragment introducing a DLT control message.
 *
 * Note: only supported for connection types TCP and UNIX socket?
 *
 * Members:
 *     serviceID: define the remote service to call
 ******************************************************************/
typedef struct elosDltControlMessage {
    uint32_t serviceID;
    uint32_t length;
} __attribute__((aligned(1), packed)) elosDltControlMessage_t;

/*******************************************************************
 * The protocol fragment introducing a DLT user message.
 *
 * Note: only supported for connection type pipe?
 *
 * Members:
 *     magicNumber: magic identifier to determine message start, shall be
 *                 `['D', 'U', 'H', 0x01]`
 *     type: the message type which follows.
 ******************************************************************/
typedef struct elosDltUserMessage {
    char magicNumber[DLT_ID_SIZE];
    elosDltUserMessageTypeE_t type;
} __attribute__((aligned(1), packed)) elosDltUserMessage_t;

/*******************************************************************
 * A DLT protocol fragment to define an serialized value to be logged
 *
 * Members:
 *     typeInfo: define the type of value
 *     argSize: define the size of the value in bytes
 *     nameSize: the size of the name string for this value
 *     name: the value name or key.
 ******************************************************************/
typedef struct elosDltLogArgument {
    uint32_t typeInfo;
    uint16_t argSize;
    uint16_t nameSize;
    char name[20];
} __attribute__((aligned(1), packed)) elosDltLogArgument_t;

/*******************************************************************
 * A DLT message to register a new application context.
 *
 * Members:
 *     header: The user message header
 *     appId: used as new application id to be register
 *     pid: the process id of the process sending this messages
 *     length: the length of the application description.
 ******************************************************************/
typedef struct elosDltgRegisterApplication_t {
    elosDltUserMessage_t header;
    char appId[DLT_ID_SIZE];
    int32_t pid;
    uint32_t length;
} __attribute__((aligned(1), packed)) elosDltRegisterApplication_t;

/*******************************************************************
 * A DLT message to unregister an existing application context.
 *
 * Members:
 *     header: The user message header
 *     appId: used as application id to be unregistered
 *     pid: the process id of the process sending this messages
 ******************************************************************/
typedef struct elosDltgUnregisterApplication_t {
    elosDltUserMessage_t header;
    char appId[DLT_ID_SIZE];
    int32_t pid;
} __attribute__((aligned(1), packed)) elosDltUnregisterApplication_t;

/*******************************************************************
 * A DLT message to register a context for an existing application context.
 *
 * Members:
 *     header: The user message header
 *     appId: used as application id to register a new context for
 *     contextId: used as new context id to be registered
 *     logLevelPosition: purpose currently unknown and unused for now
 *     logLevel: initial log level for this context
 *     traceStatus: set to 0; purpose currently unknown and unused
 *     pid: the process id of the process sending this messages
 *     length: the length of the context description.
 ******************************************************************/
typedef struct elosDltgRegisterContext {
    elosDltUserMessage_t header;
    char appId[DLT_ID_SIZE];
    char contextId[DLT_ID_SIZE];
    int32_t logLevelPosition;
    int8_t logLevel;
    int8_t traceStatus;
    int32_t pid;
    uint32_t length;
} __attribute__((aligned(1), packed)) elosDltRegisterContext_t;

/*******************************************************************
 * A DLT message to unregister a context for an existing application context.
 *
 * Members:
 *     header: The user message header
 *     appId: used as application id to unregister a new context for
 *     contextId: used as new context id to be unregistered
 *     pid: the process id of the process sending this messages
 ******************************************************************/
typedef struct elosDltgUnregisterContext {
    elosDltUserMessage_t header;
    char appId[DLT_ID_SIZE];
    char contextId[DLT_ID_SIZE];
    int32_t pid;
} __attribute__((aligned(1), packed)) elosDltUnregisterContext_t;

/*******************************************************************
 * Parameter struct used to configure a new DLT connection.
 *
 * Members:
 *     socketPath: path to unix domain socket of DLT-Daemon
 *     host: IP address or name of DLT-Daemon
 *     pipePath: path to pipe of DLT-Daemon
 *     port: port the DLT-Daemon to connect to
 *     socketFd: file descriptor of active connection or -1 if not connected
 *     messageCount: count of messages transmitted by this connection
 *     ecuId: used as ECU id in DLT log
 *     appId: used as application id in DLT log
 *     contextId: used as context id in DLT log
 ******************************************************************/
typedef struct elosDltConnection {
    char *socketPath;
    char *host;
    char *pipePath;
    int port;
    int socketFd;
    size_t messageCount;
    char ecuId[DLT_ID_SIZE];
    char appId[DLT_ID_SIZE];
    char contextId[DLT_ID_SIZE];
} elosDltConnection_t;

/*******************************************************************
 * Parameter struct used to configure a new DLT connection.
 *
 * Members:
 *     ecuId: used as ECU id in DLT log
 *     appId: used as application id in DLT log
 *     contextId: used as context id in DLT log
 ******************************************************************/
typedef struct elosDltConnectionParam {
    const char *ecuId;
    const char *contextId;
    const char *appId;
} elosDltConnectionParam_t;

__END_DECLS

Known Issues

Currently it doesn’t work to publish log message via UNIX and TCP sockets. It is possible to create an injection message (elosDltSendControlMessage) including the log message, but it fails because it is not possible to create an application and session context. This only works via pipe connections. May be with a mixed approach it is feasible.