nRF52 Mesh开发 (3) MESH Sensor Server/Client Models详解与实现


转发请注明出处。

MESH Spec规定的 Sensor Model 标准

MESH Spec定义了传感器接口的标准方法。 这样一来,任何设备都可以公开可使用的任何一组传感器,而无需为每个应用程序定义特定的状态,消息和模型。

传感器状态

传感器状态是由四个状态组成的复合状态:传感器描述,在整个sensor生命周期中保持不变; 可以设置的传感器参数和传感器踏频状态; 以及测量值;测量值可以表示为单个数据点Sensor Data状态或表示为一系列数据点的列,例如直方图。 测量值可以随时间变化。

传感器描述

如下表所示,传感器的描述状态主要包括如下几部分:传感器属性ID、传感器正公差、传感器负公差、传感器采样函数、
传感器测量周期、传感器更新间隔。具体描述可查看mesh model spec。
Sensor Descriptor states

传感器参数设置

传感器参数设置除了传感器属性ID外,每个设置都有自己的属性ID:Sensor Setting Property ID,同样是两个字节。另外还包括:Sensor Setting Access、Sensor Setting Raw。
在这里插入图片描述
Sensor Setting Access是字段是一个枚举,指示是否可以读取或写入设备属性。 下表中定义了该字段的值,
在这里插入图片描述
Sensor Setting Raw 表示传感器的设置

传感器cadence

传感器踏频状态控制传感器发送数据的频率。 能够以不同的节奏发送一系列测量值的测量值。可将传感器配置为在值向上或向下变化超过配置的增量值时发送测量值。包括以下几个字段:
在这里插入图片描述
The Fast Cadence Period Divisor 是一个7位的值,控制传感器状态消息发布频率的增加。 该值表示为发布周期的2n除数。 例如,值0x04的除数为16,而值0x00的除数为1。 快速踏频周期除数状态的有效范围是0–15,其他值被禁止。
The Status Trigger定义状态触发增量下降和状态触发增量上升字段的单位和格式。0b0的值表示该格式应由传感器属性ID的格式类型定义;值0b1表示单位为«unitless»,格式类型为0x06(uint16),该值表示为百分比变化,分辨率为0.01%。
The Status Trigger Delta Down控制触发传感器状态消息发布的测量量的负变化;Status Trigger Delta Up控制触发传感器状态消息发布的测量量的正变化。
The Status Min Interval 是一个1字节的值,它将控制发送两个连续的传感器状态数据之间的最小间隔。 该值表示为2^n毫秒。The Fast Cadence Low 定义一系列测量量的下边界,Fast Cadence Hight 定义测量量上界。

传感器数据

传感器数据状态是一对或多对传感器属性ID和数据的序列,如下图所示:
在这里插入图片描述
Sensor Data state
另外数据也可以使用图表的方式发送,如下图所示是以柱状图的方式发送。
ensor Series Column states
在这里插入图片描述

传感器可发送和接收的消息

传感器支持的消息如下图所示,在实际实现中并不需全部实现,根据所需实现必要的消息即可。具体消息类型可查看spec。
在这里插入图片描述

Sensor Server /Client Models

Sensor Server Models

Sensor Server模型是根模型(不扩展任何其他模型)。 当此模型存在于元素上时,还应提供相应的Sensor Setup Server模型(请参阅spec第4.3.2节)。模型需支持Mesh Profile规范[2]的4.2.2节中定义的模型发布,以及Mesh Mesh规范的4.2.3节中定义的模型订阅。
在这里插入图片描述
Sensor Setup Server模型扩展 Sensor Server模型
在这里插入图片描述

Sensor Client Models

Sensor Client模型是根模型(不支持扩展任何其他模型)。模型需支持Mesh Profile规范[2]的4.2.2节中定义的模型发布,以及Mesh Mesh规范的4.2.3节中定义的模型订阅。
Sensor Client elements and messages

Sensor Server /Client Models 在nrf52832上的实现

本文使用的传感器为温湿度传感器,传感器消息主要包括:数据采集时间间隔设置,数据采集时间间隔获取,数据采集时间间隔发布,温湿度数据获取,温湿度数据发布。
###传感器数据读取
本人使用的开发板是青风电子的nrf52832,传感器为青风在教程中使用到的温湿度传感器DHT11(淘宝买的)参数如下图所示
温湿度传感器DH11
数据读取代码如下(有详细的注释):
dht11.h

#ifndef __dht11_H
#define __dht11_H 


#define   ds1802          11

