summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorguo <[email protected]>2021-10-11 11:02:14 +0800
committerGitHub <[email protected]>2021-10-11 11:02:14 +0800
commit39197b438d732ac9f3e31f05960925fe43870567 (patch)
treed9a9e8c4d6e3287e019afe1dec9eba62b257485a
parent2d9ecd8437010e88464df3ba9d6cd4ff02a280ca (diff)
parentf7657a94b5643948689b06679d172d994cf653bf (diff)
Merge pull request #4885 from willianchanlovegithub/WillianChan
[add][components][utilities]Add the Var Export component
-rw-r--r--bsp/qemu-vexpress-a9/link.lds5
-rw-r--r--components/utilities/Kconfig4
-rw-r--r--components/utilities/var_export/SConscript8
-rw-r--r--components/utilities/var_export/var_export.c211
-rw-r--r--components/utilities/var_export/var_export.h94
-rw-r--r--components/utilities/var_export/var_export_cmd.c166
-rw-r--r--examples/var_export/var_export_example.c65
7 files changed, 553 insertions, 0 deletions
diff --git a/bsp/qemu-vexpress-a9/link.lds b/bsp/qemu-vexpress-a9/link.lds
index 797cd7e3ef..8e4f65b454 100644
--- a/bsp/qemu-vexpress-a9/link.lds
+++ b/bsp/qemu-vexpress-a9/link.lds
@@ -26,7 +26,12 @@ SECTIONS
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
+
+ /* section information for var export */
. = ALIGN(4);
+ __ve_table_start = .;
+ KEEP(*(SORT(*.VarExpTab.*)))
+ __ve_table_end = .;
/* section information for modules */
. = ALIGN(4);
diff --git a/components/utilities/Kconfig b/components/utilities/Kconfig
index 71869bee81..d5d878e86f 100644
--- a/components/utilities/Kconfig
+++ b/components/utilities/Kconfig
@@ -205,6 +205,10 @@ config RT_USING_UTEST
default 20
endif
+config RT_USING_VAR_EXPORT
+ bool "Enable Var Export"
+ default n
+
source "$RTT_DIR/components/utilities/rt-link/Kconfig"
endmenu
diff --git a/components/utilities/var_export/SConscript b/components/utilities/var_export/SConscript
new file mode 100644
index 0000000000..b901afaf74
--- /dev/null
+++ b/components/utilities/var_export/SConscript
@@ -0,0 +1,8 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+CPPPATH = [cwd]
+group = DefineGroup('var_export', src, depend = ['RT_USING_VAR_EXPORT'], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/utilities/var_export/var_export.c b/components/utilities/var_export/var_export.c
new file mode 100644
index 0000000000..f4623dec04
--- /dev/null
+++ b/components/utilities/var_export/var_export.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-06-04 WillianChan first version
+ * 2021-06-08 WillianChan support to MS VC++ compiler
+ */
+
+#include <var_export.h>
+
+static const ve_exporter_t *ve_exporter_table = RT_NULL;
+static rt_size_t ve_exporter_num = 0;
+
+/* for IAR compiler */
+#if defined(__ICCARM__) || defined(__ICCRX__)
+#pragma section="VarExpTab"
+#endif
+
+/* for ARM C and IAR Compiler */
+#if defined(__CC_ARM) || defined(__CLANG_ARM) || defined (__ICCARM__) || defined(__ICCRX__)
+static RT_USED const struct ve_exporter __ve_table_start
+RT_SECTION("0.""VarExpTab") = {"ve_start", "ve_start", 0};
+
+static RT_USED const struct ve_exporter __ve_table_end
+RT_SECTION("2.""VarExpTab") = {"ve_end", "ve_end", 2};
+#endif
+
+/* for MS VC++ compiler */
+#if defined(_MSC_VER)
+#pragma section("VarExpTab$a", read)
+__declspec(allocate("VarExpTab$a"))
+RT_USED const struct ve_exporter __ve_table_start = { "ve_start", "ve_start", 0};
+
+#pragma section("VarExpTab$z", read)
+__declspec(allocate("VarExpTab$z"))
+RT_USED const struct ve_exporter __ve_table_end = { "ve_end", "ve_end", 2};
+#endif
+
+/* initialize var export */
+int var_export_init(void)
+{
+ /* initialize the var export table.*/
+#if defined(__CC_ARM) || defined(__CLANG_ARM) /* for ARM C Compiler */
+ ve_exporter_table = &__ve_table_start + 1;
+ ve_exporter_num = &__ve_table_end - &__ve_table_start;
+#elif defined (__GNUC__) /* for GCC Compiler */
+ extern const int __ve_table_start;
+ extern const int __ve_table_end;
+ ve_exporter_table = (const ve_exporter_t *)&__ve_table_start;
+ ve_exporter_num = (const ve_exporter_t *)&__ve_table_end - ve_exporter_table;
+#elif defined (__ICCARM__) || defined(__ICCRX__) /* for IAR Compiler */
+ ve_exporter_table = &__ve_table_start + 1;
+ ve_exporter_num = &__ve_table_end - &__ve_table_start - 1;
+#elif defined (_MSC_VER) /* for MS VC++ compiler */
+ unsigned int *ptr_begin = (unsigned int *)&__ve_table_start;
+ unsigned int *ptr_end = (unsigned int *)&__ve_table_end;
+ static ve_exporter_t ve_exporter_tab[2048];
+ ve_exporter_t ve_exporter_temp;
+ int index_i, index_j, index_min;
+
+ /* past the three members in first ptr_begin */
+ ptr_begin += (sizeof(struct ve_exporter) / sizeof(unsigned int));
+ while (*ptr_begin == 0) ptr_begin++;
+ do ptr_end--; while (*ptr_end == 0);
+
+ ve_exporter_table = (const ve_exporter_t *)ptr_begin;
+ ve_exporter_num = (ptr_end - ptr_begin) / (sizeof(struct ve_exporter) / sizeof(unsigned int)) + 1;
+
+ /* check if the ve_exporter_num is out of bounds */
+ RT_ASSERT(ve_exporter_num < (sizeof(ve_exporter_tab) / sizeof(ve_exporter_t)));
+
+ for (index_i = 0; index_i < ve_exporter_num; index_i++)
+ {
+ ve_exporter_tab[index_i] = ve_exporter_table[index_i];
+ }
+
+ for (index_i = 0; index_i < (ve_exporter_num - 1); index_i++)
+ {
+ index_min = index_i;
+
+ for (index_j = index_i + 1; index_j < ve_exporter_num; index_j++)
+ {
+ if (rt_strcmp(ve_exporter_tab[index_j].module, ve_exporter_tab[index_min].module) < 0 &&
+ rt_strcmp(ve_exporter_tab[index_j].identifier, ve_exporter_tab[index_min].identifier) < 0)
+ {
+ index_min = index_j;
+ ve_exporter_temp = ve_exporter_tab[index_min];
+ ve_exporter_tab[index_min] = ve_exporter_tab[index_i];
+ ve_exporter_tab[index_i] = ve_exporter_temp;
+ }
+ }
+ }
+ ve_exporter_table = ve_exporter_tab;
+#endif /* __CC_ARM || __CLANG_ARM */
+
+ return ve_exporter_num;
+}
+INIT_PREV_EXPORT(var_export_init);
+
+/* initialize module */
+int ve_module_init(ve_module_t *mod, const char *module)
+{
+ const ve_exporter_t *exporter = ve_exporter_table;
+ rt_bool_t first_exist = RT_FALSE;
+ rt_size_t found_index;
+
+ for (found_index = 0; found_index < ve_exporter_num; found_index++)
+ {
+ if (!rt_strcmp(exporter->module, module))
+ {
+ if (first_exist == RT_FALSE)
+ {
+ mod->begin = exporter;
+ first_exist = RT_TRUE;
+ }
+ mod->end = exporter;
+ }
+ exporter++;
+ }
+
+ if (first_exist == RT_FALSE)
+ {
+ return -RT_ERROR;
+ }
+
+ return RT_EOK;
+}
+
+/* initialize iterator */
+void ve_iter_init(ve_module_t *mod, ve_iterator_t *iter)
+{
+ if (iter)
+ {
+ iter->exp_index = mod->begin;
+ iter->exp_end = mod->end;
+ }
+}
+
+/* iterate backward */
+const ve_exporter_t *ve_iter_next(ve_iterator_t *iter)
+{
+ if (iter->exp_index <= iter->exp_end)
+ {
+ return iter->exp_index++;
+ }
+ else
+ {
+ return RT_NULL;
+ }
+}
+
+/* binary search based on identifier */
+static const ve_exporter_t *ve_binary_search(ve_module_t *mod, const char *identifier)
+{
+ rt_size_t ve_low_num = mod->begin - ve_exporter_table;
+ rt_size_t ve_high_num = mod->end - ve_exporter_table;
+ rt_size_t ve_mid_num;
+ int strcmp_rst;
+
+ while (ve_low_num <= ve_high_num)
+ {
+ ve_mid_num = (ve_high_num - ve_low_num) / 2;
+ strcmp_rst = rt_strcmp(mod->begin[ve_mid_num].identifier, identifier);
+
+ if (strcmp_rst == 0)
+ {
+ return &mod->begin[ve_mid_num];
+ }
+ else if (strcmp_rst > 0)
+ {
+ ve_high_num = ve_mid_num + 1;
+ }
+ else
+ {
+ ve_low_num = ve_mid_num - 1;
+ }
+ }
+
+ return RT_NULL;
+}
+
+/* get the value by identifier */
+rt_base_t ve_value_get(ve_module_t *mod, const char *identifier)
+{
+ const ve_exporter_t *exporter = ve_binary_search(mod, identifier);
+
+ if (exporter)
+ {
+ return exporter->value;
+ }
+ else
+ {
+ return VE_NOT_FOUND;
+ }
+}
+
+/* check if this value exists in the module*/
+rt_bool_t ve_value_exist(ve_module_t *mod, const char *identifier)
+{
+ if (ve_binary_search(mod, identifier))
+ {
+ return RT_TRUE;
+ }
+ else
+ {
+ return RT_FALSE;
+ }
+}
diff --git a/components/utilities/var_export/var_export.h b/components/utilities/var_export/var_export.h
new file mode 100644
index 0000000000..4bab33e957
--- /dev/null
+++ b/components/utilities/var_export/var_export.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-06-04 WillianChan first version
+ * 2021-06-08 WillianChan support to MS VC++ compiler
+ */
+
+#ifndef _VAR_EXPORT_H__
+#define _VAR_EXPORT_H__
+
+#include <rtthread.h>
+
+/* exported object */
+struct ve_exporter
+{
+ const char *module; /* module name */
+ const char *identifier; /* module identifier */
+ rt_base_t value; /* module value */
+};
+typedef struct ve_exporter ve_exporter_t;
+
+/* module object */
+struct ve_module
+{
+ const ve_exporter_t *begin; /* the first module of the same name */
+ const ve_exporter_t *end; /* the last module of the same */
+};
+typedef struct ve_module ve_module_t;
+
+/* iterator object */
+struct ve_iterator
+{
+ const ve_exporter_t *exp_index; /* iterator index */
+ const ve_exporter_t *exp_end; /* iterate over exporter */
+};
+typedef struct ve_iterator ve_iterator_t;
+
+#define VE_NOT_FOUND (0xFFFFFFFFu) /* not found */
+
+/* exporter's export command */
+#if defined(__GNUC__)
+#define VAR_EXPORT(module, identi, value) \
+ const char _vexp_##identi##_module[] RT_SECTION(".rodata.vexp") = #module; \
+ const char _vexp_##identi##_identi[] RT_SECTION(".rodata.vexp") = #identi; \
+ RT_USED const struct ve_exporter _vexp_##module##identi \
+ RT_SECTION(#module".VarExpTab."#identi) = \
+ { \
+ _vexp_##identi##_module, \
+ _vexp_##identi##_identi, \
+ value, \
+ }
+#elif defined(_MSC_VER)
+#pragma section("VarExpTab$f",read)
+#define VAR_EXPORT(module, identi, value) \
+ const char _vexp_##identi##_module[] RT_SECTION(".rodata.vexp") = #module; \
+ const char _vexp_##identi##_identi[] RT_SECTION(".rodata.vexp") = #identi; \
+ __declspec(allocate("VarExpTab$f")) \
+ RT_USED const struct ve_exporter _vexp_##module##identi = \
+ { \
+ _vexp_##identi##_module, \
+ _vexp_##identi##_identi, \
+ value, \
+ }
+#else
+#define VAR_EXPORT(module, identi, value) \
+ const char _vexp_##identi##_module[] RT_SECTION(".rodata.vexp") = #module; \
+ const char _vexp_##identi##_identi[] RT_SECTION(".rodata.vexp") = #identi; \
+ RT_USED const struct ve_exporter _vexp_##module##identi \
+ RT_SECTION("1."#module".VarExpTab."#identi) = \
+ { \
+ _vexp_##identi##_module, \
+ _vexp_##identi##_identi, \
+ value, \
+ }
+#endif
+
+/* initialize var export */
+int ve_exporter_init(void);
+/* initialize module */
+int ve_module_init(ve_module_t *mod, const char *module);
+/* initialize iterator */
+void ve_iter_init(ve_module_t *mod, ve_iterator_t *iter);
+/* iterate backward */
+const ve_exporter_t *ve_iter_next(ve_iterator_t *iter);
+/* get the value by identifier */
+rt_base_t ve_value_get(ve_module_t *mod, const char *identifier);
+/* check if this value exists in the module*/
+rt_bool_t ve_value_exist(ve_module_t *mod, const char *identifier);
+
+#endif /* _VAR_EXPORT_H__ */
diff --git a/components/utilities/var_export/var_export_cmd.c b/components/utilities/var_export/var_export_cmd.c
new file mode 100644
index 0000000000..fba3cc92bb
--- /dev/null
+++ b/components/utilities/var_export/var_export_cmd.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-06-05 WillianChan first version
+ */
+
+#include <var_export.h>
+
+static int ve_cmd_help(int argc, char **argv);
+static int ve_find_module(int argc, char **argv);
+static int ve_find_value(int argc, char **argv);
+
+
+struct ve_cmd_des
+{
+ const char *cmd;
+ int (*fun)(int argc, char **argv);
+};
+
+/* dcm cmd table */
+static const struct ve_cmd_des cmd_tab[] =
+{
+ {"module", ve_find_module},
+ {"value", ve_find_value},
+};
+
+static int ve_cmd_help(int argc, char **argv)
+{
+ rt_kprintf("Usage:\n");
+ rt_kprintf("ve_find module <module> - Find by module name\n");
+ rt_kprintf("ve_find value <module> <identifier> - Find accurately\n");
+
+ return RT_EOK;
+}
+
+rt_inline void ve_object_split(int len)
+{
+ while (len--) rt_kprintf("-");
+}
+
+static int ve_find_module(int argc, char **argv)
+{
+ ve_iterator_t iter;
+ const ve_exporter_t *exporter;
+ ve_module_t module;
+ int maxlen = (RT_NAME_MAX * 2);
+ const char *item_title = "ve_module";
+
+ rt_kprintf("%-*.s identifier value\n", maxlen, item_title); ve_object_split(maxlen);
+ rt_kprintf(" ---------------- -----\n");
+
+ if (!ve_module_init(&module, argv[2]))
+ {
+ ve_iter_init(&module, &iter);
+ }
+ else
+ {
+ return -RT_ERROR;
+ }
+
+ while (1)
+ {
+ exporter = ve_iter_next(&iter);
+ if (exporter == RT_NULL)
+ {
+ return -RT_ERROR;
+ }
+ else
+ {
+ rt_kprintf("%-*.s %-*.s %d\n",
+ maxlen, exporter->module,
+ maxlen, exporter->identifier,
+ exporter->value);
+ }
+ }
+}
+
+static int ve_find_value(int argc, char **argv)
+{
+ ve_iterator_t iter;
+ const ve_exporter_t *exporter;
+ ve_module_t module;
+ int maxlen = (RT_NAME_MAX * 2);
+ const char *item_title = "ve_module";
+
+ rt_kprintf("%-*.s identifier value\n", maxlen, item_title); ve_object_split(maxlen);
+ rt_kprintf(" ---------------- -----\n");
+
+ if (!ve_module_init(&module, argv[2]))
+ {
+ ve_iter_init(&module, &iter);
+ }
+ else
+ {
+ return -RT_ERROR;
+ }
+
+ while (1)
+ {
+ exporter = ve_iter_next(&iter);
+ if (exporter == RT_NULL)
+ {
+ return -RT_ERROR;
+ }
+ else
+ {
+ if (!rt_strcmp(exporter->identifier, argv[3]))
+ {
+ rt_kprintf("%-*.s %-*.s %d\n",
+ maxlen, exporter->module,
+ maxlen, exporter->identifier,
+ exporter->value);
+
+ return RT_EOK;
+ }
+ }
+ }
+}
+
+static int ve_find(int argc, char **argv)
+{
+ int i, resule = RT_EOK;
+ const struct ve_cmd_des *run_cmd = RT_NULL;
+
+ if (argc == 1)
+ {
+ ve_cmd_help(argc, argv);
+ return RT_EOK;
+ }
+
+ /* find command function */
+ for (i = 0; i < sizeof(cmd_tab) / sizeof(cmd_tab[0]); i++)
+ {
+ if (rt_strcmp(cmd_tab[i].cmd, argv[1]) == 0)
+ {
+ run_cmd = &cmd_tab[i];
+ break;
+ }
+ }
+
+ /* not find command function, print help information */
+ if (run_cmd == RT_NULL)
+ {
+ rt_kprintf("There is no command option named %s.\n", argv[1]);
+ ve_cmd_help(argc, argv);
+ return RT_EOK;
+ }
+
+ /* run command function */
+ if (run_cmd->fun != RT_NULL)
+ {
+ resule = run_cmd->fun(argc, argv);
+ }
+
+ if (resule)
+ {
+ ve_cmd_help(argc, argv);
+ }
+
+ return RT_EOK;
+}
+MSH_CMD_EXPORT(ve_find, find the specified export variable);
diff --git a/examples/var_export/var_export_example.c b/examples/var_export/var_export_example.c
new file mode 100644
index 0000000000..9ea45de1c3
--- /dev/null
+++ b/examples/var_export/var_export_example.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-09-02 WillianChan add var_export example code
+ */
+
+#include <var_export.h>
+
+/* use VAR_EXPOR() to export 10 pieces of data into sections */
+VAR_EXPORT(module0, identi0, 0);
+VAR_EXPORT(module1, identi1, 1);
+VAR_EXPORT(module2, identi2, 2);
+VAR_EXPORT(module3, identi3, 3);
+VAR_EXPORT(module4, identi4, 4);
+VAR_EXPORT(module5, identi5, 5);
+VAR_EXPORT(module6, identi6, 6);
+VAR_EXPORT(module7, identi7, 7);
+VAR_EXPORT(module8, identi8, 8);
+VAR_EXPORT(module9, identi9, 9);
+
+void found_by_module(void)
+{
+ ve_iterator_t iter;
+ const ve_exporter_t* exporter;
+ ve_module_t module;
+ rt_base_t value;
+
+ /* query all exporters with the same name as module1 */
+ if (!ve_module_init(&module, "module1"))
+ /* initialize the iterator */
+ ve_iter_init(&module, &iter);
+ else
+ return;
+
+ while (1)
+ {
+ /* start iterating */
+ exporter = ve_iter_next(&iter);
+ if (exporter == RT_NULL)
+ break;
+ else
+ {
+ /* checks whether the value exists */
+ if (ve_value_exist(&module, "identi1") == RT_TRUE)
+ {
+ value = ve_value_get(&module, "identi1");
+ rt_kprintf("[ve_example] value = %dn", value);
+ return;
+ }
+ else
+ {
+ rt_kprintf("[ve_example] value not exist.\n");
+ return;
+ }
+ }
+ }
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+MSH_CMD_EXPORT(found_by_module, found by module);
+#endif /* RT_USING_FINSH */ \ No newline at end of file