2.7 编译时配置与初始化
本节讲述Mynewt如何管理系统配置和初始化。
Mynewt在pkg.yml和syscfg.yml文件中定义了一些配置参数。newt工具将使用这些参数:
- 生成一个系统初始化函数,该函数将调用所有特定包的系统初始化函数。
- 生成一个包含所有包配置设置和值的系统配置头文件。
- 在newt target config命令中显示的系统配置设置和值。
这种方式的好处有:
- 允许Mynewt开发者重用其他包,在实现新的包时,无需更新源文件或头文件即可轻松更改配置
- 允许应用开发者轻松查看系统配置设置和值,并确定要覆盖的目标构建的值。
系统配置设置定义与值
一个包可以选择:
- 定义并公开系统配置设置,以允许其他包能够覆盖默认的设置值。
- 覆盖所依赖包所定义的系统配置设置的值。
使用syscfg.yml文件中的defs来定义一个包的系统配置设置。defs完成系统配置设置定义的映射。
syscfg.defs:
PKGA_SYSCFG_NAME1:
description:
value:
type:
restrictions:
PKGA_SYSCFG_NAME2:
description:
value:
type:
restrictions:
每个设置的定义包含以下的键值对:
- 设置的键名,如PKGA_SYSCFG_NAME1,需要注意设置的名称需要唯一的。当多个包中出现相同的设置时,newt工具将中止。
- 值字段的映射。每个字段本身都是一个键值对属性。字段键包括:description(描述),value(值),type(类型),restriction(限制)。除value外,其余字段都是可选的。
覆盖系统配置设置的值
一个包可以在syscfg.yml文件中使用vals参数来覆盖定义在其他包中的配置值。这个机制允许:
- Mynewt开发人员实现一个包,以及轻松覆盖所依赖的包中定义的系统配置设置的值。
- 应用程序开发者可以轻松、干净的覆盖默认的配置设置,并构建一个自定义的目标。可以使用newt target show命令检查系统中的配置设置定义和值,以确定要覆盖的值。
syscfg.vals:
PKGA_SYSCFG_NAME1: VALUE1
PKGA_SYSCFG_NAME2: VALUE2
...
PKGN_SYSCFG_NAME1: VALUEN
解决覆盖冲突
newt工具使用包优先级来确定一个包是否可以覆盖一个值,并解决多个包覆盖相同的系统配置时的冲突。适合以下规则:
- 一个包只能覆盖低优先级包定义的系统配置设置的默认值。
- 当具有不同优先级的包覆盖相同的系统配置设置值时,newt使用最高优先级包的值。
- 同等优先级的包不能用不同的值覆盖相同的系统配置设置值(有同等优先级的包,参数必须统一)。除非更高优先级的包也有覆盖,否则newt工具将中止构建。
以下为从最高优先级到最低优先级的包类型:
- 目标,Target
- 应用程序,App
- unittest,目标可以包含一个应用程序或单元测试包,或都不包含。
- Lib,包括所有其他系统级别的包,如os,lib,sdk和编译器。
建议在目标级别重写默认值,而不是更新单个包syscfg.yml文件。
生成syscfg.h和引用系统配置设置
newt工具处理所有包的syscfg.yml文件,生成bin/
- 添加前缀MYNEWTVAL
- 将设置中的”/“,”-“和空格都替换为”_”
- 将所有字符转换为大写
使用时需要使用MYNEWT_VAL()宏来引用系统生成的宏定义。如my-config-name设置名,使用MYNEWT_VAL(MY_CONFIG_NAME)来引用。
系统初始化
系统启动期间,Mynewt创建了一个默认事件队列和一个主任务,用于处理默认队列中的事件。可以覆盖定义在kernel/os包中OS_MAIN_TASK_PRIO和OS_MAIN_TASK_STACK_SIZE设置值,设置不同任务优先级和堆栈尺寸。
应用程序的main函数在主任务上下文中执行,必须执行以下操作:
- 在main函数的开始,在执行其他任何处理之前,必须调用Mynewt的sysinit()函数初始化包。
- 在main函数的末尾,在无线循环中等待并分派默认事件队列中的事件。
int main(int argc, char **argv)
{
/* First, call sysinit() to perform the system and package initialization */
sysinit();
/* ... other application initialization processing ... */
/* Last, process events from the default event queue. */
while (1) {
os_eventq_run(os_eventq_dflt_get());
}
/* main never returns */
}
指定包初始化函数
sysinit()函数调用sysinit_app()函数执行目标包的系统初始化。可以选择指定一个或多个包初始化函数,sysinit_app()调用这些函数来初始化包。
包初始化函数原型:
void init_func_name(void)
包初始化函数分阶段调用,以确保低优先级的包优先于高优先级的包进行初始化。阶段为一个整数,从0开始,指定何时调用包初始化函数。Mynewt按照递增stage的顺序调用包初始化函数。具有相同stage的初始化函数的调用顺序取决于处理包的顺序,不能依赖于特定调用顺序。
使用pkg.yml文件中的pkg.init参数来指定初始化函数及调用函数的阶段号。可以指定多个初始化函数,对每个函数指定不同的阶段号。该特性允许具有相互依赖关系的包在多个阶段执行初始化。
pkg.yml文件中pkg.init参数遵循以下的语法:
pkg.init:
pkg_init_func1_name: pkg_init_func1_stage
pkg_init_func2_name: pkg_init_func2_stage
...
pkg_init_funcN_name: pkg_init_funcN_stage
其中pkg_init_func#_name是初始化函数的C函数名,pkg_init_func#_stage为整数值,从0开始,表明初始化函数在第几个阶段调用。
生成sysinit_app()函数
newt工具处理一个目标的所有pkg.yml文件中的pkg.init参数,在
/**
* This file was generated by Apache Newt (incubating) version: 1.0.0-dev
*/
#if !SPLIT_LOADER
void split_app_init(void);
void os_pkg_init(void);
void imgmgr_module_init(void);
/* ... */
void stats_module_init(void);
void
sysinit_app(void)
{
/*** Stage 0 */
/* 0.0: kernel/os */
os_pkg_init();
/*** Stage 2 */
/* 2.0: sys/flash_map */
flash_map_init();
/*** Stage 10 */
/* 10.0: sys/stats/full */
stats_module_init();
/*** Stage 20 */
/* 20.0: sys/console/full */
console_pkg_init();
/*** Stage 100 */
/* 100.0: sys/log/full */
log_init();
/* 100.1: sys/mfg */
mfg_init();
/* ... */
/*** Stage 300 */
/* 300.0: sys/config */
config_pkg_init();
/*** Stage 500 */
/* 500.0: sys/id */
id_init();
/* 500.1: sys/shell */
shell_init();
/* ... */
/* 500.4: mgmt/imgmgr */
imgmgr_module_init();
/*** Stage 501 */
/* 501.0: mgmt/newtmgr/transport/nmgr_shell */
nmgr_shell_pkg_init();
}
#endif
条件配置
可以使用系统配置设置值来有条件的指定pkg.yml和syscfg.yml文件中的参数值。语法如下:
parameter_name.PKGA_SYSCFG_NAME:
parameter_value
只有当PKGA_SYSCFG_NAME非0时,parameter_name的设置为parameter_value。
pkg.deps:
- "@apache-mynewt-core/sys/sysinit"
- "@apache-mynewt-core/util/mem"
pkg.deps.OS_CLI
- "@apache-mynewt-core/sys/shell"
示例为libs/os包中的pkg.yml文件,当OS_CLI使能时,才会依赖sys/shell包。
一旦检测到循环条件依赖,newt工具将中止构建。
参考资料:
http://mynewt.apache.org/latest/os/modules/sysinitconfig/sysinitconfig.html