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