1 Commits

Author SHA1 Message Date
h2zero
b1ae44774a WIP - compiles with mynewt 2024-12-11 08:39:34 -07:00
29 changed files with 202 additions and 2398 deletions

View File

@@ -12,10 +12,6 @@ elseif("nimble" IN_LIST BUILD_COMPONENTS OR "__nimble" IN_LIST __hack_component_
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
nimble
)
elseif("bt" IN_LIST BUILD_COMPONENTS OR "__bt" IN_LIST __hack_component_targets)
list(APPEND ESP_NIMBLE_PRIV_REQUIRES
bt
)
endif()
if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf_arduino")
@@ -24,7 +20,15 @@ if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf
)
endif()
set(srcs "src/NimBLE2904.cpp"
idf_component_register(
REQUIRED_IDF_TARGETS
"esp32"
"esp32s3"
"esp32c3"
INCLUDE_DIRS
"src"
SRCS
"src/NimBLE2904.cpp"
"src/NimBLEAddress.cpp"
"src/NimBLEAdvertisedDevice.cpp"
"src/NimBLEAdvertising.cpp"
@@ -45,25 +49,7 @@ set(srcs "src/NimBLE2904.cpp"
"src/NimBLEServer.cpp"
"src/NimBLEService.cpp"
"src/NimBLEUtils.cpp"
"src/NimBLEUUID.cpp")
if(CONFIG_BT_NIMBLE_MESH)
list(APPEND srcs "src/mesh_config_store/config/config_store.c"
"src/NimBLEMeshCreateModel.c"
"src/NimBLEMeshElement.cpp"
"src/NimBLEMeshModel.cpp"
"src/NimBLEMeshNode.cpp")
endif()
idf_component_register(
REQUIRED_IDF_TARGETS
"esp32"
"esp32s3"
"esp32c3"
INCLUDE_DIRS
"src"
SRCS "${srcs}"
"src/NimBLEUUID.cpp"
REQUIRES
bt
nvs_flash
@@ -71,7 +57,3 @@ idf_component_register(
${ESP_NIMBLE_PRIV_REQUIRES}
)
if(CONFIG_BT_NIMBLE_MESH)
idf_build_set_property(COMPILE_OPTIONS "-DMYNEWT_VAL_BLE_MESH_SETTINGS=1" APPEND)
idf_build_set_property(COMPILE_OPTIONS "-I${COMPONENT_DIR}/src/mesh_config_store" APPEND)
endif()

View File

@@ -1,7 +0,0 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(SUPPORTED_TARGETS esp32)
project(basic_on_off_level_server)

View File

@@ -1,3 +0,0 @@
PROJECT_NAME := basic_on_off_level_server
include $(IDF_PATH)/make/project.mk

View File

@@ -1,4 +0,0 @@
set(COMPONENT_SRCS "main.cpp")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View File

@@ -1,4 +0,0 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@@ -1,64 +0,0 @@
#include "NimBLEDevice.h"
#include "driver/gpio.h"
extern "C" {void app_main(void);}
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
// LED pins
#define LEDR GPIO_NUM_16
#define LEDG GPIO_NUM_17
#define LEDB GPIO_NUM_18
#define OUTPUT_PIN (1ULL<<LEDG)
static uint8_t onOffVal = 0;
static int16_t levelVal = 0;
class onOffSrvModelCallbacks : public NimBLEMeshModelCallbacks {
void setOnOff(NimBLEMeshModel *pModel, uint8_t val) {
printf("on/off set val %d, transition time: %dms\n", val, pModel->getTransTime());
onOffVal = val;
gpio_set_level(LEDG, !onOffVal);
}
uint8_t getOnOff(NimBLEMeshModel *pModel) {
printf("on/off get val %d\n", onOffVal);
return onOffVal;
}
};
class levelSrvModelCallbacks : public NimBLEMeshModelCallbacks {
void setLevel(NimBLEMeshModel *pModel, int16_t val) {
printf("Level set val %d, transition time: %dms\n", val, pModel->getTransTime());
levelVal = val;
}
int16_t getLevel(NimBLEMeshModel *pModel) {
printf("Level get val %d\n", levelVal);
return levelVal;
}
};
void app_main(void) {
gpio_config_t io_conf;
io_conf.intr_type = (gpio_int_type_t)GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = OUTPUT_PIN;
io_conf.pull_down_en = (gpio_pulldown_t)0;
io_conf.pull_up_en = (gpio_pullup_t)0;
gpio_config(&io_conf);
gpio_set_level(LEDG, 1);
NimBLEDevice::init("");
NimBLEMeshNode *pMesh = NimBLEDevice::createMeshNode(NimBLEUUID(SERVICE_UUID),0);
NimBLEMeshElement* pElem = pMesh->getElement();
NimBLEMeshModel* pModel = pElem->createModel(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, new onOffSrvModelCallbacks());
pModel->setValue(onOffVal);
//pElem = pMesh->createElement();
pModel = pElem->createModel(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, new levelSrvModelCallbacks());
pModel->setValue(levelVal);
pMesh->start();
printf("Mesh Started");
}

20
pkg.yml Normal file
View File

@@ -0,0 +1,20 @@
pkg.name: esp-nimble-cpp
pkg.type: lib
pkg.description: NimBLE CPP wrapper
pkg.author: "Ryan Powell"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
pkg.deps:
- "@apache-mynewt-nimble/nimble"
- "@apache-mynewt-nimble/nimble/host"
- "@apache-mynewt-nimble/nimble/host/services/gap"
- "@apache-mynewt-nimble/nimble/host/services/gatt"
- "@apache-mynewt-nimble/nimble/host/store/config"
- "@apache-mynewt-nimble/nimble/host/util"
pkg.source_dirs:
- src
pkg.include_dirs:
- src

View File

@@ -23,7 +23,7 @@
#include <climits>
#if defined(CONFIG_NIMBLE_CPP_IDF)
#include "nimble/nimble_port.h"
//#include "nimble/nimble_port.h"
#else
#include "nimble/porting/nimble/include/nimble/nimble_port.h"
#endif
@@ -81,7 +81,11 @@ NimBLEClient::NimBLEClient(const NimBLEAddress &peerAddress) : m_peerAddress(pee
m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
memset(&m_dcTimer, 0, sizeof(m_dcTimer));
#ifndef MYNEWT
ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(),
#else
ble_npl_callout_init(&m_dcTimer, ble_npl_eventq_dflt_get(),
#endif
NimBLEClient::dcTimerCb, this);
} // NimBLEClient
@@ -99,7 +103,7 @@ NimBLEClient::~NimBLEClient() {
delete m_pClientCallbacks;
}
ble_npl_callout_deinit(&m_dcTimer);
//ble_npl_callout_deinit(&m_dcTimer);
} // ~NimBLEClient
@@ -215,8 +219,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
m_peerAddress = address;
}
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
m_pTaskData = &taskData;
int rc = 0;
@@ -282,12 +285,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
// Wait for the connect timeout time +1 second for the connection to complete
if(ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
if (!NimBLEDevice::taskWait(m_pTaskData, m_connectTimeout + 1000)) {
m_pTaskData = nullptr;
// If a connection was made but no response from MTU exchange; disconnect
if(isConnected()) {
@@ -303,6 +301,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
return false;
} else if(taskData.rc != 0){
m_pTaskData = nullptr;
m_lastErr = taskData.rc;
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s",
taskData.rc,
@@ -314,6 +313,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
}
return false;
} else {
m_pTaskData = nullptr;
NIMBLE_LOGI(LOG_TAG, "Connection established");
}
@@ -336,12 +336,12 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttibutes) {
* @return True on success.
*/
bool NimBLEClient::secureConnection() {
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
int retryCount = 1;
do {
taskData.rc = -1;
m_pTaskData = &taskData;
int rc = NimBLEDevice::startSecurity(m_conn_id);
@@ -350,14 +350,14 @@ bool NimBLEClient::secureConnection() {
m_pTaskData = nullptr;
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
\
if (!NimBLEDevice::taskWait(m_pTaskData, 10 * 1000)) {
break;
}
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
m_pTaskData = nullptr;
if(taskData.rc != 0){
m_lastErr = taskData.rc;
return false;
@@ -734,8 +734,7 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
}
int rc = 0;
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
@@ -750,13 +749,12 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "Retrieve services timeout");
m_lastErr = taskData.rc;
return false;
}
// wait until we have all the services
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
m_lastErr = taskData.rc;
if(taskData.rc == 0){
@@ -791,26 +789,21 @@ int NimBLEClient::serviceDiscoveredCB(
return 0;
}
if(error->status == 0) {
int rc = error->status;
if (rc == 0) {
// Found a service - add it to the vector
NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service);
client->m_servicesVector.push_back(pRemoteService);
return 0;
}
if(error->status == BLE_HS_EDONE) {
pTaskData->rc = 0;
} else {
} else if (rc != BLE_HS_EDONE) {
NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s",
error->status,
NimBLEUtils::returnCodeToString(error->status));
pTaskData->rc = error->status;
rc, NimBLEUtils::returnCodeToString(rc));
}
xTaskNotifyGive(pTaskData->task);
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
NIMBLE_LOGD(LOG_TAG,"<< Service Discovered");
return error->status;
return rc;
}
@@ -1183,10 +1176,7 @@ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
} // Switch
if(client->m_pTaskData != nullptr) {
client->m_pTaskData->rc = rc;
if(client->m_pTaskData->task) {
xTaskNotifyGive(client->m_pTaskData->task);
}
NimBLEDevice::taskComplete(client->m_pTaskData, rc);
client->m_pTaskData = nullptr;
}

