/*
*********************************************************************************************************
*                                       IAR Development Kits
*                                              on the
*
*                                    M451
*
* Filename      : spi_adc.c
* Version       : V1.00
* Programmer(s) : Qian Xianghong
*********************************************************************************************************
*/

#include  "includes.h"

// 是否SMARC的流量计
//#define _SMARC_FLOWMETER_

//#define RS485_EN()  LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_2);
//#define RS485_DIS() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_2);

// 是否热式流量计
//#define _THERMAL_FLOWMETER_

// 是否希尔思S401流量计
//#define _S401_FLOWMETER_

// 默认为斯达易思流量计

// 读取超时计数
volatile uint32_t modbus_outTick = 0;

const uint8_t  VACUUM_ID[] = {1, 2};	// 真空计通信地址
#define VACUUM_CMD	4					// 真空计读取命令
#define VACUUM_ADDR	608					// 真空计起始寄存器地址
#define VACUUM_LEN	8					// 真空计读取寄存器个数

const uint8_t LEAK_ID = 3;				// 泄露报警控制器通信地址
#define LEAK_CMD	3					// 泄露报警控制器读取命令
#define LEAK_ADDR	0x08				// 泄露报警控制器起始寄存器地址
#define LEAK_LEN	8					// 泄露报警控制器读取寄存器个数

#if defined(_SMARC_FLOWMETER_)
	const uint8_t FLOW_ID = 1;				// SMARC流量计通信地址
	#define FLOW_CMD	3					// 流量计读取命令
	#define FLOW_ADDR	4068				// 流量计起始寄存器地址
	#define FLOW_LEN	12					// 流量计读取寄存器个数
#elif defined(_THERMAL_FLOWMETER_)
	const uint8_t FLOW_ID = 4;				// 热式流量计通信地址
	#define FLOW_CMD	3					// 流量计读取命令
	#define FLOW_ADDR	7					// 流量计起始寄存器地址
	#define FLOW_LEN	6					// 流量计读取寄存器个数
#elif defined(_S401_FLOWMETER_)
	const uint8_t FLOW_ID = 4;				// S401流量计通信地址
	#define FLOW_CMD	3					// 流量计读取命令
	#define FLOW_ADDR	6					// 流量计起始寄存器地址
	#define FLOW_LEN	4					// 流量计读取寄存器个数
#else
	const uint8_t FLOW_ID = 4;				// 斯达易思流量计通信地址
	#define FLOW_CMD	3					// 流量计读取命令
	#define FLOW_ADDR	0					// 流量计起始寄存器地址
	#define FLOW_LEN	15					// 流量计读取寄存器个数
#endif

const uint8_t LEAK_O2_ID = 1;				// O2浓度传感器通信地址
#define LEAK_O2_SOF	0xFF					// O2浓度传感器起始符
#define LEAK_O2_CMD	0x86					// O2浓度传感器读取命令

#pragma pack(push, 1)
typedef struct
{
	uint8_t id;
	uint8_t cmd;
	uint16_t addr;
	uint16_t len;
	uint16_t crc;
} modbus_send_t;

typedef struct
{
	struct
	{
		uint8_t id;
		uint8_t cmd;
		uint8_t len;
	} header;
	union{
		// 真空计数据
		struct
		{
			uint16_t staVacuum;		// 状态
			uint16_t lifeVacuum;	// 使用年限
			uint32_t vacuum;		// 真空度，float型，先用整形交换字节序
			uint32_t rateVacuum;	// 漏放气速率，float型，先用整形交换字节序
			uint32_t tempr;			// 温度，float型，先用整形交换字节序
		} vacuum;
		
		// 泄漏报警器数据
		struct
		{
			unsigned unit :	 4;			// 气体单位
			unsigned ratio : 4;			// 数值单位
			uint8_t type;				// 气体类型
			uint16_t	A1;				// A1报警值
			uint16_t	A2;	
			uint16_t	A3;	
			uint16_t	A4;	
			uint16_t	range;			// 量程
			uint16_t	concentrations;	// 浓度
			uint8_t	staLeak;			// 传感器状态
			unsigned : 8;
		} leak;

		// 流量计数据
		struct
		{
			uint32_t nM3_int;	// 标况累积总量整数部分
			uint16_t nM3_frac;	// 标况累积总量小数部分（放大10000倍）
			uint32_t M3_int;	// 工况累积总量整数部分
			uint16_t M3_frac;	// 工况累积总量小数部分（放大10000倍）
			uint32_t nM3_h;		// 标况流量（nM3/h，放大100倍）
			uint32_t M3_h;		// 工况流量（M3/h，放大100倍）
			int16_t	tempr;		// 温度（℃，放大10倍，第一位正负位(即数值大于0x7FFF为负)）
			uint32_t pressure;	// 压力(绝压）（KPa, 放大10倍)
			uint16_t err1;		// 异常标志位1
								//温度错误标志位: 0x0003
								//压力错误标志位: 0x0030
								//电池电量低标志位: 0x0300
								//工况流量超最大工况流量: 0x3000
								//无异常：0x0000
			uint16_t err2;		// 异常标志位2
								//存储器异常标志位: 0x0003
								//无异常：0x0000
		} flow;
		
		// SMARC流量计数据
		struct
		{
			uint32_t nM3_h;		// 标况流量: float, 方便颠倒顺序，用uint32_t型接收
			uint32_t M3_h;		// 工况流量: float, 方便颠倒顺序，用uint32_t型接收
			uint32_t tempr;		// 温度: float, 方便颠倒顺序，用uint32_t型接收
			uint32_t pressure;	// 压力: float, 方便颠倒顺序，用uint32_t型接收
			uint16_t warnFlag;	// 报警标志
			uint8_t nM3_BCD[6];	// 标况体积
		} flow_SMARC;
		
		// 热式流量计数据
		struct
		{
			uint32_t nM3_h;		// 标况流量: float, 方便颠倒顺序，用uint32_t型接收
			uint32_t nM3x100;	// 累计流量100以上，uint32_t
			uint32_t nM3r100;	// 累计流量100以下，float, 方便颠倒顺序，用uint32_t型接收
		} flow_Thermal;

		// S401流量计数据
		struct
		{
			uint32_t nM3_h;		// 流量: 分辨率0.1, uint32_t
			uint32_t nM3;		// 累积量，分辨率1，uint32_t
		} flow_S401;
	};
	uint16_t crc;	// 占位置
} modbus_recv_t;

