2.7 编译时配置与初始化

本节讲述Mynewt如何管理系统配置和初始化。

Mynewt在pkg.yml和syscfg.yml文件中定义了一些配置参数。newt工具将使用这些参数:

  • 生成一个系统初始化函数,该函数将调用所有特定包的系统初始化函数。
  • 生成一个包含所有包配置设置和值的系统配置头文件。
  • 在newt target config命令中显示的系统配置设置和值。

这种方式的好处有:

  • 允许Mynewt开发者重用其他包,在实现新的包时,无需更新源文件或头文件即可轻松更改配置
  • 允许应用开发者轻松查看系统配置设置和值,并确定要覆盖的目标构建的值。

系统配置设置定义与值

一个包可以选择:

  • 定义并公开系统配置设置,以允许其他包能够覆盖默认的设置值。
  • 覆盖所依赖包所定义的系统配置设置的值。

使用syscfg.yml文件中的defs来定义一个包的系统配置设置。defs完成系统配置设置定义的映射。

  1. syscfg.defs:
  2. PKGA_SYSCFG_NAME1:
  3. description:
  4. value:
  5. type:
  6. restrictions:
  7. PKGA_SYSCFG_NAME2:
  8. description:
  9. value:
  10. type:
  11. restrictions:

每个设置的定义包含以下的键值对:

  • 设置的键名,如PKGA_SYSCFG_NAME1,需要注意设置的名称需要唯一的。当多个包中出现相同的设置时,newt工具将中止。
  • 值字段的映射。每个字段本身都是一个键值对属性。字段键包括:description(描述),value(值),type(类型),restriction(限制)。除value外,其余字段都是可选的。

覆盖系统配置设置的值

一个包可以在syscfg.yml文件中使用vals参数来覆盖定义在其他包中的配置值。这个机制允许:

  • Mynewt开发人员实现一个包,以及轻松覆盖所依赖的包中定义的系统配置设置的值。
  • 应用程序开发者可以轻松、干净的覆盖默认的配置设置,并构建一个自定义的目标。可以使用newt target show命令检查系统中的配置设置定义和值,以确定要覆盖的值。
  1. syscfg.vals:
  2. PKGA_SYSCFG_NAME1: VALUE1
  3. PKGA_SYSCFG_NAME2: VALUE2
  4. ...
  5. PKGN_SYSCFG_NAME1: VALUEN

解决覆盖冲突

newt工具使用包优先级来确定一个包是否可以覆盖一个值,并解决多个包覆盖相同的系统配置时的冲突。适合以下规则:

  • 一个包只能覆盖低优先级包定义的系统配置设置的默认值。
  • 当具有不同优先级的包覆盖相同的系统配置设置值时,newt使用最高优先级包的值。
  • 同等优先级的包不能用不同的值覆盖相同的系统配置设置值(有同等优先级的包,参数必须统一)。除非更高优先级的包也有覆盖,否则newt工具将中止构建。

以下为从最高优先级到最低优先级的包类型:

  • 目标,Target
  • 应用程序,App
  • unittest,目标可以包含一个应用程序或单元测试包,或都不包含。
  • Lib,包括所有其他系统级别的包,如os,lib,sdk和编译器。

建议在目标级别重写默认值,而不是更新单个包syscfg.yml文件。

生成syscfg.h和引用系统配置设置

newt工具处理所有包的syscfg.yml文件,生成bin//generated/include/syscfg/syscfg.hwen文件,包含系统配置设置定义。Newt创建一个#define定义:

  • 添加前缀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函数的末尾,在无线循环中等待并分派默认事件队列中的事件。
  1. int main(int argc, char **argv)
  2. {
  3. /* First, call sysinit() to perform the system and package initialization */
  4. sysinit();
  5. /* ... other application initialization processing ... */
  6. /* Last, process events from the default event queue. */
  7. while (1) {
  8. os_eventq_run(os_eventq_dflt_get());
  9. }
  10. /* main never returns */
  11. }

指定包初始化函数

sysinit()函数调用sysinit_app()函数执行目标包的系统初始化。可以选择指定一个或多个包初始化函数,sysinit_app()调用这些函数来初始化包。

包初始化函数原型:

  1. void init_func_name(void)

包初始化函数分阶段调用,以确保低优先级的包优先于高优先级的包进行初始化。阶段为一个整数,从0开始,指定何时调用包初始化函数。Mynewt按照递增stage的顺序调用包初始化函数。具有相同stage的初始化函数的调用顺序取决于处理包的顺序,不能依赖于特定调用顺序。

使用pkg.yml文件中的pkg.init参数来指定初始化函数及调用函数的阶段号。可以指定多个初始化函数,对每个函数指定不同的阶段号。该特性允许具有相互依赖关系的包在多个阶段执行初始化。

pkg.yml文件中pkg.init参数遵循以下的语法:

  1. pkg.init:
  2. pkg_init_func1_name: pkg_init_func1_stage
  3. pkg_init_func2_name: pkg_init_func2_stage
  4. ...
  5. 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参数,在/generated/src/-sysinit_app.c中生成的sysinit_app()函数。

  1. /**
  2. * This file was generated by Apache Newt (incubating) version: 1.0.0-dev
  3. */
  4. #if !SPLIT_LOADER
  5. void split_app_init(void);
  6. void os_pkg_init(void);
  7. void imgmgr_module_init(void);
  8. /* ... */
  9. void stats_module_init(void);
  10. void
  11. sysinit_app(void)
  12. {
  13. /*** Stage 0 */
  14. /* 0.0: kernel/os */
  15. os_pkg_init();
  16. /*** Stage 2 */
  17. /* 2.0: sys/flash_map */
  18. flash_map_init();
  19. /*** Stage 10 */
  20. /* 10.0: sys/stats/full */
  21. stats_module_init();
  22. /*** Stage 20 */
  23. /* 20.0: sys/console/full */
  24. console_pkg_init();
  25. /*** Stage 100 */
  26. /* 100.0: sys/log/full */
  27. log_init();
  28. /* 100.1: sys/mfg */
  29. mfg_init();
  30. /* ... */
  31. /*** Stage 300 */
  32. /* 300.0: sys/config */
  33. config_pkg_init();
  34. /*** Stage 500 */
  35. /* 500.0: sys/id */
  36. id_init();
  37. /* 500.1: sys/shell */
  38. shell_init();
  39. /* ... */
  40. /* 500.4: mgmt/imgmgr */
  41. imgmgr_module_init();
  42. /*** Stage 501 */
  43. /* 501.0: mgmt/newtmgr/transport/nmgr_shell */
  44. nmgr_shell_pkg_init();
  45. }
  46. #endif

条件配置

可以使用系统配置设置值来有条件的指定pkg.yml和syscfg.yml文件中的参数值。语法如下:

  1. parameter_name.PKGA_SYSCFG_NAME:
  2. parameter_value

只有当PKGA_SYSCFG_NAME非0时,parameter_name的设置为parameter_value

  1. pkg.deps:
  2. - "@apache-mynewt-core/sys/sysinit"
  3. - "@apache-mynewt-core/util/mem"
  4. pkg.deps.OS_CLI
  5. - "@apache-mynewt-core/sys/shell"

示例为libs/os包中的pkg.yml文件,当OS_CLI使能时,才会依赖sys/shell包。

一旦检测到循环条件依赖,newt工具将中止构建。

参考资料:

http://mynewt.apache.org/latest/os/modules/sysinitconfig/sysinitconfig.html