1396 lines
44 KiB
C
1396 lines
44 KiB
C
#include "main.h"
|
||
#include <math.h>
|
||
#include <stdio.h>
|
||
#include "key.h"
|
||
#include "cJSON.h"
|
||
// #include "nnom.h" //神经网络的函数调用,不需要改动
|
||
#include "cal_sleep_stage.h" //计算睡眠周期
|
||
#include "myMalloc.h"
|
||
// #include "image.h"
|
||
// #include "ppg_data.h" //测试用到的数据集,这个文件是用py文件生成的,不需要改,已更新
|
||
// 保存了网络结构的参数,这个文件是用py文件生成的,不需要改
|
||
// #include "breath_heart.h" //预测呼吸心跳的模型
|
||
// #include "pre_stage.h" //预测睡眠阶段的模型
|
||
#include "stmflash.h"
|
||
#include <stdlib.h>
|
||
#include "wificom.h"
|
||
#include <stdio.h>
|
||
#include <time.h>
|
||
#include "find_peaks.h"
|
||
#include "queue_mem.h" //分配内存的函数
|
||
#include "sleepReport.h"
|
||
#include "drv_SGM58031.h"
|
||
// DSP 相关
|
||
#include "MyTool.h"
|
||
#include "arm_math.h"
|
||
#include "MyAlgorithm.h"
|
||
#include "MyBandFitter.h"
|
||
|
||
#if THE_VERSION
|
||
unsigned char version[8] = {0xA5, 0x5A, 0x08, 0x00, 0xBB, 0x01, 0x00, 0x1a}; // 版本号E.1.0.26 -> 养老版本
|
||
#else
|
||
unsigned char version[8] = {0xA5, 0x5A, 0x08, 0x00, 0xBB, 0x01, 0x01, 0x05}; // 版本号M.1.1.5 -> BCS版本
|
||
#endif
|
||
|
||
/**********************
|
||
* 魔术棒选用IROM
|
||
* IROM1:0x8010000--0x40000(初始程序,用来放置old版本)
|
||
* IROM2:0x8080000--0x40000(升级程序,需要选用这个编译的bin文件给服务器)
|
||
***********************/
|
||
// 设置一个模型运行的内存空间,40Kb,
|
||
// 后续会在main函数中对它初始化。
|
||
// 如果定义了NNOM_USING_STATIC_MEMORY,就是使用静态内存,
|
||
// 如果没有定义,修改NNOM_USING_STATIC_MEMORY的方法在nnom_port.h中,
|
||
// 这部分不需要改动,使用静态内存比较稳定,而且空间也小。
|
||
|
||
/**********************
|
||
report_get_buf
|
||
* 0~99数据存入
|
||
* 0~9:总天数+当前天数
|
||
* 10~29:当前天数+当前多少个数据+时间戳+效率,以后同理
|
||
* 200~200+1024*9 第一天数据
|
||
* 200+1024*9~200+1024*(9*2) 第二天数据
|
||
***********************/
|
||
/**********************
|
||
* report_abnormal_buf
|
||
* 0~7:时间数据存入
|
||
* 8~9:长度
|
||
* 10~11:起始时间,以后同理
|
||
* 12~13:结束时间,以后同理
|
||
***********************/
|
||
struct Sleep_report
|
||
{
|
||
// uint8_t report_save_buf[1200]; //存储buf
|
||
// uint8_t report_send_buf[1200]; //读取buf
|
||
uint8_t report_get_buf[200]; // 前期介绍
|
||
// uint8_t report_abnormal_buf[2000]; //异常存储
|
||
uint8_t time_num[8]; // 时间buf
|
||
int report_save_len; // 存储长度
|
||
int report_send_len; // 读取长度
|
||
char breathe_abnormal_flg; // 呼吸异常标志
|
||
uint16_t breathe_abnormal_length; // 呼吸异常长度
|
||
uint16_t breathe_abnormal_time; // 呼吸异常长度
|
||
char all_num; // 总天数1~7
|
||
char report_num; // 当前天数1~7
|
||
char circle_num; // 当前循环条数
|
||
char report_time_flg; // 更新时间标志位
|
||
uint32_t storage_location_num; // 当前存储数量--地址等于
|
||
uint8_t storage_location_buf[4]; // 存储数量转换buf
|
||
int equipment_status_time; // 判断离床时间
|
||
char sleep_stage_flg; // 出睡眠报告的标志位
|
||
} Sleep;
|
||
|
||
uint32_t FlashPtr = 0X08004000; // 呼吸心率上下限存储地址
|
||
int currentSize_num = 0; // 进行睡眠计算时间
|
||
char OffBed_Flag = 0;
|
||
uint16_t number0 = 0;
|
||
int BH_time = 0;
|
||
int stage_time = 0;
|
||
char start_calculate_flg = 0;
|
||
char start_stage_flg = 0;
|
||
char led_flg = 0;
|
||
char uart_flg = 0;
|
||
int uart_time = 0;
|
||
int led_num = 0;
|
||
char stage_len = 0;
|
||
float ppg_data2_buf[2] = {0};
|
||
float Local_ON_BED_Threshold = 0.0f;
|
||
float Local_OFF_BED_Threshold = 0.0f;
|
||
char ppg_stage_index = 0;
|
||
int led_time = 200;
|
||
char OffBed_Time = 0;
|
||
char queue_flg = 0;
|
||
char FFT_Count_State_Flag = 0;
|
||
char FFT_Calculate_State_Flag = 0;
|
||
char start_ConnectNet_flg = 0;
|
||
char Breathe_H = 0x19;
|
||
char Breathe_L = 0x08;
|
||
char HeartRate_H = 0x64;
|
||
char HeartRate_L = 0x37;
|
||
float Diff = 0.0f;
|
||
float Diff_Detail = 0.0f;
|
||
|
||
extern uint8_t BreathRate;
|
||
extern uint8_t HeartBeatRate;
|
||
extern uint8_t BreathRate_Record;
|
||
extern uint8_t HeartBeatRate_Record;
|
||
|
||
extern int FitterCount_Heart;
|
||
extern int FitterCount_Breath;
|
||
extern int FitterCount_CheckBed;
|
||
extern char FitterCollectDoneFlag_Heart;
|
||
extern char FitterCollectDoneFlag_Breath;
|
||
extern char FitterCollectDoneFlag_CheckBed;
|
||
|
||
extern char WarnConfigDoneFlag;
|
||
extern float32_t Energy_Ratio[4];
|
||
extern warning_config_t warning_config;
|
||
|
||
WarningMsg_t WarningMsg; // 告警消息
|
||
uint8_t g_mon, g_day, g_hour, g_min, g_sec = 0;
|
||
|
||
uint16_t Roll_Over_Count = 0; // 翻身计数
|
||
uint16_t Sleep_Report_Start_Flag = 0; // 睡眠报告开始
|
||
uint16_t TimeClock_Recalibrate_Count = 0; // 重新校准时间避免时间戳错误
|
||
// 睡眠报告的存储--15天
|
||
typedef struct SleepRecord_T
|
||
{
|
||
char SleepReport_Directory[REPORT_SAVE_SIZE]; // 存储字典
|
||
char SleepReport_CurrentSaveNum; // 当前值
|
||
char SleepReport_CurrentIndex; // 当前角标
|
||
uint8_t SleepReport_TimeStamp[8]; // 时间戳
|
||
uint8_t SleepReport_Score; // 得分
|
||
uint8_t SleepReport_Efficiency; // 效率
|
||
} SleepRecord_t;
|
||
|
||
SleepRecord_t SleepRecord;
|
||
uint32_t Calibration_Template = 0;
|
||
uint32_t Calibration_Template_2 = 0;
|
||
|
||
float Optical_Calibration_Value = 0.0f;
|
||
float Optical_Calibration_Value_OffBed = 0.0f;
|
||
float Optical_Calibration_Value_OnBed = 0.0f;
|
||
|
||
char Calibration_Off_Bed_Done_Flag = 0;
|
||
char Calibration_In_Bed_Done_Flag = 0;
|
||
|
||
char PowerOn_NetStatusFlg = 0; // 上电状态标志位
|
||
char PowerOn_OneMinuteCount = 0; // 上电一分钟计次
|
||
char PowerOn_OneMinuteCount_Start = 0; // 上电一分钟启动标志
|
||
char PowerOn_StartConfigFlg = 0; // 上电配网启动标志位
|
||
|
||
struct struct_stage get_sleep_stage;
|
||
int score_eff_buff[2] = {0};
|
||
float ppg_data_500_buf[500] = {0}; // 500发送数据集
|
||
unsigned short int ppg_stage_buf[10] = {0}; // stage 的数据,是一秒钟10个
|
||
unsigned short int BH_data_500[500] = {0};
|
||
// unsigned short int sdst[3000] = {0}; // 接收呼吸心跳中间值
|
||
|
||
signed long int max_min2[2] = {-500, 50000}; // 数据集中的最大值和最小值
|
||
|
||
unsigned short int c_BH_max = 0;
|
||
unsigned short int c_BH_index = 0;
|
||
unsigned short int c_BH_num = 0;
|
||
// unsigned char que_static_buf[1024 * 18] = {0}; // 18*300=
|
||
|
||
#ifdef NNOM_USING_STATIC_MEMORY
|
||
// uint8_t BH_static_buf[1024 * 41] = {0}; // 呼吸心跳 模型 内存
|
||
|
||
#ifndef NOT_PRE_STAGE
|
||
uint8_t Stage_static_buf[1024 * 28] = {0}; // 失眠分期 模型内存
|
||
#endif
|
||
|
||
#endif
|
||
char wifi_json_flg = 0;
|
||
// char info[512] = {0};
|
||
// uint8_t s[256] = {0};
|
||
|
||
char MovementBuffer[REPORT_BUFFER_MAX]; // 12小时的体动数据 __attribute__((at(0x080E0000)))
|
||
char HeartRateBuffer[REPORT_BUFFER_MAX]; // 12小时的心率数据__attribute__((at(0x080E0000 + (0x400))))
|
||
char BreathRateBuffer[REPORT_BUFFER_MAX]; // 12小时的呼吸数据__attribute__((at(0x080E0000 + (0x400))))
|
||
char sleepStatusBuffer[REPORT_BUFFER_MAX]; // 12小时的睡眠阶段数据__attribute__((at(0x080E0000 + (0x800))))
|
||
char sleepTempBuffer[REPORT_BUFFER_MAX + 20] = {0}; // 12小时的缓存数据(包括上报)
|
||
|
||
extern warning_config_t warning_config;
|
||
#define FLASH_SAVE_ADDR 0X080C0000 // 代码用了126K,地址需要大于它
|
||
// void c_BH_stage(nnom_model_t *BH_model, nnom_model_t *stage_model);
|
||
// void pre_bh(nnom_model_t *BH_model);
|
||
int MyDSP_Init(void);
|
||
void MyFitter(void);
|
||
|
||
/**
|
||
* @function: IWDG_Init
|
||
* @brief: None
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
void IWDG_Init(void)
|
||
{
|
||
// 1、 取消寄存器写保护:
|
||
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
|
||
// 2、设置独立看门狗的预分频系数,确定时钟:125HZ
|
||
IWDG_SetPrescaler(IWDG_Prescaler_256);
|
||
// 3、设置看门狗重装载值,确定溢出时间:32s
|
||
IWDG_SetReload(4000);
|
||
// 4、重新载入计数器
|
||
IWDG_ReloadCounter();
|
||
// 5、使能
|
||
IWDG_Enable(); // 使能看门狗 打开看门狗好像会导致光功率值跳动?
|
||
}
|
||
|
||
/**
|
||
* @function: IWDG_Feed
|
||
* @brief: 喂狗
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
void IWDG_Feed(void)
|
||
{
|
||
// 把重装载寄存器的值放到计数器中,喂狗,防止IWDG复位
|
||
// 当计数器的值减到0的时候会产生系统复位
|
||
IWDG_ReloadCounter();
|
||
}
|
||
|
||
/**
|
||
* @function: SleepReportSend
|
||
* @brief: None
|
||
* @param {unsigned char} *buf
|
||
* @param {int} size
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
char LastSleepReportPacket_Flag = 0;
|
||
char SleepReportSend(unsigned char *buf, int size, int circle_num)
|
||
{
|
||
int PacketLength = 17;
|
||
char Header[2] = {0xA5, 0x5A};
|
||
char FrameLength[2] = {0};
|
||
char FrameType[1] = {0x02};
|
||
char TimeStamp[8] = {0};
|
||
char TestScoreBuffer[2] = {0x27, 0x40};
|
||
char TestPackets[2] = {0x01, 0x01};
|
||
char TestPacketBuffer[17] = {0};
|
||
char TestDataSend[321] = {0}; // 最大 1H 的数据
|
||
uint16_t Length = size + 17;
|
||
|
||
FrameLength[1] = Length >> 8;
|
||
FrameLength[0] = Length & 0xff;
|
||
memcpy(TimeStamp, Sleep.time_num, sizeof(TimeStamp));
|
||
|
||
// 将帧头赋值
|
||
strcat(TestPacketBuffer, Header);
|
||
// 长度
|
||
TestPacketBuffer[2] = FrameLength[0];
|
||
TestPacketBuffer[3] = FrameLength[1];
|
||
// 将帧类型赋值
|
||
TestPacketBuffer[4] = FrameType[0];
|
||
// 将时间赋值
|
||
TestPacketBuffer[5] = TimeStamp[0];
|
||
TestPacketBuffer[6] = TimeStamp[1];
|
||
TestPacketBuffer[7] = TimeStamp[2];
|
||
TestPacketBuffer[8] = TimeStamp[3];
|
||
TestPacketBuffer[9] = TimeStamp[4];
|
||
TestPacketBuffer[10] = TimeStamp[5];
|
||
TestPacketBuffer[11] = TimeStamp[6];
|
||
TestPacketBuffer[12] = TimeStamp[7];
|
||
// 得分 + 效率
|
||
TestPacketBuffer[13] = get_sleep_stage.score; // 将得分和效率传递给数组;
|
||
TestPacketBuffer[14] = get_sleep_stage.eff;
|
||
// 数据包数
|
||
TestPacketBuffer[16] = circle_num + 1;
|
||
if (LastSleepReportPacket_Flag == 1)
|
||
TestPacketBuffer[15] = circle_num + 1;
|
||
else
|
||
TestPacketBuffer[15] = 24;
|
||
// 数据拷贝
|
||
memcpy(TestDataSend, TestPacketBuffer, sizeof(TestPacketBuffer));
|
||
// memcpy(TestDataSend + 17, buf, size);
|
||
memcpy(TestDataSend + 17, buf + (REPORT_SEND_COUNTS * circle_num), size);
|
||
// WIFI 发送的Buffer
|
||
wifi_crc_send((uint8_t *)TestDataSend, PacketLength + size);
|
||
// 清空buffer
|
||
memset(TestDataSend, 0, sizeof(TestDataSend));
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @function: BaseParmReport
|
||
* @brief 参数发送
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
// TODO: 增加夜间翻身次数的统计以及上报
|
||
void BaseParmReport(void)
|
||
{
|
||
int PacketLength = 32 - 4;
|
||
char Header[2] = {0xA5, 0x5A};
|
||
char FrameLength[2] = {0};
|
||
char FrameType[1] = {0x04};
|
||
char TimeStamp[8] = {0};
|
||
char ParmSendBuffer[32] = {0};
|
||
|
||
FrameLength[1] = PacketLength >> 8;
|
||
FrameLength[0] = PacketLength & 0xff;
|
||
memcpy(TimeStamp, &timeClockCount, sizeof(timeClockCount));
|
||
// 将帧头赋值
|
||
strcat(ParmSendBuffer, Header);
|
||
// 长度
|
||
ParmSendBuffer[2] = FrameLength[0];
|
||
ParmSendBuffer[3] = FrameLength[1];
|
||
// 将帧类型赋值
|
||
ParmSendBuffer[4] = FrameType[0];
|
||
// 将时间赋值
|
||
ParmSendBuffer[5] = TimeStamp[0];
|
||
ParmSendBuffer[6] = TimeStamp[1];
|
||
ParmSendBuffer[7] = TimeStamp[2];
|
||
ParmSendBuffer[8] = TimeStamp[3];
|
||
ParmSendBuffer[9] = TimeStamp[4];
|
||
ParmSendBuffer[10] = TimeStamp[5];
|
||
ParmSendBuffer[11] = TimeStamp[6];
|
||
ParmSendBuffer[12] = TimeStamp[7];
|
||
// 将参数正常赋值
|
||
ParmSendBuffer[13] = Roll_Over_Count; // 翻身次数计数
|
||
// WIFI 发送的Buffer
|
||
if (OffBed_Flag == 4) // 在床才会发送数据
|
||
#if SLEEP_DEBUG_MODE
|
||
;
|
||
#else
|
||
|
||
// 每天早上8:30 报一次夜间的翻身次数
|
||
// if ((g_hour == 8 && g_min == 30 && g_sec == 0) && Roll_Over_Count != 0)
|
||
// {
|
||
// wifi_crc_send((uint8_t *)ParmSendBuffer, 28);
|
||
// Roll_Over_Count = 0; // 翻身次数清除
|
||
// }
|
||
#endif
|
||
// 清空buffer
|
||
memset(ParmSendBuffer, 0, sizeof(ParmSendBuffer));
|
||
}
|
||
|
||
#define NumberToWrite 1200
|
||
/**
|
||
* @function:SleepReportSave
|
||
* @brief 睡眠报告存储
|
||
* @param {unsigned char} *buf:原始数据
|
||
* @param {char} SaveIndex:保存的起始地址,计算偏移
|
||
* @param {unsigned char} *TimeStamp_buf :时间戳
|
||
* @param {char} Score:得分
|
||
* @param {char} Efficiency:效率
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
char SleepReportSave(unsigned char *buf, char SaveIndex, unsigned char *TimeStamp_buf, char Score, char Efficiency)
|
||
{
|
||
uint8_t Result = 0;
|
||
uint8_t Error_cnt = 0;
|
||
uint32_t Report_Offset = 0;
|
||
Report_Offset += (0x4000 * SaveIndex);
|
||
// 由于buffer大小为7200同时扇区最大为4KB,需要存储两次,存满两个扇区
|
||
// 第一个扇区存储时间戳以及一些其他东西
|
||
unsigned char TimeStamp[8] = {0}; // 时间戳
|
||
unsigned char Sleep_Score_Eff[2] = {0}; // 睡眠得分和效率
|
||
// 用于比较
|
||
unsigned char cmp_Buffer[8] = {0}; // 时间戳
|
||
unsigned char cmp_Score_Eff_Buffer[2] = {0}; // 睡眠得分和效率
|
||
|
||
// 第二个扇区存储第一块的数据,第三个存储后面的
|
||
unsigned char temp_Buffer[NumberToWrite] = {0}; // 原始数据的缓存
|
||
// unsigned char SleepReport_Length[4] = {0}; // 睡眠报告数据长度
|
||
|
||
// 复制时间戳以及得分和效率
|
||
Sleep_Score_Eff[0] = (unsigned char)Score;
|
||
Sleep_Score_Eff[1] = (unsigned char)Efficiency;
|
||
memcpy(TimeStamp, TimeStamp_buf, sizeof(TimeStamp));
|
||
|
||
// 先擦除INFO位置的扇区
|
||
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_INFO_ADDRESS + Report_Offset);
|
||
// // NOTE: 存储时间戳
|
||
do
|
||
{
|
||
EN25QXX_Write(TimeStamp, (FLASH_SLEEP_REPORT_TIMESTAMP_ADDRESS + Report_Offset), sizeof(TimeStamp));
|
||
memset(cmp_Buffer, 0, sizeof(cmp_Buffer));
|
||
EN25QXX_Read(cmp_Buffer, (FLASH_SLEEP_REPORT_TIMESTAMP_ADDRESS + Report_Offset), sizeof(cmp_Buffer));
|
||
Result = memcmp(TimeStamp, cmp_Buffer, sizeof(TimeStamp));
|
||
} while (Result != 0);
|
||
memset(TimeStamp, 0, sizeof(TimeStamp));
|
||
memset(cmp_Buffer, 0, sizeof(cmp_Buffer));
|
||
// NOTE: 存储得分&&效率
|
||
do
|
||
{
|
||
EN25QXX_Write(Sleep_Score_Eff, (FLASH_SLEEP_REPORT_SCORE_EFFICIENCY_ADDRESS + Report_Offset), sizeof(Sleep_Score_Eff));
|
||
memset(cmp_Score_Eff_Buffer, 0, sizeof(cmp_Score_Eff_Buffer));
|
||
EN25QXX_Read(cmp_Score_Eff_Buffer, (FLASH_SLEEP_REPORT_SCORE_EFFICIENCY_ADDRESS + Report_Offset), sizeof(cmp_Score_Eff_Buffer));
|
||
Result = memcmp(Sleep_Score_Eff, cmp_Score_Eff_Buffer, sizeof(Sleep_Score_Eff));
|
||
} while (Result != 0);
|
||
memset(Sleep_Score_Eff, 0, sizeof(Sleep_Score_Eff));
|
||
memset(cmp_Score_Eff_Buffer, 0, sizeof(cmp_Score_Eff_Buffer));
|
||
|
||
// 再擦除数据块1 的扇区
|
||
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset);
|
||
// 每一块扇区存3600字节
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
// 拷贝数据
|
||
memcpy(temp_Buffer, buf + (NumberToWrite * i), NumberToWrite);
|
||
// 写块1的数据
|
||
EN25QXX_Write(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
||
// 清除数据
|
||
memset(temp_Buffer, 0, NumberToWrite);
|
||
// 读取做校验
|
||
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
||
// 比较
|
||
Result = memcmp(temp_Buffer, buf + (NumberToWrite * i), NumberToWrite);
|
||
if (Result != 0)
|
||
{
|
||
i--;
|
||
Error_cnt++;
|
||
}
|
||
if (Error_cnt >= 10)
|
||
{
|
||
Error_cnt = 0;
|
||
break;
|
||
}
|
||
}
|
||
// 清除数据
|
||
memset(temp_Buffer, 0, NumberToWrite);
|
||
// 再擦除数据块2 的扇区
|
||
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset);
|
||
// 每一块扇区存3600字节
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
// 拷贝数据
|
||
memcpy(temp_Buffer, buf + (3 * NumberToWrite) + (NumberToWrite * i), NumberToWrite);
|
||
// 写块2的数据
|
||
EN25QXX_Write(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
||
// 清除数据
|
||
memset(temp_Buffer, 0, NumberToWrite);
|
||
// 读取做校验
|
||
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
||
// 比较
|
||
Result = memcmp(temp_Buffer, buf + (3 * NumberToWrite) + (NumberToWrite * i), NumberToWrite);
|
||
if (Result != 0)
|
||
{
|
||
i--;
|
||
Error_cnt++;
|
||
}
|
||
if (Error_cnt >= 10)
|
||
break;
|
||
}
|
||
// 清除数据
|
||
memset(temp_Buffer, 0, sizeof(temp_Buffer));
|
||
// 再擦除保留数据块的扇区
|
||
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_RETAIN_ADDRESS + Report_Offset);
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @function: SleepReportGet
|
||
* @brief 获取睡眠报告
|
||
* @param {unsigned char} *buf
|
||
* @param {char} Index
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
char SleepReportGet(unsigned char *buf, char Index)
|
||
{
|
||
uint8_t Result = 0;
|
||
uint8_t Error_cnt = 0;
|
||
char FlashDataBuffer[7200] = {0};
|
||
unsigned char temp_Buffer[NumberToWrite] = {0}; // 原始数据的缓存
|
||
uint32_t Report_Offset = 0;
|
||
Report_Offset += (0x4000 * Index);
|
||
// 每一块扇区存3600字节
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
// 清除数据
|
||
memset(temp_Buffer, 0, NumberToWrite);
|
||
// 读取块1的数据
|
||
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
||
// 复制数据
|
||
memcpy(FlashDataBuffer + (NumberToWrite * i), temp_Buffer, NumberToWrite);
|
||
}
|
||
// 每一块扇区存3600字节
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
// 清除数据
|
||
memset(temp_Buffer, 0, NumberToWrite);
|
||
// 读取块2的数据
|
||
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
||
// 复制数据
|
||
memcpy(FlashDataBuffer + (NumberToWrite * i) + (3 * NumberToWrite), temp_Buffer, NumberToWrite);
|
||
}
|
||
memcpy(buf, FlashDataBuffer, sizeof(FlashDataBuffer));
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @function: get_flash_init
|
||
* @brief: 获取Flash
|
||
* @return {*}
|
||
* @author: wt
|
||
*/
|
||
void get_flash_init(void)
|
||
{
|
||
Sleep.breathe_abnormal_flg = 0;
|
||
EN25QXX_Read((u8 *)Sleep.report_get_buf, 0, 200); // 前200个数据等于整体介绍
|
||
|
||
Sleep.all_num = Sleep.report_get_buf[0]; // 总天数
|
||
Sleep.report_num = Sleep.report_get_buf[1]; // 当前天数
|
||
|
||
// Sleep.report_get_buf[0] = 0; //总天数
|
||
// Sleep.report_get_buf[1] = 0; //当前天数
|
||
// EN25QXX_Write((u8 *)Sleep.report_get_buf, 0, 200); //存储
|
||
|
||
if (Sleep.all_num == 0) // 还没有数据
|
||
{
|
||
Sleep.report_num = 1;
|
||
Sleep.all_num = 1;
|
||
}
|
||
else if ((Sleep.all_num >= 7) && (Sleep.report_num >= 7)) // 已经满了
|
||
{
|
||
Sleep.report_num = 1;
|
||
}
|
||
else if (Sleep.all_num >= 7) // 已经一轮了
|
||
{
|
||
Sleep.report_num++;
|
||
}
|
||
else // 不到一轮
|
||
{
|
||
Sleep.all_num++;
|
||
Sleep.report_num++;
|
||
}
|
||
Sleep.storage_location_num = 200 + 1024 * (9 * (Sleep.report_num - 1)); // 当前存储数量--地址等于
|
||
|
||
Sleep.report_time_flg = 1; // 更新时间戳
|
||
OffBed_Flag = 0; // 离床
|
||
Sleep.equipment_status_time = 0; // 初始离床时间0
|
||
Sleep.sleep_stage_flg = 0; // 不出睡眠报告
|
||
Sleep.circle_num = 0; // 当前循环为0
|
||
}
|
||
|
||
/**
|
||
* @function: SleepRecord_SaveDirectory
|
||
* @brief: 保存目录
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
void SleepRecord_SaveDirectory(char *buffer)
|
||
{
|
||
// 判断是否是空的
|
||
int Counter = 0;
|
||
char index = 0;
|
||
char Value = 0;
|
||
for (Counter = 0; Counter < REPORT_SAVE_SIZE; Counter++)
|
||
{
|
||
if (buffer[Counter] != DEFAULT_FF)
|
||
break;
|
||
}
|
||
// 第一次做记录
|
||
if (Counter == REPORT_SAVE_SIZE)
|
||
{
|
||
buffer[0] = 0;
|
||
index++;
|
||
Value++;
|
||
SleepRecord.SleepReport_CurrentIndex = 0;
|
||
}
|
||
else
|
||
{
|
||
// 先遍历一次
|
||
for (Counter = 0; Counter < REPORT_SAVE_SIZE; Counter++)
|
||
{
|
||
// 找到了空余区域
|
||
if (buffer[Counter] == DEFAULT_FF)
|
||
{
|
||
SleepRecord.SleepReport_CurrentIndex = Counter;
|
||
buffer[Counter] = Counter;
|
||
index = Counter + 1;
|
||
Value++;
|
||
break;
|
||
}
|
||
}
|
||
if (Counter == REPORT_SAVE_SIZE)
|
||
{
|
||
// 已经存储完成,需要顶替
|
||
for (Counter = 0; Counter < REPORT_SAVE_SIZE; Counter++)
|
||
{
|
||
if (buffer[Counter] != 0)
|
||
{
|
||
buffer[Counter] -= 1;
|
||
}
|
||
else
|
||
{
|
||
SleepRecord.SleepReport_CurrentIndex = Counter;
|
||
buffer[Counter] = REPORT_SAVE_SIZE - 1;
|
||
index = Counter;
|
||
Value = buffer[Counter];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
SleepRecord.SleepReport_CurrentSaveNum = Value;
|
||
}
|
||
|
||
/**
|
||
* @function:cjson_ReInitHook
|
||
* @brief 重新初始化钩子函数(采用自己的内存分配)
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
void cjson_ReInitHook(void)
|
||
{
|
||
static cJSON_Hooks m_iot_hooks;
|
||
m_iot_hooks.malloc_fn = mymalloc;
|
||
m_iot_hooks.free_fn = myfree;
|
||
cJSON_InitHooks(&m_iot_hooks);
|
||
}
|
||
|
||
/**
|
||
* @function: MattressFunctionInit
|
||
* @brief: 体征垫参数初始化
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
char bootResult = 0;
|
||
RCC_ClocksTypeDef get_RCC_Clock;
|
||
void MattressParameterInit(void)
|
||
{
|
||
System_Init();
|
||
// NOTE: 将静态数组的指针传入,以其作为队列的存储
|
||
// node_set_static_buf(que_static_buf, sizeof(que_static_buf));
|
||
// NOTE: 初始化队列,设置个数
|
||
// InitQueue(&Stage_q, 301, 1); // 300秒,5分钟
|
||
// NOTE: 此处用于清空睡眠阶段的结构体
|
||
// init_struct_stage(&get_sleep_stage);
|
||
wait(5); // 等待一段时间避免ESP32的串口数据有影响
|
||
get_flash_init(); // flash初始化
|
||
cjson_ReInitHook();
|
||
if ((*(__IO uint16_t *)0X08004000) != 0x1111) // 没有存储 写入默认值
|
||
{
|
||
FLASH_Unlock();
|
||
FLASH_EraseSector(FLASH_Sector_1, VoltageRange_3);
|
||
flashWrite(get_breathe_buf, 6); // 写入flash,固定一包写6个字节
|
||
FLASH_Lock();
|
||
}
|
||
else
|
||
{
|
||
Breathe_H = (*(__IO uint8_t *)0X08004002);
|
||
Breathe_L = (*(__IO uint8_t *)0X08004003);
|
||
HeartRate_H = (*(__IO uint8_t *)0X08004004);
|
||
HeartRate_L = (*(__IO uint8_t *)0X08004005);
|
||
}
|
||
if (EN25QXX_ReadID() != EN25Q64) // 检测不到EN25Q64
|
||
{
|
||
printf("EN25Q64 Check Failed!\r\n");
|
||
}
|
||
else
|
||
{
|
||
printf("EN25Q64 Check right!\r\n");
|
||
}
|
||
// 读取复位原因
|
||
if ((RCC->CSR & 0X80000000) != 0) // 1 低功耗复位
|
||
{
|
||
bootResult = Low_Power_Reset;
|
||
printf("[Reset]: Low Power Reset\r\n");
|
||
}
|
||
else if ((RCC->CSR & 0X40000000) != 0) // 2 窗口看门狗复位
|
||
{
|
||
bootResult = WWDG_Reset;
|
||
printf("[Reset]: WWDG Reset\r\n");
|
||
}
|
||
else if ((RCC->CSR & 0X20000000) != 0) // 3 独立看门狗复位
|
||
{
|
||
bootResult = IWDG_Reset;
|
||
printf("[Reset]: IWDG Reset\r\n");
|
||
}
|
||
else if ((RCC->CSR & 0X10000000) != 0) // 4 软件复位
|
||
{
|
||
bootResult = SoftWare_Reset;
|
||
printf("[Reset]: SoftWare Reset\r\n");
|
||
}
|
||
else if ((RCC->CSR & 0X08000000) != 0) // 5 上电复位
|
||
{
|
||
bootResult = PowerOn_Reset;
|
||
printf("[Reset]: PowerOn Reset\r\n");
|
||
}
|
||
else if ((RCC->CSR & 0X04000000) != 0) // 6 PIN复位
|
||
{
|
||
bootResult = Pin_Reset;
|
||
printf("[Reset]: Pin Reset\r\n");
|
||
}
|
||
RCC->CSR = 0X01000000;
|
||
// 读取时钟
|
||
RCC_GetClocksFreq(&get_RCC_Clock); /**/
|
||
printf("-----------------------------------------------\r\n");
|
||
printf("[System Clock]: HCLK_Frequency %d\r\n", get_RCC_Clock.HCLK_Frequency);
|
||
printf("[System Clock]: PCLK1_Frequency %d\r\n", get_RCC_Clock.PCLK1_Frequency);
|
||
printf("[System Clock]: PCLK2_Frequency %d\r\n", get_RCC_Clock.PCLK2_Frequency);
|
||
printf("[System Clock]: SYSCLK_Frequency %d\r\n", get_RCC_Clock.SYSCLK_Frequency);
|
||
printf("-----------------------------------------------\r\n");
|
||
}
|
||
|
||
/**
|
||
* @function: Storage_Initialization
|
||
* @brief: 存储初始化
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
extern float OPM_Original;
|
||
void Storage_Initialization(void)
|
||
{
|
||
// DONE::获取光功阈值存储数据,如果没有使用默认值
|
||
EN25QXX_Read((uint8_t *)&OPM_Original, FLASH_IN_OFF_BED_OPM_RECORD_ADDRESS, sizeof(float32_t));
|
||
EN25QXX_Read((u8 *)&Calibration_Template, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(Calibration_Template));
|
||
EN25QXX_Read((u8 *)&Calibration_Template_2, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(Calibration_Template_2));
|
||
// 如果读取数据错误则写入默认值
|
||
if (OPM_Original >= WEAK_OPM && OPM_Original <= -10.0f)
|
||
{
|
||
printf("\r\n OPM_Original : %f\r\n", OPM_Original);
|
||
}
|
||
else
|
||
{
|
||
OPM_Original = -10.0f;
|
||
EN25QXX_Write((uint8_t *)&OPM_Original,
|
||
FLASH_IN_OFF_BED_OPM_RECORD_ADDRESS,
|
||
sizeof(float32_t));
|
||
printf("\r\n OPM_Original Empty\r\n");
|
||
}
|
||
// 如果获取的数据不是空数据
|
||
if (Calibration_Template != 0xffffffff &&
|
||
Calibration_Template_2 != 0xffffffff)
|
||
{
|
||
// 增加LED灯的指示,会闪一下浅色LED
|
||
LED_G = 0;
|
||
LED_B = 0;
|
||
delay_ms(500);
|
||
LED_R = 1;
|
||
LED_G = 1;
|
||
LED_B = 1;
|
||
EN25QXX_Read((u8 *)&ON_BED_Threshold, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(ON_BED_Threshold));
|
||
EN25QXX_Read((u8 *)&OFF_BED_Threshold, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(OFF_BED_Threshold));
|
||
}
|
||
// TODO: 增加读取睡眠报告的目录参数
|
||
// 睡眠报告的配置结构--清空配置
|
||
SleepRecord.SleepReport_CurrentIndex = 0;
|
||
SleepRecord.SleepReport_CurrentSaveNum = 0;
|
||
// 读取
|
||
EN25QXX_Read((u8 *)&SleepRecord.SleepReport_Directory,
|
||
FLASH_SLEEP_REPORT_DIRECTORY_ADDRESS,
|
||
sizeof(SleepRecord.SleepReport_Directory));
|
||
Key_Cal_Flag = 0; // 此处不能删除,删除会导致上电黑掉的情况
|
||
// 设置随机种子
|
||
MySetRandom(AIN_1310);
|
||
}
|
||
|
||
/**
|
||
* @function: OPM_MattressCalibration
|
||
* @brief: 体征垫的光功校准
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
void OPM_MattressCalibration(void)
|
||
{
|
||
if (opm_cal_flag == 1) // 需要进行校准
|
||
{
|
||
IWDG_Feed(); // // NOTE:喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
||
// 青色LED = G + B
|
||
// 紫色LED = R + B
|
||
float Optical_Sum = 0.0f;
|
||
// 修正值为空,且没有进行空床校准
|
||
if (Optical_Calibration_Value == 0.0f &&
|
||
((Calibration_Off_Bed_Done_Flag == 0) ||
|
||
(Calibration_In_Bed_Done_Flag == 1)))
|
||
{
|
||
for (char i = 0; i < 10; i++)
|
||
{
|
||
LED_G = 0;
|
||
LED_B = 0;
|
||
delay_ms(8000);
|
||
LED_G = 1;
|
||
LED_B = 1;
|
||
delay_ms(8000);
|
||
get_optical_power(); // 获取光功
|
||
Optical_Sum += dbm_value_1310;
|
||
}
|
||
Optical_Calibration_Value = Optical_Sum / 10.0f; // 作均值
|
||
// 记录以及计算阈值
|
||
Optical_Calibration_Value_OffBed = Optical_Calibration_Value;
|
||
// 更新阈值
|
||
OFF_BED_Threshold = Optical_Calibration_Value_OffBed - (float)2.0;
|
||
// 更新阈值
|
||
ON_BED_Threshold = OFF_BED_Threshold - 10;
|
||
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
||
IWDG_Feed(); // NOTE:喂狗
|
||
// 空床也进行保存
|
||
EN25QXX_Write((u8 *)&ON_BED_Threshold, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(ON_BED_Threshold));
|
||
EN25QXX_Write((u8 *)&OFF_BED_Threshold, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(OFF_BED_Threshold));
|
||
Key_Cal_Flag = 0;
|
||
opm_cal_flag = 0;
|
||
Local_ON_BED_Threshold = ON_BED_Threshold;
|
||
Local_OFF_BED_Threshold = OFF_BED_Threshold;
|
||
TIM_Cmd(TIM3, ENABLE); // 使能定时器3
|
||
Calibration_In_Bed_Done_Flag = 0;
|
||
Calibration_Off_Bed_Done_Flag = 1;
|
||
}
|
||
else if (Optical_Calibration_Value == 0.0f &&
|
||
Calibration_Off_Bed_Done_Flag == 1)
|
||
{
|
||
for (char i = 0; i < 10; i++)
|
||
{
|
||
LED_R = 0;
|
||
LED_B = 0;
|
||
delay_ms(8000);
|
||
LED_R = 1;
|
||
LED_B = 1;
|
||
delay_ms(8000);
|
||
get_optical_power(); // 获取光功
|
||
Optical_Sum += dbm_value_1310;
|
||
printf("Calibration\r\n");
|
||
}
|
||
Optical_Calibration_Value = Optical_Sum / 10.0f; // 作均值
|
||
// 记录以及计算阈值
|
||
Optical_Calibration_Value_OnBed = Optical_Calibration_Value;
|
||
// 更新阈值
|
||
ON_BED_Threshold = Optical_Calibration_Value_OnBed - 10;
|
||
Key_Cal_Flag = 0;
|
||
opm_cal_flag = 0;
|
||
Local_ON_BED_Threshold = ON_BED_Threshold;
|
||
Local_OFF_BED_Threshold = OFF_BED_Threshold;
|
||
TIM_Cmd(TIM3, ENABLE); // 使能定时器3
|
||
Calibration_In_Bed_Done_Flag = 1;
|
||
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
||
IWDG_Feed(); // NOTE:喂狗
|
||
// TODO: 做记录之后再次进行存储,之后直接复位。
|
||
EN25QXX_Write((u8 *)&ON_BED_Threshold, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(ON_BED_Threshold));
|
||
EN25QXX_Write((u8 *)&OFF_BED_Threshold, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(OFF_BED_Threshold));
|
||
CalValue_Upload();
|
||
NVIC_SystemReset(); // 复位
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @function: KalmarFilter
|
||
* @brief: None
|
||
* @param {float} inData
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
float KalmarFilter(float inData)
|
||
{
|
||
static float prevData = 0; // 上一个数据
|
||
static float p = 10, q = 0.005, r = 0.005, kGain = 0.5; // q 控制误差 r 控制响应速度
|
||
p = p + q;
|
||
kGain = p / (p + r); // 计算卡尔曼增益
|
||
inData = prevData + (kGain * (inData - prevData)); // 计算本次滤波估计值
|
||
p = (1 - kGain) * p; // 更新测量方差
|
||
prevData = inData;
|
||
return inData; // 返回估计值
|
||
}
|
||
|
||
/**
|
||
* @function: main
|
||
* @brief: 主函数
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
uint16_t EnergyData = 0;
|
||
uint16_t Chip_ID_Data = 0;
|
||
uint16_t fft_HeartBeatRate_Hi = 0;
|
||
uint16_t fft_HeartBeatRate_Lo = 0;
|
||
uint16_t fft_HeartBeatRate_Result = 0;
|
||
uint16_t time_HeartBeatRate_Result = 0;
|
||
|
||
float fft_HeartBeatRate_StashBuffer[15] = {0};
|
||
int main(void)
|
||
{
|
||
VectorTableReInit();
|
||
// nnom_model_t *BH_model, *stage_model; // 两个预测模型的指针
|
||
|
||
// 睡眠报告的原始数据 可存储一天的数据 24h*60min*60sec = 7200 ;
|
||
// unsigned char SleepReportSendDataBuffer[7200] = {0};
|
||
// unsigned char SleepReportReadDataBuffer[7200] = {0};
|
||
float new_data_0,
|
||
new_data_1, new_data_2, new_data_3, new_data_4, new_data;
|
||
char index, max = 0;
|
||
int m = 0, num, it, add_g;
|
||
float md_u, md_d, md;
|
||
char FirstPowerON_Flag = 1;
|
||
struct tm *time;
|
||
time_t timestamp = 0; /* 时间戳 */
|
||
char Send_Once = 1;
|
||
int EnergyIndex = 0;
|
||
int ReSendStartCommand_Count = 0;
|
||
MattressParameterInit(); // 床垫 初始化
|
||
// 初始化IIC
|
||
IIC_Init();
|
||
// 一分钟开启BLE启动状态
|
||
PowerOn_OneMinuteBLEScan();
|
||
#if 1
|
||
// 初始化看门狗
|
||
IWDG_Init();
|
||
#ifdef NNOM_USING_STATIC_MEMORY
|
||
// nnom_set_static_buf(BH_static_buf, sizeof(BH_static_buf)); // 对运行内存进行初始化
|
||
#endif
|
||
// BH_model = nnom_model_create_BH_KC(); // 调用预测睡眠和呼吸的模型函数,初始化 //显示内存使用情况。
|
||
#ifndef NOT_PRE_STAGE
|
||
#ifdef NNOM_USING_STATIC_MEMORY
|
||
nnom_set_static_buf(Stage_static_buf, sizeof(Stage_static_buf)); // 对运行内存进行初始化
|
||
#endif
|
||
stage_model = nnom_model_create(); // 调用预测睡眠周期模型函数,初始化。该函数的h文件还没有加到这个工程里 //显示内存使用情况。
|
||
#endif
|
||
// 用于测试
|
||
if (TEST_SEND_BH_STAGE || TEST_SEND_SINGAL)
|
||
{
|
||
TIM_Cmd(TIM3, ENABLE); //
|
||
Key_Cal_Flag = 1;
|
||
}
|
||
Storage_Initialization(); // 存储初始化
|
||
Local_ON_BED_Threshold = ON_BED_Threshold;
|
||
Local_OFF_BED_Threshold = OFF_BED_Threshold;
|
||
// 读取ID
|
||
Chip_ID_Data = SGM58031_ReadData(ChipID_Reg, 0x90, 2);
|
||
if (SGM58031_WriteConfig(0x40e3))
|
||
printf("ADC Successfully initialized");
|
||
MyDSP_Init();
|
||
while (1)
|
||
{
|
||
// 用于测试
|
||
if (TEST_SEND_BH_STAGE)
|
||
{
|
||
#ifndef NOT_PRE_STAGE
|
||
c_BH_stage(BH_model, stage_model);
|
||
#else
|
||
// pre_bh(BH_model);
|
||
#endif
|
||
}
|
||
key_optical(); // 按键检测
|
||
if (USART_DealFlag)
|
||
{
|
||
USART_DealFlag = 0;
|
||
wifi_cmd_exe(); // 通讯交流
|
||
// 串口接收完毕时使能计算定时器
|
||
TIM_Cmd(TIM5, ENABLE);
|
||
}
|
||
else
|
||
CheckOverTimeValueClear();
|
||
if (Key_Cal_Flag == 0) // 配网成功
|
||
{
|
||
// 时间戳下发成功
|
||
if (TimeClock_Flag == 1)
|
||
{
|
||
TIM_Cmd(TIM2, ENABLE);
|
||
get_optical_power(); // 获取光功
|
||
MyFitter(); // 滤波器
|
||
// 第一次上电上报校准值
|
||
if (FirstPowerON_Flag)
|
||
{
|
||
FirstPowerON_Flag = 0;
|
||
CalValue_Upload();
|
||
delay_ms(50);
|
||
// 版本号上报
|
||
version_upload();
|
||
BreathRate = 0;
|
||
HeartBeatRate = 0;
|
||
// MySetRandom(AIN_1310);
|
||
// 生成随机值 心率和呼吸
|
||
// BreathRate = rand() % 11 + 14; // 产生14~24的随机数
|
||
// HeartBeatRate = rand() % 11 + 54; // 产生54~64的随机数
|
||
}
|
||
// 发送json数据
|
||
if (wifi_json_flg == 1)
|
||
{
|
||
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
||
IWDG_Feed();
|
||
// TIM_Cmd(TIM2, DISABLE);
|
||
wifi_json_send();
|
||
// TIM_Cmd(TIM2, ENABLE);
|
||
wifi_json_flg = 0;
|
||
}
|
||
// 发送数据
|
||
if (wifi_len_500_flg == 1)
|
||
{
|
||
wifi_len_500_flg = 0;
|
||
// TIM_Cmd(TIM2, DISABLE);
|
||
wifi_send();
|
||
// TIM_Cmd(TIM2, ENABLE);
|
||
// 延时50ms
|
||
delay_ms(500);
|
||
}
|
||
// 计算睡眠周期框架
|
||
if (start_stage_flg == 1) // 12秒钟算一次睡眠分期
|
||
{
|
||
start_stage_flg = 0;
|
||
// NOTE: 增加睡眠部分代码
|
||
// 睡眠报告测试
|
||
if (Send_Once)
|
||
{
|
||
Send_Once = 0;
|
||
// SleepReportGenerate(timeClockCount, 720);
|
||
}
|
||
}
|
||
// 计算呼吸心跳框架
|
||
if (start_calculate_flg == 1)
|
||
{
|
||
start_calculate_flg = 0;
|
||
//------------------------------ FFT算法 ---------------------------------------//
|
||
if (equipment_status_value == InBed_Status)
|
||
{
|
||
/*
|
||
// 心率相关
|
||
fft_HeartBeatRate_Hi = (round(fft_Output(outPutFitterOPMData_Heart,
|
||
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
||
fft_HeartBeatRate_Lo = (round(fft_Output(outPutFitterOPMData_Heart_Lo,
|
||
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
||
if (abs(fft_HeartBeatRate_Lo - fft_HeartBeatRate_Hi) < 15 ||
|
||
fft_HeartBeatRate_Hi <= 120 || fft_HeartBeatRate_Lo > 120)
|
||
fft_HeartBeatRate_Result = fft_HeartBeatRate_Lo;
|
||
else
|
||
fft_HeartBeatRate_Result = (fft_HeartBeatRate_Hi / 2);
|
||
fft_heartDataPostProcessing(fft_HeartBeatRate_Result);
|
||
// 呼吸相关
|
||
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
||
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
||
// 记录
|
||
BreathRate_Record = BreathRate;
|
||
HeartBeatRate_Record = HeartBeatRate;
|
||
*/
|
||
switch (FFT_Calculate_State_Flag)
|
||
{
|
||
// 启动计算
|
||
case FFT_Start_Calculate:
|
||
#if 0
|
||
// 心率相关
|
||
fft_HeartBeatRate_Hi = (round(fft_Output(outPutFitterOPMData_Heart,
|
||
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
||
fft_HeartBeatRate_Lo = (round(fft_Output(outPutFitterOPMData_Heart_Lo,
|
||
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
||
if (abs(fft_HeartBeatRate_Lo - fft_HeartBeatRate_Hi) < 15 ||
|
||
fft_HeartBeatRate_Hi <= 120 || fft_HeartBeatRate_Lo > 120)
|
||
fft_HeartBeatRate_Result = fft_HeartBeatRate_Lo;
|
||
else
|
||
fft_HeartBeatRate_Result = (fft_HeartBeatRate_Hi / 2);
|
||
fft_heartDataPostProcessing(fft_HeartBeatRate_Result);
|
||
// 呼吸相关
|
||
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
||
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
||
// 记录
|
||
BreathRate_Record = BreathRate;
|
||
HeartBeatRate_Record = HeartBeatRate;
|
||
if (FFT_Count_State_Flag == FFT_No_breath)
|
||
{
|
||
#if THE_VERSION
|
||
BreathRate = 0;
|
||
#else
|
||
; // BreathRate = 0;
|
||
#endif
|
||
}
|
||
#else
|
||
fft_HeartBeatCurrentFilter = FILTER_HI_TYPE;
|
||
fft_Output(outPutFitterOPMData_Heart, HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART);
|
||
memcpy(HeartValueRes2Peaks, FFT_HeartRateRes, sizeof(FFT_HeartRateRes));
|
||
|
||
fft_HeartBeatCurrentFilter = FILTER_LO_TYPE;
|
||
fft_Output(outPutFitterOPMData_Heart_Lo, HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART);
|
||
memcpy(HeartValueRes2Peaks + 2, FFT_HeartRateRes, sizeof(FFT_HeartRateRes));
|
||
|
||
time_HeartBeatRate_Result = time_domain_heart_rate(outPutFitterOPMData_Heart_Lo);
|
||
fft_HeartBeatRate_Result = MyToolSelectHp(HeartValueRes2Peaks, stash_Ratio,
|
||
fft_HeartBeatRate_StashBuffer, time_HeartBeatRate_Result);
|
||
|
||
fft_heartDataPostProcessing(fft_HeartBeatRate_Result);
|
||
// 呼吸相关
|
||
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
||
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
||
// 更新数据
|
||
MyToolMoveUpdate((float *)fft_HeartBeatRate_StashBuffer, 15, HeartBeatRate);
|
||
// 记录
|
||
BreathRate_Record = BreathRate;
|
||
HeartBeatRate_Record = HeartBeatRate;
|
||
#endif
|
||
break;
|
||
// 停止计算
|
||
case FFT_Stop_Calculate:
|
||
// 有体动情况下尽快上报数据
|
||
if ((BreathRate == 0) && (HeartBeatRate == 0))
|
||
{
|
||
BreathRate_Record = 15;
|
||
HeartBeatRate_Record = 75;
|
||
}
|
||
BreathRate = BreathRate_Record;
|
||
HeartBeatRate = HeartBeatRate_Record;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
timestamp = timeClockCount_Send / 1000;
|
||
/* 时间补偿 */
|
||
timestamp = timestamp + ((signed char)warning_config.timeZone) * 60 * 60;
|
||
/* 调用系统函数 */
|
||
time = localtime(×tamp);
|
||
g_mon = time->tm_mon; /* 月份 */
|
||
g_day = time->tm_mday; /* 日期 */
|
||
g_hour = time->tm_hour; /* 小时:0-23点,UTC+0时间*/
|
||
g_min = time->tm_min; /* 分钟:0-60 ,UTC+0时间 */
|
||
g_sec = time->tm_sec; /* 秒 :0-60,UTC+0时间 */
|
||
// 重新获取时间戳 (超过1小时或者每天的中午更新时间)
|
||
if (TimeClock_Recalibrate_Count >= TIME_CLOCK_MAX_TIMES)
|
||
{
|
||
TimeClock_Flag = 0;
|
||
TIM_ClearITPendingBit(TIM5, TIM_IT_Update); // 清除标志位
|
||
TIM_Cmd(TIM5, DISABLE); // 失能定时器5
|
||
TimeClock_Recalibrate_Count = TIME_CLOCK_MAX_TIMES;
|
||
// printf("\r\n!!!Recalibrate!!!\r\n");
|
||
}
|
||
// 超时或者联网成功则复位 同时发送清除BLE信息的指令
|
||
if (PowerOn_OneMinuteCount >= ONE_MINUTES_COUNT &&
|
||
PowerOn_OneMinuteCount_Start)
|
||
{
|
||
PowerOn_OneMinuteCount_Start = 0;
|
||
USART1_SendData(myReset, 5); // 清除指令
|
||
delay_ms(1500);
|
||
if (Key_Cal_Flag != 0) // 没有联网成功
|
||
NVIC_SystemReset(); // 复位
|
||
}
|
||
else if (PowerOn_OneMinuteCount < ONE_MINUTES_COUNT)
|
||
{
|
||
// 如果配网开始则count清除
|
||
if (PowerOn_StartConfigFlg)
|
||
PowerOn_OneMinuteCount = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
static int Value = 0;
|
||
Value++;
|
||
// LED_B=!LED_B;
|
||
LED_R = 1;
|
||
if (TimeClock_Recalibrate_Count >= TIME_CLOCK_MAX_TIMES)
|
||
{
|
||
TimeClock_Recalibrate_Count = 0;
|
||
LED_G = 0;
|
||
LED_B = 0; // 重新校准时间戳的时候青色LED闪一下
|
||
}
|
||
else
|
||
{
|
||
LED_G = 1;
|
||
LED_B = !LED_B;
|
||
}
|
||
TIM_Cmd(TIM2, DISABLE);
|
||
printf("Wait TimeStamp...\r\n");
|
||
wifi_crc_send(get_time_buf, 13);
|
||
delay_ms(500);
|
||
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
||
IWDG_Feed();
|
||
}
|
||
}
|
||
// 等待配网
|
||
else
|
||
{
|
||
ReSendStartCommand_Count++;
|
||
// printf("Wait Net...\r\n");
|
||
// AP = 1; BLE = 0
|
||
if (!NetworkConnectionWay)
|
||
LED_R = 1;
|
||
else
|
||
LED_R = 0;
|
||
LED_G = 1;
|
||
LED_B = 0;
|
||
if (start_ConnectNet_flg)
|
||
{
|
||
delay_ms(2000);
|
||
start_ConnectNet_flg = 0;
|
||
USART1_SendData(Start_Cmd, 5); // 启动配网指令
|
||
}
|
||
// 配网超时重发机制
|
||
if (ReSendStartCommand_Count >= 1000 && start_ConnectNet_flg == 0)
|
||
{
|
||
start_ConnectNet_flg = 1;
|
||
ReSendStartCommand_Count = 0;
|
||
}
|
||
IWDG_Feed();
|
||
}
|
||
OPM_MattressCalibration();
|
||
// printf("Key_Cal_Flag is %d TimeClock_Flag is %d\n", Key_Cal_Flag,TimeClock_Flag);
|
||
IWDG_Feed();
|
||
}
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* @function: three_avg
|
||
* @brief: 平均计算
|
||
* @param {unsigned short int} data
|
||
* @param {unsigned short int} max
|
||
* @param {unsigned short int} min
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
float three_avg(unsigned short int data, unsigned short int max, unsigned short int min)
|
||
{
|
||
float md_u, md_d, md;
|
||
md_u = data - min;
|
||
md_d = max - min;
|
||
md_d = md_d + 1;
|
||
md = (md_u / md_d) * 128;
|
||
return md;
|
||
}
|
||
/**
|
||
* @function:itoa_my
|
||
* @brief 整形转字符串
|
||
* @param {int} value
|
||
* @param {char} *string
|
||
* @param {int} radix
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
char *itoa_my(long value, char *string, int radix)
|
||
{
|
||
char zm[37] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||
char aa[100] = {0};
|
||
long sum = value;
|
||
char *cp = string;
|
||
int i = 0;
|
||
if (radix < 2 || radix > 36) // 增加了对错误的检测
|
||
{
|
||
return string;
|
||
}
|
||
if (value < 0)
|
||
{
|
||
return string;
|
||
}
|
||
while (sum > 0)
|
||
{
|
||
aa[i++] = zm[sum % radix];
|
||
sum /= radix;
|
||
}
|
||
for (int j = i - 1; j >= 0; j--)
|
||
{
|
||
*cp++ = aa[j];
|
||
}
|
||
*cp = '\0';
|
||
return string;
|
||
}
|
||
|
||
float32_t IIRStateF32_Breath[4 * numStages]; /* 状态缓存 */
|
||
float32_t IIRStateF32_Heart[4 * numStages]; /* 状态缓存 */
|
||
float32_t IIRStateF32_Heart_NoCut[4 * numStages]; /* 状态缓存 */
|
||
|
||
extern BandFitterConfig_t BandFitterConfig;
|
||
// static float32_t FitterOutputData[LENGTH_SAMPLES]; /* 滤波后的输出 */
|
||
/**
|
||
* @function: MyDSP_Init
|
||
* @brief 测试DSP库
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
int MyDSP_Init(void)
|
||
{
|
||
/* 实现IIR滤波,这里每次处理1个点 */
|
||
arm_biquad_cascade_df1_init_f32(&BreathPart, numStages, (float32_t *)&IIRCoeffs32BP_Breath,
|
||
(float32_t *)&IIRStateF32_Breath[0]);
|
||
/* 实现IIR滤波,这里每次处理1个点 */
|
||
arm_biquad_cascade_df1_init_f32(&HeartPart, numStages, (float32_t *)&IIRCoeffs32BP_Heart,
|
||
(float32_t *)&IIRStateF32_Heart[0]);
|
||
/* 实现IIR滤波,这里每次处理1个点 */
|
||
arm_biquad_cascade_df1_init_f32(&HeartPart_NoCut, numStages, (float32_t *)&IIRCoeffs32BP_Heart_NoCut,
|
||
(float32_t *)&IIRStateF32_Heart_NoCut[0]);
|
||
/* 实现IIR滤波,这里每次处理1个点 */
|
||
arm_biquad_cascade_df1_init_f32(&CheckPart, numStages, (float32_t *)&IIRCoeffs32BP_Breath,
|
||
(float32_t *)&IIRStateF32_Breath[0]);
|
||
return 0;
|
||
}
|
||
|
||
void MyFitter(void)
|
||
{
|
||
float32_t CopyHrBuffer[HEART_FITTER_LENGTH] = {0};
|
||
float32_t ResultBuffer[HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH] = {0};
|
||
if (FitterCollectDoneFlag_Heart)
|
||
{
|
||
FitterCount_Heart = HEART_FITTER_LENGTH - 50;
|
||
// 高频版本滤波
|
||
memset(ResultBuffer, 0, sizeof(ResultBuffer));
|
||
arm_iir_f32_bp_stream_Heart_Output(FitterOPMData_Heart, outPutFitterOPMData_Heart);
|
||
arm_iir_f32_bp_stream_Heart_Output_NoCut(outPutFitterOPMData_Heart, ResultBuffer);
|
||
arm_iir_f32_bp_stream_Heart_Output_NoCut(ResultBuffer, outPutFitterOPMData_Heart);
|
||
// 低频版本滤波
|
||
memset(ResultBuffer, 0, sizeof(ResultBuffer));
|
||
arm_iir_f32_bp_stream_Heart_Output(FitterOPMData_Heart, outPutFitterOPMData_Heart_Lo);
|
||
arm_iir_f32_bp_stream_Heart_Output_NoCut_2(outPutFitterOPMData_Heart_Lo, ResultBuffer);
|
||
arm_iir_f32_bp_stream_Heart_Output_NoCut_2(ResultBuffer, outPutFitterOPMData_Heart_Lo);
|
||
memcpy(FitterOPMData_Heart, FitterOPMData_Heart + 50,
|
||
sizeof(float32_t) * (LENGTH_SAMPLES_HEART - 50));
|
||
|
||
FitterCollectDoneFlag_Heart = 0;
|
||
}
|
||
if (FitterCollectDoneFlag_Breath)
|
||
{
|
||
FitterCount_Breath = LENGTH_SAMPLES_BREATH - 50;
|
||
arm_iir_f32_bp_stream_Breath_Output(FitterOPMData_Breath, outPutFitterOPMData_Breath);
|
||
memcpy(FitterOPMData_Breath, FitterOPMData_Breath + 50,
|
||
sizeof(float32_t) * (LENGTH_SAMPLES_BREATH - 50));
|
||
FitterCollectDoneFlag_Breath = 0;
|
||
memcpy(ResultBuffer, outPutFitterOPMData_Breath + HEART_IGNORE_LENGTH, sizeof(ResultBuffer));
|
||
Diff = MyToolFindMaxValue(ResultBuffer, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH) -
|
||
MyToolFindMinValue(ResultBuffer, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH);
|
||
Diff_Detail = MyToolFindMaxValue(ResultBuffer + 400, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH - 400) -
|
||
MyToolFindMinValue(ResultBuffer + 400, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH - 400);
|
||
// 如果小于0.5开始计算
|
||
if (Diff_Detail < 0.3f)
|
||
FFT_Count_State_Flag = FFT_Still_state;
|
||
else if (Diff_Detail < 1.2f)
|
||
FFT_Count_State_Flag = FFT_Mild_body_motion;
|
||
else if (Diff_Detail <= 4.0f)
|
||
FFT_Count_State_Flag = FFT_Medium_body_motion;
|
||
else if (Diff_Detail > 4.0f)
|
||
FFT_Count_State_Flag = FFT_Large_body_motion;
|
||
if (Diff < 0.5f)
|
||
{
|
||
FFT_Count_State_Flag = FFT_Still_state;
|
||
FFT_Calculate_State_Flag = FFT_Start_Calculate;
|
||
//---------------------------------------------
|
||
// if (Diff < 0.06f)
|
||
// // if (i_count_No_Breath == 5)
|
||
// FFT_Count_State_Flag = FFT_No_breath;
|
||
// else if (Diff < 0.5f)
|
||
// FFT_Count_State_Flag = FFT_Still_state;
|
||
}
|
||
else
|
||
{
|
||
FFT_Calculate_State_Flag = FFT_Stop_Calculate;
|
||
}
|
||
}
|
||
if (FitterCollectDoneFlag_CheckBed)
|
||
{
|
||
FitterCollectDoneFlag_CheckBed = 0;
|
||
breathInBedCheck(FitterOPMData_CheckBed);
|
||
// memcpy(FitterOPMData_CheckBed, FitterOPMData_CheckBed + 50,
|
||
// sizeof(float32_t) * (LENGTH_SAMPLES_IN_OFF_BED - 50));
|
||
FitterCount_CheckBed = LENGTH_SAMPLES_IN_OFF_BED - 50;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @function: PowerOn_OneMinuteBLEScan
|
||
* @brief: 上电一分钟蓝牙发送数据 可以被找到
|
||
* @return {*}
|
||
* @author: lzc
|
||
*/
|
||
void PowerOn_OneMinuteBLEScan(void)
|
||
{
|
||
// 上电复位才进去 其他情况不会进去
|
||
if (bootResult == PowerOn_Reset)
|
||
{
|
||
PowerOn_OneMinuteCount_Start = 1;
|
||
// 发送对应的指令进入1分钟蓝牙启动
|
||
USART1_SendData(myScan, 5); // 寻网指令
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
LED_B = !LED_B;
|
||
delay_ms(500);
|
||
}
|
||
USART1_SendData(Start_Cmd, 5); // 启动配网指令
|
||
delay_ms(500);
|
||
Key_Cal_Flag = 1;
|
||
PowerOn_OneMinuteCount = 0;
|
||
// 启动60秒倒计时
|
||
/*
|
||
while (PowerOn_OneMinuteCount < ONE_MINUTES_COUNT)
|
||
{
|
||
if (USART_DealFlag)
|
||
{
|
||
USART_DealFlag = 0;
|
||
wifi_cmd_exe(); // 通讯交流
|
||
}
|
||
// 如果配网开始则count清除
|
||
if (PowerOn_StartConfigFlg)
|
||
PowerOn_OneMinuteCount = 0;
|
||
if (Key_Cal_Flag == 0)
|
||
break;
|
||
LED_B = !LED_B;
|
||
delay_ms(500);
|
||
}*/
|
||
}
|
||
}
|