Move the TAG definition of each example to the corresponding source file (previously it is defined in the common example intialization header file), which can avoid the redefinition of TAG in some situations.
642 lines
26 KiB
C
642 lines
26 KiB
C
/* main.c - Application main entry point */
|
|
|
|
/*
|
|
* Copyright (c) 2017 Intel Corporation
|
|
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "esp_log.h"
|
|
#include "nvs_flash.h"
|
|
|
|
#include "esp_ble_mesh_defs.h"
|
|
#include "esp_ble_mesh_common_api.h"
|
|
#include "esp_ble_mesh_networking_api.h"
|
|
#include "esp_ble_mesh_provisioning_api.h"
|
|
#include "esp_ble_mesh_config_model_api.h"
|
|
#include "esp_ble_mesh_sensor_model_api.h"
|
|
|
|
#include "ble_mesh_example_init.h"
|
|
#include "board.h"
|
|
|
|
#define TAG "EXAMPLE"
|
|
|
|
#define CID_ESP 0x02E5
|
|
|
|
/* Sensor Property ID */
|
|
#define SENSOR_PROPERTY_ID_0 0x0056 /* Present Indoor Ambient Temperature */
|
|
#define SENSOR_PROPERTY_ID_1 0x005B /* Present Outdoor Ambient Temperature */
|
|
|
|
/* The characteristic of the two device properties is "Temperature 8", which is
|
|
* used to represent a measure of temperature with a unit of 0.5 degree Celsius.
|
|
* Minimum value: -64.0, maximum value: 63.5.
|
|
* A value of 0xFF represents 'value is not known'.
|
|
*/
|
|
static int8_t indoor_temp = 40; /* Indoor temperature is 20 Degrees Celsius */
|
|
static int8_t outdoor_temp = 60; /* Outdoor temperature is 30 Degrees Celsius */
|
|
|
|
#define SENSOR_POSITIVE_TOLERANCE ESP_BLE_MESH_SENSOR_UNSPECIFIED_POS_TOLERANCE
|
|
#define SENSOR_NEGATIVE_TOLERANCE ESP_BLE_MESH_SENSOR_UNSPECIFIED_NEG_TOLERANCE
|
|
#define SENSOR_SAMPLE_FUNCTION ESP_BLE_MESH_SAMPLE_FUNC_UNSPECIFIED
|
|
#define SENSOR_MEASURE_PERIOD ESP_BLE_MESH_SENSOR_NOT_APPL_MEASURE_PERIOD
|
|
#define SENSOR_UPDATE_INTERVAL ESP_BLE_MESH_SENSOR_NOT_APPL_UPDATE_INTERVAL
|
|
|
|
static uint8_t dev_uuid[ESP_BLE_MESH_OCTET16_LEN] = { 0x32, 0x10 };
|
|
|
|
static esp_ble_mesh_cfg_srv_t config_server = {
|
|
.relay = ESP_BLE_MESH_RELAY_ENABLED,
|
|
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
|
|
#if defined(CONFIG_BLE_MESH_FRIEND)
|
|
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
|
|
#else
|
|
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
|
|
#endif
|
|
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
|
|
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
|
|
#else
|
|
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
|
|
#endif
|
|
.default_ttl = 7,
|
|
/* 3 transmissions with 20ms interval */
|
|
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
|
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
|
};
|
|
|
|
NET_BUF_SIMPLE_DEFINE_STATIC(sensor_data_0, 1);
|
|
NET_BUF_SIMPLE_DEFINE_STATIC(sensor_data_1, 1);
|
|
|
|
static esp_ble_mesh_sensor_state_t sensor_states[2] = {
|
|
/* Mesh Model Spec:
|
|
* Multiple instances of the Sensor states may be present within the same model,
|
|
* provided that each instance has a unique value of the Sensor Property ID to
|
|
* allow the instances to be differentiated. Such sensors are known as multisensors.
|
|
* In this example, two instances of the Sensor states within the same model are
|
|
* provided.
|
|
*/
|
|
[0] = {
|
|
/* Mesh Model Spec:
|
|
* Sensor Property ID is a 2-octet value referencing a device property
|
|
* that describes the meaning and format of data reported by a sensor.
|
|
* 0x0000 is prohibited.
|
|
*/
|
|
.sensor_property_id = SENSOR_PROPERTY_ID_0,
|
|
/* Mesh Model Spec:
|
|
* Sensor Descriptor state represents the attributes describing the sensor
|
|
* data. This state does not change throughout the lifetime of an element.
|
|
*/
|
|
.descriptor.positive_tolerance = SENSOR_POSITIVE_TOLERANCE,
|
|
.descriptor.negative_tolerance = SENSOR_NEGATIVE_TOLERANCE,
|
|
.descriptor.sampling_function = SENSOR_SAMPLE_FUNCTION,
|
|
.descriptor.measure_period = SENSOR_MEASURE_PERIOD,
|
|
.descriptor.update_interval = SENSOR_UPDATE_INTERVAL,
|
|
.sensor_data.format = ESP_BLE_MESH_SENSOR_DATA_FORMAT_A,
|
|
.sensor_data.length = 0, /* 0 represents the length is 1 */
|
|
.sensor_data.raw_value = &sensor_data_0,
|
|
},
|
|
[1] = {
|
|
.sensor_property_id = SENSOR_PROPERTY_ID_1,
|
|
.descriptor.positive_tolerance = SENSOR_POSITIVE_TOLERANCE,
|
|
.descriptor.negative_tolerance = SENSOR_NEGATIVE_TOLERANCE,
|
|
.descriptor.sampling_function = SENSOR_SAMPLE_FUNCTION,
|
|
.descriptor.measure_period = SENSOR_MEASURE_PERIOD,
|
|
.descriptor.update_interval = SENSOR_UPDATE_INTERVAL,
|
|
.sensor_data.format = ESP_BLE_MESH_SENSOR_DATA_FORMAT_A,
|
|
.sensor_data.length = 0, /* 0 represents the length is 1 */
|
|
.sensor_data.raw_value = &sensor_data_1,
|
|
},
|
|
};
|
|
|
|
/* 20 octets is large enough to hold two Sensor Descriptor state values. */
|
|
ESP_BLE_MESH_MODEL_PUB_DEFINE(sensor_pub, 20, ROLE_NODE);
|
|
static esp_ble_mesh_sensor_srv_t sensor_server = {
|
|
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
|
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
|
.state_count = ARRAY_SIZE(sensor_states),
|
|
.states = sensor_states,
|
|
};
|
|
|
|
ESP_BLE_MESH_MODEL_PUB_DEFINE(sensor_setup_pub, 20, ROLE_NODE);
|
|
static esp_ble_mesh_sensor_setup_srv_t sensor_setup_server = {
|
|
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
|
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
|
.state_count = ARRAY_SIZE(sensor_states),
|
|
.states = sensor_states,
|
|
};
|
|
|
|
static esp_ble_mesh_model_t root_models[] = {
|
|
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
|
|
ESP_BLE_MESH_MODEL_SENSOR_SRV(&sensor_pub, &sensor_server),
|
|
ESP_BLE_MESH_MODEL_SENSOR_SETUP_SRV(&sensor_setup_pub, &sensor_setup_server),
|
|
};
|
|
|
|
static esp_ble_mesh_elem_t elements[] = {
|
|
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
|
|
};
|
|
|
|
static esp_ble_mesh_comp_t composition = {
|
|
.cid = CID_ESP,
|
|
.elements = elements,
|
|
.element_count = ARRAY_SIZE(elements),
|
|
};
|
|
|
|
static esp_ble_mesh_prov_t provision = {
|
|
.uuid = dev_uuid,
|
|
};
|
|
|
|
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
|
|
{
|
|
ESP_LOGI(TAG, "net_idx 0x%03x, addr 0x%04x", net_idx, addr);
|
|
ESP_LOGI(TAG, "flags 0x%02x, iv_index 0x%08x", flags, iv_index);
|
|
board_led_operation(LED_G, LED_OFF);
|
|
|
|
/* Initialize the indoor and outdoor temperatures for each sensor. */
|
|
net_buf_simple_add_u8(&sensor_data_0, indoor_temp);
|
|
net_buf_simple_add_u8(&sensor_data_1, outdoor_temp);
|
|
}
|
|
|
|
static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
|
|
esp_ble_mesh_prov_cb_param_t *param)
|
|
{
|
|
switch (event) {
|
|
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
|
|
param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
|
break;
|
|
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
|
|
param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
|
break;
|
|
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
|
|
prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
|
|
param->node_prov_complete.flags, param->node_prov_complete.iv_index);
|
|
break;
|
|
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_RESET_EVT");
|
|
break;
|
|
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
|
|
esp_ble_mesh_cfg_server_cb_param_t *param)
|
|
{
|
|
if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) {
|
|
switch (param->ctx.recv_op) {
|
|
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD");
|
|
ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x",
|
|
param->value.state_change.appkey_add.net_idx,
|
|
param->value.state_change.appkey_add.app_idx);
|
|
ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND");
|
|
ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
|
param->value.state_change.mod_app_bind.element_addr,
|
|
param->value.state_change.mod_app_bind.app_idx,
|
|
param->value.state_change.mod_app_bind.company_id,
|
|
param->value.state_change.mod_app_bind.model_id);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD");
|
|
ESP_LOGI(TAG, "elem_addr 0x%04x, sub_addr 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
|
param->value.state_change.mod_sub_add.element_addr,
|
|
param->value.state_change.mod_sub_add.sub_addr,
|
|
param->value.state_change.mod_sub_add.company_id,
|
|
param->value.state_change.mod_sub_add.model_id);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct example_sensor_descriptor {
|
|
uint16_t sensor_prop_id;
|
|
uint32_t pos_tolerance:12,
|
|
neg_tolerance:12,
|
|
sample_func:8;
|
|
uint8_t measure_period;
|
|
uint8_t update_interval;
|
|
} __attribute__((packed));
|
|
|
|
static void example_ble_mesh_send_sensor_descriptor_status(esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
struct example_sensor_descriptor descriptor = {0};
|
|
uint8_t *status = NULL;
|
|
uint16_t length = 0;
|
|
esp_err_t err;
|
|
int i;
|
|
|
|
status = calloc(1, ARRAY_SIZE(sensor_states) * ESP_BLE_MESH_SENSOR_DESCRIPTOR_LEN);
|
|
if (!status) {
|
|
ESP_LOGE(TAG, "No memory for sensor descriptor status!");
|
|
return;
|
|
}
|
|
|
|
if (param->value.get.sensor_descriptor.op_en == false) {
|
|
/* Mesh Model Spec:
|
|
* Upon receiving a Sensor Descriptor Get message with the Property ID field
|
|
* omitted, the Sensor Server shall respond with a Sensor Descriptor Status
|
|
* message containing the Sensor Descriptor states for all sensors within the
|
|
* Sensor Server.
|
|
*/
|
|
for (i = 0; i < ARRAY_SIZE(sensor_states); i++) {
|
|
descriptor.sensor_prop_id = sensor_states[i].sensor_property_id;
|
|
descriptor.pos_tolerance = sensor_states[i].descriptor.positive_tolerance;
|
|
descriptor.neg_tolerance = sensor_states[i].descriptor.negative_tolerance;
|
|
descriptor.sample_func = sensor_states[i].descriptor.sampling_function;
|
|
descriptor.measure_period = sensor_states[i].descriptor.measure_period;
|
|
descriptor.update_interval = sensor_states[i].descriptor.update_interval;
|
|
memcpy(status + length, &descriptor, ESP_BLE_MESH_SENSOR_DESCRIPTOR_LEN);
|
|
length += ESP_BLE_MESH_SENSOR_DESCRIPTOR_LEN;
|
|
}
|
|
goto send;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sensor_states); i++) {
|
|
if (param->value.get.sensor_descriptor.property_id == sensor_states[i].sensor_property_id) {
|
|
descriptor.sensor_prop_id = sensor_states[i].sensor_property_id;
|
|
descriptor.pos_tolerance = sensor_states[i].descriptor.positive_tolerance;
|
|
descriptor.neg_tolerance = sensor_states[i].descriptor.negative_tolerance;
|
|
descriptor.sample_func = sensor_states[i].descriptor.sampling_function;
|
|
descriptor.measure_period = sensor_states[i].descriptor.measure_period;
|
|
descriptor.update_interval = sensor_states[i].descriptor.update_interval;
|
|
memcpy(status, &descriptor, ESP_BLE_MESH_SENSOR_DESCRIPTOR_LEN);
|
|
length = ESP_BLE_MESH_SENSOR_DESCRIPTOR_LEN;
|
|
goto send;
|
|
}
|
|
}
|
|
|
|
/* Mesh Model Spec:
|
|
* When a Sensor Descriptor Get message that identifies a sensor descriptor
|
|
* property that does not exist on the element, the Descriptor field shall
|
|
* contain the requested Property ID value and the other fields of the Sensor
|
|
* Descriptor state shall be omitted.
|
|
*/
|
|
memcpy(status, ¶m->value.get.sensor_descriptor.property_id, ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN);
|
|
length = ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN;
|
|
|
|
send:
|
|
ESP_LOG_BUFFER_HEX("Sensor Descriptor", status, length);
|
|
|
|
err = esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx,
|
|
ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_STATUS, length, status);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Sensor Descriptor Status");
|
|
}
|
|
free(status);
|
|
}
|
|
|
|
static void example_ble_mesh_send_sensor_cadence_status(esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
esp_err_t err;
|
|
|
|
/* Sensor Cadence state is not supported currently. */
|
|
err = esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx,
|
|
ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_STATUS,
|
|
ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN,
|
|
(uint8_t *)¶m->value.get.sensor_cadence.property_id);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Sensor Cadence Status");
|
|
}
|
|
}
|
|
|
|
static void example_ble_mesh_send_sensor_settings_status(esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
esp_err_t err;
|
|
|
|
/* Sensor Setting state is not supported currently. */
|
|
err = esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx,
|
|
ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_STATUS,
|
|
ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN,
|
|
(uint8_t *)¶m->value.get.sensor_settings.property_id);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Sensor Settings Status");
|
|
}
|
|
}
|
|
|
|
struct example_sensor_setting {
|
|
uint16_t sensor_prop_id;
|
|
uint16_t sensor_setting_prop_id;
|
|
} __attribute__((packed));
|
|
|
|
static void example_ble_mesh_send_sensor_setting_status(esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
struct example_sensor_setting setting = {0};
|
|
esp_err_t err;
|
|
|
|
/* Mesh Model Spec:
|
|
* If the message is sent as a response to the Sensor Setting Get message or
|
|
* a Sensor Setting Set message with an unknown Sensor Property ID field or
|
|
* an unknown Sensor Setting Property ID field, the Sensor Setting Access
|
|
* field and the Sensor Setting Raw field shall be omitted.
|
|
*/
|
|
|
|
setting.sensor_prop_id = param->value.get.sensor_setting.property_id;
|
|
setting.sensor_setting_prop_id = param->value.get.sensor_setting.setting_property_id;
|
|
|
|
err = esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx,
|
|
ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_STATUS,
|
|
sizeof(setting), (uint8_t *)&setting);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Sensor Setting Status");
|
|
}
|
|
}
|
|
|
|
static uint16_t example_ble_mesh_get_sensor_data(esp_ble_mesh_sensor_state_t *state, uint8_t *data)
|
|
{
|
|
uint8_t mpid_len = 0, data_len = 0;
|
|
uint32_t mpid = 0;
|
|
|
|
if (state == NULL || data == NULL) {
|
|
ESP_LOGE(TAG, "%s, Invalid parameter", __func__);
|
|
return 0;
|
|
}
|
|
|
|
if (state->sensor_data.length == ESP_BLE_MESH_SENSOR_DATA_ZERO_LEN) {
|
|
/* For zero-length sensor data, the length is 0x7F, and the format is Format B. */
|
|
mpid = ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID(state->sensor_data.length, state->sensor_property_id);
|
|
mpid_len = ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID_LEN;
|
|
data_len = 0;
|
|
} else {
|
|
if (state->sensor_data.format == ESP_BLE_MESH_SENSOR_DATA_FORMAT_A) {
|
|
mpid = ESP_BLE_MESH_SENSOR_DATA_FORMAT_A_MPID(state->sensor_data.length, state->sensor_property_id);
|
|
mpid_len = ESP_BLE_MESH_SENSOR_DATA_FORMAT_A_MPID_LEN;
|
|
} else {
|
|
mpid = ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID(state->sensor_data.length, state->sensor_property_id);
|
|
mpid_len = ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID_LEN;
|
|
}
|
|
/* Use "state->sensor_data.length + 1" because the length of sensor data is zero-based. */
|
|
data_len = state->sensor_data.length + 1;
|
|
}
|
|
|
|
memcpy(data, &mpid, mpid_len);
|
|
memcpy(data + mpid_len, state->sensor_data.raw_value->data, data_len);
|
|
|
|
return (mpid_len + data_len);
|
|
}
|
|
|
|
static void example_ble_mesh_send_sensor_status(esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
uint8_t *status = NULL;
|
|
uint16_t buf_size = 0;
|
|
uint16_t length = 0;
|
|
uint32_t mpid = 0;
|
|
esp_err_t err;
|
|
int i;
|
|
|
|
/**
|
|
* Sensor Data state from Mesh Model Spec
|
|
* |--------Field--------|-Size (octets)-|------------------------Notes-------------------------|
|
|
* |----Property ID 1----|-------2-------|--ID of the 1st device property of the sensor---------|
|
|
* |-----Raw Value 1-----|----variable---|--Raw Value field defined by the 1st device property--|
|
|
* |----Property ID 2----|-------2-------|--ID of the 2nd device property of the sensor---------|
|
|
* |-----Raw Value 2-----|----variable---|--Raw Value field defined by the 2nd device property--|
|
|
* | ...... |
|
|
* |----Property ID n----|-------2-------|--ID of the nth device property of the sensor---------|
|
|
* |-----Raw Value n-----|----variable---|--Raw Value field defined by the nth device property--|
|
|
*/
|
|
for (i = 0; i < ARRAY_SIZE(sensor_states); i++) {
|
|
esp_ble_mesh_sensor_state_t *state = &sensor_states[i];
|
|
if (state->sensor_data.length == ESP_BLE_MESH_SENSOR_DATA_ZERO_LEN) {
|
|
buf_size += ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID_LEN;
|
|
} else {
|
|
/* Use "state->sensor_data.length + 1" because the length of sensor data is zero-based. */
|
|
if (state->sensor_data.format == ESP_BLE_MESH_SENSOR_DATA_FORMAT_A) {
|
|
buf_size += ESP_BLE_MESH_SENSOR_DATA_FORMAT_A_MPID_LEN + state->sensor_data.length + 1;
|
|
} else {
|
|
buf_size += ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID_LEN + state->sensor_data.length + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
status = calloc(1, buf_size);
|
|
if (!status) {
|
|
ESP_LOGE(TAG, "No memory for sensor status!");
|
|
return;
|
|
}
|
|
|
|
if (param->value.get.sensor_data.op_en == false) {
|
|
/* Mesh Model Spec:
|
|
* If the message is sent as a response to the Sensor Get message, and if the
|
|
* Property ID field of the incoming message is omitted, the Marshalled Sensor
|
|
* Data field shall contain data for all device properties within a sensor.
|
|
*/
|
|
for (i = 0; i < ARRAY_SIZE(sensor_states); i++) {
|
|
length += example_ble_mesh_get_sensor_data(&sensor_states[i], status + length);
|
|
}
|
|
goto send;
|
|
}
|
|
|
|
/* Mesh Model Spec:
|
|
* Otherwise, the Marshalled Sensor Data field shall contain data for the requested
|
|
* device property only.
|
|
*/
|
|
for (i = 0; i < ARRAY_SIZE(sensor_states); i++) {
|
|
if (param->value.get.sensor_data.property_id == sensor_states[i].sensor_property_id) {
|
|
length = example_ble_mesh_get_sensor_data(&sensor_states[i], status);
|
|
goto send;
|
|
}
|
|
}
|
|
|
|
/* Mesh Model Spec:
|
|
* Or the Length shall represent the value of zero and the Raw Value field shall
|
|
* contain only the Property ID if the requested device property is not recognized
|
|
* by the Sensor Server.
|
|
*/
|
|
mpid = ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID(ESP_BLE_MESH_SENSOR_DATA_ZERO_LEN,
|
|
param->value.get.sensor_data.property_id);
|
|
memcpy(status, &mpid, ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID_LEN);
|
|
length = ESP_BLE_MESH_SENSOR_DATA_FORMAT_B_MPID_LEN;
|
|
|
|
send:
|
|
ESP_LOG_BUFFER_HEX("Sensor Data", status, length);
|
|
|
|
err = esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx,
|
|
ESP_BLE_MESH_MODEL_OP_SENSOR_STATUS, length, status);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Sensor Status");
|
|
}
|
|
free(status);
|
|
}
|
|
|
|
static void example_ble_mesh_send_sensor_column_status(esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
uint8_t *status = NULL;
|
|
uint16_t length = 0;
|
|
esp_err_t err;
|
|
|
|
length = ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN +param->value.get.sensor_column.raw_value_x->len;
|
|
|
|
status = calloc(1, length);
|
|
if (!status) {
|
|
ESP_LOGE(TAG, "No memory for sensor column status!");
|
|
return;
|
|
}
|
|
|
|
memcpy(status, ¶m->value.get.sensor_column.property_id, ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN);
|
|
memcpy(status + ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN, param->value.get.sensor_column.raw_value_x->data,
|
|
param->value.get.sensor_column.raw_value_x->len);
|
|
|
|
err = esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx,
|
|
ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_STATUS, length, status);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Sensor Column Status");
|
|
}
|
|
free(status);
|
|
}
|
|
|
|
static void example_ble_mesh_send_sensor_series_status(esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
esp_err_t err;
|
|
|
|
err = esp_ble_mesh_server_model_send_msg(param->model, ¶m->ctx,
|
|
ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_STATUS,
|
|
ESP_BLE_MESH_SENSOR_PROPERTY_ID_LEN,
|
|
(uint8_t *)¶m->value.get.sensor_series.property_id);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Sensor Column Status");
|
|
}
|
|
}
|
|
|
|
static void example_ble_mesh_sensor_server_cb(esp_ble_mesh_sensor_server_cb_event_t event,
|
|
esp_ble_mesh_sensor_server_cb_param_t *param)
|
|
{
|
|
ESP_LOGI(TAG, "Sensor server, event %d, src 0x%04x, dst 0x%04x, model_id 0x%04x",
|
|
event, param->ctx.addr, param->ctx.recv_dst, param->model->model_id);
|
|
|
|
switch (event) {
|
|
case ESP_BLE_MESH_SENSOR_SERVER_RECV_GET_MSG_EVT:
|
|
switch (param->ctx.recv_op) {
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_DESCRIPTOR_GET");
|
|
example_ble_mesh_send_sensor_descriptor_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_GET");
|
|
example_ble_mesh_send_sensor_cadence_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET");
|
|
example_ble_mesh_send_sensor_settings_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_GET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_SETTINGS_GET");
|
|
example_ble_mesh_send_sensor_setting_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_GET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_GET");
|
|
example_ble_mesh_send_sensor_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_COLUMN_GET");
|
|
example_ble_mesh_send_sensor_column_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_SERIES_GET");
|
|
example_ble_mesh_send_sensor_series_status(param);
|
|
break;
|
|
default:
|
|
ESP_LOGE(TAG, "Unknown Sensor Get opcode 0x%04x", param->ctx.recv_op);
|
|
return;
|
|
}
|
|
break;
|
|
case ESP_BLE_MESH_SENSOR_SERVER_RECV_SET_MSG_EVT:
|
|
switch (param->ctx.recv_op) {
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET");
|
|
example_ble_mesh_send_sensor_cadence_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_CADENCE_SET_UNACK");
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET");
|
|
example_ble_mesh_send_sensor_setting_status(param);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_SENSOR_SETTING_SET_UNACK");
|
|
break;
|
|
default:
|
|
ESP_LOGE(TAG, "Unknown Sensor Set opcode 0x%04x", param->ctx.recv_op);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
ESP_LOGE(TAG, "Unknown Sensor Server event %d", event);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static esp_err_t ble_mesh_init(void)
|
|
{
|
|
esp_err_t err;
|
|
|
|
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
|
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
|
|
esp_ble_mesh_register_sensor_server_callback(example_ble_mesh_sensor_server_cb);
|
|
|
|
err = esp_ble_mesh_init(&provision, &composition);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to initialize mesh stack");
|
|
return err;
|
|
}
|
|
|
|
err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to enable mesh node");
|
|
return err;
|
|
}
|
|
|
|
board_led_operation(LED_G, LED_ON);
|
|
|
|
ESP_LOGI(TAG, "BLE Mesh sensor server initialized");
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
void app_main(void)
|
|
{
|
|
esp_err_t err;
|
|
|
|
ESP_LOGI(TAG, "Initializing...");
|
|
|
|
err = nvs_flash_init();
|
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
err = nvs_flash_init();
|
|
}
|
|
ESP_ERROR_CHECK(err);
|
|
|
|
board_init();
|
|
|
|
err = bluetooth_init();
|
|
if (err) {
|
|
ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
|
|
return;
|
|
}
|
|
|
|
ble_mesh_get_dev_uuid(dev_uuid);
|
|
|
|
/* Initialize the Bluetooth Mesh Subsystem */
|
|
err = ble_mesh_init();
|
|
if (err) {
|
|
ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
|
|
}
|
|
}
|