diff --git a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c index 4c32ab6d4..59e73c224 100644 --- a/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c @@ -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); diff --git a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h index b35cb0e0b..f0836756e 100644 --- a/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h @@ -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. * diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c index c728f135e..63cdb863c 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c @@ -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(¶m, 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(¶m, 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(¶m, 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(¶m, 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(¶m, ESP_BLE_MESH_HEALTH_SERVER_ATTENTION_OFF_EVT); +} diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 2dd68e2a4..1cb989a42 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -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: { diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h index d124c7d8e..5d0dcd25d 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h @@ -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_ */ diff --git a/components/bt/esp_ble_mesh/mesh_core/health_srv.c b/components/bt/esp_ble_mesh/mesh_core/health_srv.c index 96e16692d..344b62d10 100644 --- a/components/bt/esp_ble_mesh/mesh_core/health_srv.c +++ b/components/bt/esp_ble_mesh/mesh_core/health_srv.c @@ -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; } } } diff --git a/components/bt/esp_ble_mesh/mesh_core/include/health_srv.h b/components/bt/esp_ble_mesh/mesh_core/include/health_srv.h index 4e9b84077..0aa262153 100644 --- a/components/bt/esp_ble_mesh/mesh_core/include/health_srv.h +++ b/components/bt/esp_ble_mesh/mesh_core/include/health_srv.h @@ -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[];