automotive-dlt
dlt-control-common.c
Go to the documentation of this file.
1 
24 /*******************************************************************************
25 ** **
26 ** SRC-MODULE: dlt-control-common.c **
27 ** **
28 ** TARGET : linux **
29 ** **
30 ** PROJECT : DLT **
31 ** **
32 ** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com **
33 ** PURPOSE : **
34 ** **
35 ** REMARKS : **
36 ** **
37 ** PLATFORM DEPENDANT [yes/no]: yes **
38 ** **
39 ** TO BE CHANGED BY USER [yes/no]: no **
40 ** **
41 *******************************************************************************/
42 
43 /*******************************************************************************
44 ** Author Identity **
45 ********************************************************************************
46 ** **
47 ** Initials Name Company **
48 ** -------- ------------------------- ---------------------------------- **
49 ** cl Christoph Lipka ADIT **
50 ** fb Frederic Berat ADIT **
51 *******************************************************************************/
52 #define pr_fmt(fmt) "Common control: "fmt
53 
54 #include <errno.h>
55 #include <dirent.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <pthread.h>
60 #include <sys/types.h>
61 #include <sys/socket.h>
62 
63 #include "dlt_common.h"
64 #include "dlt_protocol.h"
65 #include "dlt_client.h"
66 
67 #include "dlt-control-common.h"
68 
69 #define DLT_CTRL_APID "DLTC"
70 #define DLT_CTRL_CTID "DLTC"
71 #define DLT_DAEMON_DEFAULT_CTRL_SOCK_PATH "/tmp/dlt-ctrl.sock"
72 #define DLT_RECEIVE_TEXTBUFSIZE 1024
73 
84 static int (*response_analyzer_cb)(char *, void *, int);
85 
86 static pthread_t daemon_connect_thread;
88 static int callback_return = -1;
89 static pthread_mutex_t answer_lock = PTHREAD_MUTEX_INITIALIZER;
90 static pthread_cond_t answer_cond = PTHREAD_COND_INITIALIZER;
91 
92 static int local_verbose;
93 static char local_ecuid[DLT_CTRL_ECUID_LEN]; /* Name of ECU */
94 static long local_timeout;
95 
96 int get_verbosity(void)
97 {
98  return local_verbose;
99 }
100 
101 void set_verbosity(int v)
102 {
103  local_verbose = !!v;
104 }
105 
106 char *get_ecuid(void)
107 {
108  return local_ecuid;
109 }
110 
111 void set_ecuid(char *ecuid)
112 {
113  char *ecuid_conf = NULL;
114 
115  if (local_ecuid != ecuid)
116  {
117  /* If user pass NULL, read ECUId from dlt.conf */
118  if (ecuid == NULL)
119  {
120  if (dlt_parse_config_param("ECUId", &ecuid_conf) == 0)
121  {
122  memset(local_ecuid, 0, DLT_CTRL_ECUID_LEN);
123  strncpy(local_ecuid, ecuid_conf, DLT_CTRL_ECUID_LEN);
124  local_ecuid[DLT_CTRL_ECUID_LEN - 1] = '\0';
125  }
126  else
127  {
128  pr_error("Cannot read ECUid from dlt.conf\n");
129  }
130  }
131  else
132  {
133  /* Set user passed ECUID */
134  memset(local_ecuid, 0, DLT_CTRL_ECUID_LEN);
135  strncpy(local_ecuid, ecuid, DLT_CTRL_ECUID_LEN);
136  local_ecuid[DLT_CTRL_ECUID_LEN - 1] = '\0';
137  }
138  }
139 }
140 
141 long get_timeout(void)
142 {
143  return local_timeout;
144 }
145 
146 void set_timeout(long t)
147 {
149 
150  if (t > 1)
151  {
152  local_timeout = t;
153  }
154  else
155  {
156  pr_error("Timeout to small. Set to default: %d",
158  }
159 }
160 
161 int dlt_parse_config_param(char *config_id, char **config_data)
162 {
163  FILE * pFile = NULL;
164  int value_length = DLT_RECEIVE_TEXTBUFSIZE;
165  char line[DLT_RECEIVE_TEXTBUFSIZE-1] = {0};
166  char token[DLT_RECEIVE_TEXTBUFSIZE] = {0};
167  char value[DLT_RECEIVE_TEXTBUFSIZE] = {0};
168  char *pch = NULL;
169  const char *filename = NULL;
170 
171  if (*config_data != NULL)
172  *config_data = NULL;
173 
174  /* open configuration file */
175  filename = CONFIGURATION_FILES_DIR "/dlt.conf";
176  pFile = fopen(filename, "r");
177 
178  if (pFile != NULL)
179  {
180  while (1)
181  {
182  /* fetch line from configuration file */
183  if (fgets(line, value_length - 1, pFile) != NULL)
184  {
185  if (strncmp(line, config_id, strlen(config_id)) == 0)
186  {
187  pch = strtok(line, " =\r\n");
188  token[0] = 0;
189  value[0] = 0;
190 
191  while (pch != NULL)
192  {
193  if (token[0] == 0)
194  {
195  strncpy(token, pch, sizeof(token) - 1);
196  token[sizeof(token) - 1] = 0;
197  }
198  else
199  {
200  strncpy(value, pch, sizeof(value) - 1);
201  value[sizeof(value) - 1] = 0;
202  break;
203  }
204  pch = strtok(NULL, " =\r\n");
205  }
206 
207  if (token[0] && value[0])
208  {
209  if (strcmp(token, config_id) == 0)
210  {
211  *(config_data) = (char*)
212  calloc(DLT_DAEMON_FLAG_MAX, sizeof(char));
213  strncpy(*config_data,
214  value,
216  }
217  }
218 
219  }
220  }
221  else
222  {
223  break;
224  }
225  }
226  fclose (pFile);
227  }
228  else
229  {
230  fprintf(stderr, "Cannot open configuration file: %s\n", filename);
231  }
232 
233  if (*config_data == NULL)
234  return -1;
235 
236  return 0;
237 }
238 
249 {
250  if (send(sock,
251  (const char *)(msg->headerbuffer + sizeof(DltStorageHeader)),
252  msg->headersize - sizeof(DltStorageHeader), 0) == -1)
253  {
254  pr_error("Sending message header failed: %s\n", strerror(errno));
255  return -1;
256  }
257 
258  if (send(sock, (const char *) msg->databuffer, msg->datasize, 0) == -1)
259  {
260  pr_error("Sending message failed: %s\n", strerror(errno));
261  return -1;
262  }
263 
264  return 0;
265 }
266 
276 static int prepare_extra_headers(DltMessage *msg, uint8_t *header)
277 {
278  int shift = 0;
279 
280  pr_verbose("Preparing extra headers.\n");
281 
282  if (!msg || !header)
283  {
284  return -1;
285  }
286 
287  shift = sizeof(DltStorageHeader) +
288  sizeof(DltStandardHeader) +
290 
291  /* Set header extra parameters */
292  dlt_set_id(msg->headerextra.ecu, get_ecuid());
293 
294  msg->headerextra.tmsp = dlt_uptime();
295 
296  /* Copy header extra parameters to header buffer */
298  {
299  pr_error("Cannot copy header extra parameter\n");
300  return -1;
301  }
302 
303  /* prepare extended header */
304  msg->extendedheader = (DltExtendedHeader *)(header + shift);
305 
307 
308  msg->extendedheader->noar = 1; /* one payload packet */
309 
310  /* Dummy values have to be set */
313 
314  return 0;
315 }
316 
326 static int prepare_headers(DltMessage *msg, uint8_t *header)
327 {
328  uint32_t len = 0;
329 
330  pr_verbose("Preparing headers.\n");
331 
332  if (!msg || !header)
333  {
334  return -1;
335  }
336 
337  msg->storageheader = (DltStorageHeader *) header;
338 
339  if (dlt_set_storageheader(msg->storageheader, "") == -1)
340  {
341  pr_error("Storage header initialization failed.\n");
342  return -1;
343  }
344 
345  /* prepare standard header */
346  msg->standardheader =
347  (DltStandardHeader *) (header + sizeof(DltStorageHeader));
348 
349  msg->standardheader->htyp = DLT_HTYP_WEID |
351 
352 #if (BYTE_ORDER == BIG_ENDIAN)
353  msg->standardheader->htyp = (msg->standardheader->htyp | DLT_HTYP_MSBF);
354 #endif
355 
356  msg->standardheader->mcnt = 0;
357 
358  /* prepare length information */
359  msg->headersize = sizeof(DltStorageHeader) +
360  sizeof(DltStandardHeader) +
361  sizeof(DltExtendedHeader) +
363 
364  len = msg->headersize - sizeof(DltStorageHeader) + msg->datasize;
365 
366  if (len > UINT16_MAX)
367  {
368  pr_error("Message header is too long.\n");
369  return -1;
370  }
371 
372  msg->standardheader->len = DLT_HTOBE_16(len);
373 
374  return 0;
375 }
376 
387 {
388  DltMessage *msg = NULL;
389 
390  pr_verbose("Preparing message.\n");
391 
392  if (data == NULL)
393  {
394  pr_error("Data for message body is NULL\n");
395  return NULL;
396  }
397 
398  msg = calloc(1, sizeof(DltMessage));
399 
400  if (msg == NULL)
401  {
402  pr_error("Cannot allocate memory for Dlt Message\n");
403  return NULL;
404  }
405 
406  if (dlt_message_init(msg, get_verbosity()) == -1)
407  {
408  pr_error("Cannot initialize Dlt Message\n");
409  free(msg);
410  return NULL;
411  }
412 
413  /* prepare payload of data */
414  msg->databuffersize = msg->datasize = data->size;
415 
416  /* Allocate memory for Dlt Message's buffer */
417  msg->databuffer = (uint8_t *)calloc(1, data->size);
418 
419  if (msg->databuffer == NULL)
420  {
421  pr_error("Cannot allocate memory for data buffer\n");
422  free(msg);
423  return NULL;
424  }
425 
426  /* copy data into message */
427  memcpy(msg->databuffer, data->data, data->size);
428 
429  /* prepare storage header */
430  if (prepare_headers(msg, msg->headerbuffer))
431  {
433  free(msg);
434  return NULL;
435  }
436 
437  /* prepare extra headers */
438  if (prepare_extra_headers(msg, msg->headerbuffer))
439  {
441  free(msg);
442  return NULL;
443  }
444 
445  return msg;
446 }
447 
459 static int dlt_control_init_connection(DltClient *client, void *cb)
460 {
461  int (*callback)(DltMessage *message, void *data) = cb;
462 
463  if (!cb || !client)
464  {
465  pr_error("%s Invalid parameters (%p, %p)\n", __func__, client, cb);
466  return -1;
467  }
468 
469  pr_verbose("Initializing the connection.\n");
470  if (dlt_client_init(client, get_verbosity()) != 0)
471  {
472  pr_error("Failed to register callback (NULL)\n");
473  return -1;
474  }
475 
477 
478  client->socketPath = NULL;
479  if (dlt_parse_config_param("ControlSocketPath", &client->socketPath) != 0)
480  {
481  /* Failed to read from conf, copy default */
483  {
484  pr_error("set socket path didn't succeed\n");
485  return -1;
486  }
487  }
488  client->mode = DLT_CLIENT_MODE_UNIX;
489 
490  return dlt_client_connect(client, get_verbosity());
491 }
492 
503 {
504  pr_verbose("Ready to receive DLT answers.\n");
506  return data;
507 }
508 
526 static int dlt_control_callback(DltMessage *message, void *data)
527 {
528  char text[DLT_RECEIVE_TEXTBUFSIZE] = { 0 };
529  (void) data;
530 
531  if (message == NULL)
532  {
533  pr_error("Received message is null\n");
534  return -1;
535  }
536 
537  /* prepare storage header */
538  if (DLT_IS_HTYP_WEID(message->standardheader->htyp))
539  {
540  dlt_set_storageheader(message->storageheader, message->headerextra.ecu);
541  }
542  else
543  {
544  dlt_set_storageheader(message->storageheader, "LCTL");
545  }
546 
548 
549  /* Extracting payload */
550  dlt_message_payload(message, text,
553  get_verbosity());
554 
555  /*
556  * Checking payload with the provided callback and return the result
557  */
558  pthread_mutex_lock(&answer_lock);
560  message->databuffer,
561  message->datasize);
562  pthread_cond_signal(&answer_cond);
563  pthread_mutex_unlock(&answer_lock);
564 
565  return callback_return;
566 }
567 
582 {
583  struct timespec t;
584  DltMessage *msg = NULL;
585 
586  if (!body)
587  {
588  pr_error("Invalid input (%p).\n", body);
589  return -1;
590  }
591 
592  if (clock_gettime(CLOCK_REALTIME, &t) == -1)
593  {
594  pr_error("Cannot read system time.\n");
595  return -1;
596  }
597 
598  t.tv_sec += timeout;
599 
600  /* send command to daemon here */
601  msg = dlt_control_prepare_message(body);
602 
603  if (msg == NULL)
604  {
605  pr_error("Control message preparation failed\n");
606  return -1;
607  }
608 
609  pthread_mutex_lock(&answer_lock);
610 
611  /* Re-init the return value */
612  callback_return = -1;
613 
614  if (dlt_control_send_message_to_socket(client.sock, msg) != 0)
615  {
616  pr_error("Sending message to daemon failed\n");
617  free(msg);
618  return -1;
619  }
620 
621  /* If we timeout the lock is not taken back */
622  if (!pthread_cond_timedwait(&answer_cond, &answer_lock, &t))
623  {
624  pthread_mutex_unlock(&answer_lock);
625  }
626 
627  /* Destroying the message */
629  free(msg);
630 
631  /* At this point either the value is already correct, either it's still -1.
632  * Then, we don't care to lock the access.
633  */
634  return callback_return;
635 }
636 
648 int dlt_control_init(int (*response_analyzer)(char *, void *, int),
649  char *ecuid,
650  int verbosity)
651 {
652  if (!response_analyzer || !ecuid)
653  {
654  pr_error("Invalid input (%p %p).\n", response_analyzer, ecuid);
655  return -1;
656  }
657 
658  response_analyzer_cb = response_analyzer;
659  set_ecuid(ecuid);
660  set_verbosity(verbosity);
661 
663  {
664  pr_error("Connection initialization failed\n");
665  dlt_client_cleanup(&client, get_verbosity());
666  return -1;
667  }
668 
669  /* Contact DLT daemon */
670  if (pthread_create(&daemon_connect_thread,
671  NULL,
673  NULL) != 0)
674  {
675  pr_error("Cannot create thread to communicate with DLT daemon.\n");
676  return -1;
677  }
678 
679  return 0;
680 }
681 
689 {
690  /* Stopping the listener thread */
691  pthread_cancel(daemon_connect_thread);
692  /* Closing the socket */
693  return dlt_client_cleanup(&client, get_verbosity());
694 }
int32_t datasize
Definition: dlt_common.h:423
static int prepare_extra_headers(DltMessage *msg, uint8_t *header)
Prepare the extra headers of a DLT message.
#define DLT_HTYP_UEH
Definition: dlt_protocol.h:82
int sock
Definition: dlt_client.h:92
#define DLT_HTOBE_16(x)
Definition: dlt_common.h:148
DltStorageHeader * storageheader
Definition: dlt_common.h:432
#define DLT_CTRL_CTID
#define DLT_MSIN_CONTROL_REQUEST
Definition: dlt_protocol.h:141
#define DLT_DAEMON_DEFAULT_CTRL_SOCK_PATH
#define DLT_HTYP_PROTOCOL_VERSION1
Definition: dlt_protocol.h:95
void dlt_set_id(char *id, const char *text)
Definition: dlt_common.c:324
void dlt_client_register_message_callback(int(*registerd_callback)(DltMessage *message, void *data))
Definition: dlt_client.c:105
static void * dlt_control_listen_to_daemon(void *data)
Daemon listener function.
int dlt_parse_config_param(char *config_id, char **config_data)
#define DLT_HTYP_WEID
Definition: dlt_protocol.h:84
DltReturnValue dlt_client_main_loop(DltClient *client, void *data, int verbose)
Definition: dlt_client.c:326
void set_verbosity(int v)
#define DLT_CTRL_TIMEOUT
#define DLT_STANDARD_HEADER_EXTRA_SIZE(htyp)
Definition: dlt_common.h:213
static int(* response_analyzer_cb)(char *, void *, int)
Analyze the daemon answer.
static DltClient client
#define DLT_RECEIVE_TEXTBUFSIZE
static pthread_cond_t answer_cond
static pthread_mutex_t answer_lock
DltReturnValue dlt_message_init(DltMessage *msg, int verbose)
Definition: dlt_common.c:666
#define DLT_HTYP_MSBF
Definition: dlt_protocol.h:83
int dlt_control_deinit(void)
Control communication clean-up.
DltExtendedHeader * extendedheader
Definition: dlt_common.h:435
void set_timeout(long t)
DltReturnValue dlt_message_set_extraparameters(DltMessage *msg, int verbose)
Definition: dlt_common.c:1273
static char local_ecuid[DLT_CTRL_ECUID_LEN]
static char data[kDataSize]
Definition: city-test.cc:40
#define DLT_CTRL_APID
#define DLT_CTRL_ECUID_LEN
static int callback_return
DltReturnValue dlt_set_storageheader(DltStorageHeader *storageheader, const char *ecu)
Definition: dlt_common.c:2315
int32_t databuffersize
Definition: dlt_common.h:429
DltReturnValue dlt_client_init(DltClient *client, int verbose)
Definition: dlt_client.c:133
#define DLT_HTYP_WTMS
Definition: dlt_protocol.h:86
int dlt_client_set_socket_path(DltClient *client, char *socket_path)
Definition: dlt_client.c:861
DltReturnValue dlt_client_cleanup(DltClient *client, int verbose)
Definition: dlt_client.c:301
static DltMessage * dlt_control_prepare_message(DltControlMsgBody *data)
Prepare a DLT message.
uint32_t dlt_uptime(void)
Definition: dlt_common.c:3274
DltReturnValue dlt_client_connect(DltClient *client, int verbose)
Definition: dlt_client.c:168
char * get_ecuid(void)
int32_t headersize
Definition: dlt_common.h:422
static pthread_t daemon_connect_thread
static int local_verbose
static int dlt_control_init_connection(DltClient *client, void *cb)
Initialize the connection with the daemon.
uint8_t headerbuffer[sizeof(DltStorageHeader)+sizeof(DltStandardHeader)+sizeof(DltStandardHeaderExtra)+sizeof(DltExtendedHeader)]
Definition: dlt_common.h:427
#define pr_error(fmt,...)
#define DLT_IS_HTYP_WEID(htyp)
Definition: dlt_protocol.h:91
DltStandardHeaderExtra headerextra
Definition: dlt_common.h:434
static int prepare_headers(DltMessage *msg, uint8_t *header)
Prepare the headers of a DLT message.
DltReturnValue dlt_message_payload(DltMessage *msg, char *text, int textlength, int type, int verbose)
Definition: dlt_common.c:891
static long local_timeout
int dlt_control_send_message(DltControlMsgBody *body, int timeout)
Send a message to the daemon and wait for the asynchronous answer.
DltStandardHeader * standardheader
Definition: dlt_common.h:433
DltReturnValue dlt_message_free(DltMessage *msg, int verbose)
Definition: dlt_common.c:691
#define pr_verbose(fmt,...)
int dlt_control_init(int(*response_analyzer)(char *, void *, int), char *ecuid, int verbosity)
Control communication initialization.
DltReturnValue dlt_message_header(DltMessage *msg, char *text, int textlength, int verbose)
Definition: dlt_common.c:710
#define DLT_DAEMON_FLAG_MAX
#define DLT_OUTPUT_ASCII
Definition: dlt_common.h:271
uint8_t * databuffer
Definition: dlt_common.h:428
int get_verbosity(void)
char * socketPath
Definition: dlt_client.h:96
long get_timeout(void)
static int dlt_control_callback(DltMessage *message, void *data)
Internal callback for DLT response.
DltClientMode mode
Definition: dlt_client.h:99
static int dlt_control_send_message_to_socket(int sock, DltMessage *msg)
Send a message to the daemon through the socket.
#define NULL
Definition: dlt_common.h:232
void set_ecuid(char *ecuid)