typedef union
{
	modbus_send_t send;
	modbus_recv_t recv;
	uint8_t buff[sizeof(modbus_recv_t)];
} modbus_comm_t;

// O2浓度传感器读取命令
typedef struct
{
	uint8_t		addr;
	uint8_t		cmd;
	uint8_t		reserved[5];
} leak_o2_send_t;

// O2浓度传感器返回结果
typedef struct
{
	uint8_t		cmd;
	uint16_t	concentrations;	// 浓度
	uint8_t		reserved[4];
} leak_o2_recv_t;

// O2浓度传感器通信帧
typedef union
{
	struct
	{
		uint8_t		sof;
		union
		{
			leak_o2_send_t send;
			leak_o2_recv_t recv;
		};
		uint8_t		cs;
	};
	uint8_t		buff[9];
} leak_o2_comm_t;

// DYQ-7通信协议的泄露报警器、电容采集头、压力采集头等
#define RS_MIN_FRAME_LEN	(15)
#define RS_MAX_FRAME_LEN	(39)
#define RS_MIN_DATA_LEN		(0)
#define RS_MAX_DATA_LEN		(RS_MAX_FRAME_LEN - RS_MIN_FRAME_LEN)

#define RS_FRAME_SOF		(0x1B)	// 标识一个帧的开始

#define RS_DIR_M2S			(0)		// Master->Slave
#define RS_DIR_S2M			(1)		// Slave->Master

#define RS_PROTOCOL_VER_1	(1)

// 请求命令
#define RS_CMD_READ_DATA	(5)		// 读采集数据
// 处理结果
#define RS_RESULT_SUCC		(0)		// 处理成功
#define RS_RESULT_FAIL		(-1)	// 处理失败

// 通信协议版本
const uint8_t RS_PROTOCOL_VER = RS_PROTOCOL_VER_1;	

// 485泄露报警器请求数据
typedef struct	// size = RS_MAX_FRAME_LEN
{
	uint8_t		sof;				// RS_FRMAE_SOF
	uint8_t		len;				// bytes from sof to crc（RS_MIN_FRAME_LEN~RS_MAX_FRAME_LEN）
	uint8_t		destAddr;
	uint8_t		srcAddr;
	uint8_t		srcPSN[6];
	uint8_t		dir;
	uint8_t		protocol_ver;		// RS_PROTOCOL
	uint8_t		cmd;
	uint8_t		data[RS_MAX_DATA_LEN];
	uint16_t	crc;				// 占位置，实际crc可能更靠前
} rs_frame_t;

// 485泄露报警器应答数据
typedef struct // size = 20
{
	uint16_t	adc;			// 采集ADC值
	float		measureValue;	// 采集值
	uint8_t		measureState;	// 测量值状态
	uint16_t	levelHeight;	// 液位高度
	uint16_t	volume;			// 剩余液量
	uint16_t	volumeMax;		// 有效容积
	uint16_t	quality;		// 剩余重量
	uint8_t		warnState;		// 报警状态
	uint16_t	envAdc;			// 环境温度ADC
	int16_t		envTempr;		// 环境温度
} rs_data_t;

#pragma pack(pop)

rs_frame_t RS_TranFrame;

modbus_comm_t modbus;
uint8_t modbus_idx = 0;
uint8_t vaccum_idx = 0;
data_sample_t *modbus_sample;

leak_o2_comm_t leakO2;

// 将十进制转换成BCD
void dec2bcd(uint32_t dec, uint8_t *bcd, uint8_t len)
{
	char fmt[10], str[20];
	uint8_t i;
	
	// 生成格式串（如：%010u）
	sprintf(fmt, "%%0%du", len * 2);
	// 将dec值转换成前面补0的字符串（如：000000123456)
	sprintf(str, fmt, dec);
	// 转换
	for(i = 0; i < strlen(str); i += 2)
	{
		bcd[i / 2] = ((str[i] - '0') << 4) | (str[i + 1] - '0');
	}
}

