用户程序

在内嵌模式中,用户程序和系统程序运行在同一处理器上,但是它是独立编译和链接的,可以动态下载到节点模块,扩充节点功能,用来控制外接外接各类传感器,是对节点模块的二次开发,这样不但可以节省一个外部处理器。而且用户程序只需关注新增接口和设备,这样就比较容易达到总体功耗要求。

用户程序的基本原理和注意事项可以参见下面链接:
http://www.tinywsn.net/wordpress/index.php/docs/manual/node/node-wbed/

下面的连接是用户程序开发包SDK,包含了许多的例程以及各类传感器总线的驱动:
https://gitee.com/tinywsn/fw-stm32l1-wbed-usr

传感器通过扩展板,安装在节点模块上,如下图所示,用户程序用配置软件TinyCFG下载到模块内。

软件结构

用户程序和系统程序通过消息进行交互,为了提高系统的响应效率,用户程序采用的事件驱动的状态机模型,其中消息的来源主要有三类,用户程序只需对接收消息进行响应:

  • 系统程序产生的消息
  • 中断程序产生的消息
  • 用户程序自己的消息

为了更好的配和系统程序,下图就是目推荐采用的的状态转换图:

从图中可以看出共有5个状态,其中def(默认消息处理状态)是后台状态,一直存在,其他都是前台状态,只有一个是当前激活的状态,它们之间根据接受的消息进行切换,下表对各个状态分别进行说明

符号名称说明
init初始状态系统上电进入的状态,进行程序和设备的初始化
disc断链状态当无线断链进入的状态,关闭设备进入低功耗模式
conn连接状态处理各类系统消息,发送测量结果,当转换定时器
触发时,进入转换状态
conv转换状态启动传感器转换,结束后关闭传感器,返回连接状态
def默认状态默认消息处理状态,未处理的消息都进入这个状态

初始状态

消息动作跳转
WIPC_MSG_FSM_INIT进入状态机初始化消息,开始设备初始化,开启一个同步定时器,以便提前一个时隙唤醒,完成传感器测量连接状态(如果在线)
断链状态(如果断链)
参见fw-stm32l1-wbed-usr/apps/ds18b20/s_init.c
// 初始状态机消息处理入口
wipc_result_t init_msg_proc(uint8_t msg, void *in, void *out, ctx_t *ctx)
{
  wipc_msg_tmr_init_t tmr_init;
  
  switch(msg){
  case WIPC_MSG_FSM_INIT:
    // 初始化NVM内存
    net_msg_send(WIPC_MSG_NVM_LOAD, 0, &((ctx_t*)ctx)->nvm, ctx);
    // 初始化设备
    pwr_init(true);
    led_init(((ctx_t*)ctx)->nvm.led);
      // 开启一同步定时器
    tmr_init.type = WIPC_TMR_SYNC;
      // 提前一个时隙唤醒
    tmr_init.arg.oft = -1;
    net_msg_send(WIPC_MSG_TMR_INIT, &tmr_init, 0, 0);
      // 初始化传感器
    ds18b20_init(&ctx->ds18b20);
    // 根据当前网络状态,
      // 切换到不同状态机
    if(((wipc_msg_sys_init_t*)in)->stat & WIPC_S_CONN){
      fsm_goto(conn_msg_proc, ctx);
    }else{
      fsm_goto(disc_msg_proc, ctx);
    }
    return WIPC_RES_SUCC;
  case WIPC_MSG_FSM_EXIT: 
    return WIPC_RES_SUCC;
  default:
    return WIPC_RES_CONT; 
  } 
}

连接状态

消息动作跳转
WIPC_MSG_TMR_TICK同步定时器触发消息,跳转到转换状态,开启传感器测量转换状态
WIPC_MSG_NTS_INIT节点时隙开始消息,检查传感器测量结果,发送数据
参见fw-stm32l1-wbed-usr/apps/ds18b20/s_conn.c
// 连接状态机消息处理入口
wipc_result_t conn_msg_proc(uint8_t msg, void *in, void *out, ctx_t *ctx)
{
  switch(msg){
  case WIPC_MSG_FSM_INIT:
    return WIPC_RES_SUCC;
  case WIPC_MSG_FSM_EXIT: 
    return WIPC_RES_SUCC;
  case WIPC_MSG_TMR_TICK:
     // 检查定时器的类别
    if(((wipc_msg_tmr_tick_t*)in)->type == WIPC_TMR_SYNC){
       // 跳转到转换状态
      fsm_goto(conv_msg_proc, ctx);
      return WIPC_RES_SUCC;
    }
    return WIPC_RES_SUCC; 
  case WIPC_MSG_NTS_INIT:
    // 检查转换的结果
    if(ctx->flag & CTX_F_DONE){
      uint8_t *q = CTX_USR_BUF(ctx);
      stringf((char*)q, "val,t,%.1fC", ctx->t);
         // 发送测量数据
      tx_usr_data(q, strlen((char*)q), TX_F_NONE, ctx);
      ctx->flag &=~CTX_F_DONE;
      return WIPC_RES_SUCC;
    }    
    return WIPC_RES_FAIL;
  default:
    return WIPC_RES_CONT; 
  } 
}

转换状态

