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