View File

@@ -35,7 +35,15 @@
# include "nimble/esp_port/esp-hci/include/esp_nimble_hci.h"
# endif
#else
# include "nimble/nimble/controller/include/controller/ble_phy.h"
# include "controller/ble_phy.h"
# include "host/ble_hs.h"
# include "host/util/util.h"
# include "services/gap/ble_svc_gap.h"
# include "services/gatt/ble_svc_gatt.h"
//#include "porting/nimble/include/nimble/nimble_port.h"
#include "os/os.h"
#endif
#ifndef CONFIG_NIMBLE_CPP_IDF
@@ -76,8 +84,6 @@ NimBLEAdvertising* NimBLEDevice::m_bleAdvertising = nullptr;
# endif
#endif
NimBLEMeshNode* NimBLEDevice::m_pMeshNode = nullptr;
gap_event_handler NimBLEDevice::m_customGapHandler = nullptr;
ble_gap_event_listener NimBLEDevice::m_listener;
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
@@ -92,30 +98,6 @@ uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN
uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
#endif
/**
* @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.
* @return A new instance of the server.
@@ -275,7 +257,7 @@ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
}
while(pClient->isConnected()) {
taskYIELD();
os_time_delay(1);
}
// Since we set the flag to false the app will not get a callback
// in the disconnect event so we call it here for good measure.
@@ -287,7 +269,7 @@ bool NimBLEDevice::deleteClient(NimBLEClient* pClient) {
return false;
}
while(pClient->m_pTaskData != nullptr) {
taskYIELD();
os_time_delay(1);
}
}
@@ -450,12 +432,13 @@ int NimBLEDevice::getPower(esp_ble_power_type_t powerType) {
#else
void NimBLEDevice::setPower(int dbm) {
ble_phy_txpwr_set(dbm);
//ble_phy_txpwr_set(dbm);
}
int NimBLEDevice::getPower() {
return ble_phy_txpwr_get();
// return ble_phy_txpwr_get();
return 0;
}
#endif
@@ -830,7 +813,8 @@ void NimBLEDevice::onSync(void)
// Yield for houskeeping before returning to operations.
// Occasionally triggers exception without.
taskYIELD();
//taskYIELD();
os_time_delay(1);
m_synced = true;
@@ -849,7 +833,6 @@ void NimBLEDevice::onSync(void)
}
} // onSync
/**
* @brief The main host task.
*/
@@ -859,12 +842,21 @@ void NimBLEDevice::host_task(void *param)
NIMBLE_LOGI(LOG_TAG, "BLE Host Task Started");
/* This function will return only when nimble_port_stop() is executed */
#ifndef MYNEWT
nimble_port_run();
nimble_port_freertos_deinit();
#else
while (1) {
os_eventq_run(os_eventq_dflt_get());
}
#endif
} // host_task
static struct os_task ble_nimble_task;
static os_stack_t ble_nimble_stack[1024];
/**
* @brief Initialize the %BLE environment.
* @param [in] deviceName The device name of the device.
@@ -906,7 +898,10 @@ void NimBLEDevice::init(const std::string &deviceName) {
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
ESP_ERROR_CHECK(esp_nimble_hci_init());
#endif
#ifndef MYNEWT
nimble_port_init();
#endif
// Setup callbacks for host events
ble_hs_cfg.reset_cb = NimBLEDevice::onReset;
@@ -925,15 +920,18 @@ void NimBLEDevice::init(const std::string &deviceName) {
// Set the device name.
rc = ble_svc_gap_device_name_set(deviceName.c_str());
assert(rc == 0);
#ifndef MYNEWT
ble_store_config_init();
nimble_port_freertos_init(NimBLEDevice::host_task);
#else
os_task_init(&ble_nimble_task, "ble_nimble_task", NimBLEDevice::host_task, NULL, 8,
OS_WAIT_FOREVER, ble_nimble_stack, 1024);
#endif
}
// Wait for host and controller to sync before returning and accepting new tasks
while(!m_synced){
taskYIELD();
os_time_delay(1);
}
initialized = true; // Set the initialization flag to ensure we are only initialized once.
@@ -947,9 +945,14 @@ void NimBLEDevice::init(const std::string &deviceName) {
*/
/* STATIC */
void NimBLEDevice::deinit(bool clearAll) {
#ifndef MYNEWT
int ret = nimble_port_stop();
if (ret == 0) {
nimble_port_deinit();
#else
int ret = ble_hs_shutdown(0);
if (ret == 0) {
#endif
#ifdef ESP_PLATFORM
ret = esp_nimble_hci_and_controller_deinit();
if (ret != ESP_OK) {

View File

@@ -38,8 +38,6 @@
#include "NimBLEServer.h"
#endif
#include "NimBLEMeshNode.h"
#include "NimBLEUtils.h"
#include "NimBLESecurity.h"
#include "NimBLEAddress.h"
@@ -117,9 +115,6 @@ public:
static NimBLEServer* getServer();
#endif
static NimBLEMeshNode* createMeshNode(NimBLEUUID uuid, uint8_t type);
static NimBLEMeshNode* getMeshNode();
#ifdef ESP_PLATFORM
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);
@@ -180,6 +175,31 @@ public:
static NimBLEAddress getBondedAddress(int index);
#endif
static bool taskWait(ble_task_data_t* td, uint32_t waitms ) {
#if 0 //defined INC_FREERTOS_H
td->task = xTaskGetCurrentTaskHandle();
# ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(td->task, ULONG_MAX);
# endif
// Wait for the connect timeout time +1 second for the connection to complete
return ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(waitms));
#else
ble_npl_time_t ticks = ble_npl_time_ms_to_ticks32(waitms);
while(td->rc < 0 && --ticks){
ble_npl_time_delay(1);
}
return (ticks > 0);
#endif
}
static void taskComplete(ble_task_data_t* td, int rc) {
td->rc = rc;
#if 0 //defined INC_FREERTOS_H
xTaskNotifyGive(td->task);
#endif
}
private:
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
friend class NimBLEClient;
@@ -237,7 +257,6 @@ private:
static uint8_t m_scanFilterMode;
#endif
static std::vector<NimBLEAddress> m_whiteList;
static NimBLEMeshNode* m_pMeshNode;
};

View File

@@ -12,7 +12,7 @@
#if defined(CONFIG_BT_ENABLED)
#if defined(CONFIG_NIMBLE_CPP_IDF) // using esp-idf
#if 0 // using esp-idf
# include "esp_log.h"
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
# define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
@@ -39,8 +39,8 @@
NIMBLE_CPP_LOG_PRINT(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__)
#else // using Arduino
# include "nimble/porting/nimble/include/syscfg/syscfg.h"
# include "nimble/console/console.h"
# include "syscfg/syscfg.h"
# include "console/console.h"
# ifndef CONFIG_NIMBLE_CPP_LOG_LEVEL
# if defined(ARDUINO_ARCH_ESP32) && defined(CORE_DEBUG_LEVEL)
# define CONFIG_NIMBLE_CPP_LOG_LEVEL CORE_DEBUG_LEVEL

View File

@@ -1,30 +0,0 @@
/*
* NimBLEMeshCreateModel.cpp
*
* Created: on April 27 2022
* Author H2zero
*
*/
#include "NimBLEMeshCreateModel.h"
static struct bt_mesh_model_cb mod_cb = {
//.init = modelInitCallback
};
struct bt_mesh_model createConfigSrvModel(struct bt_mesh_cfg_srv* cfg) {
struct bt_mesh_model cmod = BT_MESH_MODEL_CFG_SRV(cfg);
return cmod;
}
struct bt_mesh_model createHealthModel(struct bt_mesh_health_srv* hsrv,
struct bt_mesh_model_pub* hpub) {
struct bt_mesh_model hmod = BT_MESH_MODEL_HEALTH_SRV(hsrv, hpub);
return hmod;
}
struct bt_mesh_model createGenModel(int16_t _id, struct bt_mesh_model_op* op,
struct bt_mesh_model_pub* pub, void* udata) {
struct bt_mesh_model mod = BT_MESH_MODEL_CB(_id, op, pub, udata, &mod_cb);
return mod;
}

View File

@@ -1,35 +0,0 @@
/*
* NimBLEMeshCreateModel.h
*
* Created: on April 27 2022
* Author H2zero
*
*/
#ifndef __NIMBLE_MESH_CREATE_MODEL_H
#define __NIMBLE_MESH_CREATE_MODEL_H
#include "nimconfig.h"
#if defined(CONFIG_NIMBLE_CPP_IDF)
# include "mesh/mesh.h"
# include "mesh/cfg_srv.h"
#else
# include "nimble/nimble/host/mesh/include/mesh/mesh.h"
# include "nimble/nimble/host/mesh/include/mesh/cfg_srv.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
//int modelInitCallback(struct bt_mesh_model *model);
struct bt_mesh_model createConfigSrvModel(struct bt_mesh_cfg_srv* cfg);
struct bt_mesh_model createHealthModel(struct bt_mesh_health_srv* hsrv,
struct bt_mesh_model_pub* hpub);
struct bt_mesh_model createGenModel(int16_t _id, struct bt_mesh_model_op* op,
struct bt_mesh_model_pub* pub, void* udata);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,142 +0,0 @@
/*
* NimBLEMeshElement.cpp
*
* Created: on Aug 23 2020
* Author H2zero
*
*/
#include "NimBLEMeshElement.h"
#include "NimBLELog.h"
#include "NimBLEMeshCreateModel.h"
static const char* LOG_TAG = "NimBLEMeshElement";
NimBLEMeshElement::NimBLEMeshElement() {
m_pElem = nullptr;
m_pHealthModel = nullptr;
}
NimBLEMeshElement::~NimBLEMeshElement() {
if(m_pElem != nullptr) {
delete m_pElem;
}
if(m_pHealthModel != nullptr) {
delete m_pHealthModel;
}
for(auto &it : m_modelsVec) {
if(it.id != BT_MESH_MODEL_ID_HEALTH_SRV) {
delete (NimBLEMeshModel*)it.user_data;
}
}
m_modelsVec.clear();
}
/**
* @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.
*/
NimBLEMeshModel* NimBLEMeshElement::createModel(uint16_t type, NimBLEMeshModelCallbacks *pCallbacks) {
if(getModel(type) != nullptr) {
NIMBLE_LOGE(LOG_TAG, "Error: element already has a type %04x model", type);
return nullptr;
}
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;
case BT_MESH_MODEL_ID_HEALTH_SRV:
m_pHealthModel = new NimBLEHealthSrvModel(pCallbacks);
pModel = m_pHealthModel;
m_modelsVec.push_back(createHealthModel(&m_pHealthModel->m_healthSrv, &pModel->m_opPub));
return pModel;
default:
NIMBLE_LOGE(LOG_TAG, "Error: model type %04x not supported", type);
return nullptr;
}
m_modelsVec.push_back(createGenModel(type, pModel->m_opList, &pModel->m_opPub, pModel));
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(const 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;
}
for(auto &it : m_modelsVec) {
if(it.id == type) {
return (NimBLEMeshModel*)it.user_data;
}
}
return nullptr;
}
/**
* @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.
* @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;
}

View File

@@ -1,46 +0,0 @@
/*
* 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 NimBLEMeshModel;
class NimBLEHealthSrvModel;
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;
NimBLEMeshElement();
~NimBLEMeshElement();
void addModel(const bt_mesh_model & model);
bt_mesh_elem* start();
bt_mesh_elem *m_pElem;
NimBLEHealthSrvModel* m_pHealthModel;
std::vector<bt_mesh_model> m_modelsVec;
};
#endif // CONFIG_BT_ENABLED
#endif // MAIN_NIMBLE_MESH_ELEMENT_H_

View File

@@ -1,693 +0,0 @@
/*
* NimBLEMeshModel.cpp
*
* Created: on Aug 25 2020
* Author H2zero
*
*/
#include "NimBLEMeshModel.h"
#include "NimBLEUtils.h"
#include "NimBLELog.h"
#if defined(CONFIG_NIMBLE_CPP_IDF)
# include "nimble/nimble_port.h"
#else
# include "nimble/porting/nimble/include/nimble/nimble_port.h"
#endif
#include "NimBLEDevice.h"
#define CID_VENDOR 0x05C3
#define STANDARD_TEST_ID 0x00
static const char* LOG_TAG = "NimBLEMeshModel";
static NimBLEMeshModelCallbacks defaultCallbacks;
static const struct bt_mesh_health_srv_cb health_srv_cb = {
NimBLEHealthSrvCallbacks::faultGetCurrent,
NimBLEHealthSrvCallbacks::faultGetRegistered,
NimBLEHealthSrvCallbacks::faultClear,
NimBLEHealthSrvCallbacks::faultTest,
NimBLEHealthSrvCallbacks::attentionOn,
NimBLEHealthSrvCallbacks::attentionOff
};
/**
* @brief base model constructor
* @param [in] pCallbacks, a pointer to a callback instance for model operations
*/
NimBLEMeshModel::NimBLEMeshModel(NimBLEMeshModelCallbacks *pCallbacks,
uint16_t initDataSize, uint16_t maxDataSize)
: m_value(initDataSize, maxDataSize),
m_targetValue(initDataSize, maxDataSize)
{
if(pCallbacks == nullptr) {
m_callbacks = &defaultCallbacks;
} else {
m_callbacks = pCallbacks;
}
m_opList = nullptr;
m_lastTid = 0;
m_lastSrcAddr = 0;
m_lastDstAddr = 0;
m_lastMsgTime = 0;
m_transTime = 0;
m_delayTime = 0;
m_transStep = 0;
memset(&m_opPub, 0, sizeof(m_opPub));
}
/**
* @brief destructor
*/
NimBLEMeshModel::~NimBLEMeshModel() {
if(m_opList != nullptr) {
delete[] m_opList;
}
}
int NimBLEMeshModel::extractTransTimeDelay(os_mbuf *buf)
{
switch(buf->om_len) {
case 0x00:
m_transTime = 0;
m_delayTime = 0;
return 0;
case 0x02:
m_transTime = buf->om_data[0];
if((m_transTime & 0x3F) == 0x3F) {
// unknown transition time
m_transTime = 0;
m_delayTime = 0;
return BLE_HS_EINVAL;
}
m_delayTime = buf->om_data[1];
return 0;
default:
return BLE_HS_EMSGSIZE;
}
}
bool NimBLEMeshModel::checkRetransmit(uint8_t tid, bt_mesh_msg_ctx *ctx) {
time_t now = time(nullptr);
if(m_lastTid == tid &&
m_lastSrcAddr == ctx->addr &&
m_lastDstAddr == ctx->recv_dst &&
(now - m_lastMsgTime <= 6)) {
NIMBLE_LOGD(LOG_TAG, "Ignoring retransmit");
return true;
}
m_lastTid = tid;
m_lastSrcAddr = ctx->addr;
m_lastDstAddr = ctx->recv_dst;
m_lastMsgTime = now;
return false;
}
void NimBLEMeshModel::sendMessage(bt_mesh_model *model, bt_mesh_msg_ctx *ctx, os_mbuf *msg) {
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
NIMBLE_LOGE(LOG_TAG, "Send status failed");
}
os_mbuf_free_chain(msg);
}
void NimBLEMeshModel::startTdTimer(ble_npl_time_t timerMs) {
ble_npl_time_t ticks;
ble_npl_time_ms_to_ticks(timerMs, &ticks);
ble_npl_callout_reset(&m_tdTimer, ticks);
}
void NimBLEMeshModel::publish() {
ble_npl_callout_reset(&m_pubTimer, 1);
}
uint32_t NimBLEMeshModel::getTransTime() {
return (m_transTime & 0x3F) * NimBLEUtils::meshTransTimeMs(m_transTime);
}
uint16_t NimBLEMeshModel::getDelayTime() {
return m_delayTime * 5;
}
/**
* @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, 1, 1)
{
// Register the opcodes for this model with the required callbacks
m_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};
ble_npl_callout_init(&m_tdTimer, nimble_port_get_dflt_eventq(),
NimBLEGenOnOffSrvModel::tdTimerCb, this);
ble_npl_callout_init(&m_pubTimer, nimble_port_get_dflt_eventq(),
NimBLEGenOnOffSrvModel::pubTimerCb, this);
m_opPub.msg = NET_BUF_SIMPLE(2 + 3);
}
/**
* @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)
{
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
if(pModel->m_callbacks != &defaultCallbacks) {
pModel->setValue(pModel->m_callbacks->getOnOff(pModel));
}
pModel->setPubMsg();
if (bt_mesh_model_send(model, ctx, pModel->m_opPub.msg, NULL, NULL)) {
NIMBLE_LOGE(LOG_TAG, "Send status failed");
}
}
/**
* @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)
{
// Rather than duplicate code just call the unack function then send the status
NimBLEGenOnOffSrvModel::setOnOffUnack(model,ctx,buf);
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)
{
NimBLEMeshModel *pModel = (NimBLEMeshModel*)model->user_data;
uint8_t newval = net_buf_simple_pull_u8(buf);
uint8_t tid = net_buf_simple_pull_u8(buf);
if(pModel->checkRetransmit(tid, ctx)) {
return;
}
if(pModel->extractTransTimeDelay(buf) != 0) {
NIMBLE_LOGI(LOG_TAG, "Transition time / delay data error");
return;
}
// stop the transition timer to handle the new input
ble_npl_callout_stop(&pModel->m_tdTimer);
// Mesh spec says transition to "ON state" happens immediately
// after delay, so ignore the transition time.
if(newval == 1) {
pModel->m_transTime = 0;
}
ble_npl_time_t timerMs = 0;
if(newval != pModel->m_value[0]) {
pModel->m_targetValue.setValue(&newval, sizeof(newval));
if(pModel->m_delayTime > 0) {
timerMs = 5 * pModel->m_delayTime;
} else if(pModel->m_transTime & 0x3F) {
timerMs = NimBLEUtils::meshTransTimeMs(pModel->m_transTime);
pModel->m_transTime -= 1;
}
}
if(timerMs > 0) {
pModel->startTdTimer(timerMs);
} else {
pModel->m_value = pModel->m_targetValue;
pModel->m_callbacks->setOnOff(pModel, pModel->m_value[0]);
}
}
void NimBLEGenOnOffSrvModel::tdTimerCb(ble_npl_event *event) {
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
if(pModel->m_delayTime > 0) {
pModel->m_delayTime = 0;
}
if((pModel->m_transTime & 0x3F) && pModel->m_targetValue[0] == 0) {
pModel->startTdTimer(NimBLEUtils::meshTransTimeMs(pModel->m_transTime));
pModel->m_transTime -= 1;
pModel->publish();
return;
}
pModel->m_transTime = 0;
pModel->m_value = pModel->m_targetValue;
pModel->m_callbacks->setOnOff(pModel, pModel->m_value[0]);
}
void NimBLEGenOnOffSrvModel::pubTimerCb(ble_npl_event *event) {
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
pModel->setPubMsg();
int err = bt_mesh_model_publish(pModel->m_opPub.mod);
if(err != 0) {
NIMBLE_LOGD(LOG_TAG, "Publish rc: %d",err);
}
}
void NimBLEGenOnOffSrvModel::setPubMsg() {
bt_mesh_model_msg_init(m_opPub.msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
net_buf_simple_add_u8(m_opPub.msg, m_value[0]);
if(m_transTime > 0) {
net_buf_simple_add_u8(m_opPub.msg, m_targetValue[0]);
// If we started the transition timer in setOnOff we need to correct the reported remaining time.
net_buf_simple_add_u8(m_opPub.msg, (m_delayTime > 0) ?
m_transTime : m_transTime + 1);
}
}
void NimBLEGenOnOffSrvModel::setValue(uint8_t *val, size_t len) {
if(len != sizeof(uint8_t)) {
NIMBLE_LOGE(LOG_TAG, "NimBLEGenOnOffSrvModel: Incorrect value length");
return;
}
m_value.setValue(val, len);
}
void NimBLEGenOnOffSrvModel::setTargetValue(uint8_t *val, size_t len) {
if(len != sizeof(uint8_t)) {
NIMBLE_LOGE(LOG_TAG, "NimBLEGenOnOffSrvModel: Incorrect target value length");
return;
}
m_targetValue.setValue(val, len);
}
/**
* @brief Generic level server model constructor
* @param [in] pCallbacks, a pointer to a callback instance for model operations
*/
NimBLEGenLevelSrvModel::NimBLEGenLevelSrvModel(NimBLEMeshModelCallbacks *pCallbacks)
:NimBLEMeshModel(pCallbacks, 2, 2)
{
// Register the opcodes for this model with the required callbacks
m_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};
ble_npl_callout_init(&m_tdTimer, nimble_port_get_dflt_eventq(),
NimBLEGenLevelSrvModel::tdTimerCb, this);
ble_npl_callout_init(&m_pubTimer, nimble_port_get_dflt_eventq(),
NimBLEGenLevelSrvModel::pubTimerCb, this);
m_opPub.msg = NET_BUF_SIMPLE(2 + 5);
}
/**
* @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;
if(pModel->m_callbacks != &defaultCallbacks) {
pModel->setValue(pModel->m_callbacks->getLevel(pModel));
}
pModel->setPubMsg();
if (bt_mesh_model_send(model, ctx, pModel->m_opPub.msg, NULL, NULL)) {
NIMBLE_LOGE(LOG_TAG, "Send status failed");
}
}
/**
* @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)
{
NimBLEGenLevelSrvModel::setLevelUnack(model, ctx, 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;
int16_t newval = (int16_t) net_buf_simple_pull_le16(buf);
uint8_t tid = net_buf_simple_pull_u8(buf);
if(pModel->checkRetransmit(tid, ctx)) {
return;
}
if(pModel->extractTransTimeDelay(buf) != 0) {
NIMBLE_LOGI(LOG_TAG, "Transition time / delay data error");
return;
}
// stop the transition timer to handle the new input
ble_npl_callout_stop(&pModel->m_tdTimer);
ble_npl_time_t timerMs = 0;
int16_t curval = pModel->m_value.getValue<int16_t>(nullptr, true);
if(newval != curval) {
pModel->m_targetValue.setValue(newval);
if(pModel->m_delayTime > 0) {
timerMs = 5 * pModel->m_delayTime;
}
if(pModel->m_transTime & 0x3F) {
pModel->m_transStep = -1 * ((curval - newval) / (pModel->m_transTime & 0x3F));
if(timerMs == 0) {
timerMs = NimBLEUtils::meshTransTimeMs(pModel->m_transTime);
pModel->m_transTime -= 1;
}
}
}
if(timerMs > 0) {
pModel->startTdTimer(timerMs);
} else {
pModel->m_value = pModel->m_targetValue;
pModel->m_callbacks->setLevel(pModel, newval);
}
}
/**
* @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)
{
NimBLEGenLevelSrvModel::setDeltaUnack(model, ctx, 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;
int32_t delta = (int32_t) net_buf_simple_pull_le32(buf);
int32_t temp32 = pModel->m_value.getValue<int16_t>(nullptr, true) + delta;
if (temp32 < INT16_MIN) {
temp32 = INT16_MIN;
} else if (temp32 > INT16_MAX) {
temp32 = INT16_MAX;
}
net_buf_simple_push_le16(buf, (uint16_t)temp32);
NimBLEGenLevelSrvModel::setLevelUnack(model, ctx, buf);
}
void NimBLEGenLevelSrvModel::setMove(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
NimBLEGenLevelSrvModel::setMoveUnack(model, ctx, buf);
NimBLEGenLevelSrvModel::getLevel(model, ctx, buf);
}
void NimBLEGenLevelSrvModel::setMoveUnack(bt_mesh_model *model,
bt_mesh_msg_ctx *ctx,
os_mbuf *buf)
{
int16_t delta = (int16_t) net_buf_simple_pull_le16(buf);
// Check if a transition time is present, if not then ignore this message.
// See: bluetooth mesh specifcation
if(buf->om_len < 3) {
return;
}
put_le32(net_buf_simple_push(buf, 4), (int32_t)delta);
NimBLEGenLevelSrvModel::setDeltaUnack(model, ctx, buf);
}
void NimBLEGenLevelSrvModel::tdTimerCb(ble_npl_event *event) {
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
if(pModel->m_delayTime > 0) {
pModel->m_delayTime = 0;
}
if(pModel->m_transTime & 0x3F) {
int16_t newval = pModel->m_value.getValue<int16_t>(nullptr, true) + pModel->m_transStep;
pModel->m_value.setValue(newval);
pModel->m_callbacks->setLevel(pModel, newval);
pModel->startTdTimer(NimBLEUtils::meshTransTimeMs(pModel->m_transTime));
pModel->m_transTime -= 1;
return;
}
pModel->m_transTime = 0;
pModel->m_value = pModel->m_targetValue;
pModel->m_callbacks->setLevel(pModel, pModel->m_value.getValue<int16_t>(nullptr, true));
}
void NimBLEGenLevelSrvModel::pubTimerCb(ble_npl_event *event) {
NimBLEMeshModel *pModel = (NimBLEMeshModel*)event->arg;
pModel->setPubMsg();
int err = bt_mesh_model_publish(pModel->m_opPub.mod);
if(err != 0) {
NIMBLE_LOGD(LOG_TAG, "Publish rc: %d",err);
}
}
void NimBLEGenLevelSrvModel::setPubMsg() {
bt_mesh_model_msg_init(m_opPub.msg, BT_MESH_MODEL_OP_2(0x82, 0x08));
net_buf_simple_add_le16(m_opPub.msg, m_value.getValue<int16_t>(nullptr, true));
if(m_transTime > 0) {
net_buf_simple_add_le16(m_opPub.msg, m_targetValue.getValue<int16_t>(nullptr, true));
// If we started the transition timer in setOnOff we need to correct the reported remaining time.
net_buf_simple_add_u8(m_opPub.msg, (m_delayTime > 0) ?
m_transTime : m_transTime + 1);
}
}
void NimBLEGenLevelSrvModel::setValue(uint8_t *val, size_t len) {
if(len != sizeof(int16_t)) {
NIMBLE_LOGE(LOG_TAG, "NimBLEGenLevelSrvModel: Incorrect value length");
return;
}
m_value.setValue(val, len);
}
void NimBLEGenLevelSrvModel::setTargetValue(uint8_t *val, size_t len) {
if(len != sizeof(int16_t)) {
NIMBLE_LOGE(LOG_TAG, "NimBLEGenLevelSrvModel: Incorrect target value length");
return;
}
m_targetValue.setValue(val, len);
}
/**
* @brief Health server model constructor
* @param [in] pCallbacks, a pointer to a callback instance for model operations
*/
NimBLEHealthSrvModel::NimBLEHealthSrvModel(NimBLEMeshModelCallbacks *pCallbacks)
:NimBLEMeshModel(pCallbacks, 1, 1)
{
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;
}
void NimBLEHealthSrvModel::setFault(uint8_t fault) {
m_faults.push_back(fault);
m_hasFault = true;
}
void NimBLEHealthSrvModel::clearFaults() {
m_faults.clear();
m_hasFault = false;
}
/**
* Default model callbacks
*/
NimBLEMeshModelCallbacks::~NimBLEMeshModelCallbacks() {}
void NimBLEMeshModelCallbacks::setOnOff(NimBLEMeshModel *pModel, uint8_t val) {
NIMBLE_LOGD(LOG_TAG, "Gen On/Off set val: %d", val);
}
uint8_t NimBLEMeshModelCallbacks::getOnOff(NimBLEMeshModel *pModel) {
NIMBLE_LOGD(LOG_TAG, "Gen On/Off get");
return 0;
}
void NimBLEMeshModelCallbacks::setLevel(NimBLEMeshModel *pModel, int16_t val) {
NIMBLE_LOGD(LOG_TAG, "Gen Level set val: %d", val);
}
int16_t NimBLEMeshModelCallbacks::getLevel(NimBLEMeshModel *pModel) {
NIMBLE_LOGD(LOG_TAG, "Gen Level get");
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
*/
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");
NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model);
*test_id = pModel->m_testId;
*company_id = CID_VENDOR;
*fault_count = std::min(*(size_t*)fault_count, pModel->m_faults.size());
memcpy(faults, &pModel->m_faults[0], *fault_count);
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");
if (company_id != CID_VENDOR) {
return -BLE_HS_EINVAL;
}
NimBLEHealthSrvModel* pModel = (NimBLEHealthSrvModel*)NimBLEDevice::getMeshNode()->getHealthModel(model);
*test_id = pModel->m_testId;
*fault_count = std::min(*(size_t*)fault_count, pModel->m_faults.size());
memcpy(faults, &pModel->m_faults[0], *fault_count);
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);
}