// 计算O2浓度传感器校验和
uint8_t leak_o2_calcuCS(uint8_t *data, uint16_t len)
{
	uint8_t cs = 0;
	
	while(len--)
		cs += *data++;
	
	return (~cs) + 1;
}

// 初始化O2浓度通信帧
void leak_o2_init_frame(leak_o2_comm_t *frame)
{
	memset(frame, 0, sizeof(leak_o2_comm_t));
	frame->sof = LEAK_O2_SOF;
}

// 本函数由规管设计者（Zhang Jm）提供，用于对读出的真空值进行修正
// 本函数只适用于规管量程为-2（0.01Pa）的情况
/**
  * @brief  Function of Fuzzy Processing.
  * @param  value: vacuun value.
  * @retval None.
  */
float Mode1_Fuzzy_Process(float value)
{
  static const float beta1 = -0.2539755;
  static const float beta2 = 13.15659; 
  
  static const float theta = 0.011666666;
  static const float eta = 0.9999999;
  static const float kappa = 0.006666666;  
  float temp1, temp2, result, lower_t = 0.0101;  
  
  if((value < 0.09f) && (value > 0.04f))
  {  
    temp1 = -beta1 * value;
    temp2 = beta2 * pow(value, 2.0); 
    return(1 - exp(temp1 - temp2));
  }
  else if((value <= 0.04f) && (value > 0.005f))
  {/*y = theta*x^eta/(kappa^eta+x^eta)*/
    temp1 = pow(value, eta);
    temp2 = pow(kappa, eta) + temp1;
    result = theta * temp1 / temp2;
    if(result < lower_t)
      return(lower_t);
    else
      return(result); 
  }
  else
    return(value);
}

void Modbus_Read(USART_Handle *huart)
{
	uint8_t i;
	uint32_t reversed;
	int32_t i_reversed;
	float f;
	uint8_t c = (uint8_t) huart->Instance->RDR;

    /* Receive data */
	if(modbus_idx < sizeof(modbus_recv_t))
	{
		modbus.buff[modbus_idx++] = c;
		
		if(modbus.recv.header.id == LEAK_ID && modbus.recv.header.cmd == LEAK_CMD 
				&& modbus.recv.header.len == sizeof(modbus.recv.leak) 
				&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.leak) + sizeof(modbus.recv.crc)
				&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
		{
			/* Print the received data */
//			printf("Received data:\n");
//			for(i = 0; i < modbus_idx; i++)
//			{
//				printf("%02X ", modbus.buff[i]);
//			}
//			printf("\n");

			// 探测器状态
			modbus_sample->leak.staLeak = modbus.recv.leak.staLeak;
			// 浓度
			modbus_sample->leak.concentrations = ntohs(modbus.recv.leak.concentrations);
			if(modbus.recv.leak.ratio == 1)
				modbus_sample->leak.concentrations /= 10;
			else if(modbus.recv.leak.ratio == 2)
				modbus_sample->leak.concentrations /= 100;
			else if(modbus.recv.leak.ratio == 3)
				modbus_sample->leak.concentrations /= 1000;
			
			// 退出超时等待
			modbus_outTick = GetDelayTick(0);
		}
		else if(modbus.recv.header.id == VACUUM_ID[vaccum_idx] && modbus.recv.header.cmd == VACUUM_CMD 
				&& modbus.recv.header.len == sizeof(modbus.recv.vacuum)
				&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.vacuum) + sizeof(modbus.recv.crc)
				&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
		{
			/* Print the received data */
			printf("Received data:\n");
			for(i = 0; i < modbus_idx; i++)
			{
				printf("%02X ", modbus.buff[i]);
			}
			printf("\n");

			// 传感器状态
			modbus_sample->vacuum[vaccum_idx].staVacuum = ntohs(modbus.recv.vacuum.staVacuum);
			// 使用年限
			modbus_sample->vacuum[vaccum_idx].lifeVacuum = ntohs(modbus.recv.vacuum.lifeVacuum);
			// 真空度
			reversed = ntohl(modbus.recv.vacuum.vacuum);
			memmove(&modbus_sample->vacuum[vaccum_idx].vacuum, &reversed, sizeof(modbus_sample->vacuum[vaccum_idx].vacuum));
			// 调用真空值修正函数（2021.10.28）
			modbus_sample->vacuum[vaccum_idx].vacuum = Mode1_Fuzzy_Process(modbus_sample->vacuum[vaccum_idx].vacuum);
			// 漏放气速率
			reversed = ntohl(modbus.recv.vacuum.rateVacuum);
			memmove(&modbus_sample->vacuum[vaccum_idx].rateVacuum, &reversed, sizeof(modbus_sample->vacuum[vaccum_idx].rateVacuum));
			// 温度
			reversed = ntohl(modbus.recv.vacuum.tempr);
			memmove(&modbus_sample->vacuum[vaccum_idx].tempr, &reversed, sizeof(modbus_sample->vacuum[vaccum_idx].tempr));

			// 退出超时等待
			modbus_outTick = GetDelayTick(0);
		}
#if defined(_SMARC_FLOWMETER_)
		else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD 
				&& modbus.recv.header.len == sizeof(modbus.recv.flow_SMARC)
				&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow_SMARC) + sizeof(modbus.recv.crc)
				&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
		{
//			/* Print the received data */
//			printf("Received data:\n");
//			for(i = 0; i < modbus_idx; i++)
//			{
//				printf("%02X ", modbus.buff[i]);
//			}
//			printf("\n");

			// 标况体积总量
			// 整数部分
			reversed = 0;
			for(i = 0; i < 9; i++)
			{
				reversed *= 10;
				if(i % 2 == 0)
					reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] >> 4);
				else
					reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] & 0x0F);
			}
			dec2bcd(reversed, modbus_sample->flow.nM3, 5);
			// 小数部分
			reversed = 0;
			for(i = 9; i < 11; i++)
			{
				reversed *= 10;
				if(i % 2 == 0)
					reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] >> 4);
				else
					reversed += (modbus.recv.flow_SMARC.nM3_BCD[i / 2] & 0x0F);
			}
			dec2bcd(reversed, modbus_sample->flow.nM3 + 5, 1);
			// 标况流量
			reversed = ntohl(modbus.recv.flow_SMARC.nM3_h);
			memmove(&f, &reversed, 4);
			reversed = f * 100;
			dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
			// 工况流量
			reversed = ntohl(modbus.recv.flow_SMARC.M3_h);
			memmove(&f, &reversed, 4);
			reversed = f * 100;
			dec2bcd(reversed, modbus_sample->flow.M3_h, 4);			
			// 温度
			reversed = ntohl(modbus.recv.flow_SMARC.tempr);
			memmove(&f, &reversed, 4);
			i_reversed = f * 100;
			if(i_reversed >= 0)
				dec2bcd(i_reversed, modbus_sample->flow.tempr, 4);			
			else
			{
				dec2bcd(-i_reversed, modbus_sample->flow.tempr, 4);
				modbus_sample->flow.tempr[0] = 0x80;				
			}			
			// 压力
			reversed = ntohl(modbus.recv.flow_SMARC.pressure);
			memmove(&f, &reversed, 4);
			reversed = f * 100;
			dec2bcd(reversed, modbus_sample->flow.pressure, 4);			
			
			/* Print the converted bcd data */
			printf("Flowmeter BCD data:\n");
			for(i = 0; i < sizeof(modbus_sample->flow); i++)
			{
				printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
			}
			printf("\n");
			
			// 退出超时等待
			modbus_outTick = GetDelayTick(0);
		}
