初始版本

This commit is contained in:
xiaozhengsheng
2025-08-19 09:49:41 +08:00
parent 10f1ddf1c1
commit 6df0f7d96e
2974 changed files with 1712873 additions and 54 deletions

883
app/main.c Normal file
View File

@@ -0,0 +1,883 @@
/****************************************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 //是否使用安全连接配对LESC1使用LESC0使用传统配对
#define SEC_PARAM_KEYPRESS 0 //是否生成按键通知1生成0不生成
#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE //IO能力无输入/输出能力
#define SEC_PARAM_OOB 0 //是否支持OOB1支持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;
}
}
}
}