View File

@@ -1,197 +0,0 @@
/*
* 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"
#include "NimBLEAttValue.h"
#include <vector>
class NimBLEMeshModelCallbacks;
class NimBLEMeshModel {
public:
NimBLEMeshModel(NimBLEMeshModelCallbacks* pCallbacks,
uint16_t initDataSize = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH,
uint16_t maxDataSize = BLE_ATT_ATTR_MAX_LEN);
virtual ~NimBLEMeshModel();
int extractTransTimeDelay(os_mbuf *buf);
bool checkRetransmit(uint8_t tid, bt_mesh_msg_ctx *ctx);
void sendMessage(bt_mesh_model *model, bt_mesh_msg_ctx *ctx, os_mbuf *msg);
void startTdTimer(ble_npl_time_t timerMs);
void publish();
uint32_t getTransTime();
uint16_t getDelayTime();
virtual void setPubMsg(){};
virtual void setValue(uint8_t *val, size_t len){};
virtual void setTargetValue(uint8_t *val, size_t len){};
virtual void setFault(uint8_t){};
virtual void clearFaults(){};
template<typename T>
void setValue(const T &s) {
setValue((uint8_t*)&s, sizeof(T));
}
template<typename T>
void setTargetValue(const T &s) {
setTargetValue((uint8_t*)&s, sizeof(T));
}
template<typename T>
void getValue(T &s) {
s = (T)m_value[0];
}
template<typename T>
void getTargetValue(T &s) {
s = (T)m_targetValue[0];
}
bt_mesh_model_op* m_opList;
bt_mesh_model_pub m_opPub;
NimBLEMeshModelCallbacks* m_callbacks;
uint8_t m_lastTid;
uint16_t m_lastSrcAddr;
uint16_t m_lastDstAddr;
time_t m_lastMsgTime;
uint8_t m_transTime;
uint8_t m_delayTime;
NimBLEAttValue m_value;
NimBLEAttValue m_targetValue;
int16_t m_transStep;
ble_npl_callout m_tdTimer;
ble_npl_callout m_pubTimer;
};
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);
static void tdTimerCb(ble_npl_event *event);
static void pubTimerCb(ble_npl_event *event);
void setPubMsg() override;
void setValue(uint8_t *val, size_t len) override;
void setTargetValue(uint8_t *val, size_t len) override;
};
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);
static void tdTimerCb(ble_npl_event *event);
static void pubTimerCb(ble_npl_event *event);
void setPubMsg() override;
void setValue(uint8_t *val, size_t len) override;
void setTargetValue(uint8_t *val, size_t len) override;
};
class NimBLEHealthSrvModel : NimBLEMeshModel {
friend class NimBLEMeshElement;
friend class NimBLEMeshNode;
friend class NimBLEHealthSrvCallbacks;
NimBLEHealthSrvModel(NimBLEMeshModelCallbacks *pCallbacks);
~NimBLEHealthSrvModel(){};
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<uint8_t> m_faults;
};
class NimBLEMeshModelCallbacks {
public:
virtual ~NimBLEMeshModelCallbacks();
virtual void setOnOff(NimBLEMeshModel *pModel, uint8_t val);
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);
};
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_MODEL_H_

View File

@@ -1,210 +0,0 @@
/*
* NimBLEMeshNode.cpp
*
* Created: on July 22 2020
* Author H2zero
*
*/
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include "NimBLEMeshNode.h"
#include "NimBLELog.h"
#include "NimBLEDevice.h"
#include "NimBLEMeshCreateModel.h"
#if defined(CONFIG_NIMBLE_CPP_IDF)
# include "services/gap/ble_svc_gap.h"
# include "services/gatt/ble_svc_gatt.h"
#else
# include "nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h"
# include "nimble/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h"
#endif
#define CID_VENDOR 0x05C3
static const char* LOG_TAG = "NimBLEMeshNode";
/**
* @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));
// 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);
// Provisioning config
m_uuid = uuid;
m_prov.uuid = m_uuid.getNative()->u128.value;
m_prov.complete = NimBLEMeshNode::provComplete;
m_prov.reset = NimBLEMeshNode::provReset;
// Create the primary element
m_elemVec.push_back(new NimBLEMeshElement());
}
/**
* @brief Destructor, cleanup any resources created.
*/
NimBLEMeshNode::~NimBLEMeshNode() {
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 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.
*/
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_elemVec[0]->addModel(createConfigSrvModel(&m_serverConfig));
if(m_elemVec[0]->getModel(BT_MESH_MODEL_ID_HEALTH_SRV) == nullptr) {
m_elemVec[0]->createModel(BT_MESH_MODEL_ID_HEALTH_SRV);
}
// 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;
}
#endif // CONFIG_BT_ENABLED