#elif defined(_THERMAL_FLOWMETER_)
		else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD 
				&& modbus.recv.header.len == sizeof(modbus.recv.flow_Thermal)
				&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow_Thermal) + sizeof(modbus.recv.crc)
				&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
		{
//			/* Print the received data */
//			printf("Received data:\n");
//			for(i = 0; i < modbus_idx; i++)
//			{
//				printf("%02X ", modbus.buff[i]);
//			}
//			printf("\n");

			// 标况流量
			reversed = ntohl(modbus.recv.flow_Thermal.nM3_h);
			memmove(&f, &reversed, 4);
			reversed = f * 100;
			dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
			// 工况流量（协议无，填标况流量）
			dec2bcd(reversed, modbus_sample->flow.M3_h, 4);
			// 温度（协议无，填0）
			dec2bcd(0, modbus_sample->flow.tempr, 4);			
			// 压力（协议无，填0）
			dec2bcd(0, modbus_sample->flow.pressure, 4);			

			// 标况体积总量
			// 100以上部分
			reversed = ntohl(modbus.recv.flow_Thermal.nM3x100);
			dec2bcd(reversed, modbus_sample->flow.nM3, 4);
			// 100以下部分
			reversed = ntohl(modbus.recv.flow_Thermal.nM3r100);
			memmove(&f, &reversed, 4);
			reversed = f * 100;
			dec2bcd(reversed, modbus_sample->flow.nM3 + 4, 2);
			
			/* Print the converted bcd data */
			printf("Flowmeter BCD data:\n");
			for(i = 0; i < sizeof(modbus_sample->flow); i++)
			{
				printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
			}
			printf("\n");
			
			// 退出超时等待
			modbus_outTick = GetDelayTick(0);
		}
#elif defined(_S401_FLOWMETER_)
		else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD 
				&& modbus.recv.header.len == sizeof(modbus.recv.flow_S401)
				&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow_S401) + sizeof(modbus.recv.crc)
				&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
		{
//			/* Print the received data */
//			printf("Received data:\n");
//			for(i = 0; i < modbus_idx; i++)
//			{
//				printf("%02X ", modbus.buff[i]);
//			}
//			printf("\n");

			// 流量
			reversed = ntohl(modbus.recv.flow_S401.nM3_h) * 10; // x10->x100
			dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);
			// 工况流量（协议无，填标况流量）
			dec2bcd(reversed, modbus_sample->flow.M3_h, 4);
			// 温度（协议无，填0）
			dec2bcd(0, modbus_sample->flow.tempr, 4);			
			// 压力（协议无，填0）
			dec2bcd(0, modbus_sample->flow.pressure, 4);			

			// 累积量
			reversed = ntohl(modbus.recv.flow_S401.nM3) * 100;	// x1->x100
			dec2bcd(reversed, modbus_sample->flow.nM3, 6);
			
			/* Print the converted bcd data */
			printf("Flowmeter BCD data:\n");
			for(i = 0; i < sizeof(modbus_sample->flow); i++)
			{
				printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
			}
			printf("\n");
			
			// 退出超时等待
			modbus_outTick = GetDelayTick(0);
		}
