参考代码
This commit is contained in:
400
components/system/include/sys_init.h
Executable file
400
components/system/include/sys_init.h
Executable file
@@ -0,0 +1,400 @@
|
||||
/**
|
||||
* @file sys_init.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-06-01
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SYS_INIT_H__
|
||||
#define __SYS_INIT_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
/* initialize function -------------------------------------------------------- */
|
||||
|
||||
#define INIT_EXPORT_BOARD(FN) _INIT_EXPORT(FN, 0, 1) // 定义自动初始化函数:非常早期的初始化,此时调度器还未启动
|
||||
#define INIT_EXPORT_PREV(FN) _INIT_EXPORT(FN, 1, 1) // 定义自动初始化函数:主要是用于纯软件的初始化、没有太多依赖的函数
|
||||
#define INIT_EXPORT_DEVICE(FN) _INIT_EXPORT(FN, 2, 1) // 定义自动初始化函数:外设驱动初始化相关,比如网卡设备
|
||||
#define INIT_EXPORT_COMPONENT(FN) _INIT_EXPORT(FN, 3, 1) // 定义自动初始化函数:组件初始化,比如文件系统或者 LWIP
|
||||
#define INIT_EXPORT_ENV(FN) _INIT_EXPORT(FN, 4, 1) // 定义自动初始化函数:系统环境初始化,比如挂载文件系统
|
||||
#define INIT_EXPORT_APP(FN, PRIOR) _INIT_EXPORT(FN, 5, PRIOR) // 定义自动初始化函数:应用初始化,比如 GUI 应用(PRIOR 建议取值为 0 或 10..99)
|
||||
|
||||
/* module define -------------------------------------------------------------- */
|
||||
|
||||
#define OBJ_EXPORT_DEVICE(OBJECT, NAME) _MODULE_EXPORT(OBJECT, NAME, MODULE_TYPE_DEVICE)
|
||||
#define OBJ_EXPORT_COMPONENT(OBJECT, NAME) _MODULE_EXPORT(OBJECT, NAME, MODULE_TYPE_COMPONENT)
|
||||
|
||||
/* module api------------------------------------------------------------------ */
|
||||
|
||||
__static_inline const void *device_binding(const char *name);
|
||||
__static_inline const char *device_name(const void *object);
|
||||
__static_inline const char *device_search(const char *prefix_name, unsigned int num);
|
||||
|
||||
__static_inline const void *component_binding(const char *name);
|
||||
__static_inline const char *component_name(const void *object);
|
||||
__static_inline const char *component_search(const char *prefix_name, unsigned int num);
|
||||
|
||||
/* code ----------------------------------------------------------------------- */
|
||||
|
||||
/** @defgroup initialize function
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int (*fn)(void); // 初始化函数地址
|
||||
const char *fn_name; // debug: 函数关联名
|
||||
const char *file; // debug: 所在文件名
|
||||
uint16_t line; // debug: 所在文件行
|
||||
uint8_t level; // debug: 初始化等级
|
||||
uint8_t prior; // debug: 初始化优先级
|
||||
} sys_init_t;
|
||||
|
||||
/**
|
||||
* @def _INIT_EXPORT
|
||||
*
|
||||
* @brief 用于如下宏:
|
||||
* INIT_EXPORT_BOARD
|
||||
* INIT_EXPORT_PREV
|
||||
* INIT_EXPORT_DEVICE
|
||||
* INIT_EXPORT_COMPONENT
|
||||
* INIT_EXPORT_ENV
|
||||
* INIT_EXPORT_APP
|
||||
* 输出一个 sys_init_t 类型的数据。
|
||||
* 这些数据将被归为 "(.s_sys_init_t.*)" 段中,编译阶段被排序并链接。
|
||||
* 需要将文件 "sys_init.ld" 添加到链接脚本。
|
||||
* 用于自动初始化。
|
||||
*
|
||||
* @param FN 待函数
|
||||
*
|
||||
* @param LEVEL 按功能划分的优先级
|
||||
*
|
||||
* @param PRIOR 同一功能等级中的优先级,0..99,数值越小越优早执行
|
||||
*
|
||||
* 举例:
|
||||
* @verbatim
|
||||
* static int _init_env_template(void)
|
||||
* {
|
||||
* SYS_LOG_INF("done.\r\n");
|
||||
* return 0;
|
||||
* }
|
||||
* INIT_EXPORT_ENV(_init_env_template);
|
||||
*
|
||||
* static int _init_app_template1(void)
|
||||
* {
|
||||
* SYS_LOG_INF("done.\r\n");
|
||||
* return 0;
|
||||
* }
|
||||
* static int _init_app_template2(void)
|
||||
* {
|
||||
* SYS_LOG_INF("done.\r\n");
|
||||
* return 0;
|
||||
* }
|
||||
* INIT_EXPORT_APP(_init_app_template1, 0);
|
||||
* INIT_EXPORT_APP(_init_app_template2, 1);
|
||||
* @endverbatim
|
||||
*/
|
||||
#define _INIT_EXPORT(FN, LEVEL, PRIOR) \
|
||||
__used __section(".s_sys_init_t." #LEVEL "." #PRIOR) static sys_init_t const \
|
||||
__sys_init_##FN = { \
|
||||
.fn = FN, \
|
||||
.fn_name = #FN, \
|
||||
.line = __LINE__, \
|
||||
.file = __FILE__, \
|
||||
.level = LEVEL, \
|
||||
.prior = PRIOR, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup initialize module
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef enum __packed // 定义模块的类型
|
||||
{
|
||||
MODULE_TYPE_DEVICE, // 模块类型为驱动
|
||||
MODULE_TYPE_COMPONENT, // 模块类型为组件
|
||||
// ...
|
||||
} module_type_t;
|
||||
|
||||
typedef struct // 模块数据结构
|
||||
{
|
||||
const char *name; // 模块数据关联名
|
||||
const void *obj; // 模块数据地址
|
||||
module_type_t type; // 模块数据类型
|
||||
uint16_t line; // debug: 所在文件行
|
||||
const char *file; // debug: 所在文件名
|
||||
} module_t;
|
||||
|
||||
/**
|
||||
* @def _MODULE_EXPORT
|
||||
*
|
||||
* @brief 输出一个指定模块数据结构。用于如下宏:
|
||||
* OBJ_EXPORT_DEVICE
|
||||
* OBJ_EXPORT_COMPONENT
|
||||
* 这些数据结构将被归为 ".sys_module_data" 段中,编译阶段被链接。
|
||||
* 需要将文件 "sys_init.ld" 添加到链接脚本。
|
||||
* 使用 sys_module_binding() 可找到模块数据结构。
|
||||
*
|
||||
* @param OBJECT 子对象(符号)
|
||||
*
|
||||
* @param OBJ_NAME 子对象关联名称(字符串)。使用 sys_module_search() 可遍历已有对象关联名称
|
||||
*
|
||||
* @param MODULE_TYPE 模块类型 @ref module_type_t
|
||||
*
|
||||
* 举例:
|
||||
* @verbatim
|
||||
* #include "device_template.h"
|
||||
*
|
||||
* static void _set_data(device_template_t dev, int data);
|
||||
* static int _get_data(device_template_t dev);
|
||||
*
|
||||
* static device_template_config_t config;
|
||||
*
|
||||
* static struct device_template const device = {
|
||||
* .api = {
|
||||
* .set_data = _set_data,
|
||||
* .get_data = _get_data,
|
||||
* },
|
||||
* .config = &config,
|
||||
* };
|
||||
* OBJ_EXPORT_DEVICE(device, "DRV1");
|
||||
*
|
||||
* static void _set_data(device_template_t dev, int data)
|
||||
* {
|
||||
* dev->config->data = data;
|
||||
* }
|
||||
*
|
||||
* static int _get_data(device_template_t dev)
|
||||
* {
|
||||
* return dev->config->data;
|
||||
* }
|
||||
* @endverbatim
|
||||
*
|
||||
*/
|
||||
#define _MODULE_EXPORT(OBJECT, OBJ_NAME, MODULE_TYPE) \
|
||||
__used __section(".sys_module_data.1") static module_t const \
|
||||
__sys_module_##OBJECT = { \
|
||||
.name = OBJ_NAME, \
|
||||
.obj = &OBJECT, \
|
||||
.type = MODULE_TYPE, \
|
||||
.line = __LINE__, \
|
||||
.file = __FILE__, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结合类型和名称,精确匹配查找个由 _MODULE_EXPORT 输出的模块对象。
|
||||
*
|
||||
* @param type 由 _MODULE_EXPORT 输出的模块类型
|
||||
* @param name 由 _MODULE_EXPORT 输出的模块名
|
||||
* @return module_t * 由 _MODULE_EXPORT 输出的模块对象
|
||||
*/
|
||||
__static_inline const module_t *sys_module_binding(module_type_t type, const char *name)
|
||||
{
|
||||
if (name)
|
||||
{
|
||||
extern const module_t __sys_module_leader_0;
|
||||
extern const module_t __sys_module_leader_9;
|
||||
const module_t *module = &__sys_module_leader_0;
|
||||
const module_t *end = &__sys_module_leader_9;
|
||||
while (module < end)
|
||||
{
|
||||
if (module->type == type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
if (name[i] != module->name[i])
|
||||
break;
|
||||
if (name[i] == '\0')
|
||||
return module;
|
||||
}
|
||||
}
|
||||
module = &module[1];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结合类型和名称,查找个由 _MODULE_EXPORT 输出的模块对象名。
|
||||
*
|
||||
* @param type 由 _MODULE_EXPORT 输出的模块类型
|
||||
* @param prefix_name 由 _MODULE_EXPORT 输出的模块名的前缀。例如: prefix_name 为 "UART" ,可能查找到 "UART1", "UART2"...
|
||||
* @param num 匹配到 prefix_name 的第几次时返回,范围 0..n
|
||||
* @return const char * 匹配到的第 num 个名称为 prefix_name.* 的完整对象名,这个对象名可用于 sys_module_binding() 的参数。
|
||||
* @return NULL 表示没对象
|
||||
*/
|
||||
__static_inline const char *sys_module_search(module_type_t type, const char *prefix_name, unsigned int num)
|
||||
{
|
||||
if (prefix_name)
|
||||
{
|
||||
extern const module_t __sys_module_leader_0;
|
||||
extern const module_t __sys_module_leader_9;
|
||||
const module_t *module = &__sys_module_leader_0;
|
||||
const module_t *end = &__sys_module_leader_9;
|
||||
unsigned int match = 0;
|
||||
while (module < end)
|
||||
{
|
||||
if (module->type == type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
if (prefix_name[i] == '\0')
|
||||
{
|
||||
if (match < num)
|
||||
{
|
||||
match++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
return module->name;
|
||||
}
|
||||
}
|
||||
if (prefix_name[i] != module->name[i])
|
||||
break;
|
||||
}
|
||||
}
|
||||
module = &module[1];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取已绑定的对象的关联名
|
||||
*
|
||||
* @param object 由 sys_module_binding() 取得的对象
|
||||
* @return const char * 对象的关联名
|
||||
*/
|
||||
__static_inline const char *sys_module_name(const void *object)
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
extern const module_t __sys_module_leader_0;
|
||||
extern const module_t __sys_module_leader_9;
|
||||
const module_t *module = &__sys_module_leader_0;
|
||||
const module_t *end = &__sys_module_leader_9;
|
||||
while (module < end)
|
||||
{
|
||||
if (module->obj == object)
|
||||
{
|
||||
return module->name;
|
||||
}
|
||||
module = &module[1];
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup module
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 绑定一个由 OBJ_EXPORT_DEVICE 输出的设备对象
|
||||
*
|
||||
* @param name 由 OBJ_EXPORT_DEVICE 输出的设备名
|
||||
* @return const void * 由 OBJ_EXPORT_DEVICE 输出的设备对象
|
||||
*/
|
||||
__static_inline const void *device_binding(const char *name)
|
||||
{
|
||||
const module_t *module = sys_module_binding(MODULE_TYPE_DEVICE, name);
|
||||
if (module)
|
||||
return module->obj;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取已绑定的对象的关联名
|
||||
*
|
||||
* @param object 由 device_binding() 取得的对象
|
||||
* @return const char * 对象的关联名
|
||||
*/
|
||||
__static_inline const char *device_name(const void *object)
|
||||
{
|
||||
return sys_module_name(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找 device_binding() 可用的模块对象名。
|
||||
*
|
||||
* @param prefix_name 由 _MODULE_EXPORT 输出的模块名的前缀。例如: prefix_name 为 "UART" ,可能查找到 "UART1", "UART2"...
|
||||
* @param num 匹配到 prefix_name 的第几次时返回,范围 0..n
|
||||
* @return const char * 匹配到的第 num 个名称为 prefix_name.* 的完整对象名
|
||||
* @return NULL 表示没对象
|
||||
*/
|
||||
__static_inline const char *device_search(const char *prefix_name, unsigned int num)
|
||||
{
|
||||
return sys_module_search(MODULE_TYPE_DEVICE, prefix_name, num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绑定一个由 OBJ_EXPORT_COMPONENT 输出的设备对象
|
||||
*
|
||||
* @param name 由 OBJ_EXPORT_COMPONENT 输出的设备名
|
||||
* @return const void * 由 OBJ_EXPORT_COMPONENT 输出的设备对象
|
||||
*/
|
||||
__static_inline const void *component_binding(const char *name)
|
||||
{
|
||||
const module_t *module = sys_module_binding(MODULE_TYPE_COMPONENT, name);
|
||||
if (module)
|
||||
return module->obj;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取已绑定的对象的关联名
|
||||
*
|
||||
* @param object 由 component_binding() 取得的对象
|
||||
* @return const char * 对象的关联名
|
||||
*/
|
||||
__static_inline const char *component_name(const void *object)
|
||||
{
|
||||
return sys_module_name(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找 component_binding() 可用的模块对象名。
|
||||
*
|
||||
* @param prefix_name 由 _MODULE_EXPORT 输出的模块名的前缀。例如: prefix_name 为 "UART" ,可能查找到 "UART1", "UART2"...
|
||||
* @param num 匹配到 prefix_name 的第几次时返回,范围 0..n
|
||||
* @return const char * 匹配到的第 num 个名称为 prefix_name.* 的完整对象名
|
||||
* @return NULL 表示没对象
|
||||
*/
|
||||
__static_inline const char *component_search(const char *prefix_name, unsigned int num)
|
||||
{
|
||||
return sys_module_search(MODULE_TYPE_COMPONENT, prefix_name, num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user