View File

@@ -1,76 +0,0 @@
/*
* NimBLEMeshNode.h
*
* Created: on July 22 2020
* Author H2zero
*
*/
#ifndef MAIN_NIMBLE_MESH_NODE_H_
#define MAIN_NIMBLE_MESH_NODE_H_
#include "nimconfig.h"
#if defined(CONFIG_BT_ENABLED)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-arith"
#if defined(CONFIG_NIMBLE_CPP_IDF)
# include "mesh/glue.h"
# include "mesh/mesh.h"
#else
# include "nimble/nimble/host/mesh/include/mesh/glue.h"
# include "nimble/nimble/host/mesh/include/mesh/mesh.h"
#endif
#pragma GCC diagnostic pop
/**** FIX COMPILATION ****/
#undef min
#undef max
/**************************/
#include "NimBLEUUID.h"
#include "NimBLEMeshElement.h"
#include <vector>
class NimBLEMeshModel;
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);
NimBLEMeshModel* getHealthModel(bt_mesh_model *model);
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;
NimBLEUUID m_uuid;
std::vector<NimBLEMeshElement*> m_elemVec;
};
#endif // CONFIG_BT_ENABLED
#endif // MAIN_NIMBLE_MESH_NODE_H_

View File

@@ -16,6 +16,7 @@
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLERemoteCharacteristic.h"
#include "NimBLEDevice.h"
#include "NimBLEUtils.h"
#include "NimBLELog.h"
@@ -179,14 +180,7 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
* If we get any other error code tell the application to abort by returning non-zero in the rc.
*/
if (rc == BLE_HS_EDONE) {
pTaskData->rc = 0;
xTaskNotifyGive(pTaskData->task);
} else if(rc != 0) {
// Error; abort discovery.
pTaskData->rc = rc;
xTaskNotifyGive(pTaskData->task);
}
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc);
return rc;
@@ -216,11 +210,9 @@ int NimBLERemoteCharacteristic::nextCharCB(uint16_t conn_handle,
rc = BLE_HS_EDONE;
} else if (rc == BLE_HS_EDONE) {
pChar->m_endHandle = pChar->getRemoteService()->getEndHandle();
} else {
pTaskData->rc = rc;
}
xTaskNotifyGive(pTaskData->task);
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
return rc;
}
@@ -238,8 +230,7 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
}
int rc = 0;
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
// If we don't know the end handle of this characteristic retrieve the next one in the service
// The end handle is the next characteristic definition handle -1.
@@ -254,11 +245,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "Find end handle timeout");
return false;
}
if (taskData.rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Could not retrieve end handle rc=%d", taskData.rc);
@@ -270,6 +260,7 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
return true;
}
taskData.rc = -1;
desc_filter_t filter = {uuid_filter, &taskData};
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
@@ -283,11 +274,10 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "Discover Descriptors timeout");
return false;
}
if (taskData.rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d",
@@ -501,10 +491,8 @@ NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
int rc = 0;
int retryCount = 1;
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, &value};
do {
ble_task_data_t taskData = {this, nullptr, -1, &value};
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteCharacteristic::onReadCB,
&taskData);
@@ -514,11 +502,10 @@ NimBLEAttValue NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
return value;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "readValue timeout");
return value;
}
rc = taskData.rc;
switch(rc){
@@ -588,9 +575,7 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
}
}
pTaskData->rc = rc;
xTaskNotifyGive(pTaskData->task);
NimBLEDevice::taskComplete(pTaskData, rc);
return rc;
}
@@ -783,10 +768,8 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
return (rc==0);
}
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
do {
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
if(length > mtu) {
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
@@ -799,16 +782,17 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
NimBLERemoteCharacteristic::onWriteCB,
&taskData);
}
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "Write value timeout");
return false;
}
rc = taskData.rc;
switch(rc){
@@ -854,11 +838,10 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
return 0;
}
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
pTaskData->rc = error->status;
xTaskNotifyGive(pTaskData->task);
int rc = error->status;
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", rc, conn_handle);
NimBLEDevice::taskComplete(pTaskData, rc == BLE_HS_EDONE ? 0 : rc);
return 0;
}

