884 lines
27 KiB
C
884 lines
27 KiB
C
/****************************************Copyright (c)************************************************
|
||
** [翔宇医疗]
|
||
**--------------File Info-----------------------------------------------------------------------------
|
||
** File name : main.c
|
||
** Last modified Date:
|
||
** Last Version :
|
||
** Descriptions : 使用的SDK版本-SDK_17.0.2
|
||
**----------------------------------------------------------------------------------------------------
|
||
** Created by :
|
||
** Created date :
|
||
** Version : 1.0
|
||
** Descriptions : 2021.4.6:添加配对管理器功能,在配对管理处理事件中添加PM_EVT_CONN_SEC_CONFIG_REQ,修改参数,
|
||
实现取消配对后依然可以再次连接
|
||
2021.4.7:添加广播3分钟后芯片休眠操作,广播间隔调整为187.5ms
|
||
在BLE事件处理函数中添加pm_handler_secure_on_connection函数,实现连接成功后就绑定
|
||
2021.4.9:在GATT初始化中加入nrf_ble_gatt_att_mtu_periph_set()函数设置默认MTU大小
|
||
2021.4.12:在主函数中加入PWM初始化函数以及在定时器中调用PWM开始播放函数
|
||
2021.5.12:将最大连接间隔改为300ms,改善了在连接过程中交换MTU不成功的情况
|
||
**---------------------------------------------------------------------------------------------------*/
|
||
//引用的C库头文件
|
||
#include <stdbool.h>
|
||
#include <stdint.h>
|
||
#include <string.h>
|
||
//APP定时器需要引用的头文件
|
||
#include "bsp_btn_ble.h"
|
||
//电源管理需要引用的头文件
|
||
#include "nrf_pwr_mgmt.h"
|
||
//SoftDevice handler configuration需要引用的头文件
|
||
#include "nrf_sdh.h"
|
||
#include "nrf_sdh_soc.h"
|
||
#include "nrf_sdh_ble.h"
|
||
//排序写入模块需要引用的头文件
|
||
#include "nrf_ble_qwr.h"
|
||
//GATT需要引用的头文件
|
||
#include "nrf_ble_gatt.h"
|
||
//连接参数协商需要引用的头文件
|
||
#include "ble_conn_params.h"
|
||
//广播需要引用的头文件
|
||
#include "ble_advdata.h"
|
||
#include "ble_advertising.h"
|
||
//串口透传需要引用的头文件
|
||
#include "drv_uart.h"
|
||
//引用FDS头文件
|
||
#include "fds.h"
|
||
//配对管理器包含头文件
|
||
#include "peer_manager.h"
|
||
#include "peer_manager_handler.h"
|
||
//WDT头文件
|
||
#include "nrfx_wdt.h"
|
||
#include "nrf_drv_clock.h"
|
||
#include "IoControl.h"
|
||
#include "IIR.h"
|
||
/***********************************************/
|
||
#define DEVICE_NAME "HL-PDJ-A" // 设备名称字符串
|
||
#define UARTS_SERVICE_UUID_TYPE BLE_UUID_TYPE_BLE // 串口透传服务UUID类型:厂商自定义UUID
|
||
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) // 最小连接间隔 (0.1 秒)
|
||
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) // 最大连接间隔 (0.2 秒)
|
||
#define SLAVE_LATENCY 0 // 从机延迟
|
||
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) // 监督超时(4 秒)
|
||
#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) // 定义首次调用sd_ble_gap_conn_param_update()函数更新连接参数延迟时间(5秒)
|
||
#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000) // 定义每次调用sd_ble_gap_conn_param_update()函数更新连接参数的间隔时间(30秒)
|
||
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 // 定义放弃连接参数协商前尝试连接参数协商的最大次数(3次)
|
||
|
||
#define APP_ADV_INTERVAL 160 // 广播间隔 (100 ms),单位0.625 ms
|
||
#define APP_ADV_DURATION 0 // 广播持续时间,单位:10ms。设置为0表示不超时
|
||
|
||
#define SEC_PARAM_BOND 1 //是否支持绑定,1:支持,0:不支持
|
||
#define SEC_PARAM_MITM 0 //是否支持MITM保护,1:支持,0:不支持
|
||
#define SEC_PARAM_LESC 0 //是否使用安全连接配对(LESC),1:使用LESC,0:使用传统配对
|
||
#define SEC_PARAM_KEYPRESS 0 //是否生成按键通知,1:生成,0:不生成
|
||
#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE //IO能力:无输入/输出能力
|
||
#define SEC_PARAM_OOB 0 //是否支持OOB,1:支持,0:不支持
|
||
#define SEC_PARAM_MIN_KEY_SIZE 7 //最小加密密钥大小
|
||
#define SEC_PARAM_MAX_KEY_SIZE 16 //最大加密密钥大小
|
||
|
||
#define APP_BLE_OBSERVER_PRIO 3 //应用程序BLE事件监视者优先级,应用程序不能修改该数值
|
||
#define APP_BLE_CONN_CFG_TAG 1 //SoftDevice BLE配置标志
|
||
|
||
//用于stack dump的错误代码,可以用于栈回退时确定堆栈位置
|
||
#define DEAD_BEEF 0xDEADBEEF
|
||
|
||
//定义文件ID和该文件包含的记录的KEY
|
||
#define DEVICE_FILE (0x1000)//文件ID
|
||
#define DEVICE_SCHEME_KEY (0x1001)//记录KEY,该记录存放的文件ID=0X1001
|
||
|
||
ble_gap_addr_t addr_ios;
|
||
uint8_array_t address_ios;
|
||
|
||
// 包含参数信息的记录
|
||
fds_record_t const m_SchemePara =
|
||
{
|
||
.file_id = DEVICE_FILE,
|
||
.key = DEVICE_SCHEME_KEY,
|
||
.data.p_data = &SchemePara,
|
||
//记录的长度必须以4字节(字)为单位
|
||
.data.length_words = (sizeof(SchemePara) + 3) / sizeof(uint32_t),
|
||
};
|
||
|
||
//BLE串口透传例程中服务UUID列表
|
||
static ble_uuid_t m_adv_uuids[] =
|
||
{
|
||
{BLE_UUID_NUS_SERVICE,UARTS_SERVICE_UUID_TYPE}
|
||
};
|
||
|
||
|
||
//保存申请的喂狗通道
|
||
nrfx_wdt_channel_id m_channel_id;
|
||
|
||
/*必须的观察者函数*/
|
||
NRF_BLE_GATT_DEF(m_gatt); //定义名称为m_gatt的GATT模块实例
|
||
NRF_BLE_QWR_DEF(m_qwr); //定义一个名称为m_qwr的排队写入实例
|
||
BLE_ADVERTISING_DEF(m_advertising); //定义名称为m_advertising的广播模块实例
|
||
|
||
void WdtFeed(void);
|
||
//GATT事件处理函数
|
||
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
|
||
{
|
||
//如果是MTU交换事件
|
||
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) //如果主句发起MTU升级请求
|
||
{
|
||
//设置串口透传服务的有效数据长度(MTU-opcode-handle)
|
||
m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;///247字节
|
||
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);
|
||
}
|
||
//初始化日志打印模块
|
||
static void log_init(void)
|
||
{
|
||
//初始化log程序模块
|
||
ret_code_t err_code = NRF_LOG_INIT(NULL);
|
||
APP_ERROR_CHECK(err_code);
|
||
//设置log输出终端(根据sdk_config.h中的配置设置输出终端为UART或者RTT)
|
||
NRF_LOG_DEFAULT_BACKENDS_INIT();
|
||
}
|
||
//GAP Generic Access Profile参数初始化,该函数配置需要的GAP参数,包括设备名称,外观特征、首选连接参数
|
||
static void gap_params_init(void)
|
||
{
|
||
ret_code_t err_code;
|
||
//定义连接参数结构体变量
|
||
ble_gap_conn_params_t gap_conn_params;
|
||
ble_gap_conn_sec_mode_t sec_mode;
|
||
//设置GAP的安全模式,即设置设备名称特征的写权限,这里设置的是安全模式1等级1,即无安全性
|
||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
|
||
//设置GAP设备名称
|
||
err_code = sd_ble_gap_device_name_set(&sec_mode,
|
||
(const uint8_t *)DEVICE_NAME,
|
||
strlen(DEVICE_NAME));
|
||
APP_ERROR_CHECK(err_code);
|
||
|
||
//如果需要设置外观特征,在这里使用如下的代码设置
|
||
/* err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_);
|
||
APP_ERROR_CHECK(err_code); */
|
||
|
||
//设置首选连接参数,设置前先清零gap_conn_params
|
||
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; //监督超时
|
||
//调用协议栈API sd_ble_gap_ppcp_set配置GAP参数
|
||
err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
|
||
APP_ERROR_CHECK(err_code);
|
||
}
|
||
//初始化GATT程序模块
|
||
static void gatt_init(void)
|
||
{
|
||
//初始化GATT程序模块
|
||
ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
|
||
//检查函数返回的错误代码
|
||
APP_ERROR_CHECK(err_code);
|
||
|
||
//设置服务端的默认MTU大小
|
||
err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
|
||
APP_ERROR_CHECK(err_code);
|
||
}
|
||
//空闲状态处理函数(该函数需要放到主循环里面执行)。如果没有挂起的日志操作,则睡眠直到下一个事件发生后唤醒系统
|
||
static void idle_state_handle(void)
|
||
{
|
||
//处理挂起的log
|
||
if (NRF_LOG_PROCESS() == false)
|
||
{
|
||
//运行电源管理
|
||
nrf_pwr_mgmt_run();
|
||
}
|
||
}
|
||
//删除绑定信息
|
||
static void delete_bonds(void)
|
||
{
|
||
ret_code_t err_code;
|
||
|
||
err_code = pm_peers_delete();
|
||
APP_ERROR_CHECK(err_code);
|
||
}
|
||
|
||
//初始化电源管理模块
|
||
static void power_management_init(void)
|
||
{
|
||
ret_code_t err_code;
|
||
//初始化电源管理
|
||
err_code = nrf_pwr_mgmt_init();
|
||
//检查函数返回的错误代码
|
||
APP_ERROR_CHECK(err_code);
|
||
}
|
||
//连接参数协商模块错误处理事件,参数nrf_error包含了错误代码,通过nrf_error可以分析错误信息
|
||
static void conn_params_error_handler(uint32_t nrf_error)
|
||
{
|
||
//检查错误代码
|
||
APP_ERROR_HANDLER(nrf_error);
|
||
}
|
||
|
||
//连接参数协商模块事件处理函数
|
||
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
|
||
{
|
||
ret_code_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);
|
||
}
|
||
//连接参数协商成功
|
||
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_SUCCEEDED)
|
||
{
|
||
//功能代码;
|
||
}
|
||
}
|
||
//连接参数协商模块初始化(用于启动和执行连接参数协商规程)
|
||
static void conn_params_init(void)
|
||
{
|
||
ret_code_t err_code;
|
||
//定义连接参数协商模块初始化结构体
|
||
ble_conn_params_init_t cp_init;
|
||
//配置之前先清零
|
||
memset(&cp_init, 0, sizeof(cp_init));
|
||
//设置为NULL,从主机获取连接参数
|
||
cp_init.p_conn_params = NULL;
|
||
//连接或启动通知到首次发起连接参数更新请求之间的时间设置为5秒
|
||
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
|
||
//每次调用sd_ble_gap_conn_param_update()函数发起连接参数更新请求的之间的间隔时间设置为:30秒
|
||
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
|
||
//放弃连接参数协商前尝试连接参数协商的最大次数设置为:3次
|
||
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);
|
||
}
|
||
|
||
//BLE事件处理函数
|
||
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
|
||
{
|
||
ret_code_t err_code = NRF_SUCCESS;
|
||
//连接建立后立即启动安全(当接收到连接建立事件(BLE_GAP_EVT_CONNECTED)时启动安全性)
|
||
pm_handler_secure_on_connection(p_ble_evt);
|
||
//判断BLE事件类型,根据事件类型执行相应操作
|
||
switch (p_ble_evt->header.evt_id)
|
||
{
|
||
//断开连接事件
|
||
case BLE_GAP_EVT_DISCONNECTED:
|
||
//打印提示信息
|
||
NRF_LOG_INFO("Disconnected.");
|
||
DeviceConnectState = DisconnectState;
|
||
|
||
DisconnectControl();
|
||
break;
|
||
|
||
//连接事件
|
||
case BLE_GAP_EVT_CONNECTED:
|
||
NRF_LOG_INFO("Connected.");
|
||
DeviceConnectState = ConnectState;
|
||
|
||
DisconnectControl();
|
||
//保存连接句柄
|
||
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;
|
||
|
||
//PHY更新事件
|
||
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,
|
||
};
|
||
//响应PHY更新规程
|
||
err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
|
||
APP_ERROR_CHECK(err_code);
|
||
} break;
|
||
|
||
//GATT客户端超时事件
|
||
case BLE_GATTC_EVT_TIMEOUT:
|
||
NRF_LOG_DEBUG("GATT Client Timeout.");
|
||
//断开当前连接
|
||
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;
|
||
|
||
//GATT服务器超时事件
|
||
case BLE_GATTS_EVT_TIMEOUT:
|
||
NRF_LOG_DEBUG("GATT Server Timeout.");
|
||
//断开当前连接
|
||
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:
|
||
break;
|
||
}
|
||
}
|
||
|
||
//初始化BLE协议栈
|
||
static void ble_stack_init(void)
|
||
{
|
||
ret_code_t err_code;
|
||
//请求使能SoftDevice,该函数中会根据sdk_config.h文件中低频时钟的设置来配置低频时钟
|
||
err_code = nrf_sdh_enable_request();
|
||
APP_ERROR_CHECK(err_code);
|
||
|
||
//定义保存应用程序RAM起始地址的变量
|
||
uint32_t ram_start = 0;
|
||
|
||
//使用sdk_config.h文件的默认参数配置协议栈,获取应用程序RAM起始地址,保存到变量ram_start
|
||
err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
|
||
APP_ERROR_CHECK(err_code);
|
||
|
||
//使能BLE协议栈
|
||
err_code = nrf_sdh_ble_enable(&ram_start);
|
||
APP_ERROR_CHECK(err_code);
|
||
|
||
//注册BLE事件回调函数
|
||
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
|
||
}
|
||
|
||
//广播事件处理函数
|
||
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
|
||
{
|
||
ret_code_t err_code;
|
||
//判断广播事件类型
|
||
switch (ble_adv_evt)
|
||
{
|
||
//快速广播启动事件:快速广播启动后会产生该事件
|
||
case BLE_ADV_EVT_FAST:
|
||
NRF_LOG_INFO("Fast advertising.");
|
||
//设置广播指示灯为正在广播(D1指示灯闪烁)
|
||
// err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
|
||
// APP_ERROR_CHECK(err_code);
|
||
break;
|
||
|
||
//广播IDLE事件:广播超时后会产生该事件
|
||
case BLE_ADV_EVT_IDLE:
|
||
//断电
|
||
NRF_LOG_INFO("BLE_ADV_EVT_IDLE");
|
||
nrf_gpio_pin_clear(KEY_POWER);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
//广播初始化
|
||
static void advertising_init(void)
|
||
{
|
||
uint32_t err_code;
|
||
//定义广播初始化配置结构体变量
|
||
ble_advertising_init_t init;
|
||
|
||
err_code = sd_ble_gap_addr_get(&addr_ios);
|
||
APP_ERROR_CHECK(err_code);
|
||
|
||
address_ios.size = 6;
|
||
address_ios.p_data = addr_ios.addr;
|
||
|
||
ble_advdata_manuf_data_t test;
|
||
|
||
test.company_identifier = 0x1122;
|
||
test.data = address_ios;
|
||
|
||
|
||
//配置之前先清零
|
||
memset(&init, 0, sizeof(init));
|
||
//设备名称类型:全名
|
||
init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
|
||
//是否包含外观:包含
|
||
init.advdata.include_appearance = false;
|
||
//包含ble设备地址
|
||
// init.advdata.include_ble_device_addr = true;
|
||
init.advdata.p_manuf_specific_data = &test;
|
||
|
||
init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids)/sizeof(m_adv_uuids[0]);
|
||
init.srdata.uuids_complete.p_uuids = m_adv_uuids;
|
||
|
||
//Flag:一般可发现模式,不支持BR/EDR
|
||
init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
|
||
|
||
//设置广播模式为快速广播
|
||
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);
|
||
//设置广播配置标记。APP_BLE_CONN_CFG_TAG是用于跟踪广播配置的标记,这是为未来预留的一个参数,在将来的SoftDevice版本中,
|
||
//可以使用sd_ble_gap_adv_set_configure()配置新的广播配置
|
||
//当前SoftDevice版本(S132 V7.2.0版本)支持的最大广播集数量为1,因此APP_BLE_CONN_CFG_TAG只能写1。
|
||
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
|
||
}
|
||
|
||
//启动广播,该函数所用的模式必须和广播初始化中设置的广播模式一样
|
||
static void advertising_start(bool erase_bonds)
|
||
{
|
||
if(erase_bonds == true)
|
||
{
|
||
//删除flash中存储的配对信息,执行完删除后,会产生PM_EVT_PEERS_DELETE_SUCCEEDED事件,
|
||
//在该事件下会启动广播
|
||
delete_bonds();
|
||
}
|
||
else
|
||
{
|
||
//使用广播初始化中设置的广播模式启动广播
|
||
ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
|
||
//检查函数返回的错误代码
|
||
APP_ERROR_CHECK(err_code);
|
||
}
|
||
}
|
||
//排队写入事件处理函数,用于处理排队写入模块的错误
|
||
static void nrf_qwr_error_handler(uint32_t nrf_error)
|
||
{
|
||
//检查错误代码
|
||
APP_ERROR_HANDLER(nrf_error);
|
||
}
|
||
|
||
//服务初始化,包含初始化排队写入模块和初始化应用程序使用的服务
|
||
static void services_init(void)
|
||
{
|
||
ret_code_t err_code;
|
||
//定义排队写入初始化结构体变量
|
||
nrf_ble_qwr_init_t qwr_init = {0};
|
||
|
||
//排队写入事件处理函数
|
||
qwr_init.error_handler = nrf_qwr_error_handler;
|
||
//初始化排队写入模块
|
||
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
|
||
APP_ERROR_CHECK(err_code);
|
||
//串口透传服务初始化
|
||
service_nus_init();
|
||
}
|
||
|
||
#if 1
|
||
//配对管理器事件处理函数
|
||
static void pm_evt_handler(pm_evt_t const * p_evt)
|
||
{
|
||
//1、打印日志 2、连接已绑定设备时启动加密 3、出现错误调用错误处理程序
|
||
pm_handler_on_pm_evt(p_evt);
|
||
//清理配对设备在flash中的保存的绑定信息,当flash存储空间不足时删除
|
||
//排列最低的配对设备的信息
|
||
pm_handler_flash_clean(p_evt);
|
||
|
||
switch(p_evt->evt_id)
|
||
{
|
||
//存储的绑定信息已成功删除
|
||
case PM_EVT_PEERS_DELETE_SUCCEEDED:
|
||
//若程序启动时执行了删除绑定信息操作,在该事件下启动广播
|
||
advertising_start(false);
|
||
break;
|
||
|
||
case PM_EVT_CONN_SEC_CONFIG_REQ:
|
||
{
|
||
// 拒绝来自已经绑定对等方的配对请求.
|
||
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
|
||
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
|
||
} break;
|
||
|
||
default:
|
||
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//配对管理器初始化
|
||
static void peer_manager_init(void)
|
||
{
|
||
ble_gap_sec_params_t sec_param;
|
||
ret_code_t err_code;
|
||
|
||
//初始化配对管理器软件库
|
||
err_code = pm_init();
|
||
APP_ERROR_CHECK(err_code);
|
||
//配置安全参数前先清零结构体sec_param
|
||
memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
|
||
|
||
//初始化安全性参数结构体,
|
||
sec_param.bond = SEC_PARAM_BOND; //支持绑定
|
||
sec_param.mitm = SEC_PARAM_MITM; //无MITM保护
|
||
sec_param.lesc = SEC_PARAM_LESC; //不支持安全连接配对,即使用传统配对
|
||
sec_param.keypress = SEC_PARAM_KEYPRESS; //无按键通知
|
||
sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES; //无IO能力
|
||
sec_param.oob = SEC_PARAM_OOB; //不支持OOB
|
||
sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE; //最小加密密钥大小:7字节
|
||
sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE; //最大加密密钥大小:16字节
|
||
//本地密钥分发配置
|
||
sec_param.kdist_own.enc = 1; //分发本地LTK
|
||
sec_param.kdist_own.id = 1; //分发本地IRK
|
||
//对端密钥分发配置
|
||
sec_param.kdist_peer.enc = 1; //要求对方分发LTK
|
||
sec_param.kdist_peer.id = 1; //要求对方分发IRK
|
||
|
||
//配置安全参数
|
||
err_code = pm_sec_params_set(&sec_param);
|
||
APP_ERROR_CHECK(err_code);
|
||
//向配对管理器注册事件句柄
|
||
err_code = pm_register(pm_evt_handler);
|
||
APP_ERROR_CHECK(err_code);
|
||
}
|
||
|
||
//FDS事件处理函数
|
||
static void fds_evt_handler(fds_evt_t const * p_evt)
|
||
{
|
||
//判断事件类型
|
||
switch (p_evt->id)
|
||
{
|
||
case FDS_EVT_INIT://FDS初始化事件
|
||
if (p_evt->result == NRF_SUCCESS)//初始化成功
|
||
{
|
||
my_fds_info.busy = false;
|
||
}
|
||
break;
|
||
|
||
case FDS_EVT_WRITE://FDS写记录事件
|
||
{
|
||
if (p_evt->result == NRF_SUCCESS)//写记录成功
|
||
{
|
||
my_fds_info.busy = false;
|
||
}
|
||
} break;
|
||
|
||
case FDS_EVT_UPDATE://FDS更新记录事件
|
||
{
|
||
if (p_evt->result == NRF_SUCCESS)//写记录成功
|
||
{
|
||
my_fds_info.busy = false;
|
||
}
|
||
} break;
|
||
|
||
case FDS_EVT_GC://FDS碎片整理事件
|
||
{
|
||
if (p_evt->result == NRF_SUCCESS)//碎片整理成功
|
||
{
|
||
my_fds_info.busy = false;
|
||
}
|
||
} break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
//等待FDS初始化完成
|
||
static void wait_for_fds_ready(void)
|
||
{
|
||
while (my_fds_info.busy)
|
||
{
|
||
(void) sd_app_evt_wait();
|
||
}
|
||
}
|
||
// 读取方案并且发送
|
||
void read_scheme(void)
|
||
{
|
||
ret_code_t rc;
|
||
//定义并初始化记录描述符结构体变量
|
||
fds_record_desc_t desc = {0};
|
||
//定义并初始化记录查找令牌结构体变量
|
||
fds_find_token_t tok = {0};
|
||
|
||
uint16_t tempidvalue;
|
||
//清零tok,从头查找
|
||
memset(&tok, 0x00, sizeof(fds_find_token_t));
|
||
//在DEVICE_FILE文件中查找记录m_version_record
|
||
rc = fds_record_find(DEVICE_FILE, DEVICE_SCHEME_KEY, &desc, &tok);
|
||
//查找到记录后,读取记录内容
|
||
if(rc == NRF_SUCCESS)
|
||
{
|
||
fds_flash_record_t temp = {0};
|
||
//打开记录读取记录内容
|
||
rc = fds_record_open(&desc, &temp);
|
||
APP_ERROR_CHECK(rc);
|
||
//拷贝记录内容
|
||
memcpy(&SchemeData, temp.p_data, sizeof(SchemeData_t));
|
||
//读取后,关闭记录
|
||
rc = fds_record_close(&desc);
|
||
APP_ERROR_CHECK(rc);
|
||
// 连接状态下发送方案ID
|
||
if(DeviceConnectState == ConnectState)
|
||
{
|
||
SchemeQuery(SchemeData.SchemeIDMSB,SchemeData.SchemeIDLSB);
|
||
}
|
||
// 未连接状态下给默认的治疗方案
|
||
else
|
||
{
|
||
StimStateInfoStructInit(SchemeData);
|
||
}
|
||
|
||
}
|
||
}
|
||
// 存储管理中断处理函数
|
||
void FdsHandler(fds_record_desc_t *Desc,fds_find_token_t *Tok)
|
||
{
|
||
ret_code_t rc;
|
||
if(my_fds_info.read == true)//读取记录
|
||
{
|
||
my_fds_info.read = false;
|
||
read_scheme();//读取记录数据,并发送
|
||
}
|
||
//更新记录m_fw_record
|
||
if((my_fds_info.scheme_update == true) && (my_fds_info.busy == false))
|
||
{
|
||
//清零tok,从头查找
|
||
memset(Tok, 0x00, sizeof(fds_find_token_t));
|
||
//在DEVICE_FILE文件中查找记录m_fw_record
|
||
rc = fds_record_find(DEVICE_FILE, DEVICE_SCHEME_KEY, Desc, Tok);
|
||
if (rc == NRF_SUCCESS)
|
||
{
|
||
my_fds_info.busy = true;
|
||
my_fds_info.scheme_update = false;
|
||
//更新记录m_fw_record
|
||
rc = fds_record_update(Desc, &m_SchemePara);
|
||
APP_ERROR_CHECK(rc);
|
||
wait_for_fds_ready();
|
||
NRF_LOG_INFO("fds_record_update");
|
||
}
|
||
}
|
||
}
|
||
|
||
void wdt_event_handler(void)
|
||
{
|
||
|
||
}
|
||
void WdtInit(void)
|
||
{
|
||
ret_code_t err_code = NRF_SUCCESS;
|
||
|
||
//定义WDT配置结构体并使用
|
||
nrfx_wdt_config_t config = NRFX_WDT_DEAFULT_CONFIG;
|
||
//初始化WDT
|
||
err_code = nrfx_wdt_init(&config, wdt_event_handler);
|
||
//申请喂狗通道,也就是使用哪个
|
||
err_code = nrfx_wdt_channel_alloc(&m_channel_id);
|
||
APP_ERROR_CHECK(err_code);
|
||
//启动WDT
|
||
nrfx_wdt_enable();
|
||
}
|
||
//喂狗函数
|
||
void WdtFeed(void)
|
||
{
|
||
//喂狗
|
||
nrfx_wdt_channel_feed(m_channel_id);
|
||
}
|
||
|
||
void clocks_start(void)
|
||
{
|
||
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;//清零高频时钟启动事件
|
||
NRF_CLOCK->TASKS_HFCLKSTART = 1; //启动高频时钟
|
||
//等待高频时钟启动完成
|
||
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
|
||
}
|
||
|
||
//驱动初始化
|
||
void DeviceInit(void)
|
||
{
|
||
/* 初始化控制gpio */
|
||
GpioInit();
|
||
clocks_start();
|
||
EXIT_KEY_Init();
|
||
/* 初始化APP定时器 */
|
||
AppTimersInit();
|
||
timer3_rms_init();
|
||
/* DACPWM初始化 */
|
||
// PwmDACInit();
|
||
|
||
/* SAADC初始化 */
|
||
battery_adc_init();
|
||
rms_saadc_init();
|
||
|
||
/* 采样的PPI初始化 */
|
||
//PPIPwmInit();
|
||
PPIEegAdcInit();
|
||
/* GPIOTE初始化 */
|
||
GpioteInit();
|
||
// nrf_gpio_pin_clear(H_CTL1_PWM);
|
||
// nrf_gpio_pin_clear(H_CTL2_PWM);
|
||
/* 刺激PWM初始化 */
|
||
pwm0_common_init();
|
||
|
||
pwm2common_init();
|
||
//timer1_output_ctrl_init();
|
||
/* 喂狗初始化 */
|
||
WdtInit();
|
||
}
|
||
|
||
|
||
//广播中添加MAC地址
|
||
void MacSet(void)
|
||
{
|
||
ble_gap_addr_t addr;
|
||
|
||
uint32_t err_code = sd_ble_gap_addr_get(&addr);
|
||
APP_ERROR_CHECK(err_code);
|
||
memcpy(BLE_MAC,addr.addr,BLE_GAP_ADDR_LEN);
|
||
err_code = sd_ble_gap_addr_set(&addr);
|
||
APP_ERROR_CHECK(err_code);
|
||
}
|
||
void StartAdv(void)
|
||
{
|
||
//启动广播
|
||
advertising_start(false);
|
||
}
|
||
|
||
// 关闭广播
|
||
void StopAdv(void)
|
||
{
|
||
NRF_LOG_INFO("StopAdv!");
|
||
|
||
sd_ble_gap_adv_stop(m_advertising.adv_handle);
|
||
}
|
||
|
||
void user_ble_init(void)
|
||
{
|
||
|
||
//初始化协议栈
|
||
ble_stack_init();
|
||
|
||
//变量初始化
|
||
VariableInit();
|
||
|
||
//配置GAP参数
|
||
gap_params_init();
|
||
//初始化GATT
|
||
gatt_init();
|
||
|
||
//初始化服务
|
||
services_init();
|
||
//在广播数据中添加MAC地址
|
||
MacSet();
|
||
//初始化广播
|
||
advertising_init();
|
||
|
||
//连接参数协商初始化
|
||
conn_params_init();
|
||
//配对管理器初始化
|
||
peer_manager_init();
|
||
//LOG打印信息
|
||
NRF_LOG_INFO("BLE started.");
|
||
}
|
||
|
||
|
||
//fds存储管理初始化
|
||
void fdsInit(ret_code_t rec,fds_record_desc_t desct,fds_find_token_t token)
|
||
{
|
||
|
||
//注册FDS事件回调函数接收FS事件
|
||
(void)fds_register(fds_evt_handler);
|
||
|
||
my_fds_info.busy = true;
|
||
rec = fds_init();//初始化FDS
|
||
APP_ERROR_CHECK(rec);//用错误处理模块检查函数返回值
|
||
//FDS初始化是异步的,因此要等待FDS初始化完成
|
||
wait_for_fds_ready();
|
||
//清零tok,从头查找
|
||
memset(&token, 0x00, sizeof(fds_find_token_t));
|
||
//在DEVICE_FILE文件中查找记录m_desp_record
|
||
rec = fds_record_find(DEVICE_FILE, DEVICE_SCHEME_KEY, &desct, &token);
|
||
|
||
NRF_LOG_INFO("rec = %d",rec);
|
||
|
||
//没有查找到m_desp_record记录,写入记录
|
||
if (rec != NRF_SUCCESS)
|
||
{
|
||
my_fds_info.busy = true;
|
||
StimStateInfoStructInit(PreStorageSchemeData); // 用预存的信息给刺激参数赋值
|
||
memcpy(SchemePara.text,&PreStorageSchemeData,sizeof(PreStorageSchemeData));
|
||
rec = fds_record_write(&desct, &m_SchemePara);
|
||
APP_ERROR_CHECK(rec);
|
||
wait_for_fds_ready();
|
||
}
|
||
else
|
||
{
|
||
my_fds_info.read = true;
|
||
}
|
||
}
|
||
//主函数
|
||
int main(void)
|
||
{
|
||
ret_code_t rc;
|
||
//定义并初始化记录描述符结构体变量
|
||
fds_record_desc_t desc = {0};
|
||
//定义并初始化记录查找令牌结构体变量
|
||
fds_find_token_t tok = {0};
|
||
|
||
//初始化log程序模块
|
||
log_init();
|
||
//滤波器初始化
|
||
FilterInit();
|
||
// 设备预存信息初始化ID :101 腹直肌分离
|
||
PreStorageSchemeDataInit();
|
||
//fds存储管理初始化
|
||
fdsInit(rc,desc,tok);
|
||
//器件初始化
|
||
DeviceInit();
|
||
|
||
//初始化电源管理
|
||
power_management_init();
|
||
user_ble_init();
|
||
|
||
//启动已经创建的APP定时器
|
||
ApplicationTimersStart();
|
||
//主循环
|
||
while(true)
|
||
{
|
||
// 存储事件处理函数
|
||
FdsHandler(&desc,&tok);
|
||
//处理挂起的LOG和运行电源管理
|
||
idle_state_handle();
|
||
WdtFeed();
|
||
if(POWER_CLOSE == DeviceState)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
KeyPinHandler();// 按键中断处理
|
||
//输出电流控制
|
||
|
||
|
||
/* 适配器和电极片脱落状态变化上传 */
|
||
if(AdapterState == LastAdapterState)
|
||
{
|
||
StateUpLoad(AdapterState,ElectrodeStatusInfo);
|
||
if(AdapterState == AdapterConnected)
|
||
{
|
||
LastAdapterState = AdapterNotConnected;
|
||
}
|
||
else
|
||
{
|
||
LastAdapterState = AdapterConnected;
|
||
}
|
||
}
|
||
|
||
if(ElectrodeStatusInfo == LastElectrodeStatusInfo)
|
||
{
|
||
StateUpLoad(AdapterState,ElectrodeStatusInfo);
|
||
if(ElectrodeStatusInfo == ElectrodeFalloff)
|
||
{
|
||
LastElectrodeStatusInfo = ElectrodeConnectted;
|
||
}
|
||
else
|
||
{
|
||
LastElectrodeStatusInfo = ElectrodeFalloff;
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|