#else
		else if(modbus.recv.header.id == FLOW_ID && modbus.recv.header.cmd == FLOW_CMD 
				&& modbus.recv.header.len == sizeof(modbus.recv.flow)
				&& modbus_idx == sizeof(modbus.recv.header) + sizeof(modbus.recv.flow) + sizeof(modbus.recv.crc)
				&& MODBUS_RTU_CRC16(modbus.buff, modbus_idx) == 0)
		{
//			/* Print the received data */
//			printf("Received data:\n");
//			for(i = 0; i < modbus_idx; i++)
//			{
//				printf("%02X ", modbus.buff[i]);
//			}
//			printf("\n");

			// 标况体积总量（BCD码，放大100倍）
			if((htons(modbus.recv.flow.err2) & 0x000F) == 0x0003)			// 是否存储器错误？
				dec2bcd(0, modbus_sample->flow.nM3, 6);
			else
			{
				reversed = ntohl(modbus.recv.flow.nM3_int);			// 整数部分
				dec2bcd(reversed, modbus_sample->flow.nM3, 5);
				reversed = ntohs(modbus.recv.flow.nM3_frac);		// 小数部分
				reversed /= 100;									// 放大10000倍->放大100倍
				dec2bcd(reversed, modbus_sample->flow.nM3 + 5, 1);
			}
			// 标况流量（BCD码，放大100倍）
			reversed = ntohl(modbus.recv.flow.nM3_h);
			dec2bcd(reversed, modbus_sample->flow.nM3_h, 4);			
			// 工况流量（BCD码，放大100倍）
			reversed = ntohl(modbus.recv.flow.M3_h);
			dec2bcd(reversed, modbus_sample->flow.M3_h, 4);			
			// 温度（BCD码，放大100倍，第一字节为符号： 80H 为负，00H 为正）
			if((htons(modbus.recv.flow.err1) & 0x000F) == 0x0003) 		// 是否温度传感器错误？
				i_reversed = 0;
			else
			{
				i_reversed = ntohs(modbus.recv.flow.tempr);
				i_reversed *= 10;								// 放大10倍->放大100倍
			}
			if(i_reversed >= 0)
				dec2bcd(i_reversed, modbus_sample->flow.tempr, 4);			
			else
			{
				dec2bcd(-i_reversed, modbus_sample->flow.tempr, 4);
				modbus_sample->flow.tempr[0] = 0x80;				
			}			
			// 压力（BCD码，放大100倍）
			if((htons(modbus.recv.flow.err1) & 0x00F0) == 0x0030) 		// 是否压力传感器错误？
				reversed = 0;
			else
			{
				reversed = ntohl(modbus.recv.flow.pressure);
				reversed *= 10;									// 放大10倍->放大100倍
			}
			dec2bcd(reversed, modbus_sample->flow.pressure, 4);			

			/* Print the converted bcd data */
			printf("Flowmeter BCD data:\n");
			for(i = 0; i < sizeof(modbus_sample->flow); i++)
			{
				printf("%02X ", *(((uint8_t *) &modbus_sample->flow) + i));
			}
			printf("\n");
			
			// 退出超时等待
			modbus_outTick = GetDelayTick(0);
		}
#endif
	}
}

void LeakO2_Read(USART_Handle *huart)
{
	uint8_t i;
	uint8_t c = (uint8_t) huart->Instance->RDR;
	uint16_t concentrations = 0;
	
    /* Receive data */
	if(modbus_idx < sizeof(leak_o2_comm_t))
	{
		leakO2.buff[modbus_idx++] = c;
		
		if(modbus_idx == sizeof(leak_o2_comm_t)
				&& leakO2.sof == LEAK_O2_SOF && leakO2.recv.cmd == LEAK_O2_CMD
				&& leak_o2_calcuCS(leakO2.buff + 1, sizeof(leak_o2_comm_t) - 2) == leakO2.cs)
		{
			/* Print the received data */
			printf("Received data:\n");
			for(i = 0; i < modbus_idx; i++)
			{
				printf("%02X ", leakO2.buff[i]);
			}
			printf("\n");

#if 1			
			// 浓度: 分辨率0.1%
			concentrations = ntohs(leakO2.recv.concentrations);	
#else			
			// 测试报警输出
			concentrations = 240;
#endif
			// 浓度降到21.5%，重启泄露报警
			if(concentrations <= 215)
				Leak_Alarm_Enabled = 1;			
			// 报警阀值：浓度达到23%
			if(concentrations >= 230)
			{
				modbus_sample->leak.staLeak = LEAK_STATUS_A2_ALARM;
				modbus_sample->leak.concentrations = 1;
			}
			else
			{
				modbus_sample->leak.staLeak = LEAK_STATUS_OK;
				modbus_sample->leak.concentrations = 0;
			}
			// 退出超时等待
			modbus_outTick = GetDelayTick(0);
		}
	}
}