View File

@@ -16,6 +16,7 @@
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLERemoteDescriptor.h"
#include "NimBLEDevice.h"
#include "NimBLEUtils.h"
#include "NimBLELog.h"
@@ -127,10 +128,10 @@ NimBLEAttValue NimBLERemoteDescriptor::readValue() {
int rc = 0;
int retryCount = 1;
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, &value};
do {
ble_task_data_t taskData = {this, nullptr, -1, &value};
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteDescriptor::onReadCB,
&taskData);
@@ -140,11 +141,11 @@ NimBLEAttValue NimBLERemoteDescriptor::readValue() {
return value;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "Read desc value timeout");
return false;
}
rc = taskData.rc;
switch(rc){
@@ -208,9 +209,7 @@ int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
}
}
pTaskData->rc = rc;
xTaskNotifyGive(pTaskData->task);
NimBLEDevice::taskComplete(pTaskData, rc);
return rc;
}
@@ -247,8 +246,7 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
pTaskData->rc = error->status;
xTaskNotifyGive(pTaskData->task);
NimBLEDevice::taskComplete(pTaskData, error->status);
return 0;
}
@@ -306,10 +304,9 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
return (rc == 0);
}
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
do {
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
if(length > mtu) {
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
@@ -328,11 +325,11 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "Desc write value timeout");
return false;
}
rc = taskData.rc;
switch(rc) {

View File

@@ -199,7 +199,8 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
pTaskData->rc = error->status;
}
xTaskNotifyGive(pTaskData->task);
//xTaskNotifyGive(pTaskData->task);
NimBLEDevice::taskComplete(pTaskData, pTaskData->rc);
NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered");
return error->status;
@@ -215,8 +216,8 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
int rc = 0;
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
//TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, nullptr, -1, nullptr};
if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
@@ -238,11 +239,10 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
return false;
}
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (!NimBLEDevice::taskWait(&taskData, 10 * 1000)) {
NIMBLE_LOGE(LOG_TAG, "disc chars timeout");
return false;
}
if(taskData.rc == 0){
if (uuid_filter == nullptr) {

View File

@@ -180,7 +180,7 @@ NimBLEScan::~NimBLEScan() {
if(pScan->m_pTaskData != nullptr) {
pScan->m_pTaskData->rc = event->disc_complete.reason;
xTaskNotifyGive(pScan->m_pTaskData->task);
NimBLEDevice::taskComplete(pScan->m_pTaskData , 0);
}
return 0;
@@ -397,16 +397,12 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
}
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {nullptr, cur_task, 0, nullptr};
//TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {nullptr, nullptr, -1, nullptr};
m_pTaskData = &taskData;
if(start(duration, nullptr, is_continue)) {
#ifdef ulTaskNotifyValueClear
// Clear the task notification value to ensure we block
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
#endif
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
NimBLEDevice::taskWait(&taskData, 10 * 1000);
}
m_pTaskData = nullptr;
@@ -436,7 +432,7 @@ bool NimBLEScan::stop() {
}
if(m_pTaskData != nullptr) {
xTaskNotifyGive(m_pTaskData->task);
NimBLEDevice::taskComplete(m_pTaskData, 0);
}
NIMBLE_LOGD(LOG_TAG, "<< stop()");

View File

@@ -54,22 +54,6 @@ int NimBLEUtils::checkConnParams(ble_gap_conn_params* params) {
return 0;
}
ble_npl_time_t NimBLEUtils::meshTransTimeMs(uint8_t tt) {
switch(tt >> 6) {
case 0:
return 100;
case 1:
return 1000;
case 2:
return 10000;
case 3:
return 600000;
default:
return 0;
}
}
/**
* @brief Converts a return code from the NimBLE stack to a text string.

View File

@@ -27,7 +27,7 @@
typedef struct {
void *pATT;
TaskHandle_t task;
void * task;
int rc;
void *buf;
} ble_task_data_t;
@@ -44,7 +44,6 @@ public:
static const char* advTypeToString(uint8_t advType);
static const char* returnCodeToString(int rc);
static int checkConnParams(ble_gap_conn_params* params);
static ble_npl_time_t meshTransTimeMs(uint8_t tt);
};

View File

@@ -1,295 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef __UTIL_BASE64_H
#define __UTIL_BASE64_H
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
struct base64_decoder {
/*** public */
const char *src;
void *dst;
int src_len; /* <=0 if src ends with '\0' */
int dst_len; /* <=0 if dst unbounded */
/*** private */
char buf[4];
int buf_len;
};
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static int
pos(char c)
{
const char *p;
for (p = base64_chars; *p; p++)
if (*p == c)
return p - base64_chars;
return -1;
}
int
base64_encode(const void *data, int size, char *s, uint8_t should_pad)
{
char *p;
int i;
int c;
const unsigned char *q;
char *last;
int diff;
p = s;
q = (const unsigned char *) data;
last = NULL;
i = 0;
while (i < size) {
c = q[i++];
c *= 256;
if (i < size)
c += q[i];
i++;
c *= 256;
if (i < size)
c += q[i];
i++;
p[0] = base64_chars[(c & 0x00fc0000) >> 18];
p[1] = base64_chars[(c & 0x0003f000) >> 12];
p[2] = base64_chars[(c & 0x00000fc0) >> 6];
p[3] = base64_chars[(c & 0x0000003f) >> 0];
last = p;
p += 4;
}
if (last) {
diff = i - size;
if (diff > 0) {
if (should_pad) {
memset(last + (4 - diff), '=', diff);
} else {
p = last + (4 - diff);
}
}
}
*p = 0;
return (p - s);
}
int
base64_pad(char *buf, int len)
{
int remainder;
remainder = len % 4;
if (remainder == 0) {
return (0);
}
memset(buf, '=', 4 - remainder);
return (4 - remainder);
}
#define DECODE_ERROR -1
static unsigned int
token_decode(const char *token, int len)
{
int i;
unsigned int val = 0;
int marker = 0;
if (len < 4) {
return DECODE_ERROR;
}
for (i = 0; i < 4; i++) {
val *= 64;
if (token[i] == '=') {
marker++;
} else if (marker > 0) {
return DECODE_ERROR;
} else {
val += pos(token[i]);
}
}
if (marker > 2) {
return DECODE_ERROR;
}
return (marker << 24) | val;
}
int
base64_decoder_go(struct base64_decoder *dec)
{
unsigned int marker;
unsigned int val;
uint8_t *dst;
char sval;
int read_len;
int src_len;
int src_rem;
int src_off;
int dst_len;
int dst_off;
int i;
dst = dec->dst;
dst_off = 0;
src_off = 0;
/* A length <= 0 means "unbounded". */
if (dec->src_len <= 0) {
src_len = INT_MAX;
} else {
src_len = dec->src_len;
}
if (dec->dst_len <= 0) {
dst_len = INT_MAX;
} else {
dst_len = dec->dst_len;
}
while (1) {
src_rem = src_len - src_off;
if (src_rem == 0) {
/* End of source input. */
break;
}
if (dec->src[src_off] == '\0') {
/* End of source string. */
break;
}
/* Account for possibility of partial token from previous call. */
read_len = 4 - dec->buf_len;
/* Detect invalid input. */
for (i = 0; i < read_len; i++) {
sval = dec->src[src_off + i];
if (sval == '\0') {
/* Incomplete input. */
return -1;
}
if (sval != '=' && strchr(base64_chars, sval) == NULL) {
/* Invalid base64 character. */
return -1;
}
}
if (src_rem < read_len) {
/* Input contains a partial token. Stash it for use during the
* next call.
*/
memcpy(&dec->buf[dec->buf_len], &dec->src[src_off], src_rem);
dec->buf_len += src_rem;
break;
}
/* Copy full token into buf and decode it. */
memcpy(&dec->buf[dec->buf_len], &dec->src[src_off], read_len);
val = token_decode(dec->buf, read_len);
if (val == DECODE_ERROR) {
return -1;
}
src_off += read_len;
dec->buf_len = 0;
marker = (val >> 24) & 0xff;
if (dst_off >= dst_len) {
break;
}
dst[dst_off] = (val >> 16) & 0xff;
dst_off++;
if (marker < 2) {
if (dst_off >= dst_len) {
break;
}
dst[dst_off] = (val >> 8) & 0xff;
dst_off++;
}
if (marker < 1) {
if (dst_off >= dst_len) {
break;
}
dst[dst_off] = val & 0xff;
dst_off++;
}
}
return dst_off;
}
int
base64_decode(const char *str, void *data)
{
struct base64_decoder dec = {
.src = str,
.dst = data,
};
return base64_decoder_go(&dec);
}
int
base64_decode_maxlen(const char *str, void *data, int len)
{
struct base64_decoder dec = {
.src = str,
.dst = data,
.dst_len = len,
};
return base64_decoder_go(&dec);
}
int
base64_decode_len(const char *str)
{
int len;
len = strlen(str);
while (len && str[len - 1] == '=') {
len--;
}
return len * 3 / 4;
}
#define BASE64_ENCODE_SIZE(__size) (((((__size) - 1) / 3) * 4) + 4)
#ifdef __cplusplus
}
#endif
#endif /* __UTIL_BASE64_H__ */

