1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-06-04 WillianChan first version
9 * 2021-06-08 WillianChan support to MS VC++ compiler
10 */
11
12 #include <var_export.h>
13
14 static const ve_exporter_t *ve_exporter_table = RT_NULL;
15 static rt_size_t ve_exporter_num = 0;
16
17 /* for IAR compiler */
18 #if defined(__ICCARM__) || defined(__ICCRX__)
19 #pragma section="VarExpTab"
20 #endif
21
22 /* for ARM C and IAR Compiler */
23 #if defined(__ARMCC_VERSION) || defined (__ICCARM__) || defined(__ICCRX__)
24 static rt_used const struct ve_exporter __ve_table_start
25 rt_section("0.""VarExpTab") = {"ve_start", "ve_start", 0};
26
27 static rt_used const struct ve_exporter __ve_table_end
28 rt_section("2.""VarExpTab") = {"ve_end", "ve_end", 2};
29 #endif
30
31 /* for MS VC++ compiler */
32 #if defined(_MSC_VER)
33 #pragma section("VarExpTab$a", read)
34 __declspec(allocate("VarExpTab$a"))
35 rt_used const struct ve_exporter __ve_table_start = { "ve_start", "ve_start", 0};
36
37 #pragma section("VarExpTab$z", read)
38 __declspec(allocate("VarExpTab$z"))
39 rt_used const struct ve_exporter __ve_table_end = { "ve_end", "ve_end", 2};
40
41 /* Find var objects in VarExpTab segments */
ve_init_find_obj(unsigned int * begin,unsigned int * end,ve_exporter_t * table)42 static int ve_init_find_obj(unsigned int *begin, unsigned int *end, ve_exporter_t *table)
43 {
44 int obj_count = 0;
45
46 while (begin < end)
47 {
48 if (*begin != RT_NULL)
49 {
50 *table++ = *((struct ve_exporter *)begin);
51 begin += sizeof(struct ve_exporter) / sizeof(unsigned int);
52 obj_count += 1;
53 }
54 else
55 {
56 begin++;
57 }
58 }
59
60 return obj_count;
61 }
62 #endif /* _MSC_VER */
63
64 /* initialize var export */
var_export_init(void)65 int var_export_init(void)
66 {
67 /* initialize the var export table.*/
68 #if defined(__ARMCC_VERSION) /* for ARM C Compiler */
69 ve_exporter_table = &__ve_table_start + 1;
70 ve_exporter_num = &__ve_table_end - &__ve_table_start;
71 #elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
72 ve_exporter_table = &__ve_table_start + 1;
73 ve_exporter_num = &__ve_table_end - &__ve_table_start - 1;
74 #elif defined (__GNUC__) /* for GCC Compiler */
75 extern const int __ve_table_start;
76 extern const int __ve_table_end;
77 ve_exporter_table = (const ve_exporter_t *)&__ve_table_start;
78 ve_exporter_num = (const ve_exporter_t *)&__ve_table_end - ve_exporter_table;
79 #elif defined (_MSC_VER) /* for MS VC++ compiler */
80 unsigned int *ptr_begin = (unsigned int *)&__ve_table_start;
81 unsigned int *ptr_end = (unsigned int *)&__ve_table_end;
82 static ve_exporter_t ve_exporter_tab[2048];
83 static char __vexp_strbuf1[1024];
84 static char __vexp_strbuf2[1024];
85 ve_exporter_t ve_exporter_temp;
86 rt_size_t index_i, index_j;
87
88 /* past the three members in first ptr_begin */
89 ptr_begin += (sizeof(struct ve_exporter) / sizeof(unsigned int));
90 while (*ptr_begin == 0) ptr_begin++;
91 do ptr_end--; while (*ptr_end == 0);
92
93 /* Find var objects in custom segments to solve the problem of holes in objects in different files */
94 ve_exporter_num = ve_init_find_obj(ptr_begin, ptr_end, ve_exporter_tab);
95
96 /* check if the ve_exporter_num is out of bounds */
97 RT_ASSERT(ve_exporter_num < (sizeof(ve_exporter_tab) / sizeof(ve_exporter_t)));
98
99 /* bubble sort algorithms */
100 for (index_i = 0; index_i < (ve_exporter_num - 1); index_i++)
101 {
102 for (index_j = 0; index_j < ((ve_exporter_num - 1) - index_i); index_j++)
103 {
104 /* splice ve_exporter's module and ve_exporter's identifier into a complete string */
105 rt_snprintf(__vexp_strbuf1,
106 sizeof(__vexp_strbuf1),
107 "%s%s",
108 ve_exporter_tab[index_j].module,
109 ve_exporter_tab[index_j].identifier);
110 rt_snprintf(__vexp_strbuf2,
111 sizeof(__vexp_strbuf2),
112 "%s%s",
113 ve_exporter_tab[index_j + 1].module,
114 ve_exporter_tab[index_j + 1].identifier);
115 if (rt_strcmp(__vexp_strbuf1, __vexp_strbuf2) > 0)
116 {
117 ve_exporter_temp = ve_exporter_tab[index_j];
118 ve_exporter_tab[index_j] = ve_exporter_tab[index_j + 1];
119 ve_exporter_tab[index_j + 1] = ve_exporter_temp;
120 }
121 }
122 }
123
124 ve_exporter_table = ve_exporter_tab;
125 #endif /* __ARMCC_VERSION */
126
127 return ve_exporter_num;
128 }
129 INIT_BOARD_EXPORT(var_export_init);
130
131 /* initialize module */
ve_module_init(ve_module_t * mod,const char * module)132 int ve_module_init(ve_module_t *mod, const char *module)
133 {
134 const ve_exporter_t *exporter = ve_exporter_table;
135 rt_bool_t first_exist = RT_FALSE;
136 rt_size_t found_index;
137
138 for (found_index = 0; found_index < ve_exporter_num; found_index++)
139 {
140 if (!rt_strcmp(exporter->module, module))
141 {
142 if (first_exist == RT_FALSE)
143 {
144 mod->begin = exporter;
145 first_exist = RT_TRUE;
146 }
147 mod->end = exporter;
148 }
149 exporter++;
150 }
151
152 if (first_exist == RT_FALSE)
153 {
154 return -RT_ERROR;
155 }
156
157 return RT_EOK;
158 }
159
160 /* initialize iterator */
ve_iter_init(ve_module_t * mod,ve_iterator_t * iter)161 void ve_iter_init(ve_module_t *mod, ve_iterator_t *iter)
162 {
163 if (iter)
164 {
165 iter->exp_index = mod->begin;
166 iter->exp_end = mod->end;
167 }
168 }
169
170 /* iterate backward */
ve_iter_next(ve_iterator_t * iter)171 const ve_exporter_t *ve_iter_next(ve_iterator_t *iter)
172 {
173 if (iter->exp_index <= iter->exp_end)
174 {
175 return iter->exp_index++;
176 }
177 else
178 {
179 return RT_NULL;
180 }
181 }
182
183 /* binary search based on identifier */
ve_binary_search(ve_module_t * mod,const char * identifier)184 const ve_exporter_t *ve_binary_search(ve_module_t *mod, const char *identifier)
185 {
186 int ve_low_num = 0;
187 int ve_high_num = mod->end - mod->begin;
188 int ve_mid_num = 0;
189 int strcmp_rst = 0;
190
191 while ((ve_low_num <= ve_high_num) && (ve_high_num >= 0) && (ve_low_num >= 0))
192 {
193 ve_mid_num = (ve_high_num + ve_low_num) / 2;
194 strcmp_rst = rt_strcmp(mod->begin[ve_mid_num].identifier, identifier);
195
196 if (strcmp_rst == 0)
197 {
198 return &mod->begin[ve_mid_num];
199 }
200 else if (strcmp_rst > 0)
201 {
202 ve_high_num = ve_mid_num - 1;
203 }
204 else
205 {
206 ve_low_num = ve_mid_num + 1;
207 }
208 }
209
210 return RT_NULL;
211 }
212
213 /* get the value by identifier */
ve_value_get(ve_module_t * mod,const char * identifier)214 rt_base_t ve_value_get(ve_module_t *mod, const char *identifier)
215 {
216 const ve_exporter_t *exporter = ve_binary_search(mod, identifier);
217
218 if (exporter)
219 {
220 return exporter->value;
221 }
222 else
223 {
224 return VE_NOT_FOUND;
225 }
226 }
227
228 /* check if this value exists in the module*/
ve_value_exist(ve_module_t * mod,const char * identifier)229 rt_bool_t ve_value_exist(ve_module_t *mod, const char *identifier)
230 {
231 if (ve_binary_search(mod, identifier))
232 {
233 return RT_TRUE;
234 }
235 else
236 {
237 return RT_FALSE;
238 }
239 }
240
ve_value_count(ve_module_t * mod)241 rt_size_t ve_value_count(ve_module_t *mod)
242 {
243 return mod->end - mod->begin + 1;
244 }
245