/* * SPDX license identifier: MPL-2.0 * * Copyright (C) 2011-2015, BMW AG * * This file is part of GENIVI Project DLT - Diagnostic Log and Trace. * * This Source Code Form is subject to the terms of the * Mozilla Public License (MPL), 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/. * * For further information see http://www.genivi.org/. */ /*! * \author Alexander Wenzel * * \copyright Copyright © 2011-2015 BMW AG. \n * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/. * * \file dlt-control.c */ /******************************************************************************* ** ** ** SRC-MODULE: dlt-control.c ** ** ** ** TARGET : linux ** ** ** ** PROJECT : DLT ** ** ** ** AUTHOR : Alexander Wenzel Alexander.AW.Wenzel@bmw.de ** ** ** ** PURPOSE : ** ** ** ** REMARKS : ** ** ** ** PLATFORM DEPENDANT [yes/no]: yes ** ** ** ** TO BE CHANGED BY USER [yes/no]: no ** ** ** *******************************************************************************/ /******************************************************************************* ** Author Identity ** ******************************************************************************** ** ** ** Initials Name Company ** ** -------- ------------------------- ---------------------------------- ** ** aw Alexander Wenzel BMW ** *******************************************************************************/ #include /* for isprint() */ #include /* for atoi() */ #include /* for writev() */ #include /* for open() */ #include "dlt_client.h" #include "dlt_user.h" #include "dlt-control-common.h" #define DLT_GLOGINFO_APID_NUM_MAX 150 #define DLT_GLOGINFO_DATA_MAX 800 #define DLT_GET_LOG_INFO_HEADER 18 /*Get log info header size in response text */ #define DLT_INVALID_LOG_LEVEL 0xF #define DLT_INVALID_TRACE_STATUS 0xF /* Option of GET_LOG_INFO */ #define DLT_SERVICE_GET_LOG_INFO_OPT7 7 /* get Apid, ApDescription, Ctid, CtDescription, loglevel, tracestatus */ /** * The structure of the DLT Service header */ typedef struct { uint32_t service_id; /**< service ID */ uint8_t status; /**< response status */ } DLT_PACKED DltServiceHeader; DltClient g_dltclient; /* Function prototypes */ int dlt_receive_message_callback(DltMessage *message, void *data); typedef struct { int vflag; int yflag; char *evalue; char *avalue; char *cvalue; int svalue; char *mvalue; char *xvalue; int tvalue; int lvalue; int rvalue; int dvalue; int fvalue; int ivalue; int oflag; int gflag; int jvalue; int kvalue; int bvalue; char ecuid[4]; DltFile file; DltFilter filter; } DltReceiveData; /** * Print usage information of tool. */ void usage() { char version[255]; dlt_get_version(version, 255); printf("Usage: dlt-control [options] hostname/serial_device_name\n"); printf("Send control message to DLT daemon.\n"); printf("%s \n", version); printf("Options:\n"); printf(" -v Verbose mode\n"); printf(" -h Usage\n"); printf(" -y Serial device mode\n"); printf(" -b baudrate Serial device baudrate (Default: 115200)\n"); printf(" -e ecuid Set ECU ID (Default: RECV)\n"); printf("\n"); printf(" -a id Control message application id\n"); printf(" -c id Control message context id\n"); printf(" -s id Control message injection service id\n"); printf(" -m message Control message injection in ASCII\n"); printf(" -x message Control message injection in Hex e.g. 'ad 01 24 ef'\n"); printf(" -t milliseconds Timeout to terminate application (Default:1000)'\n"); printf(" -l loglevel Set the log level (0=off - 6=verbose default= -1)\n"); printf(" supported options:\n"); printf(" -l level -a apid -c ctid\n"); printf(" -l level -a abc* (set level for all ctxts of apps name starts with abc)\n"); printf(" -l level -a apid (set level for all ctxts of this app)\n"); printf(" -l level -c xyz* (set level for all ctxts whose name starts with xyz)\n"); printf(" -l level -c ctid (set level for the particular ctxt)\n"); printf(" -l level (set level for all the registered contexts)\n"); printf(" -r tracestatus Set the trace status (0=off - 1=on,255=default)\n"); printf(" supported options:\n"); printf(" -r tracestatus -a apid -c ctid\n"); printf(" -r tracestatus -a abc* (set status for all ctxts of apps name starts with abc)\n"); printf(" -r tracestatus -a apid (set status for all ctxts of this app)\n"); printf(" -r tracestatus -c xyz* (set status for all ctxts whose name starts with xyz)\n"); printf(" -r tracestatus -c ctid (set status for the particular ctxt)\n"); printf(" -r tracestatus (set status for all the registered contexts)\n"); printf(" -d loglevel Set the default log level (0=off - 5=verbose)\n"); printf(" -f tracestatus Set the default trace status (0=off - 1=on)\n"); printf(" -i enable Enable timing packets (0=off - 1=on)\n"); printf(" -o Store configuration\n"); printf(" -g Reset to factory default\n"); printf(" -j Get log info\n"); printf(" -k Get software version\n"); printf(" -u unix port\n"); } /** * Function for sending get log info ctrl msg and printing the response. */ void dlt_process_get_log_info(void) { char apid[DLT_ID_SIZE + 1] = { 0 }; char ctid[DLT_ID_SIZE + 1] = { 0 }; AppIDsType app; ContextIDsInfoType con; int i = 0; int j = 0; DltServiceGetLogInfoResponse *resp = (DltServiceGetLogInfoResponse *)calloc(1, sizeof(DltServiceGetLogInfoResponse)); if (NULL == resp) { fprintf(stderr, "ERROR: calloc for resp data failed.\n"); return; } /* prepare request data */ resp->service_id = DLT_SERVICE_ID_GET_LOG_INFO; resp->status = DLT_SERVICE_RESPONSE_ERROR; /* send control message*/ if (0 != dlt_client_get_log_info(&g_dltclient)) { fprintf(stderr, "ERROR: Could not get log info\n"); dlt_client_cleanup_get_log_info(resp); resp = NULL; return; } if (dlt_client_main_loop(&g_dltclient, (void *)resp, 0) == DLT_RETURN_TRUE) fprintf(stdout, "DLT-daemon's response is invalid.\n"); if (resp->service_id == DLT_SERVICE_ID_GET_LOG_INFO && resp->status >= GET_LOG_INFO_STATUS_MIN && resp->status <= GET_LOG_INFO_STATUS_MAX) { for (i = 0; i < resp->log_info_type.count_app_ids; i++) { app = resp->log_info_type.app_ids[i]; dlt_print_id(apid, app.app_id); if (app.app_description != 0) printf("APID:%4s %s\n", apid, app.app_description); else printf("APID:%4s \n", apid); for (j = 0; j < app.count_context_ids; j++) { con = app.context_id_info[j]; dlt_print_id(ctid, con.context_id); if (con.context_description != 0) printf("CTID:%4s %2d %2d %s\n", ctid, con.log_level, con.trace_status, con.context_description); else printf("CTID:%4s %2d %2d\n", ctid, con.log_level, con.trace_status); } } } dlt_client_cleanup_get_log_info(resp); resp = NULL; } /** * Function for sending get software version ctrl msg and printing the response. */ void dlt_process_get_software_version(void) { DltServiceGetSoftwareVersionResponse *resp = (DltServiceGetSoftwareVersionResponse *)calloc(1, sizeof(DltServiceGetSoftwareVersionResponse)); if (NULL == resp) { fprintf(stderr, "ERROR: calloc for resp data failed.\n"); return; } /* prepare request data */ resp->service_id = DLT_SERVICE_ID_GET_SOFTWARE_VERSION; resp->status = DLT_SERVICE_RESPONSE_ERROR; /* send control message*/ if (0 != dlt_client_get_software_version(&g_dltclient)) { fprintf(stderr, "ERROR: Get software version failed.\n"); free(resp); resp = NULL; return; } if (dlt_client_main_loop(&g_dltclient, (void *)resp, 0) == DLT_RETURN_TRUE) fprintf(stdout, "DLT-daemon's response is invalid.\n"); if (resp->service_id == DLT_SERVICE_ID_GET_SOFTWARE_VERSION && resp->status == DLT_SERVICE_RESPONSE_OK && resp->payload != NULL) { printf("%s\n", resp->payload); free(resp->payload); resp->payload = NULL; } free(resp); resp = NULL; } /** * Main function of tool. */ int main(int argc, char *argv[]) { DltReceiveData dltdata; int c; int ret; int index; char *endptr = NULL; struct timespec ts; /* Initialize dltdata */ dltdata = (DltReceiveData) { .tvalue = 1000, .lvalue = DLT_INVALID_LOG_LEVEL, .rvalue = DLT_INVALID_TRACE_STATUS, .dvalue = -1, .fvalue = -1, .ivalue = -1, .oflag = -1, .gflag = -1, }; /* Fetch command line arguments */ opterr = 0; /* Default return value */ ret = 0; while ((c = getopt (argc, argv, "vhye:b:a:c:s:m:x:t:l:r:d:f:i:ogjku")) != -1) switch (c) { case 'v': { dltdata.vflag = 1; break; } case 'h': { usage(); return -1; } case 'y': { dltdata.yflag = DLT_CLIENT_MODE_SERIAL; break; } case 'e': { dltdata.evalue = optarg; break; } case 'b': { dltdata.bvalue = atoi(optarg); break; } case 'a': { dltdata.avalue = optarg; if (strlen(dltdata.avalue) > DLT_ID_SIZE) { fprintf (stderr, "Invalid application id\n"); return -1; } break; } case 'c': { dltdata.cvalue = optarg; if (strlen(dltdata.cvalue) > DLT_ID_SIZE) { fprintf (stderr, "Invalid context id\n"); return -1; } break; } case 's': { dltdata.svalue = atoi(optarg); break; } case 'm': { dltdata.mvalue = optarg; break; } case 'x': { dltdata.xvalue = optarg; break; } case 't': { dltdata.tvalue = atoi(optarg); break; } case 'l': { dltdata.lvalue = (int) strtol(optarg, &endptr, 10); if ((dltdata.lvalue < DLT_LOG_DEFAULT) || (dltdata.lvalue > DLT_LOG_VERBOSE)) { fprintf (stderr, "invalid log level, supported log level 0-6\n"); return -1; } break; } case 'r': { dltdata.rvalue = (int) strtol(optarg, &endptr, 10); if ((dltdata.rvalue < DLT_TRACE_STATUS_DEFAULT) || (dltdata.rvalue > DLT_TRACE_STATUS_ON)) { fprintf (stderr, "invalid trace status, supported trace status -1, 0, 1\n"); return -1; } break; } case 'd': { dltdata.dvalue = atoi(optarg); break; } case 'f': { dltdata.fvalue = atoi(optarg); break; } case 'i': { dltdata.ivalue = atoi(optarg); break; } case 'o': { dltdata.oflag = 1; break; } case 'g': { dltdata.gflag = 1; break; } case 'j': { dltdata.jvalue = 1; break; } case 'k': { dltdata.kvalue = 1; break; } case 'u': { dltdata.yflag = DLT_CLIENT_MODE_UNIX; break; } case '?': { if ((optopt == 'o') || (optopt == 'f')) fprintf (stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); /* unknown or wrong option used, show usage information and terminate */ usage(); return -1; } default: { abort (); return -1; /*for parasoft */ } } /* Initialize DLT Client */ dlt_client_init(&g_dltclient, dltdata.vflag); /* Register callback to be called when message was received */ dlt_client_register_message_callback(dlt_receive_message_callback); /* Setup DLT Client structure */ if (dltdata.yflag == DLT_CLIENT_MODE_SERIAL) { g_dltclient.mode = DLT_CLIENT_MODE_SERIAL; } else if (dltdata.yflag == DLT_CLIENT_MODE_UNIX) { g_dltclient.mode = DLT_CLIENT_MODE_UNIX; g_dltclient.socketPath = NULL; dlt_parse_config_param("ControlSocketPath", &g_dltclient.socketPath); } else { g_dltclient.mode = DLT_CLIENT_MODE_TCP; } if (g_dltclient.mode == DLT_CLIENT_MODE_TCP) { for (index = optind; index < argc; index++) if (dlt_client_set_server_ip(&g_dltclient, argv[index]) == -1) { pr_error("set server ip didn't succeed\n"); return -1; } if (g_dltclient.servIP == 0) { /* no hostname selected, show usage and terminate */ fprintf(stderr, "ERROR: No hostname selected\n"); usage(); dlt_client_cleanup(&g_dltclient, dltdata.vflag); return -1; } } else if (g_dltclient.mode == DLT_CLIENT_MODE_SERIAL) { for (index = optind; index < argc; index++) if (dlt_client_set_serial_device(&g_dltclient, argv[index]) == -1) { pr_error("set serial device didn't succeed\n"); return -1; } if (g_dltclient.serialDevice == 0) { /* no serial device name selected, show usage and terminate */ fprintf(stderr, "ERROR: No serial device name specified\n"); usage(); return -1; } dlt_client_setbaudrate(&g_dltclient, dltdata.bvalue); } /* initialise structure to use DLT file */ dlt_file_init(&(dltdata.file), dltdata.vflag); /* first parse filter file if filter parameter is used */ dlt_filter_init(&(dltdata.filter), dltdata.vflag); if (dltdata.evalue) { dlt_set_id(dltdata.ecuid, dltdata.evalue); dlt_set_id(g_dltclient.ecuid, dltdata.evalue); } else { dltdata.evalue = NULL; if (dlt_parse_config_param("ECUId", &dltdata.evalue) == 0) { dlt_set_id(dltdata.ecuid, dltdata.evalue); dlt_set_id(g_dltclient.ecuid, dltdata.evalue); free (dltdata.evalue); } else { fprintf(stderr, "ERROR: Failed to read ECUId from dlt.conf \n"); } } /* Connect to TCP socket or open serial device */ if (dlt_client_connect(&g_dltclient, dltdata.vflag) != DLT_RETURN_ERROR) { /* send injection message */ if (dltdata.mvalue && dltdata.avalue && dltdata.cvalue) { /* ASCII */ printf("Send injection message:\n"); printf("AppId: %s\n", dltdata.avalue); printf("ConId: %s\n", dltdata.cvalue); printf("ServiceId: %d\n", dltdata.svalue); printf("Message: %s\n", dltdata.mvalue); /* send control message in ascii */ if (dlt_client_send_inject_msg(&g_dltclient, dltdata.avalue, dltdata.cvalue, (uint32_t) dltdata.svalue, (uint8_t *)dltdata.mvalue, (uint32_t) strlen(dltdata.mvalue)) != DLT_RETURN_OK) { fprintf(stderr, "ERROR: Could not send inject message\n"); ret = -1; } } else if (dltdata.xvalue && dltdata.avalue && dltdata.cvalue) { /* Hex */ uint8_t buffer[1024]; int size = 1024; printf("Send injection message:\n"); printf("AppId: %s\n", dltdata.avalue); printf("ConId: %s\n", dltdata.cvalue); printf("ServiceId: %d\n", dltdata.svalue); printf("Message: %s\n", dltdata.xvalue); dlt_hex_ascii_to_binary(dltdata.xvalue, buffer, &size); printf("Size: %d\n", size); /* send control message in hex */ if (dlt_client_send_inject_msg(&g_dltclient, dltdata.avalue, dltdata.cvalue, (uint32_t) dltdata.svalue, buffer, (uint32_t)size) != DLT_RETURN_OK) { fprintf(stderr, "ERROR: Could not send inject message\n"); ret = -1; } } else if (dltdata.lvalue != DLT_INVALID_LOG_LEVEL) /*&& dltdata.avalue && dltdata.cvalue)*/ { if ((dltdata.avalue == 0) && (dltdata.cvalue == 0)) { if (dltdata.vflag) { printf("Set all log level:\n"); printf("Loglevel: %d\n", dltdata.lvalue); } if (0 != dlt_client_send_all_log_level(&g_dltclient, (uint8_t) dltdata.lvalue)) { fprintf(stderr, "ERROR: Could not send log level\n"); ret = -1; } } else { /* log level */ if (dltdata.vflag) { printf("Set log level:\n"); printf("AppId: %s\n", dltdata.avalue); printf("ConId: %s\n", dltdata.cvalue); printf("Loglevel: %d\n", dltdata.lvalue); } /* send control message*/ if (0 != dlt_client_send_log_level(&g_dltclient, dltdata.avalue, dltdata.cvalue, (uint8_t) dltdata.lvalue)) { fprintf(stderr, "ERROR: Could not send log level\n"); ret = -1; } } } else if (dltdata.rvalue != DLT_INVALID_TRACE_STATUS) { if ((dltdata.avalue == 0) && (dltdata.cvalue == 0)) { if (dltdata.vflag) { printf("Set all trace status:\n"); printf("Tracestatus: %d\n", dltdata.rvalue); } if (0 != dlt_client_send_all_trace_status(&g_dltclient, (uint8_t) dltdata.rvalue)) { fprintf(stderr, "ERROR: Could not send trace status\n"); ret = -1; } } else { /* trace status */ if (dltdata.vflag) { printf("Set trace status:\n"); printf("AppId: %s\n", dltdata.avalue); printf("ConId: %s\n", dltdata.cvalue); printf("Tracestatus: %d\n", dltdata.rvalue); } /* send control message*/ if (0 != dlt_client_send_trace_status(&g_dltclient, dltdata.avalue, dltdata.cvalue, (uint8_t) dltdata.rvalue)) { fprintf(stderr, "ERROR: Could not send trace status\n"); ret = -1; } } } else if (dltdata.dvalue != -1) { /* default log level */ printf("Set default log level:\n"); printf("Loglevel: %d\n", dltdata.dvalue); /* send control message in*/ if (dlt_client_send_default_log_level(&g_dltclient, (uint8_t) dltdata.dvalue) != DLT_RETURN_OK) { fprintf (stderr, "ERROR: Could not send default log level\n"); ret = -1; } } else if (dltdata.fvalue != -1) { /* default trace status */ printf("Set default trace status:\n"); printf("TraceStatus: %d\n", dltdata.fvalue); /* send control message in*/ if (dlt_client_send_default_trace_status(&g_dltclient, (uint8_t) dltdata.fvalue) != DLT_RETURN_OK) { fprintf (stderr, "ERROR: Could not send default trace status\n"); ret = -1; } } else if (dltdata.ivalue != -1) { /* timing pakets */ printf("Set timing pakets:\n"); printf("Timing packets: %d\n", dltdata.ivalue); /* send control message in*/ if (dlt_client_send_timing_pakets(&g_dltclient, (uint8_t) dltdata.ivalue) != DLT_RETURN_OK) { fprintf (stderr, "ERROR: Could not send timing packets\n"); ret = -1; } } else if (dltdata.oflag != -1) { /* default trace status */ printf("Store config\n"); /* send control message in*/ if (dlt_client_send_store_config(&g_dltclient) != DLT_RETURN_OK) { fprintf (stderr, "ERROR: Could not send store config\n"); ret = -1; } } else if (dltdata.gflag != -1) { /* reset to factory default */ printf("Reset to factory default\n"); /* send control message in*/ if (dlt_client_send_reset_to_factory_default(&g_dltclient) != DLT_RETURN_OK) { fprintf (stderr, "ERROR: Could not send reset to factory default\n"); ret = -1; } } else if (dltdata.jvalue == 1) { /* get log info */ printf("Get log info:\n"); dlt_process_get_log_info(); } else if (dltdata.kvalue == 1) { /* Get software version */ printf("Get software version:\n"); dlt_process_get_software_version(); } /* Dlt Client Main Loop */ /*dlt_client_main_loop(&dltclient, &dltdata, dltdata.vflag); */ /* Wait timeout */ ts.tv_sec = (dltdata.tvalue * NANOSEC_PER_MILLISEC) / NANOSEC_PER_SEC; ts.tv_nsec = (dltdata.tvalue * NANOSEC_PER_MILLISEC) % NANOSEC_PER_SEC; nanosleep(&ts, NULL); } else { ret = -1; } /* Dlt Client Cleanup */ dlt_client_cleanup(&g_dltclient, dltdata.vflag); if (g_dltclient.socketPath != NULL) free(g_dltclient.socketPath); dlt_file_free(&(dltdata.file), dltdata.vflag); dlt_filter_free(&(dltdata.filter), dltdata.vflag); return ret; } int dlt_receive_message_callback(DltMessage *message, void *data) { static char resp_text[DLT_RECEIVE_BUFSIZE]; int ret = DLT_RETURN_OK; uint32_t id = 0; uint32_t uint32_tmp = 0; uint8_t *ptr; int32_t datalength; DltServiceHeader *req_header = NULL; if ((message == NULL) || (data == NULL) || !DLT_MSG_IS_CONTROL_RESPONSE(message)) return -1; /* get request service id */ req_header = (DltServiceHeader *)data; /* get response service id */ ptr = message->databuffer; datalength =(int32_t) message->datasize; DLT_MSG_READ_VALUE(uint32_tmp, ptr, datalength, uint32_t); id = DLT_ENDIAN_GET_32(message->standardheader->htyp, uint32_tmp); if ((id > DLT_SERVICE_ID) && (id < DLT_SERVICE_ID_LAST_ENTRY) && (id == req_header->service_id)) { switch (id) { case DLT_SERVICE_ID_GET_LOG_INFO: { DltServiceGetLogInfoResponse *resp = (DltServiceGetLogInfoResponse *)data; /* prepare storage header */ if (DLT_IS_HTYP_WEID(message->standardheader->htyp)) dlt_set_storageheader(message->storageheader, message->headerextra.ecu); else dlt_set_storageheader(message->storageheader, "LCTL"); /* get response data */ ret = dlt_message_header(message, resp_text, DLT_RECEIVE_BUFSIZE, 0); if (ret < 0) { fprintf(stderr, "GET_LOG_INFO message_header result failed.\n"); dlt_client_cleanup(&g_dltclient, 0); return -1; } ret = dlt_message_payload(message, resp_text, DLT_RECEIVE_BUFSIZE, DLT_OUTPUT_ASCII, 0); if (ret < 0) { fprintf(stderr, "GET_LOG_INFO message_payload result failed.\n"); dlt_client_cleanup(&g_dltclient, 0); return -1; } ret = dlt_set_loginfo_parse_service_id(resp_text, &resp->service_id, &resp->status); if ((ret == 0) && (resp->service_id == DLT_SERVICE_ID_GET_LOG_INFO)) { ret = dlt_client_parse_get_log_info_resp_text(resp, resp_text); if (ret != 0) { fprintf(stderr, "GET_LOG_INFO failed [status=%d]\n", resp->status); dlt_client_cleanup(&g_dltclient, 0); return -1; } dlt_client_cleanup(&g_dltclient, 0); } break; } case DLT_SERVICE_ID_GET_SOFTWARE_VERSION: { DltServiceGetSoftwareVersionResponse *resp = (DltServiceGetSoftwareVersionResponse *)data; resp->service_id = id; DLT_MSG_READ_VALUE(resp->status, ptr, datalength, uint8_t); DLT_MSG_READ_VALUE(uint32_tmp, ptr, datalength, uint32_t); resp->length = DLT_ENDIAN_GET_32(message->standardheader->htyp, uint32_tmp); if (resp->status != DLT_SERVICE_RESPONSE_OK) { fprintf(stderr, "GET_SOFTWARE_VERSION failed [status=%d]\n", resp->status); dlt_client_cleanup(&g_dltclient, 0); return -1; } resp->payload = (char *)calloc(resp->length + 1, sizeof(char)); if (resp->payload != NULL) memcpy(resp->payload, message->databuffer + message->datasize - resp->length, resp->length); dlt_client_cleanup(&g_dltclient, 0); break; } default: { break; } } } return ret; }