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

