#include "zble_module.h" #include #include #include "ble_bas.h" #include "znordic.h" #include "basic/version.h" #if BLE_DFU_ENABLED #include "nrf_bootloader_info.h" #endif /******************************************************************************* * 广播包配?? * *******************************************************************************/ #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 NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service (vendor specific). */ #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. */ /******************************************************************************* * GATT配置 * *******************************************************************************/ NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ /******************************************************************************* * 连接参数配置 * *******************************************************************************/ #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. */ /******************************************************************************* * CODE * *******************************************************************************/ static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< 当前连接句柄 */ static uint16_t m_mtu_size = BLE_GATT_ATT_MTU_DEFAULT - 3; static zble_event_listener_t m_event_listener; static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context) { uint32_t err_code; static zble_event_t zevent; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; zevent.eventType = kzble_event_connected; if (m_event_listener) m_event_listener(&zevent); break; case BLE_GAP_EVT_DISCONNECTED: m_conn_handle = BLE_CONN_HANDLE_INVALID; zevent.eventType = kzble_event_disconnected; if (m_event_listener) m_event_listener(&zevent); 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); 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); 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); 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); 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); ZERROR_CHECK(err_code); break; default: // No implementation needed. break; } } static void gatt_evt_handler(nrf_ble_gatt_t *p_gatt, nrf_ble_gatt_evt_t const *p_evt) { /******************************************************************************* * MTU SIZE 更新 * *******************************************************************************/ if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) { m_mtu_size = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH; NRF_LOG_DEBUG("ATT MTU exchange completed. central %d peripheral %d", p_gatt->att_mtu_desired_central, p_gatt->att_mtu_desired_periph); } } 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); ZERROR_CHECK(err_code); } } static void conn_params_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); } static void on_adv_evt(ble_adv_evt_t ble_adv_evt) { switch (ble_adv_evt) { case BLE_ADV_EVT_FAST: // err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING); // ZERROR_CHECK(err_code); break; case BLE_ADV_EVT_IDLE: // sleep_mode_enter(); break; default: break; } } void zble_module_start_adv() { uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST); ZERROR_CHECK(err_code); } void zble_module_stop_adv() { sd_ble_gap_adv_stop(m_advertising.adv_handle); // ZERROR_CHECK(err_code); } bool zble_module_is_connected() { return m_conn_handle != BLE_CONN_HANDLE_INVALID; } /******************************************************************************* * INIT * *******************************************************************************/ void zble_module_reglistener(zble_event_listener_t event_listener) { m_event_listener = event_listener; } #if BLE_DFU_ENABLED /**@brief Handler for shutdown preparation. * * @details During shutdown procedures, this function will be called at a 1 second interval * untill the function returns true. When the function returns true, it means that the * app is ready to reset to DFU mode. * * @param[in] event Power manager event. * * @retval True if shutdown is allowed by this power manager handler, otherwise false. */ static bool app_shutdown_handler(nrf_pwr_mgmt_evt_t event) { switch (event) { case NRF_PWR_MGMT_EVT_PREPARE_DFU: NRF_LOG_INFO("Power management wants to reset to DFU mode."); // YOUR_JOB: Get ready to reset into DFU mode // // If you aren't finished with any ongoing tasks, return "false" to // signal to the system that reset is impossible at this stage. // // Here is an example using a variable to delay resetting the device. // // if (!m_ready_for_reset) // { // return false; // } // else //{ // // // Device ready to enter // uint32_t err_code; // err_code = sd_softdevice_disable(); // APP_ERROR_CHECK(err_code); // err_code = app_timer_stop_all(); // APP_ERROR_CHECK(err_code); //} break; default: // YOUR_JOB: Implement any of the other events available from the power management module: // -NRF_PWR_MGMT_EVT_PREPARE_SYSOFF // -NRF_PWR_MGMT_EVT_PREPARE_WAKEUP // -NRF_PWR_MGMT_EVT_PREPARE_RESET return true; } NRF_LOG_INFO("Power management allowed to reset to DFU mode."); return true; } // lint -esym(528, m_app_shutdown_handler) /**@brief Register application shutdown handler with priority 0. */ NRF_PWR_MGMT_HANDLER_REGISTER(app_shutdown_handler, 0); static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void *p_context) { if (state == NRF_SDH_EVT_STATE_DISABLED) { // Softdevice was disabled before going into reset. Inform bootloader to skip CRC on next boot. nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC); // Go to system off. nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF); } } /* nrf_sdh state observer. */ NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) = { .handler = buttonless_dfu_sdh_state_observer, }; static void advertising_config_get(ble_adv_modes_config_t *p_config) { memset(p_config, 0, sizeof(ble_adv_modes_config_t)); p_config->ble_adv_fast_enabled = true; p_config->ble_adv_fast_interval = APP_ADV_INTERVAL; p_config->ble_adv_fast_timeout = APP_ADV_DURATION; } static void disconnect(uint16_t conn_handle, void *p_context) { UNUSED_PARAMETER(p_context); ret_code_t err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); if (err_code != NRF_SUCCESS) { NRF_LOG_WARNING("Failed to disconnect connection. Connection handle: %d Error: %d", conn_handle, err_code); } else { NRF_LOG_DEBUG("Disconnected connection handle %d", conn_handle); } } // YOUR_JOB: Update this code if you want to do anything given a DFU event (optional). /**@brief Function for handling dfu events from the Buttonless Secure DFU service * * @param[in] event Event from the Buttonless Secure DFU service. */ static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event) { switch (event) { case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE: { NRF_LOG_INFO("Device is preparing to enter bootloader mode."); // Prevent device from advertising on disconnect. ble_adv_modes_config_t config; advertising_config_get(&config); config.ble_adv_on_disconnect_disabled = true; ble_advertising_modes_config_set(&m_advertising, &config); // Disconnect all other bonded devices that currently are connected. // This is required to receive a service changed indication // on bootup after a successful (or aborted) Device Firmware Update. uint32_t conn_count = ble_conn_state_for_each_connected(disconnect, NULL); NRF_LOG_INFO("Disconnected %d links.", conn_count); break; } case BLE_DFU_EVT_BOOTLOADER_ENTER: // YOUR_JOB: Write app-specific unwritten data to FLASH, control finalization of this // by delaying reset by reporting false in app_shutdown_handler NRF_LOG_INFO("Device will enter bootloader mode."); break; case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED: NRF_LOG_ERROR("Request to enter bootloader mode failed asynchroneously."); // YOUR_JOB: Take corrective measures to resolve the issue // like calling APP_ERROR_CHECK to reset the device. break; case BLE_DFU_EVT_RESPONSE_SEND_ERROR: NRF_LOG_ERROR("Request to send a response to client failed."); // YOUR_JOB: Take corrective measures to resolve the issue // like calling APP_ERROR_CHECK to reset the device. APP_ERROR_CHECK(false); break; default: NRF_LOG_ERROR("Unknown event from ble_dfu_buttonless."); break; } } #endif // static ble_uuid_t m_adv_uuids[] = /**< Universally unique service identifier. */ // {{0x0002, BLE_UUID_TYPE_VENDOR_BEGIN}}; // static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}}; #define COMPANY_IDENTIFIER_DATA_LEGTH 2 /**< Total length of information advertised by the Beacon. */ static uint8_t p_company_identifier_data[COMPANY_IDENTIFIER_DATA_LEGTH] = { (FIRMWARE_VERSION >> 8) & 0xFF, FIRMWARE_VERSION & 0xFF, }; void zble_module_init(zble_module_cfg_t *cfg) { /** * @brief * 初始化蓝牙协议栈,并注册蓝牙事件处理函数,固定代码,勿修?? */ { NRF_SDH_BLE_OBSERVER(m_ble_observer, 3, ble_evt_handler, NULL); } /******************************************************************************* * GAP初始?? * *******************************************************************************/ { 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 *)cfg->deviceName, strlen(cfg->deviceName)); ZERROR_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); ZERROR_CHECK(err_code); } /******************************************************************************* * GATT 初始?? * *******************************************************************************/ { ret_code_t err_code; err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler); ZERROR_CHECK(err_code); err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE); ZERROR_CHECK(err_code); } /******************************************************************************* * 广播初始?? * *******************************************************************************/ { uint32_t err_code; ble_advertising_init_t init; memset(&init, 0, sizeof(init)); static ble_advdata_manuf_data_t manuf_specific_data; manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER; manuf_specific_data.data.p_data = (uint8_t *)p_company_identifier_data; manuf_specific_data.data.size = COMPANY_IDENTIFIER_DATA_LEGTH; init.advdata.name_type = BLE_ADVDATA_FULL_NAME; init.advdata.include_appearance = true; init.advdata.p_manuf_specific_data = &manuf_specific_data; // init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_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; err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR); APP_ERROR_CHECK(err_code); init.srdata.uuids_complete.uuid_cnt = 0; init.srdata.uuids_complete.p_uuids = NULL; init.config.ble_adv_fast_enabled = true; init.config.ble_adv_fast_interval = APP_ADV_INTERVAL; init.config.ble_adv_fast_timeout = 0; init.evt_handler = on_adv_evt; err_code = ble_advertising_init(&m_advertising, &init); ZERROR_CHECK(err_code); ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); } /******************************************************************************* * 蓝牙服务初始?? * *******************************************************************************/ #if BLE_DFU_ENABLED { ble_dfu_buttonless_init_t dfus_init = {0}; dfus_init.evt_handler = ble_dfu_evt_handler; ret_code_t err_code = ble_dfu_buttonless_init(&dfus_init); ZERROR_CHECK(err_code); if (cfg->on_service_init) cfg->on_service_init(); } #endif /******************************************************************************* * 连接参数初始?? * *******************************************************************************/ { 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); ZERROR_CHECK(err_code); } // zble_module_start_adv(); } int32_t zble_module_get_mtu_size() { return m_mtu_size; } bool zble_module_disconnect(){ ble_conn_state_for_each_connected(disconnect, NULL); return true; }