// 物理层校验
uint8_t rs_phy_valid(rs_frame_t *frame)
{
	if(frame->protocol_ver != RS_PROTOCOL_VER || frame->dir != RS_DIR_S2M)
	{
		// 物理层校验失败
		return 0;
	}
	return 1;
}

// mac层校验
uint8_t rs_mac_valid(rs_frame_t *frame, uint8_t dir)
{
	if(frame->destAddr != dcBuff.configBottle.addr)
	{
		// mac层校验失败
		return 0;
	}
	return 1;
}

// 初始化帧
void rs_initial_frame(rs_frame_t *frame)
{
	memset((uint8_t *) frame, 0, sizeof(rs_frame_t));
	frame->len = RS_MIN_FRAME_LEN;
}

// 追加负载数据
uint8_t rs_append_data(rs_frame_t *frame, uint8_t *data, uint8_t len)
{
	if(frame->len < RS_MIN_FRAME_LEN || frame->len + len > RS_MAX_FRAME_LEN)
		return 0;
	
	if(len > 0)
		memmove(frame->data + (frame->len - RS_MIN_FRAME_LEN), data, len);
	frame->len += len;
	return 1;
}

// 重新寻找SOF
void RS_SearchSOF(uint8_t *buf, uint16_t fromPos, uint8_t *len)
{
	uint8_t i;
	
	for(i = fromPos; i < *len && buf[i] != RS_FRAME_SOF; i++)
	{
	}
	
	*len -= i;
	memmove(buf, buf + i, *len);
}

