ble_mesh: modify health server model callbacks

This commit is contained in:
lly 2019-09-17 16:10:08 +08:00
parent 4702cd1b51
commit 805bc06127
7 changed files with 436 additions and 250 deletions

View file

@ -83,12 +83,16 @@ esp_err_t esp_ble_mesh_health_server_fault_update(esp_ble_mesh_elem_t *element)
btc_ble_mesh_health_server_args_t arg = {0};
btc_msg_t msg = {0};
if (element == NULL) {
return ESP_ERR_INVALID_ARG;
}
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HEALTH_SERVER;
msg.act = BTC_BLE_MESH_ACT_HEALTH_SERVER_FAULT_UPDATE;
arg.fault_update.element = element;
arg.health_fault_update.element = element;
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_health_server_args_t), NULL)
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);

View file

@ -47,39 +47,123 @@
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_HEALTH_CLI, \
NULL, NULL, cli_data)
/** Health Server Model callbacks */
/** @def ESP_BLE_MESH_HEALTH_PUB_DEFINE
*
* A helper to define a health publication context
*
* @param _name Name given to the publication context variable.
* @param _max Maximum number of faults the element can have.
* @param _role Role of the device which contains the model.
*/
#define ESP_BLE_MESH_HEALTH_PUB_DEFINE(_name, _max, _role) \
ESP_BLE_MESH_MODEL_PUB_DEFINE(_name, (1 + 3 + (_max)), _role)
/**
* SIG identifier of Health Fault Test.
* 0x01 ~ 0xFF: Vendor Specific Test.
*/
#define ESP_BLE_MESH_HEALTH_STANDARD_TEST 0x00
/**
* Fault values of Health Fault Test.
* 0x33 ~ 0x7F: Reserved for Future Use.
* 0x80 ~ 0xFF: Vendor Specific Warning/Error.
*/
#define ESP_BLE_MESH_NO_FAULT 0x00
#define ESP_BLE_MESH_BATTERY_LOW_WARNING 0x01
#define ESP_BLE_MESH_BATTERY_LOW_ERROR 0x02
#define ESP_BLE_MESH_SUPPLY_VOLTAGE_TOO_LOW_WARNING 0x03
#define ESP_BLE_MESH_SUPPLY_VOLTAGE_TOO_LOW_ERROR 0x04
#define ESP_BLE_MESH_SUPPLY_VOLTAGE_TOO_HIGH_WARNING 0x05
#define ESP_BLE_MESH_SUPPLY_VOLTAGE_TOO_HIGH_ERROR 0x06
#define ESP_BLE_MESH_POWER_SUPPLY_INTERRUPTED_WARNING 0x07
#define ESP_BLE_MESH_POWER_SUPPLY_INTERRUPTED_ERROR 0x08
#define ESP_BLE_MESH_NO_LOAD_WARNING 0x09
#define ESP_BLE_MESH_NO_LOAD_ERROR 0x0A
#define ESP_BLE_MESH_OVERLOAD_WARNING 0x0B
#define ESP_BLE_MESH_OVERLOAD_ERROR 0x0C
#define ESP_BLE_MESH_OVERHEAT_WARNING 0x0D
#define ESP_BLE_MESH_OVERHEAT_ERROR 0x0E
#define ESP_BLE_MESH_CONDENSATION_WARNING 0x0F
#define ESP_BLE_MESH_CONDENSATION_ERROR 0x10
#define ESP_BLE_MESH_VIBRATION_WARNING 0x11
#define ESP_BLE_MESH_VIBRATION_ERROR 0x12
#define ESP_BLE_MESH_CONFIGURATION_WARNING 0x13
#define ESP_BLE_MESH_CONFIGURATION_ERROR 0x14
#define ESP_BLE_MESH_ELEMENT_NOT_CALIBRATED_WARNING 0x15
#define ESP_BLE_MESH_ELEMENT_NOT_CALIBRATED_ERROR 0x16
#define ESP_BLE_MESH_MEMORY_WARNING 0x17
#define ESP_BLE_MESH_MEMORY_ERROR 0x18
#define ESP_BLE_MESH_SELF_TEST_WARNING 0x19
#define ESP_BLE_MESH_SELF_TEST_ERROR 0x1A
#define ESP_BLE_MESH_INPUT_TOO_LOW_WARNING 0x1B
#define ESP_BLE_MESH_INPUT_TOO_LOW_ERROR 0x1C
#define ESP_BLE_MESH_INPUT_TOO_HIGH_WARNING 0x1D
#define ESP_BLE_MESH_INPUT_TOO_HIGH_ERROR 0x1E
#define ESP_BLE_MESH_INPUT_NO_CHANGE_WARNING 0x1F
#define ESP_BLE_MESH_INPUT_NO_CHANGE_ERROR 0x20
#define ESP_BLE_MESH_ACTUATOR_BLOCKED_WARNING 0x21
#define ESP_BLE_MESH_ACTUATOR_BLOCKED_ERROR 0x22
#define ESP_BLE_MESH_HOUSING_OPENED_WARNING 0x23
#define ESP_BLE_MESH_HOUSING_OPENED_ERROR 0x24
#define ESP_BLE_MESH_TAMPER_WARNING 0x25
#define ESP_BLE_MESH_TAMPER_ERROR 0x26
#define ESP_BLE_MESH_DEVICE_MOVED_WARNING 0x27
#define ESP_BLE_MESH_DEVICE_MOVED_ERROR 0x28
#define ESP_BLE_MESH_DEVICE_DROPPED_WARNING 0x29
#define ESP_BLE_MESH_DEVICE_DROPPED_ERROR 0x2A
#define ESP_BLE_MESH_OVERFLOW_WARNING 0x2B
#define ESP_BLE_MESH_OVERFLOW_ERROR 0x2C
#define ESP_BLE_MESH_EMPTY_WARNING 0x2D
#define ESP_BLE_MESH_EMPTY_ERROR 0x2E
#define ESP_BLE_MESH_INTERNAL_BUS_WARNING 0x2F
#define ESP_BLE_MESH_INTERNAL_BUS_ERROR 0x30
#define ESP_BLE_MESH_MECHANISM_JAMMED_WARNING 0x31
#define ESP_BLE_MESH_MECHANISM_JAMMED_ERROR 0x32
/** ESP BLE Mesh Health Server callback */
typedef struct {
/** Fetch current faults */
int (*fault_get_cur)(esp_ble_mesh_model_t *model, uint8_t *test_id,
uint16_t *company_id, uint8_t *faults, uint8_t *fault_count);
/** Clear health registered faults. Initialized by the stack. */
esp_ble_mesh_cb_t fault_clear;
/** Fetch registered faults */
int (*fault_get_reg)(esp_ble_mesh_model_t *model, uint16_t company_id,
uint8_t *test_id, uint8_t *faults, uint8_t *fault_count);
/** Run a specific health test. Initialized by the stack. */
esp_ble_mesh_cb_t fault_test;
/** Clear registered faults */
int (*fault_clear)(esp_ble_mesh_model_t *model, uint16_t company_id);
/** Health attention on callback. Initialized by the stack. */
esp_ble_mesh_cb_t attention_on;
/** Run a specific test */
int (*fault_test)(esp_ble_mesh_model_t *model, uint8_t test_id, uint16_t company_id);
/** Attention on */
void (*attn_on)(esp_ble_mesh_model_t *model);
/** Attention off */
void (*attn_off)(esp_ble_mesh_model_t *model);
/** Health attention off callback. Initialized by the stack. */
esp_ble_mesh_cb_t attention_off;
} esp_ble_mesh_health_srv_cb_t;
/** Health Server Model Context */
#define ESP_BLE_MESH_HEALTH_FAULT_ARRAY_SIZE 32
/** ESP BLE Mesh Health Server test Context */
typedef struct {
uint8_t id_count; /*!< Number of Health self-test ID */
const uint8_t *test_ids; /*!< Array of Health self-test IDs */
uint16_t company_id; /*!< Company ID used to identify the Health Fault state */
uint8_t prev_test_id; /*!< Current test ID of the health fault test */
uint8_t current_faults[ESP_BLE_MESH_HEALTH_FAULT_ARRAY_SIZE]; /*!< Array of current faults */
uint8_t registered_faults[ESP_BLE_MESH_HEALTH_FAULT_ARRAY_SIZE]; /*!< Array of registered faults */
} __attribute__((packed)) esp_ble_mesh_health_test_t;
/** ESP BLE Mesh Health Server Model Context */
typedef struct {
/** Pointer to Health Server Model */
esp_ble_mesh_model_t *model;
/** Optional callback struct */
const esp_ble_mesh_health_srv_cb_t *cb;
/** Health callback struct */
esp_ble_mesh_health_srv_cb_t health_cb;
/** Attention Timer state */
struct k_delayed_work attn_timer;
struct k_delayed_work attention_timer;
/** Attention Timer start flag */
bool attention_timer_start;
/** Health Server fault test */
esp_ble_mesh_health_test_t health_test;
} esp_ble_mesh_health_srv_t;
/** Parameter of Health Fault Get */
@ -186,14 +270,54 @@ typedef enum {
ESP_BLE_MESH_HEALTH_CLIENT_EVT_MAX,
} esp_ble_mesh_health_client_cb_event_t;
/** Health Server Model callback parameter */
/** Parameter of publishing Health Current Status completion event */
typedef struct {
int error_code; /*!< Appropriate error code */
int error_code; /*!< The result of publishing Health Current Status */
esp_ble_mesh_elem_t *element; /*!< Pointer to the element which contains the Health Server Model */
} esp_ble_mesh_health_fault_update_comp_cb_t;
/** Parameters of Health Fault Clear event */
typedef struct {
esp_ble_mesh_model_t *model; /*!< Pointer to the Health Server Model */
uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */
} esp_ble_mesh_health_fault_clear_cb_t;
/** Parameters of Health Fault Test event */
typedef struct {
esp_ble_mesh_model_t *model; /*!< Pointer to the Health Server Model */
uint8_t test_id; /*!< ID of a specific test to be performed */
uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */
} esp_ble_mesh_health_fault_test_cb_t;
/** Parameter of Health Attention On event */
typedef struct {
esp_ble_mesh_model_t *model; /*!< Pointer to the Health Server Model */
uint8_t time; /*!< Duration of attention timer on (in seconds) */
} esp_ble_mesh_health_attention_on_cb_t;
/** Parameter of Health Attention Off event */
typedef struct {
esp_ble_mesh_model_t *model; /*!< Pointer to the Health Server Model */
} esp_ble_mesh_health_attention_off_cb_t;
/**
* @brief Health Server Model callback parameters union
*/
typedef union {
esp_ble_mesh_health_fault_update_comp_cb_t fault_update_comp; /*!< ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMP_EVT */
esp_ble_mesh_health_fault_clear_cb_t fault_clear; /*!< ESP_BLE_MESH_HEALTH_SERVER_FAULT_CLEAR_EVT */
esp_ble_mesh_health_fault_test_cb_t fault_test; /*!< ESP_BLE_MESH_HEALTH_SERVER_FAULT_TEST_EVT */
esp_ble_mesh_health_attention_on_cb_t attention_on; /*!< ESP_BLE_MESH_HEALTH_SERVER_ATTENTION_ON_EVT */
esp_ble_mesh_health_attention_off_cb_t attention_off; /*!< ESP_BLE_MESH_HEALTH_SERVER_ATTENTION_OFF_EVT */
} esp_ble_mesh_health_server_cb_param_t;
/** This enum value is the event of Health Server Model */
typedef enum {
ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT,
ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMP_EVT,
ESP_BLE_MESH_HEALTH_SERVER_FAULT_CLEAR_EVT,
ESP_BLE_MESH_HEALTH_SERVER_FAULT_TEST_EVT,
ESP_BLE_MESH_HEALTH_SERVER_ATTENTION_ON_EVT,
ESP_BLE_MESH_HEALTH_SERVER_ATTENTION_OFF_EVT,
ESP_BLE_MESH_HEALTH_SERVER_EVT_MAX,
} esp_ble_mesh_health_server_cb_event_t;
@ -270,7 +394,7 @@ esp_err_t esp_ble_mesh_health_client_set_state(esp_ble_mesh_client_common_param_
esp_ble_mesh_health_client_set_state_t *set_state);
/**
* @brief This function is called by the Health Server Model to start to publish its Current Health Fault.
* @brief This function is called by the Health Server Model to update the context of its Health Current status.
*
* @param[in] element: The element to which the Health Server Model belongs.
*

View file

@ -517,7 +517,7 @@ static void btc_ble_mesh_health_server_copy_req_data(btc_msg_t *msg, void *p_des
}
switch (msg->act) {
case ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT:
case ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMP_EVT:
break;
default:
break;
@ -532,7 +532,7 @@ static void btc_ble_mesh_health_server_free_req_data(btc_msg_t *msg)
}
switch (msg->act) {
case ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT:
case ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMP_EVT:
break;
default:
break;
@ -555,7 +555,7 @@ static void btc_ble_mesh_health_server_callback(esp_ble_mesh_health_server_cb_pa
void btc_ble_mesh_health_server_call_handler(btc_msg_t *msg)
{
esp_ble_mesh_health_server_cb_param_t health_server_cb = {0};
esp_ble_mesh_health_server_cb_param_t param = {0};
btc_ble_mesh_health_server_args_t *arg = NULL;
if (!msg || !msg->arg) {
@ -567,10 +567,10 @@ void btc_ble_mesh_health_server_call_handler(btc_msg_t *msg)
switch (msg->act) {
case BTC_BLE_MESH_ACT_HEALTH_SERVER_FAULT_UPDATE:
health_server_cb.error_code =
bt_mesh_fault_update((struct bt_mesh_elem *)arg->fault_update.element);
btc_ble_mesh_health_server_callback(
&health_server_cb, ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMPLETE_EVT);
param.fault_update_comp.element = arg->health_fault_update.element;
param.fault_update_comp.error_code =
bt_mesh_fault_update((struct bt_mesh_elem *)arg->health_fault_update.element);
btc_ble_mesh_health_server_callback(&param, ESP_BLE_MESH_HEALTH_SERVER_FAULT_UPDATE_COMP_EVT);
break;
default:
break;
@ -600,3 +600,43 @@ void btc_ble_mesh_health_server_cb_handler(btc_msg_t *msg)
btc_ble_mesh_health_server_free_req_data(msg);
return;
}
void btc_ble_mesh_health_server_fault_clear(struct bt_mesh_model *model, u16_t company_id)
{
esp_ble_mesh_health_server_cb_param_t param = {0};
param.fault_clear.model = (esp_ble_mesh_model_t *)model;
param.fault_clear.company_id = company_id;
btc_ble_mesh_health_server_callback(&param, ESP_BLE_MESH_HEALTH_SERVER_FAULT_CLEAR_EVT);
}
void btc_ble_mesh_health_server_fault_test(struct bt_mesh_model *model, u8_t test_id, u16_t company_id)
{
esp_ble_mesh_health_server_cb_param_t param = {0};
param.fault_test.model = (esp_ble_mesh_model_t *)model;
param.fault_test.test_id = test_id;
param.fault_test.company_id = company_id;
btc_ble_mesh_health_server_callback(&param, ESP_BLE_MESH_HEALTH_SERVER_FAULT_TEST_EVT);
}
void btc_ble_mesh_health_server_attention_on(struct bt_mesh_model *model, u8_t time)
{
esp_ble_mesh_health_server_cb_param_t param = {0};
param.attention_on.model = (esp_ble_mesh_model_t *)model;
param.attention_on.time = time;
btc_ble_mesh_health_server_callback(&param, ESP_BLE_MESH_HEALTH_SERVER_ATTENTION_ON_EVT);
}
void btc_ble_mesh_health_server_attention_off(struct bt_mesh_model *model)
{
esp_ble_mesh_health_server_cb_param_t param = {0};
param.attention_off.model = (esp_ble_mesh_model_t *)model;
btc_ble_mesh_health_server_callback(&param, ESP_BLE_MESH_HEALTH_SERVER_ATTENTION_OFF_EVT);
}

View file

@ -31,6 +31,7 @@
#include "mesh_proxy.h"
#include "cfg_cli.h"
#include "health_cli.h"
#include "health_srv.h"
#include "mesh.h"
#include "access.h"
@ -975,6 +976,13 @@ static void btc_ble_mesh_model_op_add(esp_ble_mesh_model_t *model)
}
case BLE_MESH_MODEL_ID_HEALTH_SRV: {
model->op = (esp_ble_mesh_model_op_t *)bt_mesh_health_srv_op;
struct bt_mesh_health_srv *srv = (struct bt_mesh_health_srv *)model->user_data;
if (srv) {
srv->cb.fault_clear = btc_ble_mesh_health_server_fault_clear;
srv->cb.fault_test = btc_ble_mesh_health_server_fault_test;
srv->cb.attn_on = btc_ble_mesh_health_server_attention_on;
srv->cb.attn_off = btc_ble_mesh_health_server_attention_off;
}
break;
}
case BLE_MESH_MODEL_ID_HEALTH_CLI: {

View file

@ -68,7 +68,7 @@ typedef enum {
typedef union {
struct ble_mesh_health_server_fault_update_args {
esp_ble_mesh_elem_t *element;
} fault_update;
} health_fault_update;
} btc_ble_mesh_health_server_args_t;
void btc_ble_mesh_health_server_call_handler(btc_msg_t *msg);
@ -77,4 +77,12 @@ void btc_ble_mesh_health_server_cb_handler(btc_msg_t *msg);
void btc_ble_mesh_health_server_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
void btc_ble_mesh_health_server_fault_clear(struct bt_mesh_model *model, u16_t company_id);
void btc_ble_mesh_health_server_fault_test(struct bt_mesh_model *model, u8_t test_id, u16_t company_id);
void btc_ble_mesh_health_server_attention_on(struct bt_mesh_model *model, u8_t time);
void btc_ble_mesh_health_server_attention_off(struct bt_mesh_model *model);
#endif /* _BTC_BLE_MESH_HEALTH_MODEL_H_ */

