Basic mesh implementation with on/off and level models.

This commit is contained in:
h2zero 2020-08-27 10:52:06 -06:00
parent e238a18a80
commit bc2cecd2db
10 changed files with 841 additions and 1 deletions

View file

@ -55,4 +55,3 @@ idf_component_register(
PRIV_REQUIRES PRIV_REQUIRES
${ESP_NIMBLE_PRIV_REQUIRES} ${ESP_NIMBLE_PRIV_REQUIRES}
) )

View file

@ -54,6 +54,8 @@ bool NimBLEDevice::m_synced = false;
NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr; NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
#endif #endif
NimBLEMeshNode* NimBLEDevice::m_pMeshNode = nullptr;
gap_event_handler NimBLEDevice::m_customGapHandler = nullptr; gap_event_handler NimBLEDevice::m_customGapHandler = nullptr;
ble_gap_event_listener NimBLEDevice::m_listener; ble_gap_event_listener NimBLEDevice::m_listener;
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL) #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
@ -67,6 +69,30 @@ uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN
uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE; uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
/**
* @brief Create a new mesh node.
* @param [in] uuid The uuid to advertise before being provisioned.
* @param [in] type A bitmask of the node type to create.
* @return A point to new instance of the mesh node.
*/
NimBLEMeshNode* NimBLEDevice::createMeshNode(NimBLEUUID uuid, uint8_t type) {
if(m_pMeshNode == nullptr) {
m_pMeshNode = new NimBLEMeshNode(uuid, type);
}
return m_pMeshNode;
}
/**
* @brief Get the mesh node instance.
* @return a pointer to the mesh node instance or nullptr if no node exists.
*/
NimBLEMeshNode* NimBLEDevice::getMeshNode() {
return m_pMeshNode;
}
/** /**
* @brief Create a new instance of a server. * @brief Create a new instance of a server.
* @return A new instance of the server. * @return A new instance of the server.

View file

@ -35,6 +35,8 @@
#include "NimBLEServer.h" #include "NimBLEServer.h"
#endif #endif
#include "NimBLEMeshNode.h"
#include "NimBLEUtils.h" #include "NimBLEUtils.h"
#include "NimBLESecurity.h" #include "NimBLESecurity.h"
#include "NimBLEAddress.h" #include "NimBLEAddress.h"
@ -110,6 +112,9 @@ public:
static NimBLEServer* getServer(); static NimBLEServer* getServer();
#endif #endif
static NimBLEMeshNode* createMeshNode(NimBLEUUID uuid, uint8_t type);
static NimBLEMeshNode* getMeshNode();
static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); static int getPower(esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT);
static void setCustomGapHandler(gap_event_handler handler); static void setCustomGapHandler(gap_event_handler handler);
@ -202,6 +207,7 @@ private:
static uint16_t m_scanDuplicateSize; static uint16_t m_scanDuplicateSize;
static uint8_t m_scanFilterMode; static uint8_t m_scanFilterMode;
static std::vector<NimBLEAddress> m_whiteList; static std::vector<NimBLEAddress> m_whiteList;
static NimBLEMeshNode* m_pMeshNode;
}; };

80
src/NimBLEMeshElement.cpp Normal file
View file

@ -0,0 +1,80 @@
/*
* NimBLEMeshElement.cpp
*
* Created: on Aug 23 2020
* Author H2zero
*
*/
#include "NimBLEMeshElement.h"
#include "NimBLELog.h"
static const char* LOG_TAG = "NimBLEMeshElement";
NimBLEMeshElement::NimBLEMeshElement() {
m_pElem = nullptr;
}
NimBLEMeshElement::~NimBLEMeshElement() {
if(m_pElem != nullptr) {
delete m_pElem;
}
for(auto &it : m_modelsVec) {
delete (NimBLEMeshModel*)it.user_data;
}
}
/**
* @brief Creates a model and adds it the the elements model vector.
* @param [in] type The type of model to create.
* @param [in] pCallbacks a pointer to a callback instance for this model.
*/
void NimBLEMeshElement::createModel(uint16_t type, NimBLEMeshModelCallbacks *pCallbacks) {
for(auto &it : m_modelsVec) {
if(it.id == type) {
NIMBLE_LOGE(LOG_TAG, "Error: element already has a type %04x model", type);
return;
}
}
NIMBLE_LOGD(LOG_TAG, "Creating model type: %04x", type);
NimBLEMeshModel* pModel = nullptr;
switch(type)
{
case BT_MESH_MODEL_ID_GEN_ONOFF_SRV:
pModel = new NimBLEGenOnOffSrvModel(pCallbacks);
break;
case BT_MESH_MODEL_ID_GEN_LEVEL_SRV:
pModel = new NimBLEGenLevelSrvModel(pCallbacks);
break;
default:
NIMBLE_LOGE(LOG_TAG, "Error: model type %04x not supported", type);
return;
}
m_modelsVec.push_back(bt_mesh_model{{type},0,0,0, pModel->opPub,{0},{0},pModel->opList, pModel});
}
/**
* @brief Adds a model created outside of element context to the elements model vector.
* @param [in] model A pointer to the model instance to add.
*/
void NimBLEMeshElement::addModel(bt_mesh_model* model) {
m_modelsVec.push_back(*model);
}
/**
* @brief Creates a bt_mesh_elem for registering with the nimble stack.
* @returns A pointer to the bt_mesh_elem created.
* @details Must not be called until all models have been added.
*/
bt_mesh_elem* NimBLEMeshElement::start() {
m_pElem = new bt_mesh_elem{0, 0, uint8_t(m_modelsVec.size()), 0, &m_modelsVec[0], NULL};
return m_pElem;
}

