Files
ESPC3-wireless/components/system/include/sys_init.h
2024-03-28 12:19:52 +08:00

401 lines
13 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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