View File

@@ -1,238 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef __SYS_CONFIG_H_
#define __SYS_CONFIG_H_
#include "../../nimconfig.h"
#if defined(CONFIG_NIMBLE_CPP_IDF)
# include <os/queue.h>
#else
# include "nimble/porting/nimble/include/os/queue.h"
#endif
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define CONF_MAX_DIR_DEPTH 8 /* max depth of config tree */
#define CONF_MAX_NAME_LEN (8 * CONF_MAX_DIR_DEPTH)
/**
* Type of configuration value.
*/
typedef enum conf_type {
CONF_NONE = 0,
CONF_DIR,
/** 8-bit signed integer */
CONF_INT8,
/** 16-bit signed integer */
CONF_INT16,
/** 32-bit signed integer */
CONF_INT32,
/** 64-bit signed integer */
CONF_INT64,
/** String */
CONF_STRING,
/** Bytes */
CONF_BYTES,
/** Floating point */
CONF_FLOAT,
/** Double precision */
CONF_DOUBLE,
/** Boolean */
CONF_BOOL,
/** 8-bit unsigned integer */
CONF_UINT8,
/** 16-bit unsigned integer */
CONF_UINT16,
/** 32-bit unsigned integer */
CONF_UINT32,
/** 64-bit unsigned integer */
CONF_UINT64,
} __attribute__((__packed__)) conf_type_t;
/**
* Parameter to commit handler describing where data is going to.
*/
enum conf_export_tgt {
/** Value is to be persisted */
CONF_EXPORT_PERSIST,
/** Value is to be display */
CONF_EXPORT_SHOW
};
typedef enum conf_export_tgt conf_export_tgt_t;
/**
* Handler for getting configuration items, this handler is called
* per-configuration section. Configuration sections are delimited
* by '/', for example:
*
* - section/name/value
*
* Would be passed as:
*
* - argc = 3
* - argv[0] = section
* - argv[1] = name
* - argv[2] = value
*
* The handler returns the value into val, null terminated, up to
* val_len_max.
*
* @param argc The number of sections in the configuration variable
* @param argv The array of configuration sections
* @param val A pointer to the buffer to return the configuration
* value into.
* @param val_len_max The maximum length of the val buffer to copy into.
*
* @return A pointer to val or NULL if error.
*/
typedef char *(*conf_get_handler_t)(int argc, char **argv, char *val, int val_len_max);
typedef char *(*conf_get_handler_ext_t)(int argc, char **argv, char *val, int val_len_max, void *arg);
/**
* Set the configuration variable pointed to by argc and argv. See
* description of ch_get_handler_t for format of these variables. This sets the
* configuration variable to the shadow value, but does not apply the configuration
* change. In order to apply the change, call the ch_commit() handler.
*
* @param argc The number of sections in the configuration variable.
* @param argv The array of configuration sections
* @param val The value to configure that variable to
*
* @return 0 on success, non-zero error code on failure.
*/
typedef int (*conf_set_handler_t)(int argc, char **argv, char *val);
typedef int (*conf_set_handler_ext_t)(int argc, char **argv, char *val, void *arg);
/**
* Commit shadow configuration state to the active configuration.
*
* @return 0 on success, non-zero error code on failure.
*/
typedef int (*conf_commit_handler_t)(void);
typedef int (*conf_commit_handler_ext_t)(void *arg);
/**
* Called per-configuration variable being exported.
*
* @param name The name of the variable to export
* @param val The value of the variable to export
*/
typedef void (*conf_export_func_t)(char *name, char *val);
/**
* Export all of the configuration variables, calling the export_func
* per variable being exported.
*
* @param export_func The export function to call.
* @param tgt The target of the export, either for persistence or display.
*
* @return 0 on success, non-zero error code on failure.
*/
typedef int (*conf_export_handler_t)(conf_export_func_t export_func,
conf_export_tgt_t tgt);
typedef int (*conf_export_handler_ext_t)(conf_export_func_t export_func,
conf_export_tgt_t tgt, void *arg);
/**
* Configuration handler, used to register a config item/subtree.
*/
struct conf_handler {
SLIST_ENTRY(conf_handler) ch_list;
/**
* The name of the conifguration item/subtree
*/
char *ch_name;
/**
* Whether to use the extended callbacks.
* false: standard
* true: extended
*/
bool ch_ext;
/** Get configuration value */
union {
conf_get_handler_t ch_get;
conf_get_handler_ext_t ch_get_ext;
};
/** Set configuration value */
union {
conf_set_handler_t ch_set;
conf_set_handler_ext_t ch_set_ext;
};
/** Commit configuration value */
union {
conf_commit_handler_t ch_commit;
conf_commit_handler_ext_t ch_commit_ext;
};
/** Export configuration value */
union {
conf_export_handler_t ch_export;
conf_export_handler_ext_t ch_export_ext;
};
/** Custom argument that gets passed to the extended callbacks */
void *ch_arg;
};
/**
* Register a handler for configurations items.
*
* @param cf Structure containing registration info.
*
* @return 0 on success, non-zero on failure.
*/
int conf_register(struct conf_handler *cf);
/**
* Load configuration from registered persistence sources. Handlers for
* configuration subtrees registered earlier will be called for encountered
* values.
*
* @return 0 on success, non-zero on failure.
*/
int conf_load(void);
/**
* Write a single configuration value to persisted storage (if it has
* changed value).
*
* @param name Name/key of the configuration item.
* @param var Value of the configuration item.
*
* @return 0 on success, non-zero on failure.
*/
int conf_save_one(const char *name, char *var);
#ifdef __cplusplus
}
#endif
#define SYSINIT_PANIC_ASSERT_MSG(rc, msg)
#endif /* __SYS_CONFIG_H_ */