41
src/NimBLEMeshElement.h Normal file
View file

@ -0,0 +1,41 @@
/*
* NimBLEMeshElement.h
*
* Created: on Aug 23 2020
* Author H2zero
*
*/
#ifndef MAIN_NIMBLE_MESH_ELEMENT_H_
#define MAIN_NIMBLE_MESH_ELEMENT_H_
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#include "NimBLEMeshNode.h"
#include "NimBLEMeshModel.h"
#include <vector>
class NimBLEMeshModelCallbacks;
class NimBLEMeshElement {
public:
void createModel(uint16_t type, NimBLEMeshModelCallbacks* pCallbacks=nullptr);
private:
friend class NimBLEMeshNode;
NimBLEMeshElement();
~NimBLEMeshElement();
void addModel(bt_mesh_model* model);
bt_mesh_elem* start();
bt_mesh_elem *m_pElem;
std::vector<bt_mesh_model> m_modelsVec;
};
#endif // CONFIG_BT_ENABLED
#endif // MAIN_NIMBLE_MESH_ELEMENT_H_

244
src/NimBLEMeshModel.cpp Normal file
View file

@ -0,0 +1,244 @@
/*
* NimBLEMeshModel.cpp
*
* Created: on Aug 25 2020
* Author H2zero
*
*/
#include "NimBLEMeshModel.h"
#include "NimBLELog.h"
static const char* LOG_TAG = "NimBLEMeshModel";
static NimBLEMeshModelCallbacks defaultCallbacks;
/**
* @brief base model constructor
* @param [in] pCallbacks, a pointer to a callback instance for model operations
*/
NimBLEMeshModel::NimBLEMeshModel(NimBLEMeshModelCallbacks* pCallbacks) {
if(pCallbacks == nullptr) {
m_callbacks = &defaultCallbacks;
} else {
m_callbacks = pCallbacks;
}
opList = nullptr;
opPub = nullptr;
}
/**
* @brief destructor
*/
NimBLEMeshModel::~NimBLEMeshModel(){
if(opList != nullptr) {
delete[] opList;
}
if(opPub != nullptr) {
delete[] opPub;
}
}
/**
* @brief Generic on/off server model constructor
* @param [in] pCallbacks, a pointer to a callback instance for model operations
*/
NimBLEGenOnOffSrvModel::NimBLEGenOnOffSrvModel(NimBLEMeshModelCallbacks* pCallbacks)
:NimBLEMeshModel(pCallbacks)
{
// Register the opcodes for this model with the required callbacks
opList = new bt_mesh_model_op[4]{
{ BT_MESH_MODEL_OP_2(0x82, 0x01), 0, NimBLEGenOnOffSrvModel::getOnOff },
{ BT_MESH_MODEL_OP_2(0x82, 0x02), 2, NimBLEGenOnOffSrvModel::setOnOff },
{ BT_MESH_MODEL_OP_2(0x82, 0x03), 2, NimBLEGenOnOffSrvModel::setOnOffUnack },
BT_MESH_MODEL_OP_END};
}
/**
* @brief Called by the NimBLE stack to get the on/off status of the model
*/
void NimBLEGenOnOffSrvModel::getOnOff(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEGenOnOffSrvModel *pModel = (NimBLEGenOnOffSrvModel*)model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
uint8_t *status;
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
status = (uint8_t*)net_buf_simple_add(msg, 1);
*status = pModel->m_callbacks->getOnOff();
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
NIMBLE_LOGE(LOG_TAG, "Send status failed");
}
os_mbuf_free_chain(msg);
}
/**
* @brief Called by the NimBLE stack to set the status of the model with acknowledgement.
*/
void NimBLEGenOnOffSrvModel::setOnOff(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEGenOnOffSrvModel *pModel = (NimBLEGenOnOffSrvModel*)model->user_data;
pModel->m_callbacks->setOnOff(buf->om_data[0]);
// send the status update
NimBLEGenOnOffSrvModel::getOnOff(model,ctx,buf);
}
/**
* @brief Called by the NimBLE stack to set the status of the model without acknowledgement.
*/
void NimBLEGenOnOffSrvModel::setOnOffUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEGenOnOffSrvModel *pModel = (NimBLEGenOnOffSrvModel*)model->user_data;
pModel->m_callbacks->setOnOff(buf->om_data[0]);
}
/**
* @brief Generic level server model constructor
* @param [in] pCallbacks, a pointer to a callback instance for model operations
*/
NimBLEGenLevelSrvModel::NimBLEGenLevelSrvModel(NimBLEMeshModelCallbacks* pCallbacks)
:NimBLEMeshModel(pCallbacks)
{
// Register the opcodes for this model with the required callbacks
opList = new bt_mesh_model_op[8]{
{ BT_MESH_MODEL_OP_2(0x82, 0x05), 0, NimBLEGenLevelSrvModel::getLevel },
{ BT_MESH_MODEL_OP_2(0x82, 0x06), 3, NimBLEGenLevelSrvModel::setLevel },
{ BT_MESH_MODEL_OP_2(0x82, 0x07), 3, NimBLEGenLevelSrvModel::setLevelUnack },
{ BT_MESH_MODEL_OP_2(0x82, 0x09), 5, NimBLEGenLevelSrvModel::setDelta },
{ BT_MESH_MODEL_OP_2(0x82, 0x0a), 5, NimBLEGenLevelSrvModel::setDeltaUnack },
{ BT_MESH_MODEL_OP_2(0x82, 0x0b), 3, NimBLEGenLevelSrvModel::setMove },
{ BT_MESH_MODEL_OP_2(0x82, 0x0c), 3, NimBLEGenLevelSrvModel::setMoveUnack },
BT_MESH_MODEL_OP_END};
}
/**
* @brief Called by the NimBLE stack to get the level value of the model.
*/
void NimBLEGenLevelSrvModel::getLevel(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x08));
net_buf_simple_add_le16(msg, pModel->m_callbacks->getLevel());
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
NIMBLE_LOGE(LOG_TAG, "Send status failed");
}
os_mbuf_free_chain(msg);
}
/**
* @brief Called by the NimBLE stack to set the level value of the model.
*/
void NimBLEGenLevelSrvModel::setLevel(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
pModel->m_callbacks->setLevel((int16_t) net_buf_simple_pull_le16(buf));
NimBLEGenLevelSrvModel::getLevel(model, ctx, buf);
}
/**
* @brief Called by the NimBLE stack to set the level value of the model without acknowledgement.
*/
void NimBLEGenLevelSrvModel::setLevelUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
pModel->m_callbacks->setLevel((int16_t) net_buf_simple_pull_le16(buf));
}
/**
* @brief Called by the NimBLE stack to set the level value by delta of the model.
*/
void NimBLEGenLevelSrvModel::setDelta(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
pModel->m_callbacks->setDelta((int16_t) net_buf_simple_pull_le16(buf));
NimBLEGenLevelSrvModel::getLevel(model, ctx, buf);
}
/**
* @brief Called by the NimBLE stack to set the level value by delta without acknowledgement.
*/
void NimBLEGenLevelSrvModel::setDeltaUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
pModel->m_callbacks->setDelta((int16_t) net_buf_simple_pull_le16(buf));
}
void NimBLEGenLevelSrvModel::setMove(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
}
void NimBLEGenLevelSrvModel::setMoveUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
}
/**
* Default model callbacks
*/
NimBLEMeshModelCallbacks::~NimBLEMeshModelCallbacks() {}
void NimBLEMeshModelCallbacks::setOnOff(uint8_t val) {
NIMBLE_LOGD(LOG_TAG, "Gen On/Off set val: %d", val);
}
uint8_t NimBLEMeshModelCallbacks::getOnOff() {
NIMBLE_LOGD(LOG_TAG, "Gen On/Off get");
return 0;
}
void NimBLEMeshModelCallbacks::setLevel(int16_t val) {
NIMBLE_LOGD(LOG_TAG, "Gen Level set val: %d", val);
}
int16_t NimBLEMeshModelCallbacks::getLevel() {
NIMBLE_LOGD(LOG_TAG, "Gen Level get");
return 0;
}
void NimBLEMeshModelCallbacks::setDelta(int16_t val) {
NIMBLE_LOGD(LOG_TAG, "Gen Delta set val: %d", val);
}