#define dht_IO_IN()   nrf_gpio_cfg_input(ds1802,NRF_GPIO_PIN_PULLUP);   /*!< Configures SDA pin as input  */
#define dht_IO_OUT()  do { NRF_GPIO->DIRSET = (1UL << ds1802);  } while(0)   /*!< Configures SDA pin as output */
 
									   
#define	dht_data_OUT_0  nrf_gpio_pin_clear(ds1802) 
#define	dht_data_OUT_1  nrf_gpio_pin_set(ds1802)  
#define	dht_data_IN     ((NRF_GPIO->IN >> ds1802) & 0x1UL)    

u8 dhtInit(void);
u8 dhtReadData(u8 *temp,u8 *humi);  
#endif

dht11.c

#include "dht11.h"
#include "nrf_delay.h"

/* Logging and RTT */
#include "log.h"
#include "rtt_input.h"

/******************************************************************
Function: dhtRest
Description: rest the dht11.
Input:    void
Output:  void
*******************************************************************/
void dhtRest(void)
{
    dht_IO_OUT();
    dht_data_OUT_0;
    nrf_delay_ms(25);
    dht_data_OUT_1;
    dht_data_OUT_1;
    nrf_delay_us(30);
}

/******************************************************************
Function: dhtCheck
Description: check the dht11.
Input:    void
Output:  void
*******************************************************************/
u8 dhtCheck(void)
{
    u8 time = 0;
    dht_IO_IN(); // SET INPUT
    while(dht_data_IN && time < 100)
    {
        time++;
        nrf_delay_us(1);
       
    }
    if(time >= 100)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "ERROR 1\n");
        return 1;
    }
    else 
    {
       time = 0;
    }
    while(!dht_data_IN && time < 100)
    {
        time++;
        nrf_delay_us(1);
       
    }
    if(time>=100)
	{
		 __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "ERROR 2\n");
		return 1;
	}
    //__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "NO ERROR \n");
	return 0;
}

