| /* |
| * Copyright (c) 2017-2018 Oticon A/S |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <zephyr/init.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include "bs_types.h" |
| #include "bs_tracing.h" |
| #include "bstests.h" |
| |
| /* |
| * Result of the testcase execution. |
| * Note that the executable will return the maximum of bst_result and |
| * {the HW model return code} to the shell and that |
| * {the HW model return code} will be 0 unless it fails or it is |
| * configured illegally |
| */ |
| enum bst_result_t bst_result; |
| |
| static struct bst_test_instance *current_test; |
| static struct bst_test_list *test_list_top; |
| |
| __attribute__((weak)) bst_test_install_t test_installers[] = { NULL }; |
| |
| struct bst_test_list *bst_add_tests(struct bst_test_list *tests, |
| const struct bst_test_instance *test_def) |
| { |
| int idx = 0; |
| struct bst_test_list *tail = tests; |
| struct bst_test_list *head = tests; |
| |
| if (tail) { |
| /* First we 'run to end' */ |
| while (tail->next) { |
| tail = tail->next; |
| } |
| } else { |
| if (test_def[idx].test_id != NULL) { |
| head = malloc(sizeof(struct bst_test_list)); |
| head->next = NULL; |
| head->test_instance = (struct bst_test_instance *) |
| &test_def[idx++]; |
| tail = head; |
| } |
| } |
| |
| while (test_def[idx].test_id != NULL) { |
| tail->next = malloc(sizeof(struct bst_test_list)); |
| tail = tail->next; |
| tail->test_instance = (struct bst_test_instance *) |
| &test_def[idx++]; |
| tail->next = NULL; |
| } |
| |
| return head; |
| } |
| |
| static struct bst_test_instance *bst_test_find(struct bst_test_list *tests, |
| char *test_id) |
| { |
| struct bst_test_list *top = tests; |
| |
| while (top != NULL) { |
| if (!strcmp(top->test_instance->test_id, test_id)) { |
| /* Match found */ |
| return top->test_instance; |
| } |
| top = top->next; |
| } |
| return NULL; |
| } |
| |
| void bst_install_tests(void) |
| { |
| int idx = 0; |
| |
| if (test_list_top) { |
| /* Tests were already installed */ |
| return; |
| } |
| |
| /* First execute installers until first test was installed */ |
| while (!test_list_top && test_installers[idx]) { |
| test_list_top = test_installers[idx++](test_list_top); |
| } |
| |
| /* After that simply add remaining tests to list */ |
| while (test_installers[idx]) { |
| test_installers[idx++](test_list_top); |
| } |
| } |
| |
| /** |
| * Print the tests list displayed with the --testslist command |
| * line option |
| */ |
| void bst_print_testslist(void) |
| { |
| struct bst_test_list *top; |
| |
| /* Install tests */ |
| bst_install_tests(); |
| |
| top = test_list_top; |
| while (top) { |
| bs_trace_raw(0, "TestID: %-10s\t%s\n", |
| top->test_instance->test_id, |
| top->test_instance->test_descr); |
| top = top->next; |
| } |
| } |
| |
| /** |
| * Select the testcase to be run from its id |
| */ |
| void bst_set_testapp_mode(char *test_id) |
| { |
| /* Install tests */ |
| bst_install_tests(); |
| |
| /* By default all tests start as in progress */ |
| bst_result = In_progress; |
| |
| current_test = bst_test_find(test_list_top, test_id); |
| if (!current_test) { |
| bs_trace_error_line("test id %s doesn't exist\n", test_id); |
| } |
| } |
| |
| /** |
| * Pass to the testcase the command line arguments it may have |
| * |
| * This function is called after bst_set_testapp_mode |
| * and before *init_f |
| */ |
| void bst_pass_args(int argc, char **argv) |
| { |
| if (current_test && current_test->test_args_f) { |
| current_test->test_args_f(argc, argv); |
| } |
| } |
| |
| /** |
| * Will be called before the CPU is booted |
| */ |
| void bst_pre_init(void) |
| { |
| if (current_test && current_test->test_pre_init_f) { |
| current_test->test_pre_init_f(); |
| } |
| } |
| |
| /** |
| * Will be called when the CPU has gone to sleep for the first time |
| */ |
| void bst_post_init(void) |
| { |
| if (current_test && current_test->test_post_init_f) { |
| current_test->test_post_init_f(); |
| } |
| } |
| |
| /** |
| * Will be called each time the bstest_ticker timer is triggered |
| */ |
| void bst_tick(bs_time_t time) |
| { |
| |
| if (current_test == NULL) { |
| return; |
| } |
| |
| if (current_test->test_tick_f) { |
| current_test->test_tick_f(time); |
| } else if (current_test->test_id) { |
| bs_trace_error_line("the test id %s doesn't have a tick handler" |
| " (how come did we arrive here?)\n", |
| current_test->test_id); |
| } |
| |
| } |
| |
| bool bst_irq_sniffer(int irq_number) |
| { |
| if (current_test && current_test->test_irq_sniffer_f) { |
| return current_test->test_irq_sniffer_f(irq_number); |
| } else { |
| return false; |
| } |
| } |
| |
| static int bst_fake_device_driver_pre2_init(const struct device *arg) |
| { |
| ARG_UNUSED(arg); |
| if (current_test && current_test->test_fake_ddriver_prekernel_f) { |
| current_test->test_fake_ddriver_prekernel_f(); |
| } |
| return 0; |
| } |
| |
| static int bst_fake_device_driver_post_init(const struct device *arg) |
| { |
| ARG_UNUSED(arg); |
| if (current_test && current_test->test_fake_ddriver_postkernel_f) { |
| current_test->test_fake_ddriver_postkernel_f(); |
| } |
| return 0; |
| } |
| |
| SYS_INIT(bst_fake_device_driver_pre2_init, PRE_KERNEL_1, 0); |
| SYS_INIT(bst_fake_device_driver_post_init, POST_KERNEL, 0); |
| |
| void bst_main(void) |
| { |
| if (current_test && current_test->test_main_f) { |
| current_test->test_main_f(); |
| } |
| } |
| |
| /** |
| * Will be called when the device is being terminated |
| */ |
| uint8_t bst_delete(void) |
| { |
| if (current_test && current_test->test_delete_f) { |
| current_test->test_delete_f(); |
| } |
| |
| while (test_list_top) { |
| struct bst_test_list *tmp = test_list_top->next; |
| |
| free(test_list_top); |
| test_list_top = tmp; |
| } |
| |
| return bst_result; |
| } |