provisioner config client demo

示例说明

示例功能简介

该示例主要体现的功能点如下:

  • 设备支持PB-ADV client,且可以支持多server同时入网。
  • 满足SIG 对 Provision client的 要求。
  • 可以直接入网 generic onoff server 的例程。

示例运行概要

硬件环境

该示例运行在 BLE Dongle 开发板上(开发板的详细信息,参考硬件支持包),用到硬件外设如下:

  • 按键

    botton 3 button 4 同时按下 ,心跳灯会快闪,设备重启并重新初始化。

  • 指示灯

    • led1 :
      • 绿灯
        • 熄灭, 保留;
        • 熄灭, 保留;
      • 蓝灯
        • 熄灭, 保留;
        • 常亮, 保留;
      • 红灯
        • 熄灭, 保留;
        • 常亮, 保留;
    • led2 :
      • 绿灯
        • 闪烁, 设备正常工作;
        • 常亮/长灭, 设备异常;
      • 蓝灯
        • 熄灭, 保留;
        • 熄灭, 保留;
      • 红灯
        • 熄灭, 保留;
        • 常亮, 保留;

软件环境

  • 设备端运行 ble mesh sdk 的 examples 目录下 provisioner_config_client示例。
  • 同时需要另外一个设备运行 unprovsion device 程序,请注意该设备的UUID,以及未入网设备支持的相关OOB能力。 本例程对应的角色为provisioner,通过业务栈自动发现设备,并通知到 相关的接口函数,用户只要实现接口就可以入网控制设备。

软件运行流程

1. 用户自己函数入口

在 mesh_user_main.c 中, mesh_user_main_init()初始化自己数据。(需要注意:不能阻塞)

2. 开启mesh协议栈调度

在用户函数执行完后,系统自动开启ble协议栈调度。

3. 示例代码

void mesh_user_main_init(void)
{
        ///user data init
    provisioner_config_client_init();

        LOG(LOG_LVL_INFO,"mesh_user_main_init\n");
}

例程初始状态

设备正常上电后:
  • led1 :
    • 绿灯
      • 熄灭, 保留;
    • 蓝灯
      • 熄灭, 保留;
    • 红灯
      • 熄灭, 保留;
  • led2 :
    • 绿灯
      • 闪烁, 设备正常工作;
    • 蓝灯
      • 熄灭, 保留;
    • 红灯
      • 熄灭, 保留;

ble mesh 角色设置

设置流程

static void user_role_init(void)
{
    //1.role init
    provision_init(MESH_ROLE_UNPROV_DEVICE, mesh_provisioner_evt_cb);
    //2. data init
    provisioner_data_init();
//3. set client own uniaddr
init_elmt_addr(USER_CLENT_UNICAST_ADDRESS);
}

1. 定义协议栈内部事件通知回调函数

    /* provision device event callback function */
static void mesh_provisioner_evt_cb(mesh_prov_evt_type_t type , mesh_prov_evt_param_t param)
{
LOG(LOG_LVL_INFO,"mesh_provisioner_evt_cb type : %d\n",type);
switch(type)
{
    case  PROV_EVT_BEACON :
    {
        //action link open : 这个是协议栈收到unprov beacon通知用户,用户可以判断uuid是否为需要入网的设备,下面的判断是简单的例程
        if(!memcmp(param.prov.param.p_beacon->dev_uuid + GAP_BD_ADDR_LEN,beacon_value +GAP_BD_ADDR_LEN,MESH_DEVICE_UUID_LENGTH-GAP_BD_ADDR_LEN))
        {
            start_provision_dev(param.prov.param.p_beacon->dev_uuid);
        }
        else
        {
              LOG(LOG_LVL_INFO,"invalid device");
              log_hex_data(param.prov.param.p_beacon->dev_uuid, MESH_DEVICE_UUID_LENGTH);
        }
    }
    break;
    // 收到LINK ACK的通知,可以不处理
    case  PROV_EVT_LINK_ACK ://(NO ACTION)
    {

    }
    break;
    // 收到capabilities的通知,provisioner可以根据这个记录用户的相关能力,选择合适的
    case  PROV_EVT_CAPABILITIES :
    {

    }
    break;
    // 这个需要provisioner 根据在PROV_EVT_CAPABILITIES 事件收到的 capabilities与自身能力来构建start报文
    case PROV_EVT_REQUEST_START:
    {
          admin_provisioner_set_start_pdu(param);
    }
    break;
    // 通知输入对方的public key
    case  PROV_EVT_READ_PEER_PUBLIC_KEY_OOB : //alert input dialog
    {
        //action read peer public key
        read_public_key(param);
    }
    break;
    // 这个事件是请求 provisioner output auth info,以方便再 unprov device输入
    case  PROV_EVT_AUTH_DISPLAY_NUMBER : //provisioner expose random number (NO ACTION)
    {
         LOG(LOG_LVL_INFO,"ooutput auth = ");
         log_hex_data(param.prov.param.p_output_val, AUTHVALUE_LEN);
         make_light_blink(param.prov.param.p_output_val[AUTHVALUE_LEN -1]);

    }
    break;
    // 这个事件是请求 provisioner 输入 auth info
    case  PROV_EVT_AUTH_INPUT_NUMBER : //alert input dialog
    {
         LOG(LOG_LVL_INFO,"input auth = \n");
         make_user_attention();
         memcpy(dev_uuid,param.prov.dev_uuid,AUTHVALUE_LEN);
    }
    break;
    // 通知入网完成
    case  PROV_EVT_PROVISION_DONE :  //(NO ACTION)
    {

    }
    break;
    default:break;
}

}