消息动作跳转
WIPC_MSG_FSM_INIT进入状态机初始化消息, 重新初始化处于低功耗模式的设备,打开传感器的电源,等待上电稳定
WIPC_MSG_WAIT_DONE上电稳定完成,启动传感器的转换
WIPC_MSG_CONV_DONE传感器转换结束,获取测量数据连接状态
WIPC_MSG_WAIT_TMRO传感器转换失败,跳转回原来状态连接状态
WIPC_MSG_FSM_EXIT退出状态机析构化消息, 关闭设备使得它们进入低功耗模,关闭传感器电源
参见fw-stm32l1-wbed-usr/apps/ds18b20/s_conv.c
// 转换状态机消息处理入口
wipc_result_t conv_msg_proc(uint8_t msg, void *in, void *out, ctx_t *ctx)
{
  switch(msg){
  case WIPC_MSG_FSM_INIT:
    // 打开电源,重新初始化设备
    pwr_reinit(true);
    led_reinit(ctx->nvm.led);
    ds18b20_reinit(&ctx->ds18b20);
    // 等待传感器电源稳定
    dev_wait_msec(&ctx->ds18b20.wait, DS18B20_PWRON_MSEC, ctx);
    return WIPC_RES_SUCC;
  case WIPC_MSG_FSM_EXIT: 
    // 停止系统时钟节拍
    drv_wait_halt(&ctx->ds18b20.wait);
    // 关闭电源和设备
    ds18b20_deinit(&ctx->ds18b20);
    led_deinit();
    pwr_deinit();
    return WIPC_RES_SUCC;
  case WIPC_MSG_LPM_REQ:
    // 阻止系统进入低功耗模式 
    return WIPC_RES_FAIL;
  case WIPC_MSG_SYS_TICK:
    // msec tick
    drv_msec_tick(&ctx->ds18b20.wait, &ctx->ds18b20);
    return WIPC_RES_SUCC;
  case WIPC_MSG_WAIT_TMRO:
    // 传感器转换失败
    fsm_goto(conn_msg_proc, ctx);
    return WIPC_RES_SUCC;  
  case WIPC_MSG_WAIT_DONE:
      // 重置一下传感器
    ds18b20_reset(&ctx->ds18b20);
    // 启动传感器的转换
    if(!ds18b20_conv(&ctx->ds18b20)){
      fsm_goto(conn_msg_proc, ctx);
      return WIPC_RES_FAIL;
    }
    return WIPC_RES_SUCC;
  case WIPC_MSG_CONV_DONE:
    // 传感器转换结束
    if(ds18b20_get(&ctx->ds18b20, &ctx->t)){
      ctx->flag |= CTX_F_DONE;
    }
    // goto conn
    fsm_goto(conn_msg_proc, ctx);  
    return WIPC_RES_SUCC;
  default:
    return WIPC_RES_CONT; 
  } 
}

断链状态

消息动作跳转
WIPC_MSG_FSM_INIT进入状态机初始化消息, 关闭设备使得它们进入低功耗模,关闭传感器电源
参见fw-stm32l1-wbed-usr/apps/ds18b20/s_disc.c
// 断链状态消息处理入口
wipc_result_t disc_msg_proc(uint8_t msg, void *in, void *out, ctx_t *ctx)
{
  switch(msg){
  case WIPC_MSG_FSM_INIT:
    // 停止系统时钟节拍
    drv_wait_halt(&ctx->ds18b20.wait);
    // 关闭电源和设备
    ds18b20_deinit(&ctx->ds18b20);
    led_deinit();
    pwr_deinit();
    return WIPC_RES_SUCC;
  case WIPC_MSG_FSM_EXIT: 
    return WIPC_RES_SUCC;
  default:
    return WIPC_RES_CONT; 
  } 
}

默认状态

消息动作跳转
WIPC_MSG_NET_CONN接受到网络连接消息,切换到连接状态
WIPC_MSG_NET_DISC接受到网络断链消息,切换到断链状态
WIPC_MSG_USR_DATA接受到网络的命令,解析命令,执行响应动作
参见fw-stm32l1-wbed-usr/apps/ds18b20/s_def.c
// 默认状态消息处理入口
wipc_result_t def_msg_proc(uint8_t msg, void *in, void *out, ctx_t *ctx)
{
  switch(msg){
  case WIPC_MSG_LPM_REQ:
    return WIPC_RES_SUCC;
  case WIPC_MSG_LPM_INIT:
    return WIPC_RES_SUCC;
  case WIPC_MSG_LPM_EXIT:
    return WIPC_RES_SUCC;  
  case WIPC_MSG_NET_CONN:
      // 切换到连接状态
    fsm_goto(conn_msg_proc, ctx);
    return WIPC_RES_SUCC;
  case WIPC_MSG_NET_DISC:
      // 切换到断链状态
    fsm_goto(disc_msg_proc, ctx);
    return WIPC_RES_SUCC;    
  case WIPC_MSG_USR_DATA:
      // 接受到网络命令
    return rx_usr_data(in, out, ctx);
  case WIPC_MSG_IRQ_VTOR:
    return WIPC_RES_SUCC;
  default:
    return WIPC_RES_FAIL;
  }
}