1 Commits

Author SHA1 Message Date
h2zero
b1ae44774a WIP - compiles with mynewt 2024-12-11 08:39:34 -07:00
30 changed files with 205 additions and 2425 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,28 +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/NimBLEMeshCreateModel.c"
"src/NimBLEMeshElement.cpp"
"src/NimBLEMeshModel.cpp"
"src/NimBLEMeshNode.cpp")
endif()
if(CONFIG_NIMBLE_CPP_PERSIST_MESH_SETTINGS)
list(APPEND srcs "src/mesh_config_store/config/config_store.c")
endif()
idf_component_register(
REQUIRED_IDF_TARGETS
"esp32"
"esp32s3"
"esp32c3"
INCLUDE_DIRS
"src"
SRCS "${srcs}"
"src/NimBLEUUID.cpp"
REQUIRES
bt
nvs_flash
@@ -74,7 +57,3 @@ idf_component_register(
${ESP_NIMBLE_PRIV_REQUIRES}
)
if(CONFIG_BT_NIMBLE_MESH AND CONFIG_NIMBLE_CPP_PERSIST_MESH_SETTINGS)
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()

14
Kconfig
View File

@@ -33,7 +33,7 @@ config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
Enabling this option will display return code values as text
messages in the debug log. This will use approximately 8kB
of flash memory.
config NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
bool "Show NimBLE gap events as text in debug log."
default "n"
@@ -47,7 +47,7 @@ config NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
default "n"
help
Enabling this option will display advertisment types recieved
while scanning as text messages in the debug log.
while scanning as text messages in the debug log.
This will use approximately 250 bytes of flash memory.
config NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED
@@ -68,13 +68,5 @@ config NIMBLE_CPP_ATT_VALUE_INIT_LENGTH
when the constructor is called. This is also the size used when a remote
characteristic or descriptor is constructed before a value is read/notifed.
Increasing this will reduce reallocations but increase memory footprint.
config NIMBLE_CPP_PERSIST_MESH_SETTINGS
bool "Enable persistent storage of mesh config settings."
default "n"
depends on BT_NIMBLE_MESH
help
Enabling this option will store the provisioning and app key settings
in non-volatile storage when using NimBLE Mesh.
endmenu

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,35 +0,0 @@
/*
* NimBLEMeshCreateModel.cpp
*
* Created: on April 27 2022
* Author H2zero
*
*/
#include "nimconfig.h"
#if CONFIG_BT_NIMBLE_MESH
#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;
}
#endif // CONFIG_BT_NIMBLE_MESH

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,145 +0,0 @@
/*
* NimBLEMeshElement.cpp
*
* Created: on Aug 23 2020
* Author H2zero
*
*/
#include "nimconfig.h"
#if CONFIG_BT_NIMBLE_MESH
#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;
}
#endif // CONFIG_BT_NIMBLE_MESH

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,700 +0,0 @@
/*
* NimBLEMeshModel.cpp
*
* Created: on Aug 25 2020
* Author H2zero
*
*/
#include "nimconfig.h"
#if CONFIG_BT_NIMBLE_MESH
#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));
memset(&m_tdTimer, 0, sizeof(m_tdTimer));
memset(&m_pubTimer, 0, sizeof(m_pubTimer));
}
/**
* @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);
}
#endif // CONFIG_BT_NIMBLE_MESH

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,209 +0,0 @@
/*
* NimBLEMeshNode.cpp
*
* Created: on July 22 2020
* Author H2zero
*
*/
#include "nimconfig.h"
#if CONFIG_BT_NIMBLE_MESH
#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_NIMBLE_MESH

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) assert(rc)
#endif /* __SYS_CONFIG_H_ */

View File

@@ -1,136 +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 && CONFIG_NIMBLE_CPP_PERSIST_MESH_SETTINGS
#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 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;
}
}
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 && MYNEWT_VAL_BLE_MESH_SETTINGS
#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