XCP_SIM
linux/hw.c
1 /*
2  * BlueParrot XCP
3  *
4  * (C) 2007-2021 by Christoph Schueler <github.com/Christoph2,
5  * cpu12.gems@googlemail.com>
6  *
7  * All Rights Reserved
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * s. FLOSS-EXCEPTION.txt
24  */
25 
26 #define _GNU_C_SOURCE
27 
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <pthread.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <time.h>
38 #include <unistd.h>
39 
41 #include "xcp.h"
42 #include "xcp_hw.h"
45 /*
46 ** Local Types.
47 */
48 
49 typedef struct tagHwStateType {
50  struct timespec StartingTime;
51 } HwStateType;
52 
53 /*
54 ** Local Defines.
55 */
56 #define TIMER_PS_1NS (1UL)
57 #define TIMER_PS_10NS (10UL)
58 #define TIMER_PS_100NS (100UL)
59 #define TIMER_PS_1US (1000UL)
60 #define TIMER_PS_10US (10000UL)
61 #define TIMER_PS_100US (100000UL)
62 #define TIMER_PS_1MS (1000000UL)
63 #define TIMER_PS_10MS (10000000UL)
64 #define TIMER_PS_100MS (100000000UL)
65 #define TIMER_PS_1S (1000000000UL)
66 
67 /* Set timer prescaler */
68 #if XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_1NS
69 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_1NS)
70 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_10NS
71 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_10NS)
72 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_100NS
73 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_100NS)
74 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_1US
75 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_1US)
76 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_10US
77 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_10US=
78 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_100US
79 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_100US)
80 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_1MS
81 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_1MS)
82 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_10MS
83 #define XCP_HW_TIMER_PRESCALER (TIMER_PS_10MS)
84 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_100MS
85 #define XCP_HW_TIMER_PRESCALRE (TIMER_PS_100MS)
86 #elif XCP_DAQ_TIMESTAMP_UNIT == XCP_DAQ_TIMESTAMP_UNIT_1S
87 #define XCP_HW_TIMER_PRESCALRE (TIMER_PS_1S)
88 #else
89 #error Timestamp-unit not supported.
90 #endif // XCP_DAQ_TIMESTAMP_UNIT
91 
92 #define TIMER_MASK_1 (0x000000FFUL)
93 #define TIMER_MASK_2 (0x0000FFFFUL)
94 #define TIMER_MASK_4 (0xFFFFFFFFUL)
95 
96 #define SIG SIGRTMIN
97 
98 /*
99 ** Local Function Prototypes.
100 */
101 static void XcpHw_InitLocks(void);
102 static uint64_t XcpHw_GetElapsedTime(uint32_t prescaler);
103 static void XcpHw_DeinitLocks();
104 static struct timespec Timespec_Diff(struct timespec start, struct timespec end);
105 static void InitTUI(void);
106 static void DeinitTUI(void);
107 
108 /*
109 ** External Function Prototypes.
110 */
111 
112 void *XcpHw_MainFunction();
113 
114 bool XcpDaq_QueueEmpty(void);
115 bool XcpDaq_QueueDequeue(uint16_t *len, uint8_t *data);
116 
117 void exitFunc(void);
118 
119 /*
120 ** Global Variables.
121 */
122 pthread_t XcpHw_ThreadID[4];
123 
124 /*
125  * Local Types.
126  */
127 #define XCPHW_APPLICATION_STATES (32)
128 
130  volatile uint8_t counter[XCPHW_APPLICATION_STATES];
132 
133 /*
134 ** Local Variables.
135 */
136 static HwStateType HwState = {0};
137 pthread_mutex_t XcpHw_Locks[XCP_HW_LOCK_COUNT];
138 static struct timespec XcpHw_TimerResolution = {0};
139 static timer_t XcpHw_AppMsTimer;
140 static unsigned long long XcpHw_FreeRunningCounter = 0ULL;
141 static XcpHw_ApplicationStateType XcpHw_ApplicationState;
142 static pthread_cond_t XcpHw_TransmissionEvent;
143 static pthread_mutex_t XcpHw_TransmissionMutex;
144 
145 /*
146 ** Global Functions.
147 */
148 
149 static void termination_handler(int sig) {
150  printf("Terminating due to ");
151  switch (sig) {
152  case SIGKILL:
153  printf("SIGKILL");
154  break;
155  case SIGSTOP:
156  printf("SIGSTOP");
157  break;
158  case SIGQUIT:
159  printf("SIGQUIT");
160  break;
161  case SIGILL:
162  printf("SIGILL");
163  break;
164  case SIGTRAP:
165  printf("SIGTRAP");
166  break;
167  case SIGABRT:
168  printf("SIGABRT");
169  break;
170  case SIGSEGV:
171  printf("SIGSEGV");
172  break;
173  default:
174  printf("Signal: %u", sig);
175  }
176  printf(".\n");
177  exit(9);
178 }
179 
180 static void handler(int sig, siginfo_t *si, void *uc) {
181  /* Note: calling printf() from a signal handler is not safe
182  * (and should not be done in production programs), since
183  * printf() is not async-signal-safe; see signal-safety(7).
184  * Nevertheless, we use printf() here as a simple way of
185  * showing that the handler was called. */
186 
187  // printf("Caught signal %u %lu\n", sig, XcpHw_GetTimerCounter());
188 
189  // print_siginfo(si);
190  // signal(sig, SIG_IGN);
191 }
192 
193 void XcpHw_Init(void) {
194  int status = 0;
195  struct sigevent sev = {0};
196  timer_t timerid = 0;
197  struct itimerspec its = {0};
198  long long freq_nanosecs = 1000 * 1000 * 1000LL;
199  sigset_t mask = {0};
200  struct sigaction sa = {0};
201 
202  XCP_UNREFERENCED_PARAMETER(timerid);
203  XCP_UNREFERENCED_PARAMETER(status);
204 
205  signal(SIGKILL, termination_handler);
206  signal(SIGSTOP, termination_handler);
207  signal(SIGQUIT, termination_handler);
208  signal(SIGILL, termination_handler);
209  signal(SIGTRAP, termination_handler);
210  signal(SIGABRT, termination_handler);
211  signal(SIGSEGV, termination_handler);
212 
213  XcpHw_FreeRunningCounter = 0ULL;
214 
215  if (clock_getres(CLOCK_MONOTONIC, &XcpHw_TimerResolution) == -1) {
216  XcpHw_ErrorMsg("XcpHw_Init::clock_getres()", errno);
217  }
218 
219  if (clock_gettime(CLOCK_MONOTONIC, &HwState.StartingTime) == -1) {
220  XcpHw_ErrorMsg("XcpHw_Init::clock_gettime()", errno);
221  }
222  fflush(stdout);
223 #if 0
224  _setmode(_fileno(stdout), _O_WTEXT); /* Permit Unicode output on console */
225  _setmode(_fileno(stdout), _O_U8TEXT); /* Permit Unicode output on console */
226 #endif
227 
228  /* Establish handler for timer signal */
229  // printf("Establishing handler for signal %d\n", SIG);
230  sa.sa_flags = SA_SIGINFO;
231  sa.sa_sigaction = handler;
232  sigemptyset(&sa.sa_mask);
233  if (sigaction(SIG, &sa, NULL) == -1) {
234  XcpHw_ErrorMsg("XcpHw_Init::sigaction()", errno);
235  }
236 
237  /* Block timer signal temporarily */
238  // printf("Blocking signal %d\n", SIG);
239  sigemptyset(&mask);
240  sigaddset(&mask, SIG);
241  if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) {
242  XcpHw_ErrorMsg("XcpHw_Init::sigprocmask()", errno);
243  }
244 
245  /* Create the timer */
246  sev.sigev_notify = SIGEV_SIGNAL;
247  sev.sigev_signo = SIG;
248  sev.sigev_value.sival_ptr = &XcpHw_AppMsTimer;
249  // Parameter sevp could be NULL!?
250  if (timer_create(CLOCK_MONOTONIC, &sev, &XcpHw_AppMsTimer) == -1) {
251  XcpHw_ErrorMsg("XcpHw_Init::timer_create()", errno);
252  }
253 
254  /* Start the timer */
255  its.it_value.tv_sec = freq_nanosecs / 1000000000;
256  its.it_value.tv_nsec = freq_nanosecs % 1000000000;
257  its.it_interval.tv_sec = its.it_value.tv_sec;
258  its.it_interval.tv_nsec = its.it_value.tv_nsec;
259  if (timer_settime(XcpHw_AppMsTimer, 0, &its, NULL) == -1) {
260  XcpHw_ErrorMsg("XcpHw_Init::timer_settime()", errno);
261  }
262 
263  if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
264  XcpHw_ErrorMsg("XcpHw_Init::sigprocmask()", errno);
265  }
266  XcpHw_InitLocks();
267  pthread_cond_init(&XcpHw_TransmissionEvent, NULL);
268  pthread_mutex_init(&XcpHw_TransmissionMutex, NULL);
269 }
270 
271 void XcpHw_Deinit(void) {
272  XcpHw_DeinitLocks();
273  pthread_cond_destroy(&XcpHw_TransmissionEvent);
274  pthread_cond_destroy(&XcpHw_TransmissionEvent);
275  pthread_mutex_destroy(&XcpHw_TransmissionMutex);
276 }
277 
278 static struct timespec Timespec_Diff(struct timespec start, struct timespec end) {
279  struct timespec temp;
280 
281  if ((end.tv_nsec - start.tv_nsec) < 0) {
282  temp.tv_sec = end.tv_sec - start.tv_sec - 1;
283  temp.tv_nsec = 1000000000L + end.tv_nsec - start.tv_nsec;
284  } else {
285  temp.tv_sec = end.tv_sec - start.tv_sec;
286  temp.tv_nsec = end.tv_nsec - start.tv_nsec;
287  }
288  return temp;
289 }
290 
291 
292 static uint64_t XcpHw_GetElapsedTime(uint32_t prescaler)
293 {
294 
295  struct timespec now = {0};
296  struct timespec dt = {0};
297  uint64_t timestamp = 0ULL;
298 
299  if (clock_gettime(CLOCK_MONOTONIC_RAW, &now) == -1) {
300  XcpHw_ErrorMsg("XcpHw_Init::clock_getres()", errno);
301  }
302  dt = Timespec_Diff(HwState.StartingTime, now);
303  XcpHw_FreeRunningCounter =
304  ((unsigned long long)(dt.tv_sec) * (unsigned long long)1000 * 1000 * 1000) + ((unsigned long long)dt.tv_nsec);
305  timestamp = XcpHw_FreeRunningCounter / prescaler;
306  return timestamp;
307 }
308 
309 
310 uint32_t XcpHw_GetTimerCounter(void) {
311  uint64_t timestamp = XcpHw_GetElapsedTime(XCP_HW_TIMER_PRESCALER);
312 
313  timestamp = XcpHw_FreeRunningCounter % UINT_MAX;
314 
315 #if XCP_DAQ_TIMESTAMP_SIZE == XCP_DAQ_TIMESTAMP_SIZE_1
316  timestamp &= TIMER_MASK_1;
317 #elif XCP_DAQ_TIMESTAMP_SIZE == XCP_DAQ_TIMESTAMP_SIZE_2
318  timestamp &= TIMER_MASK_2;
319 #elif XCP_DAQ_TIMESTAMP_SIZE == XCP_DAQ_TIMESTAMP_SIZE_4
320  timestamp &= TIMER_MASK_4;
321 #else
322 #error Timestamp-size not supported.
323 #endif // XCP_DAQ_TIMESTAMP_SIZE
324 
325  return (uint32_t)timestamp;
326 }
327 
328 
329 uint32_t XcpHw_GetTimerCounterMS(void) {
330  uint64_t timestamp = XcpHw_GetElapsedTime(TIMER_PS_1MS);
331 
332  return (uint32_t)timestamp & TIMER_MASK_4;
333 }
334 
335 
336 void XcpHw_TransmitDtos(void) {
337  uint16_t len;
338  uint8_t data[XCP_MAX_DTO + XCP_TRANSPORT_LAYER_BUFFER_OFFSET];
339  uint8_t *dataOut = Xcp_GetDtoOutPtr();
340 
341  while (!XcpDaq_QueueEmpty()) {
342  XcpDaq_QueueDequeue(&len, dataOut);
343  // printf("\tDTO -- len: %d data: \t", len);
344  Xcp_SetDtoOutLen(len);
345  Xcp_SendDto();
346  }
347 }
348 
349 static void XcpHw_InitLocks(void) {
350  uint8_t idx = UINT8(0);
351 
352  for (idx = UINT8(0); idx < XCP_HW_LOCK_COUNT; ++idx) {
353  pthread_mutex_init(&XcpHw_Locks[idx], NULL);
354  }
355 }
356 
357 static void XcpHw_DeinitLocks(void) {
358  uint8_t idx = UINT8(0);
359 
360  for (idx = UINT8(0); idx < XCP_HW_LOCK_COUNT; ++idx) {
361  pthread_mutex_destroy(&XcpHw_Locks[idx]);
362  }
363 }
364 
365 void XcpHw_AcquireLock(uint8_t lockIdx) {
366  if (lockIdx >= XCP_HW_LOCK_COUNT) {
367  return;
368  }
369  pthread_mutex_lock(&XcpHw_Locks[lockIdx]);
370 }
371 
372 void XcpHw_ReleaseLock(uint8_t lockIdx) {
373  if (lockIdx >= XCP_HW_LOCK_COUNT) {
374  return;
375  }
376  pthread_mutex_unlock(&XcpHw_Locks[lockIdx]);
377 }
378 
379 void XcpHw_SignalTransmitRequest(void) {
380  pthread_mutex_lock(&XcpHw_TransmissionMutex);
381  pthread_cond_signal(&XcpHw_TransmissionEvent);
382 }
383 
384 void XcpHw_WaitTransmitRequest(void) { pthread_cond_wait(&XcpHw_TransmissionEvent, &XcpHw_TransmissionMutex); }
385 
386 void XcpHw_ErrorMsg(char *const fun, int errorCode) { fprintf(stderr, "[%s] failed with: [%d]\n", fun, errorCode); }
387 
388 /*
389  *
390  * Sleep for `usec` microseconds.
391  *
392  */
393 void XcpHw_Sleep(uint64_t usec) { usleep(usec); }