XCP_SIM
terminal.c
1 /*
2  * BlueParrot XCP
3  *
4  * (C) 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 #include <ctype.h>
27 
28 #if !defined(_WIN32)
29 #include <pthread.h>
30 #endif
31 
33 #include "flsemu.h"
34 #include "xcp.h"
35 #include "xcp_hw.h"
36 #include "xcp_terminal.h"
39 #if defined(_WIN32)
40 #include <Windows.h>
41 #else
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/select.h>
46 #include <termios.h>
47 #include <unistd.h>
48 #endif
49 
50 #if !defined(_WIN32)
51 struct termios orig_termios;
52 
53 static void reset_terminal_mode(void);
54 static void set_options(void);
55 static void set_raw_terminal_mode(void);
56 static int kbhit(void);
57 static int getch(void);
58 #endif
59 
60 static void SystemInformation(void);
61 static void DisplayHelp(void);
62 void FlsEmu_Info(void);
63 void Xcp_DisplayInfo(void);
64 void XcpDaq_PrintDAQDetails(void);
65 void XcpDaq_Info(void);
66 
67 #if defined(_WIN32)
68 void *XcpTerm_Thread(void *param) {
69  HANDLE hStdin;
70  DWORD cNumRead;
71  DWORD fdwMode;
72  DWORD idx;
73  INPUT_RECORD irInBuf[128];
74  KEY_EVENT_RECORD key;
75 
76  XCP_UNREFERENCED_PARAMETER(param);
77 
78  hStdin = GetStdHandle(STD_INPUT_HANDLE);
79  if (hStdin == INVALID_HANDLE_VALUE) {
80  XcpHw_ErrorMsg("GetStdHandle", GetLastError());
81  }
82 
83  fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
84  if (!SetConsoleMode(hStdin, fdwMode)) {
85  XcpHw_ErrorMsg("SetConsoleMode", GetLastError());
86  }
87 
88  XCP_FOREVER {
89  WaitForSingleObject(hStdin, 1000);
90 
91  if (!GetNumberOfConsoleInputEvents(hStdin, &cNumRead)) {
92  XcpHw_ErrorMsg("PeekConsoleInput", GetLastError());
93  } else {
94  if (cNumRead) {
95  if (!ReadConsoleInput(hStdin, irInBuf, 128, &cNumRead)) {
96  XcpHw_ErrorMsg("ReadConsoleInput", GetLastError());
97  }
98  for (idx = 0; idx < cNumRead; ++idx) {
99  switch (irInBuf[idx].EventType) {
100  case KEY_EVENT:
101  key = irInBuf[idx].Event.KeyEvent;
102  if (key.bKeyDown) {
103  if (key.wVirtualKeyCode == VK_ESCAPE) {
104  XcpThrd_Exit();
105  }
106  switch (tolower(key.uChar.AsciiChar)) {
107  case 'q':
108  XcpThrd_Exit();
109 #if !defined(_MSC_VER)
110  [[noreturn]];
111 #endif /* _MSC_VER */
112  case 'h':
113  DisplayHelp();
114  break;
115  case 'i':
116  SystemInformation();
117  break;
118  case 'd':
119  XcpDaq_PrintDAQDetails();
120  break;
121  default:
122  break;
123  }
124  }
125  break;
126  default:
127  break;
128  }
129  }
130  }
131  }
132  }
133 }
134 #else
135 static void reset_terminal_mode(void) { tcsetattr(0, TCSANOW, &orig_termios); }
136 
137 static void set_options(void) {
138  struct termios term;
139 
140  tcgetattr(STDIN_FILENO, &term);
141  term.c_lflag &= ~(ECHO | ISIG | IEXTEN);
142  term.c_iflag &= ~(IXON | ICRNL | ISTRIP | BRKINT | INPCK);
143  term.c_cflag |= CS8;
144  term.c_oflag |= OPOST;
145  tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
146 }
147 
148 static void set_raw_terminal_mode(void) {
149  struct termios new_termios;
150 
151  tcgetattr(0, &orig_termios);
152  memcpy(&new_termios, &orig_termios, sizeof(new_termios));
153 
154  atexit(reset_terminal_mode);
155  cfmakeraw(&new_termios);
156  set_options();
157  tcsetattr(0, TCSANOW, &new_termios);
158 }
159 
160 static int kbhit(void) {
161  struct timeval tv = {0L, 0L};
162  fd_set fds;
163 
164  FD_ZERO(&fds);
165  FD_SET(0, &fds);
166  return select(1, &fds, NULL, NULL, &tv);
167 }
168 
169 static int getch(void) {
170  int len;
171  unsigned char buf[256];
172 
173  if ((len = read(0, &buf, sizeof(buf))) < 0) {
174  return -1;
175  } else {
176  // printf("%d %x %c\n", len, buf[0], buf[0]);
177  if (len == 1) {
178  // Only plain chars for now.
179  return buf[0];
180  } else {
181  return -1;
182  }
183  }
184 }
185 
186 void *XcpTerm_Thread(void *param) {
187  int key = 0;
188 
189  set_raw_terminal_mode();
190  while (1) {
191  while (!kbhit()) {
192  }
193  key = getch();
194  if (key != -1) {
195  switch (tolower(key)) {
196  case '\x1b':
197  case 'q':
198  XcpThrd_Exit();
199  case 'h':
200  DisplayHelp();
201  break;
202  case 'i':
203  SystemInformation();
204  break;
205  case 'd':
206  XcpDaq_PrintDAQDetails();
207  break;
208  }
209  }
210  }
211 }
212 #endif // defined
213 
214 static void SystemInformation(void) {
215 #if XCP_ENABLE_STATISTICS == XCP_ON
216  Xcp_StateType const *state = Xcp_GetState();
217 #endif /* XCP_ENABLE_STATISTICS */
218 
219  printf("\n\rSystem-Information\n\r");
220  printf("------------------\n\r");
221  XcpTl_PrintConnectionInformation();
222  printf("MAX_CTO : %d MAX_DTO: %d\n\r", XCP_MAX_CTO, XCP_MAX_DTO);
223  printf("Slave-Blockmode : %s\n\r",
224  (XCP_ENABLE_SLAVE_BLOCKMODE == XCP_ON) ? "Yes" : "No");
225  printf("Master-Blockmode: %s\n\r",
226  (XCP_ENABLE_MASTER_BLOCKMODE == XCP_ON) ? "Yes" : "No");
227 
228 #if XCP_ENABLE_CAL_COMMANDS == XCP_ON
229  printf("Calibration : Yes Protected: %s\n\r",
230  (XCP_PROTECT_CAL == XCP_ON) ? "Yes" : "No");
231 #else
232  printf("Calibration : No\n\r");
233 #endif /* XCP_ENABLE_CAL_COMMANDS */
234 
235 #if XCP_ENABLE_PAG_COMMANDS == XCP_ON
236  printf("Paging : Yes Protected: %s\n\r",
237  (XCP_PROTECT_PAG == XCP_ON) ? "Yes" : "No");
238 #else
239  printf("Paging : No\n\r");
240 #endif /* XCP_ENABLE_PAG_COMMANDS */
241 
242 #if XCP_ENABLE_DAQ_COMMANDS == XCP_ON
243  printf("DAQ : Yes Protected: [DAQ: %s STIM: %s]\n\r",
244  (XCP_PROTECT_DAQ == XCP_ON) ? "Yes" : "No",
245  (XCP_PROTECT_STIM == XCP_ON) ? "Yes" : "No");
246 #else
247  printf("DAQ : No\n\r");
248 #endif /* XCP_ENABLE_DAQ_COMMANDS */
249 
250 #if XCP_ENABLE_PGM_COMMANDS
251  printf("Programming : Yes Protected: %s\n\r",
252  (XCP_PROTECT_PGM == XCP_ON) ? "Yes" : "No");
253 #else
254  printf("Programming : No\n\r");
255 #endif /* XCP_ENABLE_PGM_COMMANDS */
256  printf("\n\r");
257  XcpDaq_Info();
258  if (FlsEmu_Initialized()) {
259  FlsEmu_Info();
260  }
261 #if XCP_ENABLE_STATISTICS == XCP_ON
262  printf("\n\rStatistics\n\r");
263  printf("----------\n\r");
264  printf("CTOs rec'd : %d\n\r", state->statistics.ctosReceived);
265  printf("CROs busy : %d\n\r", state->statistics.crosBusy);
266  printf("CROs send : %d\n\r", state->statistics.crosSend);
267 #endif /* XCP_ENABLE_STATISTICS */
268  printf("---------------------------------------------------------------------"
269  "----------\n\r");
270 }
271 
272 static void DisplayHelp(void) {
273  printf("\n\rh\t\tshow this help message\n\r");
274  printf("<ESC> or q\texit\n\r");
275  printf("i\t\tsystem information\n\r");
276  printf("d\t\tDAQ configuration\n\r");
277 }
278 
279 void FlsEmu_Info(void) {
280  uint8_t idx;
281  uint8_t *ptr;
282  FlsEmu_SegmentType *segment;
283 
284  printf("\n\rFlash-Emulator\n\r");
285  printf("--------------\n\r");
286  printf("Segment Mapped Virtual Size(KB) Pagesize(KB) "
287  "#Pages\n\r");
288  for (idx = 0; idx < FlsEmu_GetConfig()->numSegments; ++idx) {
289  ptr = FlsEmu_BasePointer(idx);
290  segment = FlsEmu_GetConfig()->segments[idx];
291  printf("%-20.20s %p %p %8d %4d %6d\n\r", segment->name,
292  (void *)segment->baseAddress, ptr, segment->memSize / 1024,
293  segment->pageSize / 1024, FlsEmu_NumPages(idx));
294  }
295  printf("\n\r");
296 }
297 
298 void Xcp_DisplayInfo(void) {
299  XcpTl_PrintConnectionInformation();
300  printf("Press h for help.\n\r");
301  fflush(stdout);
302 }
303 
304 #if XCP_ENABLE_DAQ_COMMANDS == XCP_ON
305 void XcpDaq_PrintDAQDetails(void) {
306  XcpDaq_ListIntegerType listIdx;
307  XcpDaq_ODTIntegerType odtIdx;
308  XcpDaq_ODTEntryIntegerType odtEntriyIdx;
309  XcpDaq_ListConfigurationType const *listConf;
310  XcpDaq_ListStateType *listState;
311  XcpDaq_ODTType const *odt;
312  XcpDaq_ODTEntryType const *entry;
313  uint8_t mode;
314  uint32_t total;
315  XcpDaq_ODTIntegerType firstPid;
316 
317  printf("\n\rDAQ configuration\n\r");
318  printf("-----------------\n\r");
319  for (listIdx = (XcpDaq_ListIntegerType)0; listIdx < XcpDaq_GetListCount();
320  ++listIdx) {
321  listState = XcpDaq_GetListState(listIdx);
322  listConf = XcpDaq_GetListConfiguration(listIdx);
323  mode = listState->mode;
324  total = UINT16(0);
325  XcpDaq_GetFirstPid(listIdx, &firstPid);
326 #if XCP_DAQ_CONFIG_TYPE == XCP_DAQ_CONFIG_TYPE_DYNAMIC
327  printf("DAQ-List #%d [%s] firstPid: %d mode: ", listIdx,
328  (listIdx < XCP_MIN_DAQ) ? "predefined" : "dynamic", firstPid);
329 #elif XCP_DAQ_CONFIG_TYPE == XCP_DAQ_CONFIG_TYPE_STATIC
330  printf("DAQ-List #%d [%s] firstPid: %d mode: ", listIdx,
331  (listIdx < XCP_MIN_DAQ) ? "predefined" : "static", firstPid);
332 #elif XCP_DAQ_CONFIG_TYPE == XCP_DAQ_CONFIG_TYPE_NONE
333  printf("DAQ-List #%d [predefined] firstPid: %d mode: ", listIdx, firstPid);
334 #endif /* XCP_DAQ_CONFIG_TYPE */
335 
336  if (mode & XCP_DAQ_LIST_MODE_DIRECTION) {
337  printf("STIM ");
338  } else {
339  printf("DAQ ");
340  }
341  if (mode & XCP_DAQ_LIST_MODE_SELECTED) {
342  printf("SELECTED ");
343  }
344  if (mode & XCP_DAQ_LIST_MODE_STARTED) {
345  printf("STARTED ");
346  }
347  if (mode & XCP_DAQ_LIST_MODE_ALTERNATING) {
348  printf("ALTERNATING ");
349  }
350  if (mode & XCP_DAQ_LIST_MODE_PID_OFF) {
351  printf("PID_OFF ");
352  }
353  if (mode & XCP_DAQ_LIST_MODE_TIMESTAMP) {
354  printf("TIMESTAMP ");
355  }
356  printf("\n\r");
357  for (odtIdx = (XcpDaq_ODTIntegerType)0; odtIdx < listConf->numOdts;
358  ++odtIdx) {
359  odt = XcpDaq_GetOdt(listIdx, odtIdx);
360  printf(" ODT #%d\n\r", odtIdx);
361  for (odtEntriyIdx = (XcpDaq_ODTEntryIntegerType)0;
362  odtEntriyIdx < odt->numOdtEntries; ++odtEntriyIdx) {
363  entry = XcpDaq_GetOdtEntry(listIdx, odtIdx, odtEntriyIdx);
364  printf(" Entry #%d [0x%08x] %d Byte(s)\n\r", odtEntriyIdx,
365  entry->mta.address, entry->length);
366  total += entry->length;
367  }
368  }
369  printf(" -------------\n\r");
370  printf(" %-5d Byte(s)\n\r", total);
371  }
372  printf("---------------------------------------------------------------------"
373  "----------\n\r");
374 }
375 
376 void XcpDaq_Info(void) {
377  Xcp_StateType const *Xcp_State;
378 
379  Xcp_State = Xcp_GetState();
380 
381  printf("DAQ\n\r---\n\r");
382 #if XCP_ENABLE_DAQ_COMMANDS == XCP_ON
383  printf("Processor state : ");
384  switch (Xcp_State->daqProcessor.state) {
385  case XCP_DAQ_STATE_UNINIT:
386  printf("Uninitialized");
387  break;
388  case XCP_DAQ_STATE_CONFIG_INVALID:
389  printf("Configuration invalid");
390  break;
391  case XCP_DAQ_STATE_CONFIG_VALID:
392  printf("Configuration valid");
393  break;
394  case XCP_DAQ_STATE_STOPPED:
395  printf("Stopped");
396  break;
397  case XCP_DAQ_STATE_RUNNING:
398  printf("Running");
399  break;
400  }
401  printf("\n\r");
402 #if XCP_DAQ_ENABLE_DYNAMIC_LISTS == XCP_ON
403  printf("Allocated DAQ entities: %d of %d\n\r",
404  XcpDaq_GetDynamicDaqEntityCount(), XCP_DAQ_MAX_DYNAMIC_ENTITIES);
405 #endif /* XCP_DAQ_ENABLE_DYNAMIC_LISTS */
406 
407 #else
408  printf("\tfunctionality not supported.\n\r");
409 #endif
410 }
411 #endif /* XCP_ENABLE_DAQ_COMMANDS */