diff options
Diffstat (limited to 'src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp')
-rw-r--r-- | src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp b/src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp new file mode 100644 index 0000000..5ebfc0c --- /dev/null +++ b/src/dlt-qnx-system/dlt-qnx-slogger2-adapter.cpp @@ -0,0 +1,251 @@ +/** + * Copyright (C) 2018-2020 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * DLT QNX system functionality source file. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Nguyen Dinh Thi <Thi.NguyenDinh@vn.bosch.com> ADIT 2018 + * \author Felix Herrmann <fherrmann@de.adit-jv.com> ADIT 2020 + * + * \file: dlt-qnx-slogger2-adapter.cpp + * For further information see http://www.genivi.org/. + */ +#include <cerrno> +#include <cstring> +#include <iostream> +#include <string> +#include <vector> +#include <unordered_map> + +#include <pthread.h> +#include <sys/slog2.h> +#include <sys/json.h> +#include <slog2_parse.h> + +#include "dlt-qnx-system.h" +#include "dlt_cpp_extension.hpp" + +/* Teach dlt about json_decoder_error_t */ +template<> +inline int32_t logToDlt(DltContextData &log, const json_decoder_error_t &value) +{ + return logToDlt(log, static_cast<int>(value)); +} + +extern DltContext dltQnxSystem; + +static DltContext dltQnxSlogger2Context; + +extern DltQnxSystemThreads g_threads; +static std::unordered_map<std::string, DltContext*> g_slog2file; + +static void dlt_context_map_read(const char *json_filename) +{ + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_VERBOSE, + "Loading Slog2Ctxt Map from json file: ", json_filename); + + auto dec = json_decoder_create(); + if (json_decoder_parse_file(dec, json_filename) != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_ERROR, + "Could not load Slog2Ctxt Map from json file: ", json_filename); + return; + } + + const char *ctxtID, *name, *description; + + /* go to first element in dlt-slog2ctxt.json e.g. "ADIO" */ + auto ret = json_decoder_push_object(dec, nullptr, false); + while (ret == JSON_DECODER_OK) { + ctxtID = json_decoder_name(dec); + + /* go into the element e.g. { name: "", description: "" } */ + ret = json_decoder_push_object(dec, nullptr, false); + if (ret != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_WARN, __func__, + ": json parser error while descending into context dict. ret=", ret); + break; + } + + ret = json_decoder_get_string(dec, "name", &name, false); + if (ret != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_WARN, __func__, + ": json parser error while retrieving 'name' element of ", ctxtID, ". ret=", ret); + break; + } + + ret = json_decoder_get_string(dec, "description", &description, false); + if (ret != JSON_DECODER_OK) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_WARN, __func__, + ": json parser error while retrieving 'description' element of ", ctxtID, ". ret=", ret); + break; + } + + auto ctxt = new DltContext; + g_slog2file.emplace(name, ctxt); + + auto search = g_slog2file.find(name); + if (search == g_slog2file.end()) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_INFO, + "Could not emplace slog2ctxt map key: ", name); + } else { + dlt_register_context(ctxt, ctxtID, description); + } + + ret = json_decoder_pop(dec); + } + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_DEBUG, + "Added ", g_slog2file.size(), " elements into the mapping table."); +} + +/** + * Map the slog2 logfile name to a dlt context + * e.g. i2c_service.2948409 -> Context with id "I2CS" + */ +static DltContext *dlt_context_from_slog2file(const char *file_name) { + auto d = strchr(file_name, '.'); + + if (d == nullptr) + return &dltQnxSlogger2Context; + + auto name = std::string(file_name).substr(0, d - file_name); + + auto search = g_slog2file.find(name); + if (search == g_slog2file.end()) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_VERBOSE, + "slog2 filename not found in mapping: ", name.c_str()); + return &dltQnxSlogger2Context; + } else { + return search->second; + } +} + +/** + * Function which is invoked by slog2_parse_all() + * See slog2_parse_all api docs on qnx.com for details + */ +static int sloggerinfo_callback(slog2_packet_info_t *info, void *payload, void *param) +{ + DltQnxSystemConfiguration* conf = (DltQnxSystemConfiguration*) param; + + if (param == NULL) + return -1; + + DltLogLevelType loglevel; + switch (info->severity) + { + case SLOG2_SHUTDOWN: + case SLOG2_CRITICAL: + loglevel = DLT_LOG_FATAL; + break; + case SLOG2_ERROR: + loglevel = DLT_LOG_ERROR; + break; + case SLOG2_WARNING: + loglevel = DLT_LOG_WARN; + break; + case SLOG2_NOTICE: + case SLOG2_INFO: + loglevel = DLT_LOG_INFO; + break; + case SLOG2_DEBUG1: + loglevel = DLT_LOG_DEBUG; + break; + case SLOG2_DEBUG2: + loglevel = DLT_LOG_VERBOSE; + break; + default: + loglevel = DLT_LOG_INFO; + break; + } + + DltContextData log_local; /* Used in DLT_* macros, do not rename */ + DltContext *ctxt = dlt_context_from_slog2file(info->file_name); + + int ret; + ret = dlt_user_log_write_start(ctxt, &log_local, loglevel); + + /* OK means loglevel under threshold */ + if (ret == DLT_RETURN_OK) { + return 0; + } + + if (ret != DLT_RETURN_TRUE) { + fprintf(stderr, "%s: could not log to DLT status=%d\n", __func__, ret); + return -1; + } + + if (conf->qnxslogger2.useOriginalTimestamp == 1) { + /* convert from ns to .1 ms */ + log_local.user_timestamp = (uint32_t) (info->timestamp / 100000); + log_local.use_timestamp = DLT_USER_TIMESTAMP; + } else { + DLT_UINT64(info->timestamp); + } + + DLT_UINT16(info->sequence_number); + DLT_STRING((char *)info->file_name); + DLT_STRING((char *)info->buffer_name); + DLT_UINT16(info->thread_id); + DLT_UINT8(info->severity); + DLT_STRING((char *)payload); + + dlt_user_log_write_finish(&log_local); + + return 0; +} + +static void *slogger2_thread(void *v_conf) +{ + DltQnxSystemConfiguration *conf = (DltQnxSystemConfiguration *)v_conf; + + if (v_conf == NULL) + return reinterpret_cast<void*>(EINVAL); + + slog2_packet_info_t packet_info = SLOG2_PACKET_INFO_INIT; + + DLT_LOG(dltQnxSystem, DLT_LOG_DEBUG, + DLT_STRING("dlt-qnx-slogger2-adapter, in thread.")); + DLT_REGISTER_CONTEXT(dltQnxSlogger2Context, conf->qnxslogger2.contextId, + "SLOGGER2 Adapter"); + + dlt_context_map_read(CONFIGURATION_FILES_DIR "/dlt-slog2ctxt.json"); + + /** + * Thread will block inside this function to get new log because + * flag = SLOG2_PARSE_FLAGS_DYNAMIC + */ + int ret = slog2_parse_all( + SLOG2_PARSE_FLAGS_DYNAMIC, /* live streaming of all buffers merged */ + NULL, NULL, &packet_info, sloggerinfo_callback, (void*) conf); + if (ret == -1) { + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_ERROR, + "slog2_parse_all() returned error=", ret); + ret = EBADMSG; + } + + DLT_LOG_CXX(dltQnxSystem, DLT_LOG_DEBUG, __func__, ": Exited main loop."); + + DLT_UNREGISTER_CONTEXT(dltQnxSlogger2Context); + + /* Send a signal to main thread to wake up sigwait */ + pthread_kill(g_threads.mainThread, SIGTERM); + return reinterpret_cast<void*>(ret); +} + +void start_qnx_slogger2(DltQnxSystemConfiguration *conf) +{ + static pthread_attr_t t_attr; + static pthread_t pt; + + DLT_LOG_CXX(dltQnxSlogger2Context, DLT_LOG_DEBUG, + "dlt-qnx-slogger2-adapter, start syslog"); + pthread_create(&pt, &t_attr, slogger2_thread, conf); + g_threads.threads[g_threads.count++] = pt; +} |