HL-PDJ-1/app/main.c
xiaozhengsheng 6df0f7d96e 初始版本
2025-08-19 09:49:41 +08:00

884 lines
27 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************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;
}
}
}
}