View file

@ -27,130 +27,112 @@
#include "foundation.h"
#include "mesh_common.h"
#define HEALTH_TEST_STANDARD 0x00
#include "btc_ble_mesh_health_model.h"
/* Maximum message length is 384 in BLE Mesh. Here for health fault status,
* due to 1 octet opcode and 4 octets TransMIC, 379 octets can be used to
* store health fault status.
*/
#define HEALTH_FAULT_MAX_LEN 379
#define HEALTH_TEST_STANDARD 0x00
#define HEALTH_NO_FAULT 0x00
/* Health Server context of the primary element */
struct bt_mesh_health_srv *health_srv;
static void health_get_registered(struct bt_mesh_model *mod,
u16_t company_id,
struct net_buf_simple *msg)
/**
* When an Element receives a Health Fault Get, or a Health Fault Test, or
* a Health Fault Test Unacknowledged, or a Health Fault Clear, or a Health
* Fault Clear Unacknowledged message that is not successfully processed
* (i.e. the Company ID field that does not identify any Health Fault state
* present in the node), it shall ignore the message.
* The Health Fault state is identified by Company ID and may be present in
* the node for more than one Company ID.
*/
static u8_t health_get_curr_fault_count(struct bt_mesh_model *model)
{
struct bt_mesh_health_srv *srv = mod->user_data;
u8_t *test_id;
struct bt_mesh_health_srv *srv = model->user_data;
u8_t count = 0;
size_t i;
BT_DBG("Company ID 0x%04x", company_id);
if (!srv) {
BT_ERR("%s, No Health Server context provided", __func__);
return;
for (i = 0U; i < ARRAY_SIZE(srv->test.curr_faults); i++) {
if (srv->test.curr_faults[i] != HEALTH_NO_FAULT) {
count++;
}
}
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS);
return count;
}
test_id = net_buf_simple_add(msg, 1);
net_buf_simple_add_le16(msg, company_id);
static void health_get_fault_value(struct bt_mesh_model *model,
struct net_buf_simple *msg,
bool current)
{
struct bt_mesh_health_srv *srv = model->user_data;
size_t array_size;
size_t i;
if (srv->cb && srv->cb->fault_get_reg) {
u8_t fault_count = net_buf_simple_tailroom(msg) - 4;
int err;
array_size = current ? ARRAY_SIZE(srv->test.curr_faults) : ARRAY_SIZE(srv->test.reg_faults);
err = srv->cb->fault_get_reg(mod, company_id, test_id,
net_buf_simple_tail(msg),
&fault_count);
if (err) {
BT_ERR("%s, Failed to get faults (err %d)", __func__, err);
*test_id = HEALTH_TEST_STANDARD;
} else {
net_buf_simple_add(msg, fault_count);
for (i = 0U; i < array_size; i++) {
if (net_buf_simple_tailroom(msg) == 0) {
return;
}
u8_t fault = current ? srv->test.curr_faults[i] : srv->test.reg_faults[i];
if (fault != HEALTH_NO_FAULT) {
net_buf_simple_add_u8(msg, fault);
}
} else {
BT_WARN("No callback for getting faults");
*test_id = HEALTH_TEST_STANDARD;
}
}
static size_t health_get_current(struct bt_mesh_model *mod,
struct net_buf_simple *msg)
static bool health_is_test_id_exist(struct bt_mesh_model *model, u8_t test_id)
{
struct bt_mesh_health_srv *srv = mod->user_data;
const struct bt_mesh_comp *comp;
u8_t *test_id, *company_ptr;
u16_t company_id;
u8_t fault_count;
struct bt_mesh_health_srv *srv = model->user_data;
u8_t i;
for (i = 0U; i < srv->test.id_count; i++) {
if (srv->test.test_ids[i] == test_id) {
return true;
}
}
return false;
}
static int health_send_fault_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
struct bt_mesh_health_srv *srv = model->user_data;
struct net_buf_simple *msg = NULL;
int err;
if (!srv) {
BT_ERR("%s, No Health Server context provided", __func__);
return 0;
msg = bt_mesh_alloc_buf(4 + ARRAY_SIZE(srv->test.reg_faults) + 4);
if (!msg) {
BT_ERR("%s, Failed to allocate memory", __func__);
return -ENOMEM;
}
bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS);
test_id = net_buf_simple_add(msg, 1);
company_ptr = net_buf_simple_add(msg, sizeof(company_id));
comp = bt_mesh_comp_get();
if (srv->cb && srv->cb->fault_get_cur) {
fault_count = net_buf_simple_tailroom(msg);
err = srv->cb->fault_get_cur(mod, test_id, &company_id,
net_buf_simple_tail(msg),
&fault_count);
if (err) {
BT_ERR("%s, Failed to get faults (err %d)", __func__, err);
sys_put_le16(comp->cid, company_ptr);
*test_id = HEALTH_TEST_STANDARD;
fault_count = 0U;
} else {
sys_put_le16(company_id, company_ptr);
net_buf_simple_add(msg, fault_count);
}
} else {
BT_WARN("No callback for getting faults");
sys_put_le16(comp->cid, company_ptr);
*test_id = HEALTH_TEST_STANDARD;
fault_count = 0U;
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS);
net_buf_simple_add_u8(msg, srv->test.prev_test_id);
net_buf_simple_add_le16(msg, srv->test.company_id);
if (ctx->recv_op != OP_HEALTH_FAULT_CLEAR) {
/**
* For Health Fault Clear, the FaultArray field in Health Fault Status
* shall be empty.
*/
health_get_fault_value(model, msg, false);
}
return fault_count;
err = bt_mesh_model_send(model, ctx, msg, NULL, NULL);
if (err) {
BT_ERR("%s, Failed to send Health Fault Status response", __func__);
}
bt_mesh_free_buf(msg);
return err;
}
static void health_fault_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *sdu = NULL;
u16_t company_id;
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("company_id 0x%04x", company_id);
sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, HEALTH_FAULT_MAX_LEN));
if (!sdu) {
BT_ERR("%s, Failed to allocate memory", __func__);
return;
}
health_get_registered(model, company_id, sdu);
if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) {
BT_ERR("%s, Unable to send Health Current Status", __func__);
}
bt_mesh_free_buf(sdu);
return;
}
static void health_fault_clear_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
@ -161,12 +143,14 @@ static void health_fault_clear_unrel(struct bt_mesh_model *model,
}
company_id = net_buf_simple_pull_le16(buf);
if (company_id != srv->test.company_id) {
BT_ERR("%s, Unknown Company ID 0x%04x", __func__, company_id);
return;
}
BT_DBG("company_id 0x%04x", company_id);
if (srv->cb && srv->cb->fault_clear) {
srv->cb->fault_clear(model, company_id);
}
health_send_fault_status(model, ctx);
}
static void health_fault_clear(struct bt_mesh_model *model,
@ -174,7 +158,6 @@ static void health_fault_clear(struct bt_mesh_model *model,
struct net_buf_simple *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
struct net_buf_simple *sdu = NULL;
u16_t company_id;
if (!srv) {
@ -183,49 +166,21 @@ static void health_fault_clear(struct bt_mesh_model *model,
}
company_id = net_buf_simple_pull_le16(buf);
if (company_id != srv->test.company_id) {
BT_ERR("%s, Unknown Company ID 0x%04x", __func__, company_id);
return;
}
BT_DBG("company_id 0x%04x", company_id);
if (srv->cb && srv->cb->fault_clear) {
srv->cb->fault_clear(model, company_id);
memset(srv->test.reg_faults, HEALTH_NO_FAULT, ARRAY_SIZE(srv->test.reg_faults));
if (srv->cb.fault_clear) {
srv->cb.fault_clear(model, company_id);
}
sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, HEALTH_FAULT_MAX_LEN));
if (!sdu) {
BT_ERR("%s, Failed to allocate memory", __func__);
return;
}
health_get_registered(model, company_id, sdu);
if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) {
BT_ERR("%s, Unable to send Health Current Status", __func__);
}
bt_mesh_free_buf(sdu);
return;
}
static void health_fault_test_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
u8_t test_id;
if (!srv) {
BT_ERR("%s, No Health Server context provided", __func__);
return;
}
test_id = net_buf_simple_pull_u8(buf);
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("test 0x%02x company 0x%04x", test_id, company_id);
if (srv->cb && srv->cb->fault_test) {
srv->cb->fault_test(model, test_id, company_id);
if (ctx->recv_op == OP_HEALTH_FAULT_CLEAR) {
health_send_fault_status(model, ctx);
}
}
@ -234,7 +189,6 @@ static void health_fault_test(struct bt_mesh_model *model,
struct net_buf_simple *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
struct net_buf_simple *sdu = NULL;
u16_t company_id;
u8_t test_id;
@ -246,34 +200,28 @@ static void health_fault_test(struct bt_mesh_model *model,
}
test_id = net_buf_simple_pull_u8(buf);
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("test 0x%02x company 0x%04x", test_id, company_id);
if (srv->cb && srv->cb->fault_test) {
int err;
err = srv->cb->fault_test(model, test_id, company_id);
if (err) {
BT_WARN("Running fault test failed with err %d", err);
return;
}
}
sdu = bt_mesh_alloc_buf(MIN(BLE_MESH_TX_SDU_MAX, HEALTH_FAULT_MAX_LEN));
if (!sdu) {
BT_ERR("%s, Failed to allocate memory", __func__);
if (health_is_test_id_exist(model, test_id) == false) {
BT_ERR("%s, Unknown Test ID 0x%02x", __func__, test_id);
return;
}
health_get_registered(model, company_id, sdu);
if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) {
BT_ERR("%s, Unable to send Health Current Status", __func__);
company_id = net_buf_simple_pull_le16(buf);
if (company_id != srv->test.company_id) {
BT_ERR("%s, Unknown Company ID 0x%04x", __func__, company_id);
return;
}
bt_mesh_free_buf(sdu);
return;
BT_DBG("test 0x%02x company 0x%04x", test_id, company_id);
srv->test.prev_test_id = test_id;
if (srv->cb.fault_test) {
srv->cb.fault_test(model, test_id, company_id);
}
if (ctx->recv_op == OP_HEALTH_FAULT_TEST) {
health_send_fault_status(model, ctx);
}
}
static void send_attention_status(struct bt_mesh_model *model,
@ -293,7 +241,6 @@ static void send_attention_status(struct bt_mesh_model *model,
BT_DBG("%u second%s", time, (time == 1U) ? "" : "s");
bt_mesh_model_msg_init(&msg, OP_ATTENTION_STATUS);
net_buf_simple_add_u8(&msg, time);
if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
@ -310,9 +257,9 @@ static void attention_get(struct bt_mesh_model *model,
send_attention_status(model, ctx);
}
static void attention_set_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
static void health_set_attention(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
u8_t time;
@ -329,9 +276,11 @@ static void attention_set(struct bt_mesh_model *model,
{
BT_DBG("%s", __func__);
attention_set_unrel(model, ctx, buf);
health_set_attention(model, ctx, buf);
send_attention_status(model, ctx);
if (ctx->recv_op == OP_ATTENTION_SET) {
send_attention_status(model, ctx);
}
}
static void send_health_period_status(struct bt_mesh_model *model,
@ -341,7 +290,6 @@ static void send_health_period_status(struct bt_mesh_model *model,
NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4);
bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_STATUS);
net_buf_simple_add_u8(&msg, model->pub->period_div);
if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
@ -358,9 +306,9 @@ static void health_period_get(struct bt_mesh_model *model,
send_health_period_status(model, ctx);
}
static void health_period_set_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
static void health_set_period(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
u8_t period;
@ -381,34 +329,64 @@ static void health_period_set(struct bt_mesh_model *model,
{
BT_DBG("%s", __func__);
health_period_set_unrel(model, ctx, buf);
health_set_period(model, ctx, buf);
send_health_period_status(model, ctx);
if (ctx->recv_op == OP_HEALTH_PERIOD_SET) {
send_health_period_status(model, ctx);
}
}
const struct bt_mesh_model_op bt_mesh_health_srv_op[] = {
{ OP_HEALTH_FAULT_GET, 2, health_fault_get },
{ OP_HEALTH_FAULT_GET, 2, health_fault_get },
{ OP_HEALTH_FAULT_CLEAR, 2, health_fault_clear },
{ OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear_unrel },
{ OP_HEALTH_FAULT_TEST, 3, health_fault_test },
{ OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test_unrel },
{ OP_HEALTH_PERIOD_GET, 0, health_period_get },
{ OP_HEALTH_PERIOD_SET, 1, health_period_set },
{ OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set_unrel },
{ OP_ATTENTION_GET, 0, attention_get },
{ OP_ATTENTION_SET, 1, attention_set },
{ OP_ATTENTION_SET_UNREL, 1, attention_set_unrel },
{ OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear },
{ OP_HEALTH_FAULT_TEST, 3, health_fault_test },
{ OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test },
{ OP_HEALTH_PERIOD_GET, 0, health_period_get },
{ OP_HEALTH_PERIOD_SET, 1, health_period_set },
{ OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set },
{ OP_ATTENTION_GET, 0, attention_get },
{ OP_ATTENTION_SET, 1, attention_set },
{ OP_ATTENTION_SET_UNREL, 1, attention_set },
BLE_MESH_MODEL_OP_END,
};
static int health_pub_update(struct bt_mesh_model *mod)
static size_t health_get_current(struct bt_mesh_model *model,
struct net_buf_simple *msg)
{
struct bt_mesh_model_pub *pub = mod->pub;
struct bt_mesh_health_srv *srv = model->user_data;
if (!srv) {
BT_ERR("%s, No Health Server context provided", __func__);
return 0;
}
if (msg->size < 4) {
BT_ERR("%s, Too small health publication msg size %d", __func__, msg->size);
return 0;
}
bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS);
net_buf_simple_add_u8(msg, srv->test.prev_test_id);
net_buf_simple_add_le16(msg, srv->test.company_id);
health_get_fault_value(model, msg, true);
return health_get_curr_fault_count(model);
}
static int health_pub_update(struct bt_mesh_model *model)
{
struct bt_mesh_model_pub *pub = model->pub;
size_t count;
BT_DBG("%s", __func__);
count = health_get_current(mod, pub->msg);
if (!pub || !pub->msg) {
BT_ERR("%s, Invalid health publication context", __func__);
return -EINVAL;
}
count = health_get_current(model, pub->msg);
if (count) {
pub->fast_period = 1U;
} else {
@ -420,29 +398,29 @@ static int health_pub_update(struct bt_mesh_model *mod)
int bt_mesh_fault_update(struct bt_mesh_elem *elem)
{
struct bt_mesh_model *mod;
struct bt_mesh_model *model;
mod = bt_mesh_model_find(elem, BLE_MESH_MODEL_ID_HEALTH_SRV);
if (!mod) {
model = bt_mesh_model_find(elem, BLE_MESH_MODEL_ID_HEALTH_SRV);
if (!model) {
BT_ERR("%s, Health Server does not exist", __func__);
return -EINVAL;
}
if (!mod->pub) {
if (!model->pub) {
BT_ERR("%s, Health Server has no publication support", __func__);
return -EIO;
return -EINVAL;
}
/* Let periodic publishing, if enabled, take care of sending the
* Health Current Status.
*/
if (bt_mesh_model_pub_period_get(mod)) {
if (bt_mesh_model_pub_period_get(model)) {
return 0;
}
health_pub_update(mod);
health_pub_update(model);
return bt_mesh_model_publish(mod);
return bt_mesh_model_publish(model);
}
static void attention_off(struct k_work *work)
@ -457,17 +435,23 @@ static void attention_off(struct k_work *work)
return;
}
if (srv->cb && srv->cb->attn_off) {
srv->cb->attn_off(srv->model);
if (srv->cb.attn_off) {
srv->cb.attn_off(srv->model);
}
srv->attn_timer_start = false;
}
int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary)
{
struct bt_mesh_health_srv *srv = model->user_data;
/* Health Server Model shall be supported by a primary element and may be
* supported by any secondary elements.
*/
if (!srv) {
if (!primary) {
/* If Health Server is in the secondary element with NULL user_data. */
return 0;
}
@ -475,6 +459,11 @@ int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary)
return -EINVAL;
}
if (srv->test.id_count == 0 || !srv->test.test_ids) {
BT_ERR("%s, No Health Test ID provided", __func__);
return -EINVAL;
}
if (!model->pub) {
BT_ERR("%s, Health Server has no publication support", __func__);
return -EINVAL;
@ -485,6 +474,10 @@ int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary)
k_delayed_work_init(&srv->attn_timer, attention_off);
srv->model = model;
srv->attn_timer_start = false;
memset(srv->test.curr_faults, HEALTH_NO_FAULT, ARRAY_SIZE(srv->test.curr_faults));
memset(srv->test.reg_faults, HEALTH_NO_FAULT, ARRAY_SIZE(srv->test.reg_faults));
if (primary) {
health_srv = srv;
@ -514,16 +507,20 @@ void bt_mesh_attention(struct bt_mesh_model *model, u8_t time)
}
if (time) {
if (srv->cb && srv->cb->attn_on) {
srv->cb->attn_on(model);
if (srv->cb.attn_on) {
srv->cb.attn_on(model, time);
}
k_delayed_work_submit(&srv->attn_timer, time * 1000U);
srv->attn_timer_start = true;
} else {
k_delayed_work_cancel(&srv->attn_timer);
if (srv->cb && srv->cb->attn_off) {
srv->cb->attn_off(model);
if (srv->attn_timer_start == true) {
if (srv->cb.attn_off) {
srv->cb.attn_off(model);
}
srv->attn_timer_start = false;
}
}
}

View file

@ -21,25 +21,15 @@
*/
struct bt_mesh_health_srv_cb {
/* Fetch current faults */
int (*fault_get_cur)(struct bt_mesh_model *model, u8_t *test_id,
u16_t *company_id, u8_t *faults,
u8_t *fault_count);
/* Fetch registered faults */
int (*fault_get_reg)(struct bt_mesh_model *model, u16_t company_id,
u8_t *test_id, u8_t *faults,
u8_t *fault_count);
/* Clear registered faults */
int (*fault_clear)(struct bt_mesh_model *model, u16_t company_id);
void (*fault_clear)(struct bt_mesh_model *model, u16_t company_id);
/* Run a specific test */
int (*fault_test)(struct bt_mesh_model *model, u8_t test_id,
u16_t company_id);
void (*fault_test)(struct bt_mesh_model *model, u8_t test_id,
u16_t company_id);
/* Attention on */
void (*attn_on)(struct bt_mesh_model *model);
void (*attn_on)(struct bt_mesh_model *model, u8_t time);
/* Attention off */
void (*attn_off)(struct bt_mesh_model *model);
@ -55,15 +45,30 @@ struct bt_mesh_health_srv_cb {
#define BLE_MESH_HEALTH_PUB_DEFINE(_name, _max_faults) \
BLE_MESH_MODEL_PUB_DEFINE(_name, NULL, (1 + 3 + (_max_faults)))
struct bt_mesh_health_test {
u8_t id_count; /* Number of Health self-test ID */
const u8_t *test_ids; /* Array of Health self-test IDs */
u16_t company_id; /* Company ID used to identify the Health Fault state */
u8_t prev_test_id; /* Most currently performed test id */
u8_t curr_faults[32]; /* Array of current faults */
u8_t reg_faults[32]; /* Array of registered faults */
} __attribute__((packed));
/** Mesh Health Server Model Context */
struct bt_mesh_health_srv {
struct bt_mesh_model *model;
/* Optional callback struct */
const struct bt_mesh_health_srv_cb *cb;
struct bt_mesh_health_srv_cb cb;
/* Attention Timer state */
struct k_delayed_work attn_timer;
/* Attention Timer start flag */
bool attn_timer_start;
/* Health Server fault test */
struct bt_mesh_health_test test;
};
extern const struct bt_mesh_model_op bt_mesh_health_srv_op[];