2. 设置角色,注册事件回调

provision_init(MESH_ROLE_UNPROV_DEVICE, mesh_provisioner_evt_cb);

3. 初始化角色相关的数据

static void provisioner_data_init(void)
{
 volatile mesh_prov_evt_param_t evt_param;

 uint8_t  bd_addr[GAP_BD_ADDR_LEN];

 //get bd_addr
 mesh_core_params_t core_param;
 core_param.mac_address = bd_addr;
 mesh_core_params_get(MESH_CORE_PARAM_MAC_ADDRESS,&core_param);

 //1. Method of configuring network access
 evt_param.prov.param.method = PROVISION_BY_ADV;
 provision_config(PROV_SET_PROVISION_METHOD,evt_param);
 //2. distribution data
 //send message will use the first netkey.
 //See @access_tx_pdu_set -> @get_netkey_by_dst_addr -> @dm_netkey_get_first_handle
   evt_param.prov.param.p_distribution = &m_prov_user.distribution;
   provision_config(PROV_SET_DISTRIBUTION_DATA,evt_param);


 //4. PROV_SET_INVITE_DURATION
 evt_param.prov.param.attention_duration = USER_ATTENTION_DURATION;
 provision_config(PROV_SET_INVITE_DURATION,evt_param);
 //5. private key
 memcpy(m_prov_user.prov_private_key,bd_addr,GAP_BD_ADDR_LEN);
 evt_param.prov.param.p_prov_private_key = m_prov_user.prov_private_key;
 provision_config(PROV_SET_PRIVATE_KEY,evt_param);

}

4. 协议栈开始完整运行

监听协议栈事件。。。。

ble mesh 协议栈和应用协议栈的信息交互

实现消息交互的处理函数

**相关的API函数,可以参考appfreertosmeshprovisionapiprovision_api.c

根据收到的事件,做相应处理或回复

    //协议->用户
typedef enum
{
/*******PROVISIONER*******/
PROV_EVT_BEACON,
PROV_EVT_LINK_ACK,    //(NO ACTION)
PROV_EVT_CAPABILITIES,
PROV_EVT_REQUEST_START,
PROV_EVT_READ_PEER_PUBLIC_KEY_OOB,
PROV_EVT_AUTH_DISPLAY_NUMBER,//provisioner expose random number (NO ACTION)
PROV_EVT_AUTH_INPUT_NUMBER,   //alert input dialog
PROV_EVT_PROVISION_DONE,    //(NO ACTION)

/*******UNPROV DEVICE*******/
UNPROV_EVT_INVITE_MAKE_ATTENTION,//(NO ACTION)
UNPROV_EVT_EXPOSE_PUBLIC_KEY, //(NO ACTION)
UNPROV_EVT_AUTH_INPUT_NUMBER,//alert input dialog
UNPROV_EVT_AUTH_DISPLAY_NUMBER,//unprov_device expose random number //(NO ACTION)
UNPROV_EVT_PROVISION_DONE, //(NO ACTION)
} mesh_prov_evt_type_t;

    //用户->协议栈(回复)
    typedef enum
    {
        /*******PROVISIONER*******/
        //PROV_EVT_AUTH_INPUT_NUMBER
        PROV_ACTION_AUTH_INPUT_NUMBER_DONE,//input random number done
        //PROV_EVT_READ_PEER_PUBLIC_KEY_OOB
        PROV_ACTION_READ_PEER_PUBLIC_KEY_OOB_DONE,
        //PROV_EVT_BEACON
        PROV_ACTION_SET_LINK_OPEN,
        //PROV_EVT_CAPABILITIES
        PROV_ACTION_SEND_START_PDU,

        /*******UNPROV DEVICE*******/
        //UNPROV_EVT_AUTH_INPUT_NUMBER
        UNPROV_ACTION_AUTH_INPUT_NUMBER_DONE,//input random number done
    } mesh_prov_action_type_t;

    void provision_action_send (mesh_prov_action_type_t type , mesh_prov_evt_param_t param);