/** * 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 ADIT 2018 * \author Felix Herrmann ADIT 2020 * * \file: dlt-qnx-slogger2-adapter.cpp * For further information see http://www.genivi.org/. */ #include #include #include #include #include #include #include #include #include #include #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(value)); } extern DltContext dltQnxSystem; static DltContext dltQnxSlogger2Context; extern DltQnxSystemThreads g_threads; static std::unordered_map 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(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(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; }