View File

@@ -1,137 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "nimconfig.h"
#ifdef ESP_PLATFORM
#if CONFIG_BT_NIMBLE_MESH
#include "config.h"
#include "nvs.h"
#include <string.h>
static struct conf_handler* config_handler;
int conf_parse_name(char *name, int *name_argc, char *name_argv[])
{
char *tok;
char *tok_ptr;
const char *sep = "/";
int i;
tok = strtok_r(name, sep, &tok_ptr);
i = 0;
while (tok) {
name_argv[i++] = tok;
tok = strtok_r(NULL, sep, &tok_ptr);
}
*name_argc = i;
return 0;
}
int conf_load(void)
{
esp_err_t err;
nvs_handle_t handle;
err = nvs_open(config_handler->ch_name, NVS_READONLY, &handle);
if (err != ESP_OK) return err;
nvs_iterator_t it = nvs_entry_find("nvs", config_handler->ch_name, NVS_TYPE_ANY);
while (it != NULL) {
nvs_entry_info_t info;
nvs_entry_info(it, &info);
it = nvs_entry_next(it);
size_t required_size = 0;
err = nvs_get_str(handle, info.key, NULL, &required_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
char* val = malloc(required_size);
if (required_size > 0) {
err = nvs_get_str(handle, info.key, val, &required_size);
if (err != ESP_OK) {
free(val);
return err;
}
printf("key '%s', type '%d' value %s \n", info.key, info.type, val);
}
int name_argc;
char *name_argv[8];
conf_parse_name(info.key, &name_argc, name_argv);
config_handler->ch_set(name_argc, &name_argv[0], val);
free(val);
}
nvs_close(handle);
config_handler->ch_commit();
return ESP_OK;
}
int conf_save_one(const char *name, char *var)
{
esp_err_t err;
nvs_handle_t handle;
int name_argc;
char *name_argv[CONF_MAX_DIR_DEPTH];
char n[CONF_MAX_NAME_LEN];
strcpy(n, name);
conf_parse_name(n, &name_argc, name_argv);
err = nvs_open(name_argv[0], NVS_READWRITE, &handle);
if (err != ESP_OK) return err;
const char* key = name_argv[1];
if (name_argc > 2) {
key = name;
while (*key != '/') {
key++;
}
key++;
}
if (var) {
err = nvs_set_str(handle, key, var);
if (err != ESP_OK) return err;
} else {
err = nvs_erase_key(handle, key);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
}
err = nvs_commit(handle);
if (err != ESP_OK) return err;
nvs_close(handle);
return ESP_OK;
}
int conf_register(struct conf_handler *cf)
{
config_handler = cf;
return 0;
}
#endif // CONFIG_BT_NIMBLE_MESH
#endif // ESP_PLATFORM

View File

@@ -6,6 +6,7 @@
*/
#pragma once
#ifdef ESP_PLATFORM
#include "sdkconfig.h"
#include "nimconfig_rename.h"
@@ -131,7 +132,6 @@
/** @brief Un-comment to use external PSRAM for the NimBLE host */
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1
/** @brief Un-comment to change the core NimBLE host runs on */
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0
@@ -139,3 +139,15 @@
#define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
#endif // _DOXYGEN_
#else
#include "syscfg/syscfg.h"
#define CONFIG_BT_ENABLED
#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
#define CONFIG_NIMBLE_CPP_IDF
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
#define CONFIG_NIMBLE_CPP_LOG_LEVEL 0
#endif