1 /**
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifdef CONFIG_TESTSUITE_SUPPORT_MULTI_CORE
17 #include "ipc.h"
18 #include "timer.h"
19 #include "securec.h"
20 #include "stdarg.h"
21 #include "osal_addr.h"
22 #include "debug_print.h"
23 #include "test_suite_console.h"
24 #ifndef CONFIG_TESTSUITE_SUPPORT_PRINT_USE_IPC
25 #include "test_suite_uart.h"
26 #endif
27 #include "test_suite_channel.h"
28 #include "test_suite_commands_processor.h"
29 #include "test_suite_task.h"
30 #include "test_suite_ipc.h"
31
32 #define MIN_DOT_BUFFER_NUMBER 10
33
34 #define TEST_SUITE_UART_LEN_MAX 512
35 #ifndef CONFIG_TESTSUITE_SUPPORT_PRINT_USE_IPC
36 #define TEST_SUITE_UART_RX_BUFFER_SIZE 128
37 #endif
38
39 #ifdef CONFIG_TESTSUITE_SUPPORT_MULTI_CORE
40 /*
41 * -- Defines
42 */
43 #define core_flag(x) (1 << (x))
44
45 /*
46 * -- Types
47 */
48 typedef struct {
49 bool inuse;
50 uint16_t length;
51 char msg[IPC_TEST_SUITE_STRING_LENTGH + 1]; /* Include trailing \0 */
52 char status;
53 } feed_back_buffer;
54 #endif
55
56 static char g_test_suite_log_buffer[IPC_TEST_SUITE_STRING_LENTGH];
57
58 static uint8_t g_test_suite_log_buffer_pos = 0;
59 static bool g_test_suite_log_buffer_cr = false;
60 static bool g_test_suite_log_buffer_nl = false;
61 void test_suite_log_helper_char(char data);
62 static void g_test_suite_log_reset_buffer(void);
63 bool g_test_suite_log_buffer_write_char(char data);
64
65 #ifndef CONFIG_TESTSUITE_SUPPORT_PRINT_USE_IPC
66 static uart_bus_t g_test_suite_uart = TEST_SUITE_UART_BUS;
67 static uint8_t g_test_suite_uart_rx_buffer_test[TEST_SUITE_UART_RX_BUFFER_SIZE];
68 #endif
69
70 static char g_test_suite_function_processor_command_buffer[TEST_SUITE_PRIVATE_COMMAND_BUFFER_SIZE + 1];
71
72 #ifdef CONFIG_TESTSUITE_SUPPORT_MULTI_CORE
73 static volatile feed_back_buffer g_response[CORES_MAX_NUMBER_PHYSICAL];
74 static volatile uint8_t g_echo_cores;
75 static volatile uint8_t g_unexpected_log; /* uses the same flags as g_echo_cores */
76 /** Color codes for security radio and apps */
77 static term_color_t g_term_colors[CORES_MAX_NUMBER_PHYSICAL] = { TERM_COLOR_PINK, TERM_COLOR_CYAN, TERM_COLOR_WHITE };
78 #endif
79
test_suite_log_send_test_status(int status)80 void test_suite_log_send_test_status(int status)
81 {
82 /* Use IPC to send to CORES_CORE_IMPLEMENTING_THE_CONSOLE core! */
83 ipc_payload payload;
84 if (memset_s((void *)&payload, sizeof(ipc_payload), 0, sizeof(ipc_payload)) != EOK) {
85 return;
86 }
87
88 payload.testsuite.length = 0;
89 payload.testsuite.status = status;
90
91 /* Horrible... Waiting for ever! At least not in interrupt context! */
92 while (true) {
93 if (ipc_send_message (CORES_CORE_IMPLEMENTING_THE_CONSOLE,
94 IPC_ACTION_TS_MESSAGE_CNF, &payload, payload.testsuite.length + 0x4,
95 IPC_PRIORITY_LOWEST, false) != IPC_STATUS_MAILBOX_BUSY) {
96 break;
97 }
98 }
99
100 /* Reset test_suite_log_buffer. */
101 g_test_suite_log_buffer_pos = 0;
102 }
103 #ifndef CONFIG_TESTSUITE_SUPPORT_PRINT_USE_IPC
test_suite_uart_write(const char * buffer,uint16_t length)104 static void test_suite_uart_write(const char *buffer, uint16_t length)
105 {
106 #ifdef CONFIG_DRIVERS_USB_SERIAL_GADGET
107 if (g_test_uart_mode == TEST_USB_SERIAL) {
108 usb_serial_write(0, buffer, length);
109 } else {
110 uapi_uart_write(TEST_SUITE_UART_BUS, (uint8_t *)buffer, (uint32_t)length, 0);
111 }
112 #else
113 uapi_uart_write(TEST_SUITE_UART_BUS, (uint8_t *)buffer, (uint32_t)length, 0);
114 #endif
115 }
116 #endif
117
test_suite_log_send_msg(void)118 static void test_suite_log_send_msg(void)
119 {
120 #ifdef CONFIG_TESTSUITE_SUPPORT_PRINT_USE_IPC
121 /* Use IPC to send to the core implementing the console! */
122 ipc_payload payload;
123 if (memset_s((void *)&payload, sizeof(ipc_payload), 0, sizeof(ipc_payload)) != EOK) {
124 return;
125 }
126
127 payload.testsuite.length = g_test_suite_log_buffer_pos;
128 if (memcpy_s((void *)payload.testsuite.msg, payload.testsuite.length,
129 g_test_suite_log_buffer, g_test_suite_log_buffer_pos) != EOK) {
130 return;
131 }
132
133 payload.testsuite.status = CMD_TEST_RUNNING;
134
135 /* Horrible... Waiting for ever! At least not in interrupt context! */
136 while (true) {
137 if (ipc_send_message (CORES_CORE_IMPLEMENTING_THE_CONSOLE,
138 IPC_ACTION_TS_MESSAGE_CNF, &payload, payload.testsuite.length,
139 IPC_PRIORITY_LOWEST, false) != IPC_STATUS_MAILBOX_BUSY) {
140 break;
141 }
142 }
143 #else
144 test_suite_uart_write(g_test_suite_log_buffer, g_test_suite_log_buffer_pos);
145 #endif
146 g_test_suite_log_reset_buffer();
147 }
148
test_suite_log_flush(void)149 void test_suite_log_flush(void)
150 {
151 /* If there is something to transmit do it */
152 if (g_test_suite_log_buffer_pos > 0) {
153 test_suite_log_send_msg();
154 }
155
156 return;
157 }
158
g_test_suite_log_buffer_write_char(char data)159 bool g_test_suite_log_buffer_write_char(char data)
160 {
161 g_test_suite_log_buffer[g_test_suite_log_buffer_pos++] = data;
162
163 if (data == '\r') {
164 g_test_suite_log_buffer_cr = true;
165 }
166 if (data == '\n') {
167 g_test_suite_log_buffer_cr = true; /* Change to make it more unix compatible */
168 g_test_suite_log_buffer_nl = true;
169 }
170
171 return ((g_test_suite_log_buffer_pos >= IPC_TEST_SUITE_STRING_LENTGH) ||
172 (g_test_suite_log_buffer_cr && g_test_suite_log_buffer_nl));
173 }
174
g_test_suite_log_reset_buffer(void)175 void g_test_suite_log_reset_buffer(void)
176 {
177 /* Reset test_suite_log_buffer. */
178 g_test_suite_log_buffer_pos = 0;
179 g_test_suite_log_buffer_cr = false;
180 g_test_suite_log_buffer_nl = false;
181 }
182
test_suite_log_helper_char(char data)183 void test_suite_log_helper_char(char data)
184 {
185 bool terminate;
186 terminate = g_test_suite_log_buffer_write_char(data);
187 /* Ensure \0 terminated by leaving additional space! */
188 if (terminate == true) {
189 test_suite_log_send_msg();
190 }
191
192 return;
193 }
194
test_suite_log_helper_send(const char * str)195 void test_suite_log_helper_send(const char *str)
196 {
197 for (uint32_t i = 0; i < strlen(str); i++) {
198 test_suite_log_helper_char(str[i]);
199 }
200 test_suite_log_flush();
201 }
202
test_suite_log_helper_sendf(const char * str,...)203 void test_suite_log_helper_sendf(const char *str, ...)
204 {
205 static char s[TEST_SUITE_UART_LEN_MAX]; /* This needs to be large enough to store the string */
206 int32_t str_len;
207
208 va_list args;
209 va_start(args, str);
210 str_len = vsprintf_s(s, sizeof(s), str, args);
211 va_end(args);
212
213 if (str_len < 0) {
214 return;
215 }
216
217 test_suite_log_helper_send(s);
218 test_suite_log_flush();
219 }
220
test_suite_log_helper_send_line(const char * str)221 void test_suite_log_helper_send_line(const char *str)
222 {
223 test_suite_log_helper_send(str);
224 test_suite_log_helper_send("\r\n");
225 test_suite_log_flush();
226 }
227
228 /**
229 * From security interrupt line
230 */
security_message_handler(ipc_action_t message,const volatile ipc_payload * payload_p,cores_t src,uint32_t id)231 static bool security_message_handler(ipc_action_t message,
232 const volatile ipc_payload *payload_p, cores_t src, uint32_t id)
233 {
234 if (message != IPC_ACTION_TS_MESSAGE_REQ) {
235 PRINT("received action is invalid : %d.\r\n", message);
236 return false;
237 }
238 if (src != CORES_CORE_IMPLEMENTING_THE_CONSOLE) {
239 PRINT("received src is invalid : %d.\r\n", src);
240 return false;
241 }
242 unused(id);
243 test_suite_write_msgqueue((uint8_t *)payload_p->testsuite.msg, payload_p->testsuite.length);
244 /* Message fully processed. */
245 return true;
246 }
247
test_suite_ipc_init(void)248 void test_suite_ipc_init(void)
249 {
250 #ifndef CONFIG_TESTSUITE_SUPPORT_PRINT_USE_IPC
251 uart_buffer_config_t uart_buffer_config;
252
253 uart_pin_config_t uart_pin_config = {
254 .tx_pin = TEST_SUITE_UART_TX_PIN,
255 .rx_pin = TEST_SUITE_UART_RX_PIN,
256 .cts_pin = PIN_NONE,
257 .rts_pin = PIN_NONE
258 };
259
260 uart_attr_t uart_line_config = {
261 .baud_rate = TEST_SUITE_UART_BAUD_RATE,
262 .data_bits = UART_DATA_BIT_8,
263 .stop_bits = UART_STOP_BIT_1,
264 .parity = UART_PARITY_NONE
265 };
266
267 uart_buffer_config.rx_buffer_size = TEST_SUITE_UART_RX_BUFFER_SIZE;
268 uart_buffer_config.rx_buffer = g_test_suite_uart_rx_buffer_test;
269 (void)uapi_uart_init(TEST_SUITE_UART_BUS, &uart_pin_config, &uart_line_config, NULL, &uart_buffer_config);
270 #endif
271 /* Register IRQ callback for IPC... */
272 /* Should have been done earlier really, but hey... */
273 ipc_register_handler(IPC_ACTION_TS_MESSAGE_REQ, security_message_handler);
274 }
275
test_suite_ipc_deinit(void)276 void test_suite_ipc_deinit(void)
277 {
278 }
279
280 /**
281 * @brief Gets test suite ipc functions
282 * @return test suite ipc functions address
283 * @else
284 * @brief 获取测试套件ipc功能函数
285 * @return 测试套件ipc功能函数接口地址
286 * @endif
287 */
test_suite_ipc_funcs_get(void)288 test_suite_channel_funcs_t *test_suite_ipc_funcs_get(void)
289 {
290 static test_suite_channel_funcs_t test_suite_ipc_funcs = {
291 .init = test_suite_ipc_init,
292 .deinit = test_suite_ipc_deinit,
293 .send_char = test_suite_log_helper_char,
294 .send = test_suite_log_helper_send,
295 .sendf = test_suite_log_helper_sendf,
296 .send_line = test_suite_log_helper_send_line,
297 };
298 return &test_suite_ipc_funcs;
299 }
300
test_suite_commands_echo_clear(cores_t core)301 void test_suite_commands_echo_clear(cores_t core)
302 {
303 switch (core) {
304 case CORES_BT_CORE:
305 g_echo_cores &= ~core_flag(CORES_BT_CORE);
306 break;
307 case CORES_PROTOCOL_CORE:
308 g_echo_cores &= ~core_flag(CORES_PROTOCOL_CORE);
309 break;
310 case CORES_APPS_CORE:
311 g_echo_cores &= ~core_flag(CORES_APPS_CORE);
312 break;
313 default:
314 PRINT("input core is invalid : %d \r\n", core);
315 break;
316 }
317 }
318
test_suite_commands_send_to_core(cores_t core,char * cmd)319 static void test_suite_commands_send_to_core(cores_t core, char *cmd)
320 {
321 ipc_payload payload;
322 if (memset_s((void *)&payload, sizeof(ipc_payload), 0, sizeof(ipc_payload)) != EOK) {
323 return;
324 }
325
326 payload.testsuite.length = strlen(cmd) + 1; /* include the null terminated */
327 if (strncpy_s((char *)payload.testsuite.msg, IPC_TEST_SUITE_STRING_LENTGH,
328 (char *)cmd, payload.testsuite.length) != EOK) {
329 return;
330 }
331 /* Horrible... Waiting for ever! */
332 while (1) {
333 if (ipc_send_message(core, IPC_ACTION_TS_MESSAGE_REQ, &payload, payload.testsuite.length + 0x4,
334 IPC_PRIORITY_LOWEST, false) != IPC_STATUS_MAILBOX_BUSY) {
335 break;
336 }
337 }
338 }
339
340 /*
341 * Iterate through all the cores and show the output if there is an
342 * unexpected log or is the core line we are polling (the one that is asserting echo_cores)
343 */
test_suite_commands_poll_line(cores_t core)344 static void test_suite_commands_poll_line(cores_t core)
345 {
346 for (cores_t core_i = CORES_BT_CORE; core_i < CORES_MAX_NUMBER_PHYSICAL; core_i++) {
347 if (((core_i == core) || (g_unexpected_log & core_flag(core_i))) && g_response[core_i].inuse) {
348 if (g_response[core_i].length) {
349 test_suite_console_set_color(g_term_colors[core_i]);
350 test_suite_uart_send((char *)g_response[core_i].msg);
351 } else {
352 /* No string in the packet */
353 test_suite_console_display_test_status(g_response[core_i].status);
354 test_suite_commands_echo_clear(core_i);
355 }
356
357 g_response[core_i].inuse = false;
358 }
359
360 /* if it is not the core having the control report unrequested "[U]" log */
361 if ((core_i != core) && (g_unexpected_log & core_flag(core_i))) {
362 test_suite_console_set_color(TERM_COLOR_RED);
363 test_suite_uart_send("[U]");
364 g_unexpected_log &= ~core_flag(core_i);
365 }
366 }
367 }
368
test_suite_ipc_clear_core_flag(void)369 void test_suite_ipc_clear_core_flag(void)
370 {
371 if (g_echo_cores & core_flag(CORES_APPS_CORE)) {
372 g_echo_cores &= ~(core_flag(CORES_APPS_CORE));
373 }
374 if (g_echo_cores & core_flag(CORES_BT_CORE)) {
375 g_echo_cores &= ~(core_flag(CORES_BT_CORE));
376 }
377 }
378
379 /**
380 * Blocking, command is the command witout the name of the core
381 */
test_suite_commands_execute_in_external_core(cores_t core,char * command,uint32_t timeout)382 void test_suite_commands_execute_in_external_core(cores_t core, char *command, uint32_t timeout)
383 {
384 static timer_handle_t timer = 0;
385 g_echo_cores |= core_flag(core);
386 test_suite_commands_send_to_core(core, command);
387 if (timeout != 0) {
388 uapi_timer_create(DEFAULT_TIMER, &timer);
389 uapi_timer_start(timer, timeout * TEST_SUITE_TIMER_S_TO_US, test_suite_commands_timeout_callback, 0);
390 }
391
392 /* Wait for cores to signal finish state */
393 while ((g_echo_cores & core_flag(core)) != 0) {
394 feed_back_buffer *buffer = NULL;
395 uint32_t buffer_len = TEST_SUITE_MSG_QUEUE_MAX_SIZE;
396 buffer = osal_kmalloc(buffer_len, OSAL_GFP_KERNEL);
397 if (buffer == NULL) {
398 PRINT("[%s][%d]:malloc faile.\r\n", __func__, __LINE__);
399 return;
400 }
401 memset_s(buffer, TEST_SUITE_MSG_QUEUE_MAX_SIZE, 0, buffer_len);
402 test_suite_receive_cmd_queue(buffer, &buffer_len);
403 test_suite_commands_poll_line(core);
404 osal_kfree(buffer);
405 }
406 if (timeout != 0) {
407 uapi_timer_stop(timer);
408 uapi_timer_delete(timer);
409 }
410 }
411
test_suite_commands_ipc_message_handler(ipc_action_t message,const volatile ipc_payload * payload_p,cores_t src,uint32_t id)412 bool test_suite_commands_ipc_message_handler(ipc_action_t message,
413 const volatile ipc_payload *payload_p, cores_t src, uint32_t id)
414 {
415 volatile feed_back_buffer *buffer = NULL;
416 bool release = true;
417
418 unused(id);
419 unused(message);
420 unused(src);
421 if (message != IPC_ACTION_TS_MESSAGE_CNF) {
422 PRINT("receive action is invalid : %d .\r\n", message);
423 return false;
424 }
425 if (src >= CORES_MAX_NUMBER_PHYSICAL) {
426 PRINT("receive src is invalid: %d.\r\n", src);
427 return false;
428 }
429
430 buffer = &(g_response[src]);
431
432 if (!buffer->inuse) {
433 if (memcpy_s((char *)buffer->msg, IPC_TEST_SUITE_STRING_LENTGH,
434 (char *)payload_p->testsuite.msg, payload_p->testsuite.length) != EOK) {
435 return false;
436 }
437
438 buffer->msg[payload_p->testsuite.length] = '\0';
439
440 buffer->length = payload_p->testsuite.length;
441 buffer->status = payload_p->testsuite.status;
442
443 buffer->inuse = true;
444
445 /* A message from a core that was apparently not running a test has been received. */
446 if ((g_echo_cores & core_flag(src)) == 0) {
447 g_unexpected_log |= core_flag(src);
448 }
449 } else {
450 release = false;
451 }
452
453 test_suite_write_cmd_queue(&buffer, sizeof(feed_back_buffer));
454 return release;
455 }
456
457 #endif