• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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