// 模块任务主体：处理射频接收数据
void RS_ParseFrame(USART_Handle *huart)
{
	uint8_t *RS_ModuleData = (uint8_t *) &RS_TranFrame;
	uint16_t i;
	uint8_t frameOk, frameErr;
	uint8_t c = (uint8_t) huart->Instance->RDR;

	uint32_t mask;
	rs_data_t *rsData = (rs_data_t *) (RS_TranFrame.data + sizeof(mask));
	
	if(modbus_idx == 0 && c != RS_FRAME_SOF)
		return;
	
	RS_ModuleData[modbus_idx++] = c;

	do
	{
		frameErr = (modbus_idx >= 2 &&
			(RS_ModuleData[1] < RS_MIN_FRAME_LEN || RS_ModuleData[1] > RS_MAX_FRAME_LEN));
		if(frameErr)
		{
			// 从1开始寻找SOF
			RS_SearchSOF(RS_ModuleData, 1, &modbus_idx);
		}

		frameOk = (modbus_idx >= 2 && RS_ModuleData[1] >= RS_MIN_FRAME_LEN && RS_ModuleData[1] <= RS_MAX_FRAME_LEN
			&& modbus_idx >= RS_ModuleData[1]);
		if(frameOk)
		{
			if(MODBUS_RTU_CRC16(RS_ModuleData, RS_ModuleData[1]) == 0)
			{
				if(rs_phy_valid(&RS_TranFrame) && rs_mac_valid(&RS_TranFrame, RS_DIR_M2S))
				{
					// 收到一帧
					printf("\r\nRS recv %d bytes:\r\n", RS_ModuleData[1]);
					for(i = 0; i < RS_ModuleData[1]; i++)
						printf(" %02X", RS_ModuleData[i]);
					printf("\r\n");
					
					// 处理这一帧
					memmove(&mask, RS_TranFrame.data, 4);
					mask = ntohl(mask);
					if(RS_TranFrame.srcAddr == 0x51)
					{
						// 泄漏报警数据
						if((mask & 0x61000000) == 0x61000000)	// 检查数据掩码
						{
							modbus_sample->leak.typeLeak = LEAK_TYPE_MODBUS;
							if(rsData->measureState > 1) 
								modbus_sample->leak.staLeak = LEAK_STATUS_FAULT;
							else if(rsData->warnState == 4)
								modbus_sample->leak.staLeak = LEAK_STATUS_A2_ALARM;
							else
								modbus_sample->leak.staLeak = LEAK_STATUS_OK;
								
							if(rsData->warnState < 3)
								modbus_sample->leak.concentrations = 0;
							else
							{
								memmove(&mask, &rsData->measureValue, 4);
								mask = ntohl(mask);
								memmove(&rsData->measureValue, &mask, 4);
								modbus_sample->leak.concentrations = rsData->measureValue / 1000;
							}
						}
					}
					else if(RS_TranFrame.srcAddr == 0x31)
					{
						// 差压/电容数据，在采集模块里计算
						if((mask & 0xE0000000) == 0xE0000000)	// 检查数据掩码
						{
							if(dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
							{
								// 电容测量：只要电容值，不管归一化状态
								modbus_sample->staDPress.status = SENSOR_STATUS_NORMAL;
							}
							else
								modbus_sample->staDPress.status = rsData->measureState;
							modbus_sample->adDPress = ntohs(rsData->adc);
							modbus_sample->diff = ntohf(rsData->measureValue);
							if(dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
							{
								// 电容只保留1位小数
								modbus_sample->diff = ((int16_t) (modbus_sample->diff * 10)) * 0.1;
							}
						}
					}
					else if(RS_TranFrame.srcAddr == 0x41)
					{
						// 压力数据，在采集模块里计算
						if((mask & 0xE0000000) == 0xE0000000)	// 检查数据掩码
						{
							modbus_sample->staPress.status = rsData->measureState;
							modbus_sample->adPress = ntohs(rsData->adc);
							modbus_sample->pressure = ntohf(rsData->measureValue);
						}
					}
					// 退出超时等待
					modbus_outTick = GetDelayTick(0);
				}
				
				// 继续寻找下一帧
				modbus_idx -= RS_ModuleData[1];
				memmove(RS_ModuleData, RS_ModuleData + RS_ModuleData[1], modbus_idx);
				// 从0开始寻找SOF
				RS_SearchSOF(RS_ModuleData, 0, &modbus_idx);
			}
			else
			{
				// 从1开始寻找SOF
				RS_SearchSOF(RS_ModuleData, 1, &modbus_idx);
			}
		}
	} while(frameOk || frameErr);
}

void Sensor_Init()
{
	LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
	/**LPUART1 GPIO Configuration  
	PA2   ------> LPUART1_TX
	PA3   ------> LPUART1_RX
	PB1   ------> LPUART1_DE 
	*/
	GPIO_InitStruct.Pin = LL_GPIO_PIN_2|LL_GPIO_PIN_3;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);

	GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
	LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	//RS485_DIS();
}

void Sensor_Open(uint32_t baudrate)
{	
  LL_LPUART_InitTypeDef LPUART_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
  
  NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
  NVIC_EnableIRQ(LPUART1_IRQn);

  LPUART_InitStruct.BaudRate = baudrate;
  LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
  LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
  LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
  LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
  LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
  LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
  LL_LPUART_EnableDEMode(LPUART1);
  LL_LPUART_SetDESignalPolarity(LPUART1, LL_LPUART_DE_POLARITY_HIGH);
  LL_LPUART_SetDEAssertionTime(LPUART1, 0);
  LL_LPUART_SetDEDeassertionTime(LPUART1, 0);

  SET_BIT(LPUART1->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
  LL_LPUART_Enable(LPUART1);
}

// 切换串口至Modubs通信模式
void Modbus_Open()
{	
	LL_LPUART_Disable(hlpuart1.Instance);
	// 设置中断回调函数
	hlpuart1.RxISR = Modbus_Read;
	// 修改波特率
	Sensor_Open(9600);
}

// 切换到O2浓度传感器通信模式
void LeakO2_Open()
{
	LL_LPUART_Disable(hlpuart1.Instance);
	// 设置中断回调函数
	hlpuart1.RxISR = LeakO2_Read;
	// 修改波特率
	Sensor_Open(9600);
}

// 切换串口至DYQ-7通信模式
void Modbus_Close()
{
	LL_LPUART_Disable(hlpuart1.Instance);
	// 设置中断回调函数
	hlpuart1.RxISR = RS_ParseFrame;
	// 修改波特率
	Sensor_Open(19200);
}

static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
{
//	RS485_EN();
//	delay_us(1);
	// 设置超时和结果
	modbus_outTick = GetDelayTick(500);
	UART_Transmit_IT(&hlpuart1, pu8TxBuf, u32WriteBytes);
//	delay_ms(9);	// 至少8ms，保险起见9ms
//	RS485_DIS();
}

// 物理层发送
uint8_t  rs_uart_send(rs_frame_t *frame, uint8_t destAddr, uint8_t dir)
{
	uint16_t crc;
	uint8_t i;

	// 填写固定字段
	frame->sof = RS_FRAME_SOF;
	frame->destAddr = destAddr;
	frame->srcAddr = dcBuff.configBottle.addr;
	memmove(frame->srcPSN, dcBuff.configBottle.PSN, 6);
	frame->dir = dir;
	frame->protocol_ver = RS_PROTOCOL_VER;

	crc = MODBUS_RTU_CRC16((uint8_t *) frame, frame->len - 2);
	((uint8_t *) frame)[frame->len - 2] = crc >> 8;
	((uint8_t *) frame)[frame->len - 1] = crc & 0xFF;
	
	printf("\r\nRS send %d bytes:\r\n", frame->len);
	for(i = 0; i < frame->len; i++)
		printf(" %02X", ((uint8_t *) frame)[i]);
	printf("\r\n");
	
	RS485_SendDataByte((uint8_t *) frame, frame->len);
	
	return 1;
}

// 读取真空计数据
void Sensor_ReadVacuum(uint8_t sensorIdx, data_sample_t *sample)
{
	Modbus_Open();

	// 默认读取失败
	sample->vacuum[sensorIdx].staVacuum = VACUUM_STATUS_COMM_FAULT;
	sample->vacuum[sensorIdx].lifeVacuum = 0;
	sample->vacuum[sensorIdx].vacuum = 0;
	sample->vacuum[sensorIdx].rateVacuum = 0;
	
	// 初始化
	modbus_sample = sample;
	vaccum_idx = sensorIdx;
	modbus_idx = 0;
	
	// 发送
	modbus.send.id = VACUUM_ID[sensorIdx];
	modbus.send.cmd = VACUUM_CMD;
	modbus.send.addr = htons(VACUUM_ADDR - 1);
	modbus.send.len = htons(VACUUM_LEN);
	modbus.send.crc = htons(MODBUS_RTU_CRC16(modbus.buff, sizeof(modbus_send_t) - 2));
	RS485_SendDataByte(modbus.buff, sizeof(modbus_send_t));
	
	// 等待中断处理
}

// 读取流量计数据
void Sensor_ReadFlow(data_sample_t *sample)
{
	Modbus_Open();

	// 默认读取失败
	memset(&sample->flow, 0, sizeof(sample->flow));

	// 初始化
	modbus_sample = sample;
	modbus_idx = 0;

	// 发送
	modbus.send.id = FLOW_ID;
	modbus.send.cmd = FLOW_CMD;
	modbus.send.addr = htons(FLOW_ADDR);
	modbus.send.len = htons(FLOW_LEN);
	modbus.send.crc = htons(MODBUS_RTU_CRC16(modbus.buff, sizeof(modbus_send_t) - 2));
	RS485_SendDataByte(modbus.buff, sizeof(modbus_send_t));
	
	// 等待中断处理
}

// 读取氧传感器数据
void Sensor_ReadLeakO2(data_sample_t *sample)
{
	uint8_t reSample = 0;

	LeakO2_Open();

	// 默认读取失败
	sample->leak.staLeak = LEAK_STATUS_COMM_FAULT;
	sample->leak.concentrations = 0;
	// 传感器类型
	sample->leak.typeLeak = LEAK_TYPE_SWITCH | LEAK_TYPE_CURRENT | LEAK_TYPE_MODBUS;
	
	// 初始化
	modbus_sample = sample;
	modbus_idx = 0;
	
	// 发送
	leak_o2_init_frame(&leakO2);
	leakO2.send.addr = LEAK_O2_ID;
	leakO2.send.cmd = LEAK_O2_CMD;
	leakO2.cs = leak_o2_calcuCS(leakO2.buff + 1, sizeof(leak_o2_comm_t) - 2);
	RS485_SendDataByte(leakO2.buff, sizeof(leak_o2_comm_t));
	
	// 等待中断处理
}

// 读取泄漏报警数据
void Sensor_ReadLeak(data_sample_t *sample)
{
	uint8_t reSample = 0;

	Modbus_Close();

	// 默认读取失败
	sample->leak.staLeak = LEAK_STATUS_COMM_FAULT;
	sample->leak.concentrations = 0;
	// 传感器类型
	sample->leak.typeLeak = LEAK_TYPE_SWITCH | LEAK_TYPE_CURRENT | LEAK_TYPE_MODBUS;
	
	// 初始化
	modbus_sample = sample;
	modbus_idx = 0;
	
	// 发送
#if 0
	modbus.send.id = LEAK_ID;
	modbus.send.cmd = LEAK_CMD;
	modbus.send.addr = htons(LEAK_ADDR);
	modbus.send.len = htons(LEAK_LEN);
	modbus.send.crc = htons(MODBUS_RTU_CRC16(modbus.buff, sizeof(modbus_send_t) - 2));
	RS485_SendDataByte(modbus.buff, sizeof(modbus_send_t));
#else
	rs_initial_frame(&RS_TranFrame);
	RS_TranFrame.cmd = RS_CMD_READ_DATA;
	rs_append_data(&RS_TranFrame, (uint8_t *) &reSample, 1);
	rs_uart_send(&RS_TranFrame, 0x50, RS_DIR_M2S);
#endif
	
	// 等待中断处理
}

// 读取差压/电容数据
void Sensor_ReadDPress(data_sample_t *sample)
{
	uint8_t reSample = 0;

	Modbus_Close();

	// 默认读取失败
	sample->staDPress.status = SENSOR_STATUS_NOCONNECT;
	sample->adDPress = 0;
	sample->diff = 0;
	
	// 初始化
	modbus_sample = sample;
	modbus_idx = 0;
	
	// 发送
	rs_initial_frame(&RS_TranFrame);
	RS_TranFrame.cmd = RS_CMD_READ_DATA;
	rs_append_data(&RS_TranFrame, (uint8_t *) &reSample, 1);
	rs_uart_send(&RS_TranFrame, 0x31, RS_DIR_M2S);
	
	// 等待中断处理
}

// 读取压力数据
void Sensor_ReadPress(data_sample_t *sample)
{
	uint8_t reSample = 0;

	Modbus_Close();

	// 默认读取失败
	sample->staPress.status = SENSOR_STATUS_NOCONNECT;
	sample->adPress = 0;
	sample->pressure = 0;
	
	// 初始化
	modbus_sample = sample;
	modbus_idx = 0;
	
	// 发送
	rs_initial_frame(&RS_TranFrame);
	RS_TranFrame.cmd = RS_CMD_READ_DATA;
	rs_append_data(&RS_TranFrame, (uint8_t *) &reSample, 1);
	rs_uart_send(&RS_TranFrame, 0x41, RS_DIR_M2S);
	
	// 等待中断处理
}
