1 /*
2  * Copyright (c) 2017-2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/init.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include "bs_types.h"
10 #include "bs_tracing.h"
11 #include "bstests.h"
12 
13 /*
14  * Result of the testcase execution.
15  * Note that the executable will return the maximum of bst_result and
16  * {the HW model return code} to the shell and that
17  * {the HW model return code} will be 0 unless it fails or it is
18  * configured illegally
19  */
20 enum bst_result_t bst_result;
21 
22 static struct bst_test_instance *current_test;
23 static struct bst_test_list *test_list_top;
24 
25 __attribute__((weak)) bst_test_install_t test_installers[] = { NULL };
26 
bst_add_tests(struct bst_test_list * tests,const struct bst_test_instance * test_def)27 struct bst_test_list *bst_add_tests(struct bst_test_list *tests,
28 				const struct bst_test_instance *test_def)
29 {
30 	int idx = 0;
31 	struct bst_test_list *tail = tests;
32 	struct bst_test_list *head = tests;
33 
34 	if (tail) {
35 		/* First we 'run to end' */
36 		while (tail->next) {
37 			tail = tail->next;
38 		}
39 	} else {
40 		if (test_def[idx].test_id != NULL) {
41 			head = malloc(sizeof(struct bst_test_list));
42 			head->next = NULL;
43 			head->test_instance = (struct bst_test_instance *)
44 						&test_def[idx++];
45 			tail = head;
46 		}
47 	}
48 
49 	while (test_def[idx].test_id != NULL) {
50 		tail->next = malloc(sizeof(struct bst_test_list));
51 		tail = tail->next;
52 		tail->test_instance = (struct bst_test_instance *)
53 					&test_def[idx++];
54 		tail->next = NULL;
55 	}
56 
57 	return head;
58 }
59 
bst_test_find(struct bst_test_list * tests,char * test_id)60 static struct bst_test_instance *bst_test_find(struct bst_test_list *tests,
61 					  char *test_id)
62 {
63 	struct bst_test_list *top = tests;
64 
65 	while (top != NULL) {
66 		if (!strcmp(top->test_instance->test_id, test_id)) {
67 			/* Match found */
68 			return top->test_instance;
69 		}
70 		top = top->next;
71 	}
72 	return NULL;
73 }
74 
bst_install_tests(void)75 void bst_install_tests(void)
76 {
77 	int idx = 0;
78 
79 	if (test_list_top) {
80 		/* Tests were already installed */
81 		return;
82 	}
83 
84 	/* First execute installers until first test was installed */
85 	while (!test_list_top && test_installers[idx]) {
86 		test_list_top = test_installers[idx++](test_list_top);
87 	}
88 
89 	/* After that simply add remaining tests to list */
90 	while (test_installers[idx]) {
91 		test_installers[idx++](test_list_top);
92 	}
93 }
94 
95 /**
96  * Print the tests list displayed with the --testslist command
97  * line option
98  */
bst_print_testslist(void)99 void bst_print_testslist(void)
100 {
101 	struct bst_test_list *top;
102 
103 	/* Install tests */
104 	bst_install_tests();
105 
106 	top = test_list_top;
107 	while (top) {
108 		bs_trace_raw(0, "TestID: %-10s\t%s\n",
109 			     top->test_instance->test_id,
110 			     top->test_instance->test_descr);
111 		top = top->next;
112 	}
113 }
114 
115 /**
116  * Select the testcase to be run from its id
117  */
bst_set_testapp_mode(char * test_id)118 void bst_set_testapp_mode(char *test_id)
119 {
120 	/* Install tests */
121 	bst_install_tests();
122 
123 	/* By default all tests start as in progress */
124 	bst_result = In_progress;
125 
126 	current_test = bst_test_find(test_list_top, test_id);
127 	if (!current_test) {
128 		bs_trace_error_line("test id %s doesn't exist\n", test_id);
129 	}
130 }
131 
132 /**
133  * Pass to the testcase the command line arguments it may have
134  *
135  * This function is called after bst_set_testapp_mode
136  * and before *init_f
137  */
bst_pass_args(int argc,char ** argv)138 void bst_pass_args(int argc, char **argv)
139 {
140 	if (current_test && current_test->test_args_f) {
141 		current_test->test_args_f(argc, argv);
142 	}
143 }
144 
145 /**
146  * Will be called before the CPU is booted
147  */
bst_pre_init(void)148 void bst_pre_init(void)
149 {
150 	if (current_test && current_test->test_pre_init_f) {
151 		current_test->test_pre_init_f();
152 	}
153 }
154 
155 /**
156  * Will be called when the CPU has gone to sleep for the first time
157  */
bst_post_init(void)158 void bst_post_init(void)
159 {
160 	if (current_test && current_test->test_post_init_f) {
161 		current_test->test_post_init_f();
162 	}
163 }
164 
165 /**
166  * Will be called each time the bstest_ticker timer is triggered
167  */
bst_tick(bs_time_t time)168 void bst_tick(bs_time_t time)
169 {
170 
171 	if (current_test == NULL) {
172 		return;
173 	}
174 
175 	if (current_test->test_tick_f) {
176 		current_test->test_tick_f(time);
177 	} else if (current_test->test_id) {
178 		bs_trace_error_line("the test id %s doesn't have a tick handler"
179 				    " (how come did we arrive here?)\n",
180 				    current_test->test_id);
181 	}
182 
183 }
184 
bst_irq_sniffer(int irq_number)185 bool bst_irq_sniffer(int irq_number)
186 {
187 	if (current_test && current_test->test_irq_sniffer_f) {
188 		return current_test->test_irq_sniffer_f(irq_number);
189 	} else {
190 		return false;
191 	}
192 }
193 
bst_fake_device_driver_pre2_init(void)194 static int bst_fake_device_driver_pre2_init(void)
195 {
196 	if (current_test && current_test->test_fake_ddriver_prekernel_f) {
197 		current_test->test_fake_ddriver_prekernel_f();
198 	}
199 	return 0;
200 }
201 
bst_fake_device_driver_post_init(void)202 static int bst_fake_device_driver_post_init(void)
203 {
204 	if (current_test && current_test->test_fake_ddriver_postkernel_f) {
205 		current_test->test_fake_ddriver_postkernel_f();
206 	}
207 	return 0;
208 }
209 
210 SYS_INIT(bst_fake_device_driver_pre2_init, PRE_KERNEL_1, 0);
211 SYS_INIT(bst_fake_device_driver_post_init, POST_KERNEL, 0);
212 
bst_main(void)213 void bst_main(void)
214 {
215 	if (current_test && current_test->test_main_f) {
216 		current_test->test_main_f();
217 	}
218 }
219 
220 /**
221  * Will be called when the device is being terminated
222  */
bst_delete(void)223 uint8_t bst_delete(void)
224 {
225 	if (current_test && current_test->test_delete_f) {
226 		current_test->test_delete_f();
227 	}
228 
229 	while (test_list_top) {
230 		struct bst_test_list *tmp = test_list_top->next;
231 
232 		free(test_list_top);
233 		test_list_top = tmp;
234 	}
235 
236 	return bst_result;
237 }
238