diff --git a/src/NimBLEMeshElement.cpp b/src/NimBLEMeshElement.cpp index 43b2e65..f3e99ac 100644 --- a/src/NimBLEMeshElement.cpp +++ b/src/NimBLEMeshElement.cpp @@ -13,13 +13,18 @@ static const char* LOG_TAG = "NimBLEMeshElement"; NimBLEMeshElement::NimBLEMeshElement() { m_pElem_t = nullptr; + m_pHealthModel = nullptr; } + + NimBLEMeshElement::~NimBLEMeshElement() { if(m_pElem_t != nullptr) { delete m_pElem_t; } - delete m_pHealthModel; + if(m_pHealthModel != nullptr) { + delete m_pHealthModel; + } for(auto &it : m_modelsVec) { if(it.id != BT_MESH_MODEL_ID_HEALTH_SRV) { @@ -30,6 +35,7 @@ NimBLEMeshElement::~NimBLEMeshElement() { m_modelsVec.clear(); } + /** * @brief Creates a model and adds it the the elements model vector. * @param [in] type The type of model to create. @@ -58,7 +64,7 @@ NimBLEMeshModel* NimBLEMeshElement::createModel(uint16_t type, NimBLEMeshModelCa case BT_MESH_MODEL_ID_HEALTH_SRV: m_pHealthModel = new NimBLEHealthSrvModel(pCallbacks); pModel = m_pHealthModel; - m_modelsVec.push_back(bt_mesh_model{{BT_MESH_MODEL_ID_HEALTH_SRV},0,0,0,&pModel->m_opPub,{0},{0},bt_mesh_health_srv_op,pModel->getHealth_t()}); + m_modelsVec.push_back(bt_mesh_model{{type},0,0,0,&pModel->m_opPub,{0},{0},bt_mesh_health_srv_op,&m_pHealthModel->m_healthSrv}); return pModel; default: @@ -70,15 +76,21 @@ NimBLEMeshModel* NimBLEMeshElement::createModel(uint16_t type, NimBLEMeshModelCa return 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) { +void NimBLEMeshElement::addModel(bt_mesh_model *model) { m_modelsVec.push_back(*model); } +/** + * @brief Get a pointer to the model in the element with the type specified. + * @param [in] The model type requested. + * @returns A pointer to the model or nullptr if not found. + */ NimBLEMeshModel* NimBLEMeshElement::getModel(uint16_t type) { if(type == BT_MESH_MODEL_ID_HEALTH_SRV) { return m_pHealthModel; @@ -94,6 +106,28 @@ NimBLEMeshModel* NimBLEMeshElement::getModel(uint16_t type) { } +/** + * @brief Get a pointer to a model with matching type and ID. + * @param [in] eidx The element ID to compare. + * @param [in] midx The model ID to compare. + * @param [in] The model type requested. + * @returns A pointer to the model or nullptr if not found. + */ +NimBLEMeshModel* NimBLEMeshElement::getModelByIdx(uint8_t eidx, uint8_t midx, uint16_t type) { + for(auto &it : m_modelsVec) { + if(it.elem_idx == eidx && it.mod_idx == midx) { + if(type == BT_MESH_MODEL_ID_HEALTH_SRV) { + return m_pHealthModel; + } else { + return (NimBLEMeshModel*)it.user_data; + } + } + } + + return nullptr; +} + + /** * @brief Creates a bt_mesh_elem for registering with the nimble stack. * @returns A pointer to the bt_mesh_elem created. diff --git a/src/NimBLEMeshElement.h b/src/NimBLEMeshElement.h index 257c9ad..6543b58 100644 --- a/src/NimBLEMeshElement.h +++ b/src/NimBLEMeshElement.h @@ -26,6 +26,7 @@ class NimBLEMeshElement { public: NimBLEMeshModel* createModel(uint16_t type, NimBLEMeshModelCallbacks* pCallbacks=nullptr); NimBLEMeshModel* getModel(uint16_t type); + NimBLEMeshModel* getModelByIdx(uint8_t eidx, uint8_t midx, uint16_t type); private: friend class NimBLEMeshNode; diff --git a/src/NimBLEMeshModel.cpp b/src/NimBLEMeshModel.cpp index 8bddc5b..1e52fe7 100644 --- a/src/NimBLEMeshModel.cpp +++ b/src/NimBLEMeshModel.cpp @@ -12,6 +12,11 @@ #include "nimble/nimble_port.h" +#include "NimBLEDevice.h" + +#define CID_VENDOR 0x05C3 +#define STANDARD_TEST_ID 0x00 + static const char* LOG_TAG = "NimBLEMeshModel"; static NimBLEMeshModelCallbacks defaultCallbacks; @@ -133,10 +138,6 @@ uint16_t NimBLEMeshModel::getDelayTime() { } -bt_mesh_health_srv* NimBLEMeshModel::getHealth_t() { - return nullptr; -} - /** * @brief Generic on/off server model constructor * @param [in] pCallbacks, a pointer to a callback instance for model operations @@ -245,6 +246,7 @@ void NimBLEGenOnOffSrvModel::setOnOffUnack(bt_mesh_model *model, } } + void NimBLEGenOnOffSrvModel::tdTimerCb(ble_npl_event *event) { NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg; if(pModel->m_delayTime > 0) { @@ -286,6 +288,7 @@ void NimBLEGenOnOffSrvModel::setPubMsg() { } } + void NimBLEGenOnOffSrvModel::setValue(uint8_t *val, size_t len) { if(len != sizeof(uint8_t)) { NIMBLE_LOGE(LOG_TAG, "NimBLEGenOnOffSrvModel: Incorrect value length"); @@ -294,6 +297,7 @@ void NimBLEGenOnOffSrvModel::setValue(uint8_t *val, size_t len) { m_value[0] = *val; } + void NimBLEGenOnOffSrvModel::setTargetValue(uint8_t *val, size_t len) { if(len != sizeof(uint8_t)) { NIMBLE_LOGE(LOG_TAG, "NimBLEGenOnOffSrvModel: Incorrect target value length"); @@ -302,6 +306,7 @@ void NimBLEGenOnOffSrvModel::setTargetValue(uint8_t *val, size_t len) { m_targetValue[0] = *val; } + /** * @brief Generic level server model constructor * @param [in] pCallbacks, a pointer to a callback instance for model operations @@ -543,11 +548,21 @@ NimBLEHealthSrvModel::NimBLEHealthSrvModel(NimBLEMeshModelCallbacks *pCallbacks) { memset(&m_healthSrv, 0, sizeof(m_healthSrv)); m_healthSrv.cb = &health_srv_cb; + m_opPub.msg = NET_BUF_SIMPLE(1 + 3); + m_hasFault = false; + m_testId = 0; } -bt_mesh_health_srv* NimBLEHealthSrvModel::getHealth_t() { - return &m_healthSrv; +void NimBLEHealthSrvModel::setFault(uint8_t fault) { + m_faults.push_back(fault); + m_hasFault = true; +} + + +void NimBLEHealthSrvModel::clearFaults() { + m_faults.clear(); + m_hasFault = false; } @@ -574,6 +589,23 @@ int16_t NimBLEMeshModelCallbacks::getLevel(NimBLEMeshModel *pModel) { return 0; } +void NimBLEMeshModelCallbacks::attentionOn(NimBLEMeshModel *pModel) { + NIMBLE_LOGD(LOG_TAG, "Attention On Default"); +} + +void NimBLEMeshModelCallbacks::attentionOff(NimBLEMeshModel *pModel) { + NIMBLE_LOGD(LOG_TAG, "Attention Off Default"); +} + +void NimBLEMeshModelCallbacks::faultTest(NimBLEMeshModel *pModel) { + NIMBLE_LOGD(LOG_TAG, "Fault Test"); +} + +void NimBLEMeshModelCallbacks::faultClear(NimBLEMeshModel *pModel) { + NIMBLE_LOGD(LOG_TAG, "Fault Clear"); +} + + /** * @brief Health server callbacks */ @@ -582,6 +614,12 @@ int NimBLEHealthSrvCallbacks::faultGetCurrent(bt_mesh_model *model, uint8_t *tes uint8_t *fault_count) { NIMBLE_LOGD(LOG_TAG, "faultGetCurrent - default"); + + NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model); + *test_id = pModel->m_testId; + *company_id = CID_VENDOR; + faults = &pModel->m_faults[0]; + *fault_count = pModel->m_faults.size(); return 0; } @@ -590,27 +628,64 @@ int NimBLEHealthSrvCallbacks::faultGetRegistered(bt_mesh_model *model, uint16_t uint8_t *fault_count) { NIMBLE_LOGD(LOG_TAG, "faultGetRegistered - default"); + + if (company_id != CID_VENDOR) { + return -BLE_HS_EINVAL; + } + + NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model); + *test_id = pModel->m_testId; + faults = &pModel->m_faults[0]; + *fault_count = pModel->m_faults.size(); + return 0; } int NimBLEHealthSrvCallbacks::faultClear(bt_mesh_model *model, uint16_t company_id) { NIMBLE_LOGD(LOG_TAG, "faultClear - default"); + + if (company_id != CID_VENDOR) { + return -BLE_HS_EINVAL; + } + + NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model); + pModel->m_callbacks->faultClear(pModel); + pModel->clearFaults(); + return 0; } int NimBLEHealthSrvCallbacks::faultTest(bt_mesh_model *model, uint8_t test_id, uint16_t company_id) { NIMBLE_LOGD(LOG_TAG, "faultTest - default"); + + if (company_id != CID_VENDOR) { + return -BLE_HS_EINVAL; + } + + if (test_id != STANDARD_TEST_ID) { + return -BLE_HS_EINVAL; + } + + NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model); + pModel->setFault(0); + pModel->m_testId = test_id; + pModel->m_callbacks->faultTest(pModel); + return 0; } void NimBLEHealthSrvCallbacks::attentionOn(bt_mesh_model *model) { NIMBLE_LOGD(LOG_TAG, "attentionOn - default"); + NimBLEMeshModel* pModel = NimBLEDevice::getMeshNode()->getHealthModel(model); + pModel->m_callbacks->attentionOn(pModel); } void NimBLEHealthSrvCallbacks::attentionOff(bt_mesh_model *model) { NIMBLE_LOGD(LOG_TAG, "attentionOff - default"); + NimBLEMeshModel* pModel = NimBLEDevice::getMeshNode()->getHealthModel(model); + pModel->m_callbacks->attentionOff(pModel); } diff --git a/src/NimBLEMeshModel.h b/src/NimBLEMeshModel.h index 98b8c96..e625469 100644 --- a/src/NimBLEMeshModel.h +++ b/src/NimBLEMeshModel.h @@ -33,7 +33,8 @@ public: virtual void setPubMsg(){}; virtual void setValue(uint8_t *val, size_t len){}; virtual void setTargetValue(uint8_t *val, size_t len){}; - virtual bt_mesh_health_srv* getHealth_t(); + virtual void setFault(uint8_t){}; + virtual void clearFaults(){}; template void setValue(const T &s) { @@ -138,13 +139,20 @@ class NimBLEGenLevelSrvModel : NimBLEMeshModel { class NimBLEHealthSrvModel : NimBLEMeshModel { friend class NimBLEMeshElement; friend class NimBLEMeshNode; + friend class NimBLEHealthSrvCallbacks; NimBLEHealthSrvModel(NimBLEMeshModelCallbacks *pCallbacks); ~NimBLEHealthSrvModel(){}; - bt_mesh_health_srv* getHealth_t() override; +public: + void setFault(uint8_t) override; + void clearFaults() override; +private: bt_mesh_health_srv m_healthSrv; + bool m_hasFault; + uint8_t m_testId; + std::vector m_faults; }; @@ -155,6 +163,11 @@ public: virtual uint8_t getOnOff(NimBLEMeshModel *pModel); virtual void setLevel(NimBLEMeshModel *pModel, int16_t val); virtual int16_t getLevel(NimBLEMeshModel *pModel); + virtual void attentionOn(NimBLEMeshModel *pModel); + virtual void attentionOff(NimBLEMeshModel *pModel); + virtual void faultTest(NimBLEMeshModel *pModel); + virtual void faultClear(NimBLEMeshModel *pModel); + }; diff --git a/src/NimBLEMeshNode.cpp b/src/NimBLEMeshNode.cpp index 6a332d8..02386fa 100644 --- a/src/NimBLEMeshNode.cpp +++ b/src/NimBLEMeshNode.cpp @@ -128,6 +128,25 @@ NimBLEMeshElement* NimBLEMeshNode::createElement() { } +/** + * @brief Get a pointer to the health model instance that matches the ID's of the input model. + * @param [in] model A pointer to the NimBLE internal model instance. + * @returns A pointer to the model. + */ +NimBLEMeshModel* NimBLEMeshNode::getHealthModel(bt_mesh_model *model) { + NimBLEMeshModel* pModel; + + for(auto &it : m_elemVec) { + pModel = it->getModelByIdx(model->elem_idx, model->mod_idx, BT_MESH_MODEL_ID_HEALTH_SRV); + if(pModel != nullptr) { + return pModel; + } + } + + return nullptr; +} + + /** * @brief Start the Mesh mode. * @returns true on success. diff --git a/src/NimBLEMeshNode.h b/src/NimBLEMeshNode.h index 8ce35dc..23c9934 100644 --- a/src/NimBLEMeshNode.h +++ b/src/NimBLEMeshNode.h @@ -29,6 +29,8 @@ #include +class NimBLEMeshModel; + typedef enum { RELAY = 0x01 << 0, BEACON = 0x01 << 1, @@ -40,9 +42,10 @@ class NimBLEMeshElement; class NimBLEMeshNode { public: - bool start(); - NimBLEMeshElement* createElement(); - NimBLEMeshElement* getElement(uint8_t index = 0); + bool start(); + NimBLEMeshElement* createElement(); + NimBLEMeshElement* getElement(uint8_t index = 0); + NimBLEMeshModel* getHealthModel(bt_mesh_model *model); private: friend class NimBLEDevice;