91
src/NimBLEMeshModel.h Normal file
View file

@ -0,0 +1,91 @@
/*
* NimBLEMeshModel.h
*
* Created: on Aug 25 2020
* Author H2zero
*
*/
#ifndef MAIN_NIMBLE_MESH_MODEL_H_
#define MAIN_NIMBLE_MESH_MODEL_H_
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#include "NimBLEMeshElement.h"
class NimBLEMeshModelCallbacks;
class NimBLEMeshModel {
public:
NimBLEMeshModel(NimBLEMeshModelCallbacks* pCallbacks);
~NimBLEMeshModel();
bt_mesh_model_op* opList;
bt_mesh_model_pub* opPub;
NimBLEMeshModelCallbacks* m_callbacks;
};
class NimBLEGenOnOffSrvModel : NimBLEMeshModel {
friend class NimBLEMeshElement;
friend class NimBLEMeshNode;
NimBLEGenOnOffSrvModel(NimBLEMeshModelCallbacks* pCallbacks);
~NimBLEGenOnOffSrvModel();
static void getOnOff(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setOnOff(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setOnOffUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
};
class NimBLEGenLevelSrvModel : NimBLEMeshModel {
friend class NimBLEMeshElement;
friend class NimBLEMeshNode;
NimBLEGenLevelSrvModel(NimBLEMeshModelCallbacks* pCallbacks);
~NimBLEGenLevelSrvModel();
static void getLevel(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setLevel(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setLevelUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setDelta(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setDeltaUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setMove(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
static void setMoveUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf);
};
class NimBLEMeshModelCallbacks {
public:
virtual ~NimBLEMeshModelCallbacks();
virtual void setOnOff(uint8_t);
virtual uint8_t getOnOff();
virtual void setLevel(int16_t);
virtual int16_t getLevel();
virtual void setDelta(int16_t);
};
#endif // CONFIG_BT_ENABLED
#endif // MAIN_NIMBLE_MESH_MODEL_H_

263
src/NimBLEMeshNode.cpp Normal file
View file

@ -0,0 +1,263 @@
/*
* NimBLEMeshNoce.cpp
*
* Created: on July 22 2020
* Author H2zero
*
*/
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include "NimBLEMeshNode.h"
#include "NimBLELog.h"
#include "NimBLEDevice.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#define CID_VENDOR 0x05C3
static const char* LOG_TAG = "NimBLEMeshNode";
/**
* Health server callback struct
*/
static const struct bt_mesh_health_srv_cb health_srv_cb = {
NimBLEHealthSrvCallbacks::faultGetCurrent,
NimBLEHealthSrvCallbacks::faultGetRegistered,
NimBLEHealthSrvCallbacks::faultClear,
NimBLEHealthSrvCallbacks::faultTest,
NimBLEHealthSrvCallbacks::attentionOn,
NimBLEHealthSrvCallbacks::attentionOff
};
/**
* @brief Construct a mesh node.
* @param [in] uuid The uuid used to advertise for provisioning.
* @param [in] type Bitmask of the node features supported.
*/
NimBLEMeshNode::NimBLEMeshNode(const NimBLEUUID &uuid, uint8_t type) {
assert(uuid.bitSize() == 128);
memset(&m_serverConfig, 0, sizeof(m_serverConfig));
memset(&m_prov, 0, sizeof(m_prov));
memset(&m_comp, 0, sizeof(m_comp));
memset(&m_healthPub, 0, sizeof(m_healthPub));
// Default server config
m_serverConfig.relay = BT_MESH_RELAY_DISABLED;/*(type & NIMBLE_MESH::RELAY) ?
BT_MESH_RELAY_ENABLED :
BT_MESH_RELAY_DISABLED;*/
m_serverConfig.beacon = BT_MESH_BEACON_ENABLED;
m_serverConfig.frnd = BT_MESH_FRIEND_DISABLED;/*(type & NIMBLE_MESH::FRIEND) ?
BT_MESH_FRIEND_ENABLED :
BT_MESH_FRIEND_DISABLED;*/
m_serverConfig.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED; /*(type & NIMBLE_MESH::RELAY) ?
BT_MESH_GATT_PROXY_ENABLED :
BT_MESH_GATT_PROXY_DISABLED;*/
m_serverConfig.default_ttl = 7;
// 3 transmissions with 20ms interval
m_serverConfig.net_transmit = BT_MESH_TRANSMIT(2, 20);
m_serverConfig.relay_retransmit = BT_MESH_TRANSMIT(2, 20);
// Default health server config
m_healthSrv = {0};
m_healthSrv.cb = &health_srv_cb;
// Default health pub config
m_healthPub.msg = BT_MESH_HEALTH_FAULT_MSG(0);
// Provisioning config
m_uuid = uuid;
m_prov.uuid = m_uuid.getNative()->u128.value;
m_prov.complete = NimBLEMeshNode::provComplete;
m_prov.reset = NimBLEMeshNode::provReset;
m_configSrvModel = nullptr;
m_configHthModel = nullptr;
// Create the primary element
m_elemVec.push_back(new NimBLEMeshElement());
}
/**
* @brief Destructor, cleanup any resources created.
*/
NimBLEMeshNode::~NimBLEMeshNode() {
if(m_configSrvModel != nullptr) {
delete m_configSrvModel;
}
if(m_configHthModel != nullptr) {
delete m_configHthModel;
}
if(m_comp.elem != nullptr) {
free (m_comp.elem);
}
}
/**
* @brief Called from the callbacks when provisioning changes.
*/
void NimBLEMeshNode::setProvData(uint16_t netIdx, uint16_t addr) {
m_primAddr = addr;
m_primNetIdx = netIdx;
}
/**
* @brief callback, Called by NimBLE stack when provisioning is complete.
*/
void NimBLEMeshNode::provComplete(uint16_t netIdx, uint16_t addr) {
NIMBLE_LOGI(LOG_TAG,
"provisioning complete for netIdx 0x%04x addr 0x%04x",
netIdx, addr);
NimBLEDevice::getMeshNode()->setProvData(netIdx, addr);
}
/**
* @brief callback, Called by NimBLE stack when provisioning is reset.
*/
void NimBLEMeshNode::provReset() {
NIMBLE_LOGI(LOG_TAG, "provisioning reset");
NimBLEDevice::getMeshNode()->setProvData(0, 0);
}
/**
* @brief get a pointer an element.
* @param [in] index The element vector index of the element.
* @returns a pointer to the element requested.
*/
NimBLEMeshElement* NimBLEMeshNode::getElement(uint8_t index) {
return m_elemVec[index];
}
/**
* @brief Create a new mesh element.
* @returns a pointer to the newly created element.
*/
NimBLEMeshElement* NimBLEMeshNode::createElement() {
m_elemVec.push_back(new NimBLEMeshElement());
return m_elemVec.back();
}
/**
* @brief Start the Mesh mode.
* @returns true on success.
*/
bool NimBLEMeshNode::start() {
// Reset and restart gatts so we can register mesh gatt
ble_gatts_reset();
ble_svc_gap_init();
ble_svc_gatt_init();
bt_mesh_register_gatt();
ble_gatts_start();
// Config server and primary health models are required in the primary element
// create them here and add them as the first models.
m_configSrvModel = new bt_mesh_model{{BT_MESH_MODEL_ID_CFG_SRV},0,0,0,nullptr,{0},{0},bt_mesh_cfg_srv_op,&m_serverConfig};
for(int i = 0; i < CONFIG_BT_MESH_MODEL_KEY_COUNT; i++) {
m_configSrvModel->keys[i] = BT_MESH_KEY_UNUSED;
}
for(int i = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) {
m_configSrvModel->groups[i] = BT_MESH_ADDR_UNASSIGNED;
}
m_configHthModel = new bt_mesh_model{{BT_MESH_MODEL_ID_HEALTH_SRV},0,0,0,&m_healthPub,{0},{0},bt_mesh_health_srv_op,&m_healthSrv};
m_elemVec[0]->addModel(m_configSrvModel);
m_elemVec[0]->addModel(m_configHthModel);
// setup node composition
m_comp.cid = CID_VENDOR;
m_comp.elem = (bt_mesh_elem*)calloc(m_elemVec.size(), sizeof(bt_mesh_elem));
if(m_comp.elem == nullptr) {
NIMBLE_LOGE(LOG_TAG, "Error: No Mem");
return false;
}
for(size_t i = 0; i < m_elemVec.size(); i++) {
memcpy((void*)&m_comp.elem[i], (void*)m_elemVec[i]->start(),sizeof(bt_mesh_elem));
}
m_comp.elem_count = (uint8_t)m_elemVec.size();
// Use random address
ble_addr_t addr;
int err = ble_hs_id_gen_rnd(1, &addr);
assert(err == 0);
err = ble_hs_id_set_rnd(addr.val);
assert(err == 0);
err = bt_mesh_init(addr.type, &m_prov, &m_comp);
if (err) {
NIMBLE_LOGE(LOG_TAG, "Initializing mesh failed (err %d)", err);
return false;
}
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
if (bt_mesh_is_provisioned()) {
NIMBLE_LOGI(LOG_TAG, "Mesh network restored from flash");
}
return true;
}
/**
* @brief Health server callbacks
*/
int NimBLEHealthSrvCallbacks::faultGetCurrent(bt_mesh_model *model, uint8_t *test_id,
uint16_t *company_id, uint8_t *faults,
uint8_t *fault_count)
{
NIMBLE_LOGD(LOG_TAG, "faultGetCurrent - default");
return 0;
}
int NimBLEHealthSrvCallbacks::faultGetRegistered(bt_mesh_model *model, uint16_t company_id,
uint8_t *test_id, uint8_t *faults,
uint8_t *fault_count)
{
NIMBLE_LOGD(LOG_TAG, "faultGetRegistered - default");
return 0;
}
int NimBLEHealthSrvCallbacks::faultClear(bt_mesh_model *model, uint16_t company_id)
{
NIMBLE_LOGD(LOG_TAG, "faultClear - default");
return 0;
}
int NimBLEHealthSrvCallbacks::faultTest(bt_mesh_model *model, uint8_t test_id, uint16_t company_id)
{
NIMBLE_LOGD(LOG_TAG, "faultTest - default");
return 0;
}
void NimBLEHealthSrvCallbacks::attentionOn(bt_mesh_model *model)
{
NIMBLE_LOGD(LOG_TAG, "attentionOn - default");
}
void NimBLEHealthSrvCallbacks::attentionOff(bt_mesh_model *model)
{
NIMBLE_LOGD(LOG_TAG, "attentionOff - default");
}
#endif // CONFIG_BT_ENABLED

89
src/NimBLEMeshNode.h Normal file
View file

@ -0,0 +1,89 @@
/*
* NimBLEMeshNode.h
*
* Created: on July 22 2020
* Author H2zero
*
*/
#ifndef MAIN_NIMBLE_MESH_NODE_H_
#define MAIN_NIMBLE_MESH_NODE_H_
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include "nimconfig.h"
#include "mesh/glue.h"
#include "mesh/mesh.h"
/**** FIX COMPILATION ****/
#undef min
#undef max
/**************************/
#include "NimBLEUUID.h"
#include "NimBLEMeshElement.h"
#include <vector>
typedef enum {
RELAY = 0x01 << 0,
BEACON = 0x01 << 1,
FRIEND = 0x01 << 2,
PROXY = 0x01 << 3,
} NIMBLE_MESH;
class NimBLEMeshElement;
class NimBLEMeshNode {
public:
bool start();
NimBLEMeshElement* createElement();
NimBLEMeshElement* getElement(uint8_t index = 0);
private:
friend class NimBLEDevice;
friend class NimBLEMeshElement;
NimBLEMeshNode(const NimBLEUUID &uuid, uint8_t type);
~NimBLEMeshNode();
static void provComplete(uint16_t netIdx, uint16_t addr);
static void provReset();
void setProvData(uint16_t netIdx, uint16_t addr);
bt_mesh_cfg_srv m_serverConfig;
bt_mesh_prov m_prov;
bt_mesh_comp m_comp;
uint16_t m_primAddr;
uint16_t m_primNetIdx;
bt_mesh_model* m_configSrvModel;
bt_mesh_model* m_configHthModel;
bt_mesh_health_srv m_healthSrv;
bt_mesh_model_pub m_healthPub;
NimBLEUUID m_uuid;
std::vector<NimBLEMeshElement*> m_elemVec;
};
class NimBLEHealthSrvCallbacks {
public:
static int faultGetCurrent(bt_mesh_model *model, uint8_t *test_id,
uint16_t *company_id, uint8_t *faults,
uint8_t *fault_count);
static int faultGetRegistered(bt_mesh_model *model, uint16_t company_id,
uint8_t *test_id, uint8_t *faults,
uint8_t *fault_count);
static int faultClear(bt_mesh_model *model, uint16_t company_id);
static int faultTest(bt_mesh_model *model, uint8_t test_id, uint16_t company_id);
static void attentionOn(bt_mesh_model *model);
static void attentionOff(bt_mesh_model *model);
};
#endif // CONFIG_BT_ENABLED
#endif // MAIN_NIMBLE_MESH_NODE_H_

View file

@ -84,6 +84,7 @@
/** @brief Un-comment to use external PSRAM for the NimBLE host */ /** @brief Un-comment to use external PSRAM for the NimBLE host */
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1 #define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1
/** @brief Un-comment to change the core NimBLE host runs on */ /** @brief Un-comment to change the core NimBLE host runs on */
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0 #define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0