BLE 연결 파라미터 기존과 동일하게 변경
This commit is contained in:
+149
-12
@@ -4,8 +4,8 @@
|
||||
*
|
||||
* Original VesiScan-Basic BLE implementation ported to Zephyr/NCS:
|
||||
* - NUS (Nordic UART Service) for data exchange
|
||||
* - Advertising: 40ms interval, 3-min timeout
|
||||
* - Connection: 30ms interval, 0 latency, 4s supervision timeout
|
||||
* - Advertising: 40ms interval, 10-min timeout
|
||||
* - Connection: 15ms interval, 0 latency, 10s supervision timeout
|
||||
* - TX power +8 dBm, 2M PHY preferred
|
||||
* - Dev mode: no security / Production mode: bonding + passkey (TODO)
|
||||
******************************************************************************/
|
||||
@@ -35,6 +35,9 @@ LOG_MODULE_REGISTER(ble_svc, LOG_LEVEL_INF);
|
||||
static struct bt_conn *current_conn;
|
||||
static ble_data_rx_cb_t rx_callback;
|
||||
static bool dfu_advertising_mode;
|
||||
static bool advertising_unlimited;
|
||||
static uint8_t conn_param_update_attempts;
|
||||
static int64_t last_rx_conn_param_update_ms;
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_SMP)
|
||||
#define BLE_REQUIRED_SECURITY_LEVEL BT_SECURITY_L4
|
||||
@@ -60,6 +63,8 @@ static struct k_sem nus_tx_done_sem;
|
||||
|
||||
/* BLE API는 ISR/콜백에서 직접 호출하면 안전하지 않을 수 있으므로 k_work 사용 */
|
||||
static struct k_work adv_restart_work;
|
||||
static struct k_work_delayable adv_timeout_work;
|
||||
static struct k_work_delayable conn_param_update_work;
|
||||
static const bt_addr_le_t fixed_identity_addr = {
|
||||
.type = BT_ADDR_LE_RANDOM,
|
||||
.a = {
|
||||
@@ -271,6 +276,85 @@ static void adv_restart_handler(struct k_work *work)
|
||||
led_set_state(LED_STATE_ADVERTISING);
|
||||
}
|
||||
|
||||
static void adv_timeout_handler(struct k_work *work)
|
||||
{
|
||||
ARG_UNUSED(work);
|
||||
|
||||
if (!ble_connection_st && !advertising_unlimited && !dfu_advertising_mode)
|
||||
{
|
||||
DBG_PRINTF("[BLE] Advertising timeout\r\n");
|
||||
(void)ble_advertising_stop();
|
||||
}
|
||||
}
|
||||
|
||||
static bool ble_conn_param_is_preferred(uint16_t interval, uint16_t latency,
|
||||
uint16_t timeout)
|
||||
{
|
||||
return (interval == BLE_MIN_CONN_INTERVAL) &&
|
||||
(latency == BLE_SLAVE_LATENCY) &&
|
||||
(timeout == BLE_CONN_SUP_TIMEOUT);
|
||||
}
|
||||
|
||||
static int ble_request_preferred_conn_params(bool count_attempt)
|
||||
{
|
||||
struct bt_le_conn_param conn_param =
|
||||
{
|
||||
.interval_min = BLE_MIN_CONN_INTERVAL,
|
||||
.interval_max = BLE_MAX_CONN_INTERVAL,
|
||||
.latency = BLE_SLAVE_LATENCY,
|
||||
.timeout = BLE_CONN_SUP_TIMEOUT,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (current_conn == NULL)
|
||||
{
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
if (count_attempt)
|
||||
{
|
||||
conn_param_update_attempts++;
|
||||
}
|
||||
|
||||
DBG_PRINTF("[BLE] Request params: interval=%u latency=%u timeout=%u attempt=%u\r\n",
|
||||
BLE_MIN_CONN_INTERVAL,
|
||||
BLE_SLAVE_LATENCY,
|
||||
BLE_CONN_SUP_TIMEOUT,
|
||||
conn_param_update_attempts);
|
||||
|
||||
err = bt_conn_le_param_update(current_conn, &conn_param);
|
||||
if (err)
|
||||
{
|
||||
DBG_ERR("[BLE] Param update failed err=%d -> disconnect\r\n", err);
|
||||
(void)bt_conn_disconnect(current_conn, BT_HCI_ERR_UNACCEPT_CONN_PARAM);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void conn_param_update_handler(struct k_work *work)
|
||||
{
|
||||
ARG_UNUSED(work);
|
||||
|
||||
if (current_conn == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn_param_update_attempts >= BLE_CONN_PARAM_MAX_ATTEMPTS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ble_request_preferred_conn_params(true) == 0 &&
|
||||
conn_param_update_attempts < BLE_CONN_PARAM_MAX_ATTEMPTS)
|
||||
{
|
||||
k_work_schedule(&conn_param_update_work,
|
||||
K_MSEC(BLE_CONN_PARAM_RETRY_INTERVAL_MS));
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* Advertising data
|
||||
*============================================================================*/
|
||||
@@ -312,15 +396,10 @@ static void connected(struct bt_conn *conn, uint8_t err)
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
|
||||
DBG_CORE("[BLE] Peer: %s\r\n", addr_str);
|
||||
|
||||
/* Connection parameters (30ms interval) */
|
||||
struct bt_le_conn_param conn_param =
|
||||
{
|
||||
.interval_min = BLE_MIN_CONN_INTERVAL,
|
||||
.interval_max = BLE_MAX_CONN_INTERVAL,
|
||||
.latency = BLE_SLAVE_LATENCY,
|
||||
.timeout = BLE_CONN_SUP_TIMEOUT,
|
||||
};
|
||||
bt_conn_le_param_update(conn, &conn_param);
|
||||
conn_param_update_attempts = 0U;
|
||||
last_rx_conn_param_update_ms = 0;
|
||||
k_work_schedule(&conn_param_update_work,
|
||||
K_MSEC(BLE_CONN_PARAM_FIRST_DELAY_MS));
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_SMP)
|
||||
err = bt_conn_set_security(conn, BLE_REQUIRED_SECURITY_LEVEL);
|
||||
@@ -339,6 +418,10 @@ static void connected(struct bt_conn *conn, uint8_t err)
|
||||
|
||||
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
{
|
||||
k_work_cancel_delayable(&conn_param_update_work);
|
||||
conn_param_update_attempts = 0U;
|
||||
last_rx_conn_param_update_ms = 0;
|
||||
|
||||
if (current_conn)
|
||||
{
|
||||
bt_conn_unref(current_conn);
|
||||
@@ -346,17 +429,48 @@ static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
}
|
||||
|
||||
ble_connection_st = false;
|
||||
advertising_unlimited = true;
|
||||
DBG_CORE("[BLE] Disconnected (reason 0x%02x)\r\n", reason);
|
||||
|
||||
/* 워크큐에서 advertising 재시작 */
|
||||
k_work_submit(&adv_restart_work);
|
||||
}
|
||||
|
||||
static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
|
||||
{
|
||||
ARG_UNUSED(conn);
|
||||
|
||||
if (!ble_conn_param_is_preferred(param->interval_min,
|
||||
param->latency,
|
||||
param->timeout) ||
|
||||
(param->interval_max != BLE_MAX_CONN_INTERVAL))
|
||||
{
|
||||
DBG_PRINTF("[BLE] Override requested params: min=%u max=%u latency=%u timeout=%u\r\n",
|
||||
param->interval_min,
|
||||
param->interval_max,
|
||||
param->latency,
|
||||
param->timeout);
|
||||
param->interval_min = BLE_MIN_CONN_INTERVAL;
|
||||
param->interval_max = BLE_MAX_CONN_INTERVAL;
|
||||
param->latency = BLE_SLAVE_LATENCY;
|
||||
param->timeout = BLE_CONN_SUP_TIMEOUT;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void le_param_updated(struct bt_conn *conn, uint16_t interval,
|
||||
uint16_t latency, uint16_t timeout)
|
||||
{
|
||||
ARG_UNUSED(conn);
|
||||
|
||||
DBG_PRINTF("[BLE] Params: interval=%d latency=%d timeout=%d\r\n",
|
||||
interval, latency, timeout);
|
||||
|
||||
if (ble_conn_param_is_preferred(interval, latency, timeout))
|
||||
{
|
||||
k_work_cancel_delayable(&conn_param_update_work);
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_SMP)
|
||||
@@ -379,6 +493,7 @@ BT_CONN_CB_DEFINE(conn_callbacks) =
|
||||
{
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
.le_param_req = le_param_req,
|
||||
.le_param_updated = le_param_updated,
|
||||
#if IS_ENABLED(CONFIG_BT_SMP)
|
||||
.security_changed = security_changed,
|
||||
@@ -401,6 +516,19 @@ static void nus_received(struct bt_conn *conn, const uint8_t *data, uint16_t len
|
||||
#endif
|
||||
|
||||
DBG_CORE("[NUS RX] len=%u\r\n", len);
|
||||
|
||||
if (current_conn == conn)
|
||||
{
|
||||
int64_t now_ms = k_uptime_get();
|
||||
|
||||
if ((last_rx_conn_param_update_ms == 0) ||
|
||||
((now_ms - last_rx_conn_param_update_ms) >= BLE_CONN_PARAM_RETRY_INTERVAL_MS))
|
||||
{
|
||||
last_rx_conn_param_update_ms = now_ms;
|
||||
(void)ble_request_preferred_conn_params(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_callback)
|
||||
{
|
||||
rx_callback(data, len);
|
||||
@@ -433,6 +561,8 @@ int ble_service_init(ble_data_rx_cb_t rx_cb)
|
||||
k_sem_init(&nus_tx_done_sem, 0, 1);
|
||||
|
||||
k_work_init(&adv_restart_work, adv_restart_handler);
|
||||
k_work_init_delayable(&adv_timeout_work, adv_timeout_handler);
|
||||
k_work_init_delayable(&conn_param_update_work, conn_param_update_handler);
|
||||
|
||||
err = ble_configure_fixed_identity();
|
||||
if (err)
|
||||
@@ -490,7 +620,7 @@ int ble_advertising_start(void)
|
||||
struct bt_le_adv_param adv_param = BT_LE_ADV_PARAM_INIT(
|
||||
BT_LE_ADV_OPT_CONN,
|
||||
APP_ADV_INTERVAL, /* min interval */
|
||||
APP_ADV_INTERVAL + 16, /* max interval (slight window) */
|
||||
APP_ADV_INTERVAL, /* max interval */
|
||||
NULL /* undirected */
|
||||
);
|
||||
|
||||
@@ -501,6 +631,12 @@ int ble_advertising_start(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
k_work_cancel_delayable(&adv_timeout_work);
|
||||
if (!advertising_unlimited && !dfu_advertising_mode)
|
||||
{
|
||||
k_work_schedule(&adv_timeout_work, K_MSEC(APP_ADV_DURATION * 10));
|
||||
}
|
||||
|
||||
DBG_PRINTF("[BLE] Advertising started (%s)\r\n", dfu_advertising_mode ? "SMP" : "NUS");
|
||||
return 0;
|
||||
}
|
||||
@@ -514,6 +650,7 @@ int ble_advertising_stop(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
k_work_cancel_delayable(&adv_timeout_work);
|
||||
DBG_PRINTF("[BLE] Advertising stopped\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,16 @@
|
||||
#define BLE_DEV_MODE 0 /* 1: Dev (no security), 0: Production */
|
||||
|
||||
#define APP_ADV_INTERVAL 64 /* 64 x 0.625ms = 40ms */
|
||||
#define APP_ADV_DURATION 18000 /* 18000 x 10ms = 180s (3 min) */
|
||||
#define APP_ADV_DURATION 60000 /* 60000 x 10ms = 600s (10 min) */
|
||||
|
||||
#define BLE_MIN_CONN_INTERVAL 24 /* 30ms / 1.25ms = 24 */
|
||||
#define BLE_MAX_CONN_INTERVAL 24 /* 30ms / 1.25ms = 24 */
|
||||
#define BLE_MIN_CONN_INTERVAL 12 /* 15ms / 1.25ms = 12 */
|
||||
#define BLE_MAX_CONN_INTERVAL 12 /* 15ms / 1.25ms = 12 */
|
||||
#define BLE_SLAVE_LATENCY 0
|
||||
#define BLE_CONN_SUP_TIMEOUT 400 /* 4000ms / 10ms = 400 */
|
||||
#define BLE_CONN_SUP_TIMEOUT 1000 /* 10000ms / 10ms = 1000 */
|
||||
|
||||
#define BLE_CONN_PARAM_FIRST_DELAY_MS 5000
|
||||
#define BLE_CONN_PARAM_RETRY_INTERVAL_MS 30000
|
||||
#define BLE_CONN_PARAM_MAX_ATTEMPTS 3
|
||||
|
||||
#define BLE_TX_POWER 8 /* +8 dBm */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user