diff --git a/.vscode/settings.json b/.vscode/settings.json
index a818b7e..9ba7cb6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -30,13 +30,15 @@
"sys.h": "c",
"nrf_log.h": "c",
"version.h": "c",
- "zble_service.h": "c",
+ "zble_module.h": "c",
"pca10112.h": "c",
"pca10100.h": "c",
"board.h": "c",
"stdio.h": "c",
"nrf_log_ctrl.h": "c",
"nrf_log_default_backends.h": "c",
- "nrf_delay.h": "c"
+ "nrf_delay.h": "c",
+ "zhrs_service.h": "c",
+ "ble_srv_common.h": "c"
}
}
\ No newline at end of file
diff --git a/README.md b/README.md
index d446a89..de8b202 100644
--- a/README.md
+++ b/README.md
@@ -26,4 +26,19 @@ sdk\components\boards\pca10100.h
+```
+
+```
+设备行为:
+1. 按下按键或者电极触发后开始广播
+
+2. 当电极没有触发,且蓝牙没有连接,且超时10s后,停止广播,进入低功耗模式
+
+3. 设备状态
+
+ 关机(休眠)
+ 开机蓝牙未连接(广播中)
+ 蓝牙已连接
+
+
```
\ No newline at end of file
diff --git a/app/app.uvoptx b/app/app.uvoptx
index da0a52e..c2bba90 100644
--- a/app/app.uvoptx
+++ b/app/app.uvoptx
@@ -398,8 +398,8 @@
0
0
0
- .\src\zble_service.c
- zble_service.c
+ .\src\zble_module.c
+ zble_module.c
0
0
@@ -415,6 +415,18 @@
0
0
+
+ 1
+ 5
+ 1
+ 0
+ 0
+ 0
+ .\src\zdatachannel_service.c
+ zdatachannel_service.c
+ 0
+ 0
+
@@ -425,7 +437,7 @@
0
2
- 5
+ 6
1
0
0
@@ -445,7 +457,7 @@
0
3
- 6
+ 7
1
0
0
@@ -457,7 +469,7 @@
3
- 7
+ 8
1
0
0
@@ -477,7 +489,7 @@
0
4
- 8
+ 9
1
0
0
@@ -497,7 +509,7 @@
0
5
- 9
+ 10
1
0
0
@@ -509,7 +521,7 @@
5
- 10
+ 11
1
0
0
@@ -521,7 +533,7 @@
5
- 11
+ 12
1
0
0
@@ -533,7 +545,7 @@
5
- 12
+ 13
1
0
0
@@ -545,7 +557,7 @@
5
- 13
+ 14
1
0
0
@@ -557,7 +569,7 @@
5
- 14
+ 15
1
0
0
@@ -569,7 +581,7 @@
5
- 15
+ 16
1
0
0
@@ -581,7 +593,7 @@
5
- 16
+ 17
1
0
0
@@ -601,7 +613,7 @@
0
6
- 17
+ 18
1
0
0
@@ -621,7 +633,7 @@
0
7
- 18
+ 19
1
0
0
@@ -633,7 +645,7 @@
7
- 19
+ 20
1
0
0
@@ -645,7 +657,7 @@
7
- 20
+ 21
1
0
0
@@ -657,7 +669,7 @@
7
- 21
+ 22
1
0
0
@@ -669,7 +681,7 @@
7
- 22
+ 23
1
0
0
@@ -681,7 +693,7 @@
7
- 23
+ 24
1
0
0
@@ -693,7 +705,7 @@
7
- 24
+ 25
1
0
0
@@ -705,7 +717,7 @@
7
- 25
+ 26
1
0
0
@@ -725,7 +737,7 @@
0
8
- 26
+ 27
1
0
0
@@ -737,7 +749,7 @@
8
- 27
+ 28
1
0
0
@@ -749,7 +761,7 @@
8
- 28
+ 29
1
0
0
@@ -761,7 +773,7 @@
8
- 29
+ 30
1
0
0
@@ -773,7 +785,7 @@
8
- 30
+ 31
1
0
0
@@ -785,7 +797,7 @@
8
- 31
+ 32
1
0
0
@@ -797,7 +809,7 @@
8
- 32
+ 33
1
0
0
@@ -809,7 +821,7 @@
8
- 33
+ 34
1
0
0
@@ -821,7 +833,7 @@
8
- 34
+ 35
1
0
0
@@ -833,7 +845,7 @@
8
- 35
+ 36
1
0
0
@@ -845,7 +857,7 @@
8
- 36
+ 37
1
0
0
@@ -857,7 +869,7 @@
8
- 37
+ 38
1
0
0
@@ -869,7 +881,7 @@
8
- 38
+ 39
1
0
0
@@ -881,7 +893,7 @@
8
- 39
+ 40
1
0
0
@@ -893,7 +905,7 @@
8
- 40
+ 41
1
0
0
@@ -905,7 +917,7 @@
8
- 41
+ 42
1
0
0
@@ -917,7 +929,7 @@
8
- 42
+ 43
1
0
0
@@ -929,7 +941,7 @@
8
- 43
+ 44
1
0
0
@@ -941,7 +953,7 @@
8
- 44
+ 45
1
0
0
@@ -953,7 +965,7 @@
8
- 45
+ 46
1
0
0
@@ -965,7 +977,7 @@
8
- 46
+ 47
1
0
0
@@ -977,7 +989,7 @@
8
- 47
+ 48
1
0
0
@@ -989,7 +1001,7 @@
8
- 48
+ 49
1
0
0
@@ -1001,7 +1013,7 @@
8
- 49
+ 50
1
0
0
@@ -1013,7 +1025,7 @@
8
- 50
+ 51
1
0
0
@@ -1033,7 +1045,7 @@
0
9
- 51
+ 52
1
0
0
@@ -1045,7 +1057,7 @@
9
- 52
+ 53
1
0
0
@@ -1057,7 +1069,7 @@
9
- 53
+ 54
1
0
0
@@ -1069,7 +1081,7 @@
9
- 54
+ 55
1
0
0
@@ -1081,7 +1093,7 @@
9
- 55
+ 56
1
0
0
@@ -1093,7 +1105,7 @@
9
- 56
+ 57
1
0
0
@@ -1113,7 +1125,7 @@
0
10
- 57
+ 58
1
0
0
@@ -1125,7 +1137,7 @@
10
- 58
+ 59
1
0
0
@@ -1137,7 +1149,7 @@
10
- 59
+ 60
1
0
0
@@ -1157,7 +1169,7 @@
0
11
- 60
+ 61
1
0
0
@@ -1169,7 +1181,7 @@
11
- 61
+ 62
1
0
0
@@ -1181,7 +1193,7 @@
11
- 62
+ 63
1
0
0
@@ -1201,7 +1213,7 @@
0
12
- 63
+ 64
1
0
0
diff --git a/app/app.uvprojx b/app/app.uvprojx
index 4f40246..e9e26aa 100644
--- a/app/app.uvprojx
+++ b/app/app.uvprojx
@@ -394,15 +394,20 @@
main.c
- zble_service.c
+ zble_module.c
1
- .\src\zble_service.c
+ .\src\zble_module.c
board.c
1
.\src\board.c
+
+ zdatachannel_service.c
+ 1
+ .\src\zdatachannel_service.c
+
@@ -4058,15 +4063,20 @@
main.c
- zble_service.c
+ zble_module.c
1
- .\src\zble_service.c
+ .\src\zble_module.c
board.c
1
.\src\board.c
+
+ zdatachannel_service.c
+ 1
+ .\src\zdatachannel_service.c
+
diff --git a/app/main.c b/app/main.c
index f71b293..ac3afaa 100644
--- a/app/main.c
+++ b/app/main.c
@@ -1,27 +1,13 @@
+#if 1
#include "board.h"
#include "nrf_delay.h"
#include "project_cfg.h"
#include "sys.h"
#include "version.h"
-#include "zble_service.h"
-
-zble_service_cfg_t cfg = {.deviceName = "iflytop"};
+#include "zble_module.h"
+#include "zdatachannel_service.h"
#if 0
-void developer_test(void) {
- // 测试LED
- debug_light_init(DEBUG_LIGHT_IO_INDEX);
-
- // 测试BUTTON
- uint8_t io_index[] = {11, 12, 24};
- zbsp_gpio_state_monitor(1000, (uint8_t*)io_index, ZARRAY_SIZE(io_index));
-
- // 测试睡眠唤醒
- zbsp_enter_sleep(3000, 11, true);
-}
-#endif
-// #define BUTTON_1
-// #define BUTTON_2
void qingfengboard_test(void) {
// 测试LED
debug_light_init(15);
@@ -33,18 +19,52 @@ void qingfengboard_test(void) {
// 测试睡眠唤醒
zbsp_enter_sleep(3000, 5, true);
}
+#endif
+
+ZDATACANNEL_DEF(m_zhrs, 2 /*回调事件优先级*/, 1 /*client num*/);
+
+static const char* hex2str(uint8_t data, int32_t len) {
+ static char rx[64] = {0};
+ memset(rx, 0, sizeof(rx));
+ for (int32_t i = 0; i < len; i++) {
+ sprintf(rx + i * 2, "%02X", data);
+ }
+ return rx;
+}
+
+void zdatachannel_data_handler(zdatachannel_evt_t* p_evt) {
+ /**
+ * @brief 接收到指令数据
+ */
+ if (p_evt->type == ZDATACANNEL_EVT_RX_DATA) {
+ ZLOGI("rx:%s", hex2str(p_evt->params.rx_data.p_data[0], p_evt->params.rx_data.length));
+ }
+}
+void on_service_init(void) {
+ /**
+ * @brief 数据通道初始化
+ */
+ ZLOGI("init zdatachannel service");
+ zdatachannel_init_t zdatachannle_init;
+ memset(&zdatachannle_init, 0, sizeof(zdatachannle_init));
+ zdatachannle_init.data_handler = zdatachannel_data_handler;
+ ZERROR_CHECK(zdatachannel_init(&m_zhrs, &zdatachannle_init));
+}
int main(void) {
zsys_init();
- zble_service_init(&cfg);
-
-
NRF_LOG_INFO("compile time :%s", __TIME__);
NRF_LOG_INFO("Version :%d", VERSION);
NRF_LOG_INFO("Manufacturer :%s", MANUFACTURER_NAME);
- /*******************************************************************************
- * 开发板测试 *
- *******************************************************************************/
- qingfengboard_test();
+
+ static zble_module_cfg_t cfg = //
+ {
+ .deviceName = "iflytop",
+ .on_service_init = on_service_init,
+ };
+ zble_module_init(&cfg);
+
+ zble_module_start_adv();
zsys_loop();
}
+#endif
diff --git a/app/src/zble_service.c b/app/src/zble_module.c
similarity index 88%
rename from app/src/zble_service.c
rename to app/src/zble_module.c
index c06b26f..fcd9864 100644
--- a/app/src/zble_service.c
+++ b/app/src/zble_module.c
@@ -1,6 +1,6 @@
-#include "zble_service.h"
+#include "zble_module.h"
#include
#include
@@ -21,7 +21,6 @@ static ble_uuid_t m_adv_uuids[] = /**< Universally u
#define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
#define APP_ADV_DURATION 18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */
-#define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */
/*******************************************************************************
* GATT配置 *
@@ -49,15 +48,15 @@ static uint16_t m_mtu_size = BLE_GATT_ATT_MTU_DEFAULT - 3;
static void sleep_mode_enter(void) {
#if 0
uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
// Prepare wakeup buttons.
err_code = bsp_btn_ble_sleep_mode_prepare();
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
// Go to system-off mode (this function will not return; wakeup will cause a reset).
err_code = sd_power_system_off();
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
#endif
}
@@ -81,31 +80,31 @@ static void ble_evt_handler(ble_evt_t const* p_ble_evt, void* p_context) {
.tx_phys = BLE_GAP_PHY_AUTO,
};
err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
} break;
case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
// Pairing not supported
err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
break;
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
// No system attributes have been stored.
err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
break;
case BLE_GATTC_EVT_TIMEOUT:
// Disconnect on GATT Client timeout event.
err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
break;
case BLE_GATTS_EVT_TIMEOUT:
// Disconnect on GATT Server timeout event.
err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
break;
default:
@@ -126,7 +125,7 @@ static void on_conn_params_evt(ble_conn_params_evt_t* p_evt) {
uint32_t err_code;
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) {
err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
}
}
static void conn_params_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); }
@@ -134,44 +133,35 @@ static void on_adv_evt(ble_adv_evt_t ble_adv_evt) {
uint32_t err_code;
switch (ble_adv_evt) {
case BLE_ADV_EVT_FAST:
- err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
- APP_ERROR_CHECK(err_code);
+ // err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
+ // ZERROR_CHECK(err_code);
break;
case BLE_ADV_EVT_IDLE:
- sleep_mode_enter();
+ // sleep_mode_enter();
break;
default:
break;
}
}
-void zble_service_start_adv() {
+void zble_module_start_adv() {
uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
+}
+void zble_module_stop_adv() {
+ uint32_t err_code = sd_ble_gap_adv_stop(m_advertising.adv_handle);
+ ZERROR_CHECK(err_code);
}
-void zble_service_stop_adv() {}
/*******************************************************************************
* INIT *
*******************************************************************************/
-void zble_service_init(zble_service_cfg_t* cfg) {
+void zble_module_init(zble_module_cfg_t* cfg) {
/**
* @brief
* 初始化蓝牙协议栈,并注册蓝牙事件处理函数,固定代码,勿修改
*/
- {
- ret_code_t err_code;
- err_code = nrf_sdh_enable_request();
- APP_ERROR_CHECK(err_code);
- uint32_t ram_start = 0;
- err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
- APP_ERROR_CHECK(err_code);
- // Enable BLE stack.
- err_code = nrf_sdh_ble_enable(&ram_start);
- APP_ERROR_CHECK(err_code);
- // Register a handler for BLE events.
- NRF_SDH_BLE_OBSERVER(m_ble_observer, 3, ble_evt_handler, NULL);
- }
+ { NRF_SDH_BLE_OBSERVER(m_ble_observer, 3, ble_evt_handler, NULL); }
/*******************************************************************************
* GAP初始化 *
*******************************************************************************/
@@ -183,7 +173,7 @@ void zble_service_init(zble_service_cfg_t* cfg) {
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t*)cfg->deviceName, strlen(cfg->deviceName));
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
@@ -193,7 +183,7 @@ void zble_service_init(zble_service_cfg_t* cfg) {
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
}
/*******************************************************************************
@@ -203,16 +193,18 @@ void zble_service_init(zble_service_cfg_t* cfg) {
ret_code_t err_code;
err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
}
/*******************************************************************************
* 蓝牙服务初始化 *
*******************************************************************************/
{
+ // if (cfg->on_service_init) cfg->on_service_init();
+
uint32_t err_code;
ble_nus_init_t nus_init;
nrf_ble_qwr_init_t qwr_init = {0};
@@ -254,7 +246,7 @@ void zble_service_init(zble_service_cfg_t* cfg) {
init.evt_handler = on_adv_evt;
err_code = ble_advertising_init(&m_advertising, &init);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}
@@ -277,8 +269,8 @@ void zble_service_init(zble_service_cfg_t* cfg) {
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
- APP_ERROR_CHECK(err_code);
+ ZERROR_CHECK(err_code);
}
- // zble_service_start_adv();
+ // zble_module_start_adv();
}
\ No newline at end of file
diff --git a/app/src/zble_module.h b/app/src/zble_module.h
new file mode 100644
index 0000000..a630a0a
--- /dev/null
+++ b/app/src/zble_module.h
@@ -0,0 +1,20 @@
+#pragma once
+#include
+
+/**
+ * @brief
+ */
+
+typedef void (*on_service_init_t)(void);
+
+typedef struct {
+ const char* deviceName;
+ on_service_init_t on_service_init;
+} zble_module_cfg_t;
+
+void zble_module_init(zble_module_cfg_t* cfg);
+
+void zble_module_start_adv();
+void zble_module_stop_adv();
+
+void zble_module_is_connected();
diff --git a/app/src/zble_service copy.c b/app/src/zble_service copy.c
deleted file mode 100644
index b098a86..0000000
--- a/app/src/zble_service copy.c
+++ /dev/null
@@ -1,584 +0,0 @@
-
-
-#include
-#include
-
-#include "app_timer.h"
-#include "app_uart.h"
-#include "app_util_platform.h"
-#include "ble_advdata.h"
-#include "ble_advertising.h"
-#include "ble_conn_params.h"
-#include "ble_hci.h"
-#include "ble_nus.h"
-#include "bsp_btn_ble.h"
-#include "nordic_common.h"
-#include "nrf.h"
-#include "nrf_ble_gatt.h"
-#include "nrf_ble_qwr.h"
-#include "nrf_pwr_mgmt.h"
-#include "nrf_sdh.h"
-#include "nrf_sdh_ble.h"
-#include "nrf_sdh_soc.h"
-
-#if defined(UART_PRESENT)
-#include "nrf_uart.h"
-#endif
-#if defined(UARTE_PRESENT)
-#include "nrf_uarte.h"
-#endif
-
-#include "nrf_log.h"
-#include "nrf_log_ctrl.h"
-#include "nrf_log_default_backends.h"
-
-#define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */
-
-#define DEVICE_NAME "Nordic_UART" /**< Name of device. Will be included in the advertising data. */
-#define NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service (vendor specific). */
-
-#define APP_BLE_OBSERVER_PRIO 3 /**< Application's BLE observer priority. You shouldn't need to modify this value. */
-
-#define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
-
-#define APP_ADV_DURATION 18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
-
-#define MIN_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
-#define MAX_CONN_INTERVAL MSEC_TO_UNITS(75, UNIT_1_25_MS) /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
-#define SLAVE_LATENCY 0 /**< Slave latency. */
-#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */
-#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
-#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
-#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */
-
-#define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
-
-#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
-#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */
-
-BLE_NUS_DEF(m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT); /**< BLE NUS service instance. */
-NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
-NRF_BLE_QWR_DEF(m_qwr); /**< Context for the Queued Write module.*/
-BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */
-
-static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
-static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
-static ble_uuid_t m_adv_uuids[] = /**< Universally unique service identifier. */
- {{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};
-
-/**@brief Function for assert macro callback.
- *
- * @details This function will be called in case of an assert in the SoftDevice.
- *
- * @warning This handler is an example only and does not fit a final product. You need to analyse
- * how your product is supposed to react in case of Assert.
- * @warning On assert from the SoftDevice, the system can only recover on reset.
- *
- * @param[in] line_num Line number of the failing ASSERT call.
- * @param[in] p_file_name File name of the failing ASSERT call.
- */
-void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name) { app_error_handler(DEAD_BEEF, line_num, p_file_name); }
-
-/**@brief Function for initializing the timer module.
- */
-static void timers_init(void) {
- ret_code_t err_code = app_timer_init();
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Function for the GAP initialization.
- *
- * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
- * the device. It also sets the permissions and appearance.
- */
-static void gap_params_init(void) {
- uint32_t err_code;
- ble_gap_conn_params_t gap_conn_params;
- ble_gap_conn_sec_mode_t sec_mode;
-
- BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
-
- err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME));
- APP_ERROR_CHECK(err_code);
-
- memset(&gap_conn_params, 0, sizeof(gap_conn_params));
-
- gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
- gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
- gap_conn_params.slave_latency = SLAVE_LATENCY;
- gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
-
- err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Function for handling Queued Write Module errors.
- *
- * @details A pointer to this function will be passed to each service which may need to inform the
- * application about an error.
- *
- * @param[in] nrf_error Error code containing information about what went wrong.
- */
-static void nrf_qwr_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); }
-
-/**@brief Function for handling the data from the Nordic UART Service.
- *
- * @details This function will process the data received from the Nordic UART BLE Service and send
- * it to the UART module.
- *
- * @param[in] p_evt Nordic UART Service event.
- */
-/**@snippet [Handling the data received over BLE] */
-static void nus_data_handler(ble_nus_evt_t *p_evt) {
- if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
- uint32_t err_code;
-
- NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
- NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
-
- for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++) {
- do {
- err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
- if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY)) {
- NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
- APP_ERROR_CHECK(err_code);
- }
- } while (err_code == NRF_ERROR_BUSY);
- }
- if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r') {
- while (app_uart_put('\n') == NRF_ERROR_BUSY)
- ;
- }
- }
-}
-/**@snippet [Handling the data received over BLE] */
-
-/**@brief Function for initializing services that will be used by the application.
- */
-static void services_init(void) {
- uint32_t err_code;
- ble_nus_init_t nus_init;
- nrf_ble_qwr_init_t qwr_init = {0};
-
- // Initialize Queued Write Module.
- qwr_init.error_handler = nrf_qwr_error_handler;
-
- err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
- APP_ERROR_CHECK(err_code);
-
- // Initialize NUS.
- memset(&nus_init, 0, sizeof(nus_init));
-
- nus_init.data_handler = nus_data_handler;
-
- err_code = ble_nus_init(&m_nus, &nus_init);
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Function for handling an event from the Connection Parameters Module.
- *
- * @details This function will be called for all events in the Connection Parameters Module
- * which are passed to the application.
- *
- * @note All this function does is to disconnect. This could have been done by simply setting
- * the disconnect_on_fail config parameter, but instead we use the event handler
- * mechanism to demonstrate its use.
- *
- * @param[in] p_evt Event received from the Connection Parameters Module.
- */
-static void on_conn_params_evt(ble_conn_params_evt_t *p_evt) {
- uint32_t err_code;
-
- if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) {
- err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
- APP_ERROR_CHECK(err_code);
- }
-}
-
-/**@brief Function for handling errors from the Connection Parameters module.
- *
- * @param[in] nrf_error Error code containing information about what went wrong.
- */
-static void conn_params_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); }
-
-/**@brief Function for initializing the Connection Parameters module.
- */
-static void conn_params_init(void) {
- uint32_t err_code;
- ble_conn_params_init_t cp_init;
-
- memset(&cp_init, 0, sizeof(cp_init));
-
- cp_init.p_conn_params = NULL;
- cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
- cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
- cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
- cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
- cp_init.disconnect_on_fail = false;
- cp_init.evt_handler = on_conn_params_evt;
- cp_init.error_handler = conn_params_error_handler;
-
- err_code = ble_conn_params_init(&cp_init);
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Function for putting the chip into sleep mode.
- *
- * @note This function will not return.
- */
-static void sleep_mode_enter(void) {
- uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
- APP_ERROR_CHECK(err_code);
-
- // Prepare wakeup buttons.
- err_code = bsp_btn_ble_sleep_mode_prepare();
- APP_ERROR_CHECK(err_code);
-
- // Go to system-off mode (this function will not return; wakeup will cause a reset).
- err_code = sd_power_system_off();
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Function for handling advertising events.
- *
- * @details This function will be called for advertising events which are passed to the application.
- *
- * @param[in] ble_adv_evt Advertising event.
- */
-static void on_adv_evt(ble_adv_evt_t ble_adv_evt) {
- uint32_t err_code;
-
- switch (ble_adv_evt) {
- case BLE_ADV_EVT_FAST:
- err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
- APP_ERROR_CHECK(err_code);
- break;
- case BLE_ADV_EVT_IDLE:
- sleep_mode_enter();
- break;
- default:
- break;
- }
-}
-
-/**@brief Function for handling BLE events.
- *
- * @param[in] p_ble_evt Bluetooth stack event.
- * @param[in] p_context Unused.
- */
-static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context) {
- uint32_t err_code;
-
- switch (p_ble_evt->header.evt_id) {
- case BLE_GAP_EVT_CONNECTED:
- NRF_LOG_INFO("Connected");
- err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
- APP_ERROR_CHECK(err_code);
- m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
- err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
- APP_ERROR_CHECK(err_code);
- break;
-
- case BLE_GAP_EVT_DISCONNECTED:
- NRF_LOG_INFO("Disconnected");
- // LED indication will be changed when advertising starts.
- m_conn_handle = BLE_CONN_HANDLE_INVALID;
- break;
-
- case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
- NRF_LOG_DEBUG("PHY update request.");
- ble_gap_phys_t const phys = {
- .rx_phys = BLE_GAP_PHY_AUTO,
- .tx_phys = BLE_GAP_PHY_AUTO,
- };
- err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
- APP_ERROR_CHECK(err_code);
- } break;
-
- case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
- // Pairing not supported
- err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
- APP_ERROR_CHECK(err_code);
- break;
-
- case BLE_GATTS_EVT_SYS_ATTR_MISSING:
- // No system attributes have been stored.
- err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
- APP_ERROR_CHECK(err_code);
- break;
-
- case BLE_GATTC_EVT_TIMEOUT:
- // Disconnect on GATT Client timeout event.
- err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
- APP_ERROR_CHECK(err_code);
- break;
-
- case BLE_GATTS_EVT_TIMEOUT:
- // Disconnect on GATT Server timeout event.
- err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
- APP_ERROR_CHECK(err_code);
- break;
-
- default:
- // No implementation needed.
- break;
- }
-}
-
-/**@brief Function for the SoftDevice initialization.
- *
- * @details This function initializes the SoftDevice and the BLE event interrupt.
- */
-static void ble_stack_init(void) {
- ret_code_t err_code;
-
- err_code = nrf_sdh_enable_request();
- APP_ERROR_CHECK(err_code);
-
- // Configure the BLE stack using the default settings.
- // Fetch the start address of the application RAM.
- uint32_t ram_start = 0;
- err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
- APP_ERROR_CHECK(err_code);
-
- // Enable BLE stack.
- err_code = nrf_sdh_ble_enable(&ram_start);
- APP_ERROR_CHECK(err_code);
-
- // Register a handler for BLE events.
- NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
-}
-
-/**@brief Function for handling events from the GATT library. */
-void gatt_evt_handler(nrf_ble_gatt_t *p_gatt, nrf_ble_gatt_evt_t const *p_evt) {
- if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) {
- m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
- NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
- }
- NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x", p_gatt->att_mtu_desired_central, p_gatt->att_mtu_desired_periph);
-}
-
-/**@brief Function for initializing the GATT library. */
-void gatt_init(void) {
- ret_code_t err_code;
-
- err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
- APP_ERROR_CHECK(err_code);
-
- err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Function for handling events from the BSP module.
- *
- * @param[in] event Event generated by button press.
- */
-void bsp_event_handler(bsp_event_t event) {
- uint32_t err_code;
- switch (event) {
- case BSP_EVENT_SLEEP:
- sleep_mode_enter();
- break;
-
- case BSP_EVENT_DISCONNECT:
- err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
- if (err_code != NRF_ERROR_INVALID_STATE) {
- APP_ERROR_CHECK(err_code);
- }
- break;
-
- case BSP_EVENT_WHITELIST_OFF:
- if (m_conn_handle == BLE_CONN_HANDLE_INVALID) {
- err_code = ble_advertising_restart_without_whitelist(&m_advertising);
- if (err_code != NRF_ERROR_INVALID_STATE) {
- APP_ERROR_CHECK(err_code);
- }
- }
- break;
-
- default:
- break;
- }
-}
-
-/**@brief Function for handling app_uart events.
- *
- * @details This function will receive a single character from the app_uart module and append it to
- * a string. The string will be be sent over BLE when the last character received was a
- * 'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
- */
-/**@snippet [Handling the data received over UART] */
-void uart_event_handle(app_uart_evt_t *p_event) {
- static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
- static uint8_t index = 0;
- uint32_t err_code;
-
- switch (p_event->evt_type) {
- case APP_UART_DATA_READY:
- UNUSED_VARIABLE(app_uart_get(&data_array[index]));
- index++;
-
- if ((data_array[index - 1] == '\n') || (data_array[index - 1] == '\r') || (index >= m_ble_nus_max_data_len)) {
- if (index > 1) {
- NRF_LOG_DEBUG("Ready to send data over BLE NUS");
- NRF_LOG_HEXDUMP_DEBUG(data_array, index);
-
- do {
- uint16_t length = (uint16_t)index;
- err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
- if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_RESOURCES) && (err_code != NRF_ERROR_NOT_FOUND)) {
- APP_ERROR_CHECK(err_code);
- }
- } while (err_code == NRF_ERROR_RESOURCES);
- }
-
- index = 0;
- }
- break;
-
- case APP_UART_COMMUNICATION_ERROR:
- APP_ERROR_HANDLER(p_event->data.error_communication);
- break;
-
- case APP_UART_FIFO_ERROR:
- APP_ERROR_HANDLER(p_event->data.error_code);
- break;
-
- default:
- break;
- }
-}
-/**@snippet [Handling the data received over UART] */
-
-/**@brief Function for initializing the UART module.
- */
-/**@snippet [UART Initialization] */
-static void uart_init(void) {
- uint32_t err_code;
- app_uart_comm_params_t const comm_params = {
- .rx_pin_no = RX_PIN_NUMBER,
- .tx_pin_no = TX_PIN_NUMBER,
- .rts_pin_no = RTS_PIN_NUMBER,
- .cts_pin_no = CTS_PIN_NUMBER,
- .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
- .use_parity = false,
-#if defined(UART_PRESENT)
- .baud_rate = NRF_UART_BAUDRATE_115200
-#else
- .baud_rate = NRF_UARTE_BAUDRATE_115200
-#endif
- };
-
- APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_event_handle, APP_IRQ_PRIORITY_LOWEST, err_code);
- APP_ERROR_CHECK(err_code);
-}
-/**@snippet [UART Initialization] */
-
-/**@brief Function for initializing the Advertising functionality.
- */
-static void advertising_init(void) {
- uint32_t err_code;
- ble_advertising_init_t init;
-
- memset(&init, 0, sizeof(init));
-
- init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
- init.advdata.include_appearance = false;
- init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
-
- init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
- init.srdata.uuids_complete.p_uuids = m_adv_uuids;
-
- init.config.ble_adv_fast_enabled = true;
- init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
- init.config.ble_adv_fast_timeout = APP_ADV_DURATION;
- init.evt_handler = on_adv_evt;
-
- err_code = ble_advertising_init(&m_advertising, &init);
- APP_ERROR_CHECK(err_code);
-
- ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
-}
-
-/**@brief Function for initializing buttons and leds.
- *
- * @param[out] p_erase_bonds Will be true if the clear bonding button was pressed to wake the application up.
- */
-static void buttons_leds_init(bool *p_erase_bonds) {
- bsp_event_t startup_event;
-
- uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
- APP_ERROR_CHECK(err_code);
-
- err_code = bsp_btn_ble_init(NULL, &startup_event);
- APP_ERROR_CHECK(err_code);
-
- *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
-}
-
-/**@brief Function for initializing the nrf log module.
- */
-static void log_init(void) {
- ret_code_t err_code = NRF_LOG_INIT(NULL);
- APP_ERROR_CHECK(err_code);
-
- NRF_LOG_DEFAULT_BACKENDS_INIT();
-}
-
-/**@brief Function for initializing power management.
- */
-static void power_management_init(void) {
- ret_code_t err_code;
- err_code = nrf_pwr_mgmt_init();
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Function for handling the idle state (main loop).
- *
- * @details If there is no pending log operation, then sleep until next the next event occurs.
- */
-static void idle_state_handle(void) {
- if (NRF_LOG_PROCESS() == false) {
- nrf_pwr_mgmt_run();
- }
-}
-
-/**@brief Function for starting advertising.
- */
-static void advertising_start(void) {
- uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
- APP_ERROR_CHECK(err_code);
-}
-
-/**@brief Application main function.
- */
-int main(void) {
- bool erase_bonds;
- // // Initialize.
- // uart_init();
- // log_init();
-
- // timers_init();
- // buttons_leds_init(&erase_bonds);
- // power_management_init();
- // ble_stack_init();
- // gap_params_init();
- // gatt_init();
- services_init();
- advertising_init();
- conn_params_init();
-
- // Start execution.
- printf("\r\nUART started.\r\n");
- NRF_LOG_INFO("Debug logging for UART over RTT started.");
- advertising_start();
-
- // Enter main loop.
- for (;;) {
- idle_state_handle();
- }
-}
-
-/**
- * @}
- */
diff --git a/app/src/zble_service.h b/app/src/zble_service.h
deleted file mode 100644
index e5564d1..0000000
--- a/app/src/zble_service.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-#include
-
-typedef struct {
- uint8_t mark; // 占位
- // const char *service_uuid; // 服务UUID
- // const char *cmd_tx_uuid; //
- // const char *cmd_rx_uuid;
- // const char *special_tx_uuid;
-
- const char* deviceName;
-
-} zble_service_cfg_t;
-
-typedef enum {
- konconnect,
- kdisconnect,
-} event_t;
-
-typedef void (*zble_service_cmd_rx_cb_t)(uint8_t* data, uint32_t len);
-
-void zble_service_init(zble_service_cfg_t* cfg);
-void zble_service_send_by_cmd_channel(uint8_t* data, uint32_t len);
-void zble_service_send_by_record_channel(uint8_t* data, uint32_t len);
-
-void zble_service_start_adv();
-void zble_service_stop_adv();
diff --git a/app/src/zdatachannel_service.c b/app/src/zdatachannel_service.c
new file mode 100644
index 0000000..4a45c70
--- /dev/null
+++ b/app/src/zdatachannel_service.c
@@ -0,0 +1,249 @@
+#include "zdatachannel_service.h"
+
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_log.h"
+#include "sdk_common.h"
+
+#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
+#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */
+
+#define ZDATACANNEL_MAX_RX_CHAR_LEN ZDATACANNEL_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
+#define ZDATACANNEL_MAX_TX_CHAR_LEN ZDATACANNEL_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */
+
+#define NUS_BASE_UUID \
+ { \
+ { 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E } \
+ } /**< Used vendor specific UUID. */
+
+/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_connect(zdatachannel_t *p_nus, ble_evt_t const *p_ble_evt) {
+ ret_code_t err_code;
+ zdatachannel_evt_t evt;
+ ble_gatts_value_t gatts_val;
+ uint8_t cccd_value[2];
+ zdatachannel_client_context_t *p_client = NULL;
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, p_ble_evt->evt.gap_evt.conn_handle, (void *)&p_client);
+ if (err_code != NRF_SUCCESS) {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.", p_ble_evt->evt.gap_evt.conn_handle);
+ }
+
+ /* Check the hosts CCCD value to inform of readiness to send data using the RX characteristic */
+ memset(&gatts_val, 0, sizeof(ble_gatts_value_t));
+ gatts_val.p_value = cccd_value;
+ gatts_val.len = sizeof(cccd_value);
+ gatts_val.offset = 0;
+
+ err_code = sd_ble_gatts_value_get(p_ble_evt->evt.gap_evt.conn_handle, p_nus->tx_handles.cccd_handle, &gatts_val);
+
+ if ((err_code == NRF_SUCCESS) && (p_nus->data_handler != NULL) && ble_srv_is_notification_enabled(gatts_val.p_value)) {
+ if (p_client != NULL) {
+ p_client->is_notification_enabled = true;
+ }
+
+ memset(&evt, 0, sizeof(zdatachannel_evt_t));
+ evt.type = ZDATACANNEL_EVT_COMM_STARTED;
+ evt.p_nus = p_nus;
+ evt.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ evt.p_link_ctx = p_client;
+
+ p_nus->data_handler(&evt);
+ }
+}
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_write(zdatachannel_t *p_nus, ble_evt_t const *p_ble_evt) {
+ ret_code_t err_code;
+ zdatachannel_evt_t evt;
+ zdatachannel_client_context_t *p_client;
+ ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, p_ble_evt->evt.gatts_evt.conn_handle, (void *)&p_client);
+ if (err_code != NRF_SUCCESS) {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.", p_ble_evt->evt.gatts_evt.conn_handle);
+ }
+
+ memset(&evt, 0, sizeof(zdatachannel_evt_t));
+ evt.p_nus = p_nus;
+ evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+ evt.p_link_ctx = p_client;
+
+ if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) && (p_evt_write->len == 2)) {
+ if (p_client != NULL) {
+ if (ble_srv_is_notification_enabled(p_evt_write->data)) {
+ p_client->is_notification_enabled = true;
+ evt.type = ZDATACANNEL_EVT_COMM_STARTED;
+ } else {
+ p_client->is_notification_enabled = false;
+ evt.type = ZDATACANNEL_EVT_COMM_STOPPED;
+ }
+
+ if (p_nus->data_handler != NULL) {
+ p_nus->data_handler(&evt);
+ }
+ }
+ } else if ((p_evt_write->handle == p_nus->rx_handles.value_handle) && (p_nus->data_handler != NULL)) {
+ evt.type = ZDATACANNEL_EVT_RX_DATA;
+ evt.params.rx_data.p_data = p_evt_write->data;
+ evt.params.rx_data.length = p_evt_write->len;
+
+ p_nus->data_handler(&evt);
+ } else {
+ // Do Nothing. This event is not relevant for this service.
+ }
+}
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event from the SoftDevice.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_hvx_tx_complete(zdatachannel_t *p_nus, ble_evt_t const *p_ble_evt) {
+ ret_code_t err_code;
+ zdatachannel_evt_t evt;
+ zdatachannel_client_context_t *p_client;
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, p_ble_evt->evt.gatts_evt.conn_handle, (void *)&p_client);
+ if (err_code != NRF_SUCCESS) {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.", p_ble_evt->evt.gatts_evt.conn_handle);
+ return;
+ }
+
+ if ((p_client->is_notification_enabled) && (p_nus->data_handler != NULL)) {
+ memset(&evt, 0, sizeof(zdatachannel_evt_t));
+ evt.type = ZDATACANNEL_EVT_TX_RDY;
+ evt.p_nus = p_nus;
+ evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+ evt.p_link_ctx = p_client;
+
+ p_nus->data_handler(&evt);
+ }
+}
+
+void zdatachannel_on_ble_evt(ble_evt_t const *p_ble_evt, void *p_context) {
+ if ((p_context == NULL) || (p_ble_evt == NULL)) {
+ return;
+ }
+
+ zdatachannel_t *p_nus = (zdatachannel_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id) {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_nus, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_nus, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_hvx_tx_complete(p_nus, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+uint32_t zdatachannel_init(zdatachannel_t *p_nus, zdatachannel_init_t const *p_nus_init) {
+ ret_code_t err_code;
+ ble_uuid_t ble_uuid;
+ ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
+ ble_add_char_params_t add_char_params;
+
+ VERIFY_PARAM_NOT_NULL(p_nus);
+ VERIFY_PARAM_NOT_NULL(p_nus_init);
+
+ // Initialize the service structure.
+ p_nus->data_handler = p_nus_init->data_handler;
+
+ /**@snippet [Adding proprietary Service to the SoftDevice] */
+ // Add a custom base UUID.
+ err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
+ VERIFY_SUCCESS(err_code);
+
+ ble_uuid.type = p_nus->uuid_type;
+ ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
+
+ // Add the service.
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_nus->service_handle);
+ /**@snippet [Adding proprietary Service to the SoftDevice] */
+ VERIFY_SUCCESS(err_code);
+
+ // Add the RX Characteristic.
+ memset(&add_char_params, 0, sizeof(add_char_params));
+ add_char_params.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
+ add_char_params.uuid_type = p_nus->uuid_type;
+ add_char_params.max_len = ZDATACANNEL_MAX_RX_CHAR_LEN;
+ add_char_params.init_len = sizeof(uint8_t);
+ add_char_params.is_var_len = true;
+ add_char_params.char_props.write = 1;
+ add_char_params.char_props.write_wo_resp = 1;
+
+ add_char_params.read_access = SEC_OPEN;
+ add_char_params.write_access = SEC_OPEN;
+
+ err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles);
+ if (err_code != NRF_SUCCESS) {
+ return err_code;
+ }
+
+ // Add the TX Characteristic.
+ /**@snippet [Adding proprietary characteristic to the SoftDevice] */
+ memset(&add_char_params, 0, sizeof(add_char_params));
+ add_char_params.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
+ add_char_params.uuid_type = p_nus->uuid_type;
+ add_char_params.max_len = ZDATACANNEL_MAX_TX_CHAR_LEN;
+ add_char_params.init_len = sizeof(uint8_t);
+ add_char_params.is_var_len = true;
+ add_char_params.char_props.notify = 1;
+
+ add_char_params.read_access = SEC_OPEN;
+ add_char_params.write_access = SEC_OPEN;
+ add_char_params.cccd_write_access = SEC_OPEN;
+
+ return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles);
+ /**@snippet [Adding proprietary characteristic to the SoftDevice] */
+}
+
+uint32_t zdatachannel_data_send(zdatachannel_t *p_nus, uint8_t *p_data, uint16_t *p_length, uint16_t conn_handle) {
+ ret_code_t err_code;
+ ble_gatts_hvx_params_t hvx_params;
+ zdatachannel_client_context_t *p_client;
+
+ VERIFY_PARAM_NOT_NULL(p_nus);
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *)&p_client);
+ VERIFY_SUCCESS(err_code);
+
+ if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL)) {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ if (!p_client->is_notification_enabled) {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (*p_length > ZDATACANNEL_MAX_DATA_LEN) {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_nus->tx_handles.value_handle;
+ hvx_params.p_data = p_data;
+ hvx_params.p_len = p_length;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+
+ return sd_ble_gatts_hvx(conn_handle, &hvx_params);
+}
diff --git a/app/src/zdatachannel_service.h b/app/src/zdatachannel_service.h
new file mode 100644
index 0000000..f9cffd0
--- /dev/null
+++ b/app/src/zdatachannel_service.h
@@ -0,0 +1,95 @@
+#ifndef ZDATACANNEL_H__
+#define ZDATACANNEL_H__
+
+#include
+#include
+
+#include "ble.h"
+#include "ble_link_ctx_manager.h"
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_nus instance.
+ *
+ * @param _name Name of the instance.
+ * @param[in] _nus_max_clients Maximum number of NUS clients connected at a time.
+ * @hideinitializer
+ */
+#define ZDATACANNEL_DEF(_name, _ble_observer_prio,_nus_max_clients) \
+ BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage), (_nus_max_clients), sizeof(zdatachannel_client_context_t)); \
+ static zdatachannel_t _name = {.p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage)}; \
+ NRF_SDH_BLE_OBSERVER(_name##_obs, _ble_observer_prio, zdatachannel_on_ble_evt, &_name)
+
+#define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
+
+#define OPCODE_LENGTH 1
+#define HANDLE_LENGTH 2
+
+/**@brief Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
+#if defined(NRF_SDH_BLE_GATT_MAX_MTU_SIZE) && (NRF_SDH_BLE_GATT_MAX_MTU_SIZE != 0)
+#define ZDATACANNEL_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH)
+#else
+#define ZDATACANNEL_MAX_DATA_LEN (BLE_GATT_MTU_SIZE_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH)
+#warning NRF_SDH_BLE_GATT_MAX_MTU_SIZE is not defined.
+#endif
+
+/**@brief Nordic UART Service event types. */
+typedef enum {
+ ZDATACANNEL_EVT_RX_DATA, /**< Data received. */
+ ZDATACANNEL_EVT_TX_RDY, /**< Service is ready to accept new data to be transmitted. */
+ ZDATACANNEL_EVT_COMM_STARTED, /**< Notification has been enabled. */
+ ZDATACANNEL_EVT_COMM_STOPPED, /**< Notification has been disabled. */
+} zdatachannel_evt_type_t;
+
+typedef struct zdatachannel_s zdatachannel_t;
+
+typedef struct {
+ uint8_t const* p_data; /**< A pointer to the buffer with received data. */
+ uint16_t length; /**< Length of received data. */
+} zdatachannel_evt_rx_data_t;
+
+typedef struct {
+ bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/
+} zdatachannel_client_context_t;
+
+typedef struct {
+ zdatachannel_evt_type_t type; /**< Event type. */
+ zdatachannel_t* p_nus; /**< A pointer to the instance. */
+ uint16_t conn_handle; /**< Connection handle. */
+ zdatachannel_client_context_t* p_link_ctx; /**< A pointer to the link context. */
+ union {
+ zdatachannel_evt_rx_data_t rx_data; /**< @ref ZDATACANNEL_EVT_RX_DATA event data. */
+ } params;
+} zdatachannel_evt_t;
+
+typedef void (*zdatachannel_data_handler_t)(zdatachannel_evt_t* p_evt);
+
+typedef struct {
+ zdatachannel_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
+} zdatachannel_init_t;
+
+struct zdatachannel_s {
+ uint8_t uuid_type; /**< UUID type for Nordic UART Service Base UUID. */
+ uint16_t service_handle; /**< Handle of Nordic UART Service (as provided by the SoftDevice). */
+ ble_gatts_char_handles_t tx_handles; /**< Handles related to the TX characteristic (as provided by the SoftDevice). */
+ ble_gatts_char_handles_t rx_handles; /**< Handles related to the RX characteristic (as provided by the SoftDevice). */
+ blcm_link_ctx_storage_t* const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
+ zdatachannel_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
+};
+
+uint32_t zdatachannel_init(zdatachannel_t* p_nus, zdatachannel_init_t const* p_nus_init);
+void zdatachannel_on_ble_evt(ble_evt_t const* p_ble_evt, void* p_context);
+uint32_t zdatachannel_data_send(zdatachannel_t* p_nus, uint8_t* p_data, uint16_t* p_length, uint16_t conn_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ZDATACANNEL_H__
+
+/** @} */
diff --git a/libznordic b/libznordic
index 3678551..5c809e7 160000
--- a/libznordic
+++ b/libznordic
@@ -1 +1 @@
-Subproject commit 3678551881438d95c91c36b2f2277219084e2a05
+Subproject commit 5c809e793ce8fc2f764a68f1eade7e59f39b1259