/******************************************************************
Function: dhtReadBit
Description: read one bit of dht data.
Input:    void
Output:  0 or 1
*******************************************************************/
u8 dhtReadBit(void)
{
    u8 time = 0;
    while(dht_data_IN && time < 100)
    {
        time++;
        nrf_delay_us(1);
    }
    time = 0;
    while(!dht_data_IN && time < 100)
    {
        time++;
        nrf_delay_us(1);
    }
    nrf_delay_us(40);
    if(dht_data_IN)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/******************************************************************
Function: dhtReadByte
Description: read one byte of dht data.
Input:    void
Output:  data
*******************************************************************/
u8 dhtReadByte(void)
{
    u8 data;
    data = 0;
    for(int i = 0; i < 8; i++)
    {
       data = data << 1;
       data = data | dhtReadBit();
    }
    return data;
}

/******************************************************************
Function: dhtReadData
Description: read all data.
Input:    void
Output:  temp humi
*******************************************************************/
u8 dhtReadData(u8 *temp, u8 *humi)
{
    u8 data[5];
    dhtRest();
    if(dhtCheck() == 0)
    {
        for(int i = 0; i < 5; i++)
        {
            data[i] = dhtReadByte();
        }
        if(data[4] == data[0] +data[1] + data[2] + data[3])
        {
            *humi = data[0];
            *temp = data[2];
        }
    }
    else 
    {
        printf("read data error\n");
        return 1;
    }
    return 0;
}

/******************************************************************
Function: dhtInit
Description: initall the dht.
Input:    void
Output:  dhtCheck()
*******************************************************************/
u8 dhtInit()
{
    dhtRest();
    //__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DHT INIT \n");
    return dhtCheck();
}

Sensor(温湿度计) model 消息实现

消息包括:温湿度采集时间设置/无回复类型、温湿度采集时间设置获取、温湿度采集时间发布、温湿度获取、温湿度发布。
首先需要定义一个company ID

/** Vendor specific company ID for Simple OnOff model */
#define SENSOR_DHT_COMPANY_ID    (ACCESS_COMPANY_ID_NORDIC)

每个消息都需要一个操作码,用于assess层识别不同的消息,操作码定义如下:

/**sensor_dht opcodes**/
typedef enum
{
    SENSOR_DHT_OPCODE_SETTING_SET = 0xD1,
    SENSOR_DHT_OPCODE_SETTING_GET = 0xD2,
    SENSOR_DHT_OPCODE_SETTING_SET_UNRELIABLE = 0xD3,
    SENSOR_DHT_OPCODE_SETTING_STATUS = 0XD4,
    SENSOR_DHT_OPCODE_GET = 0XD5,
    SENSOR_DHT_OPCODE_STATUS = 0XD6
} sensor_dht_opcode_t;

下面是各个消息结构,setting message 中可根据实际需求增添功能,用于功能简单下面的实现略去了SIG规范中的sensor ID与setting ID

/** Message format for the  Setting Set message. */
typedef struct __attribute((packed))
{
    //uint16_t property_id;/**< sensor_dht property id. */
    //uint16_t setting_property_id;/**< sensor_dht setting property id. */
    uint8_t period_time; /**< the data send period. */
} sensor_dht_msg_setting_set_t;

/** Message format for the  Setting Get message. */
typedef struct __attribute((packed))
{
    //uint16_t property_id;/**< sensor_dht property id. */
    //uint16_t setting_property_id;/**< sensor_dht setting property id. */ 
} sensor_dht_msg_setting_get_t;

/** Message format for the dht  Setting Set unreliable message . */
typedef struct __attribute((packed))
{
    //uint16_t property_id;/**< sensor_dht property id. */
    //uint16_t setting_property_id;/**< sensor_dht setting property id. */
    uint8_t period_time; /**< the data send period. */
} sensor_dht_msg_setting_set_unreliable_t;

/** Message format for the sensor_dht Setting Status message . */
typedef struct __attribute((packed))
{
    //uint16_t property_id;/**< sensor_dht property id. */
    //uint16_t setting_property_id;/**< sensor_dht setting property id. */
    uint8_t period_time; /**< the data send period. */
} sensor_dht_msg_setting_status_t;

/** Message format for the dht  Get message . */
typedef struct __attribute((packed))
{
    //uint16_t property_id;

}sensor_dht_msg_get_t;

/** Message format for the sensor_dht Status message . */
typedef struct __attribute((packed))
{
    uint8_t temp;
    uint8_t humi;
} sensor_dht_msg_status_t;

###sensor(温湿度计)server model实现
model是一个具体的功能实例,server多用于发送状态消息,接收设置等消息,所以需要用到opcode、server ID,消息回调函数,使用struct封装这些内容,在接收到setting消息后,access层可根据opcode和server ID回调不同的函数。access_model_handle_t是access定义的一个结构体,用于注册连接opcode、server ID 和回调函数。

/** Sensor dht server model ID */
#define SENSOR_DHT_SERVER_MODEL_ID (0x0000)

/** Forward declaration*/
typedef struct __sensor_dht_server  sensor_dht_server_t;

/** sensor dht setting set callback type*/
typedef uint8_t (*sensor_dht_setting_set_cb_t) (const sensor_dht_server_t *p_self,
                                           uint8_t period_time);

/** sensor dht setting get callback type*/
typedef uint8_t (*sensor_dht_setting_get_cb_t)(const sensor_dht_server_t *p_self);

/** sensor dht get callback type*/
typedef void (*sensor_dht_get_cb_t)(const sensor_dht_server_t *p_self);
/** sensor dht server state structure*/
struct __sensor_dht_server
{
    /** Model handel assigned to the server*/
    access_model_handle_t model_handle;
    /** Setting get callback.*/
    sensor_dht_setting_get_cb_t setting_get_cb;
    /** Setting set callback.*/
    sensor_dht_setting_set_cb_t setting_set_cb;
    /** Sensor dht data Get callback.*/
    sensor_dht_get_cb_t get_cb;
};

另外还需要声明model 初始化函数、状态发布函数作为API供model实现时使用。

/******************************************************************
Function: sensor_dht_server_init
Description: initall the sensor_dht_server.
Input:    p_server  Sensor dht server structure pointer
          element_index  Element index to add the server model

Output:  NRF_SUCCESS         Successfully added client.
         NRF_ERROR_NULL      NULL pointer supplied to function.
         NRF_ERROR_NO_MEM    No more memory available to allocate model.
         NRF_ERROR_FORBIDDEN Multiple model instances per element is not allowed.
         NRF_ERROR_NOT_FOUND Invalid element index.
*******************************************************************/
uint32_t sensor_dht_server_init(sensor_dht_server_t *p_server, uint16_t element_index);

/******************************************************************
Function: sensor_dht_server_setting_status_publish
Description: publish the sensor dht setting status.
Input:    p_server  Sensor dht server structure pointer
          period_time  the time interval of presnet sensor status

Output:  NRF_SUCCESS         Successfully added client.
         NRF_ERROR_NULL      NULL pointer supplied to function.
         NRF_ERROR_NO_MEM    No more memory available to allocate model.
         NRF_ERROR_FORBIDDEN Multiple model instances per element is not allowed.
         NRF_ERROR_NOT_FOUND      Invalid model handle or model not bound to element.
         NRF_ERROR_INVALID_ADDR   The element index is greater than the number of local unicast
 *                                  addresses stored by the @ref DEVICE_STATE_MANAGER.
         NRF_ERROR_INVALID_PARAM  Model not bound to appkey, publish address not set or wrong
 *                                  opcode format.
         NRF_ERROR_INVALID_LENGTH Attempted to send message larger than @ref ACCESS_MESSAGE_LENGTH_MAX
*******************************************************************/
uint32_t sensor_dht_server_setting_status_publish(sensor_dht_server_t * p_server, uint8_t period_time);

/******************************************************************
Function: sensor_dht_server_status_publish
Description: publish the sensor dht setting status.
Input:    p_server  Sensor dht server structure pointer
          temp      sensor temperature data 
          humi      sensor humidity data

Output:  NRF_SUCCESS         Successfully added client.
         NRF_ERROR_NULL      NULL pointer supplied to function.
         NRF_ERROR_NO_MEM    No more memory available to allocate model.
         NRF_ERROR_FORBIDDEN Multiple model instances per element is not allowed.
         NRF_ERROR_NOT_FOUND      Invalid model handle or model not bound to element.
         NRF_ERROR_INVALID_ADDR   The element index is greater than the number of local unicast
 *                                  addresses stored by the @ref DEVICE_STATE_MANAGER.
         NRF_ERROR_INVALID_PARAM  Model not bound to appkey, publish address not set or wrong
 *                                  opcode format.
         NRF_ERROR_INVALID_LENGTH Attempted to send message larger than @ref ACCESS_MESSAGE_LENGTH_MAX
*******************************************************************/
uint32_t sensor_dht_server_status_publish(sensor_dht_server_t * p_server, uint8_t temp, uint8_t humi);

###sensor(温湿度计)client model 实现
client用于发送setting等消息,接收status消息。在实现中与server基本一致,多出一个消息传输时间管理,具体代码如下:

/** Acknowledged message transation timeout */
#ifndef SENSOR_DHT_CLIENT_ACKED_TRANSACTION_TIMEOUT
#define SENSOR_DHT_CLIENT_ACKED_TRANSACTION_TIMEOUT (SEC_TO_US(60))
#endif

/** Sensor dht Client model ID */
#define SENSOR_DHT_CLIENT_MODEL_ID (0x0000)

/** Sensor dht Client state codes */
typedef enum
{
    /** The server did not reply to a setting status */
    SENSOR_DHT_SETTING_STATUS_ERROR_NO_REPLAY,
    /** Setting status set was cancelled */
    SENSOR_DHT_SETTING_STATUS_CANCELLED
} sensor_setting_status_t;

/** Forward declaration. */
typedef struct __sensor_dht_client sensor_dht_client_t;

/** sensor dht setting status callback type*/
typedef void (*sensor_dht_setting_status_cb_t)(const sensor_dht_client_t *p_self, 
                                               const sensor_dht_msg_setting_status_t *p_setting_status,
                                               const uint16_t src);

/** sensor dht status callback type*/
typedef void (*sensor_dht_status_cb_t)(const sensor_dht_client_t *p_self, 
                                       const sensor_dht_msg_status_t *p_status,
                                       const uint16_t src);

/** sensor dht timeout callback type*/
typedef void(*sensor_dht_timeout_cb_t)(access_model_handle_t handle, void *p_self);

/** sensor client state structure*/
struct __sensor_dht_client
{
    /** Model handle assigned to the client. */
    access_model_handle_t model_handle;
    /** setting status callback called after status received from server*/
    sensor_dht_setting_status_cb_t setting_status_cb;
    /** status callback called after status received from server*/
    sensor_dht_status_cb_t status_cb;
    /** periodic timer timeout callback used for periodic publication*/
    sensor_dht_timeout_cb_t timeout_cb;
    /** internal client state*/
    struct 
    {
        bool reliable_transfer_active; /**< Variable used to determine if a transfer is currently active. */
        sensor_dht_msg_setting_set_t setting_data;  /**< Variable reflecting the data stored in the server. */
    } state;
    
};

/******************************************************************
Function: sensor_dht_client_init
Description: initall the sensor_dht_client.
Input:    p_client  Sensor dht Client structure pointer
          element_index  Element index to add the server model

Output:  NRF_SUCCESS         Successfully added client.
         NRF_ERROR_NULL      NULL pointer supplied to function.
         NRF_ERROR_NO_MEM    No more memory available to allocate model.
         NRF_ERROR_FORBIDDEN Multiple model instances per element is not allowed.
         NRF_ERROR_NOT_FOUND Invalid element index.
*******************************************************************/
uint32_t sensor_dht_client_init(sensor_dht_client_t *p_client, uint16_t element_index);

/******************************************************************
Function: sensor_dht_client_setting_set
Description: Sets the state of the Sensor dht  server.
Input:    p_client  Sensor dht Client structure pointer
          period_time  the time interval of presnet sensor status
          
Output:  NRF_SUCCESS              Successfully sent message.
         NRF_ERROR_NULL           NULL pointer in function arguments
         NRF_ERROR_NO_MEM         Not enough memory available for message.
         NRF_ERROR_NOT_FOUND      Invalid model handle or model not bound to element.
         NRF_ERROR_INVALID_ADDR   The element index is greater than the number of local unicast
                                   addresses stored by the @ref DEVICE_STATE_MANAGER.
         NRF_ERROR_INVALID_STATE  Message already scheduled for a reliable transfer.
         NRF_ERROR_INVALID_PARAM  Model not bound to appkey, publish address not set or wrong
                                   opcode format.
*******************************************************************/
uint32_t sensor_dht_client_setting_set(sensor_dht_client_t *p_client, uint8_t period_time);

/******************************************************************
Function: sensor_dht_client_setting_set
Description: Sets the setting state of the Sensor dht  server without reliable.
Input:    p_client  Sensor dht Client structure pointer
          period_time  the time interval of presnet sensor status
          
Output:  NRF_SUCCESS              Successfully sent message.
         NRF_ERROR_NULL           NULL pointer in function arguments
         NRF_ERROR_NO_MEM         Not enough memory available for message.
         NRF_ERROR_NOT_FOUND      Invalid model handle or model not bound to element.
         NRF_ERROR_INVALID_ADDR   The element index is greater than the number of local unicast
                                   addresses stored by the @ref DEVICE_STATE_MANAGER.
         NRF_ERROR_INVALID_STATE  Message already scheduled for a reliable transfer.
         NRF_ERROR_INVALID_PARAM  Model not bound to appkey, publish address not set or wrong
                                   opcode format.
*******************************************************************/
uint32_t sensor_dht_client_setting_set_unreliable(sensor_dht_client_t *p_client, uint8_t period_time);

/******************************************************************
Function: sensor_dht_client_setting_get
Description: Gets the setting state of the Sensor dht  server.
Input:    p_client  Sensor dht Client structure pointer
          
Output:  NRF_SUCCESS              Successfully sent message.
         NRF_ERROR_NULL           NULL pointer in function arguments
         NRF_ERROR_NO_MEM         Not enough memory available for message.
         NRF_ERROR_NOT_FOUND      Invalid model handle or model not bound to element.
         NRF_ERROR_INVALID_ADDR   The element index is greater than the number of local unicast
                                   addresses stored by the @ref DEVICE_STATE_MANAGER.
         NRF_ERROR_INVALID_STATE  Message already scheduled for a reliable transfer.
         NRF_ERROR_INVALID_PARAM  Model not bound to appkey, publish address not set or wrong
                                   opcode format.
*******************************************************************/
uint32_t sensor_dht_client_setting_get(sensor_dht_client_t *p_client);

/******************************************************************
Function: sensor_dht_client_get
Description: Gets the state of the Sensor dht  server.
Input:    p_client  Sensor dht Client structure pointer
          
Output:  NRF_SUCCESS              Successfully sent message.
         NRF_ERROR_NULL           NULL pointer in function arguments
         NRF_ERROR_NO_MEM         Not enough memory available for message.
         NRF_ERROR_NOT_FOUND      Invalid model handle or model not bound to element.
         NRF_ERROR_INVALID_ADDR   The element index is greater than the number of local unicast
                                   addresses stored by the @ref DEVICE_STATE_MANAGER.
         NRF_ERROR_INVALID_STATE  Message already scheduled for a reliable transfer.
         NRF_ERROR_INVALID_PARAM  Model not bound to appkey, publish address not set or wrong
                                   opcode format.
*******************************************************************/
uint32_t sensor_dht_client_get(sensor_dht_client_t *p_client);

/******************************************************************
Function: sensor_dht_client_pending_msg_cancel
Description: Cancel any ongoing reliable message transfer.
Input:    p_client  Sensor dht Client structure pointer      
Output:  
*******************************************************************/
void sensor_dht_client_pending_msg_cancel(sensor_dht_client_t *p_client);

#总结
目前市场上MESH的应用场景多为智能照明,在传感器领域的需求需要进一步的开发。平时多看几遍协议,有利于深入理解MESH特性。
作者目前已不再做蓝牙Mesh相关项目,协议或许有些更新。在2020年时做的sensor model 代码仅供大家参考,请点击sensor model 源码

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值