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特性,另外如需sensor model 完整代碼,請點擊sensor model 源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章