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

#include  "includes.h"

#include "drv_dtu.h"
#include "drv_gps.h"
#include "ccs_prediction.h"

// 初始唤醒次数(快速发送）
#define INITIAL_TRAN_COUNT 6

// 绝对值
#define abs(x) ((x) < 0 ? -(x) : (x))

// GPS上报数据的时间戳，年基数为2010
#define GPS_BASE_YEAR	2010

// Boot-loader地址（在线升级以后重启运行）
#define LDROM_BASE			0x100000ul	// 1M

// GPRS串口接收的循环缓冲
#define DTU_TASKM_DATA_COUNT 200
loopbuff_t DTU_TaskM;
uint8_t DTU_TaskM_Data[sizeof(uint8_t) * (DTU_TASKM_DATA_COUNT + 1)] = {0};

// 强制上传数据
volatile uint8_t DTU_dataConn = 0;
// 强制连接维护平台
volatile uint8_t DTU_ldmsConn = 0;
// 维护平台连接计时
volatile uint32_t DTU_ldmsTime = 0;
// 最近一条上传数据的采集时间
volatile uint32_t DTU_dataTime = 0;

// 发送成功时间
volatile uint32_t DTU_succTime = 0;

// 这个缓冲区比较大，不放在stack里面
char DTU_gpsData[2][DTU_GPSDATA_SIZE] = {0}; // 扩展内存
char DTU_recvBuff[DTU_RECVBUFF_SIZE] = {0}; // 扩展内存

// 一次请求升级包数据大小
#define UPGRADE_DATA_LEN 1024

// DTU_Task任务和服务器之间的收发缓冲
#define TASK_SENDBUFF_SIZE	400
uint8_t Task_sendBuff[TASK_SENDBUFF_SIZE] = {0}; // 扩展内存

#if UPGRADE_DATA_LEN >= SFLASH_ERASE_SIZE
	#define TASK_RECVBUFF_SIZE	(UPGRADE_DATA_LEN + 32)
#else
	#define TASK_RECVBUFF_SIZE	(SFLASH_ERASE_SIZE)
#endif
//uint8_t Task_recvBuff[TASK_RECVBUFF_SIZE] = {0}; // 扩展内存
uint8_t Task_recvBuff[1200] = {0}; // 扩展内存
// 信号量，用于通知执行任务
volatile uint8_t DTU_semGPS = 0;		
volatile uint8_t DTU_semGPRS = 0;		
volatile uint8_t DTU_semSync = 0;

// 用于发送到服务器的数据结构
// 和蓝牙的相应命令一致
#pragma pack(push, 1)

typedef struct
{
	uint16_t	mark;
	unsigned	ver : 7;
	unsigned	trans : 1;
	unsigned	reserved: 8;
	uint16_t	len;
	union
	{
		uint16_t	cmd;
		struct
		{
			uint8_t		err;
			uint8_t		cmd_L;
		};
	};
} bluetooth_recv_t;

typedef bluetooth_recv_t bluetooth_send_t;

typedef struct
{
	unsigned staEPress3 :	2;
	unsigned staETempr1 :	2;
	unsigned staETempr2 :	2;
	unsigned staETempr3 :	2;

	unsigned staDiff :		2;
	unsigned staPress :		2;
	unsigned staEPress1 :	2;
	unsigned staEPress2 :	2;
	
} bluetooth_sensor_t;

typedef struct
{
	unsigned maskStamp :	1;
	unsigned maskEPress1 :	1;
	unsigned maskEPress2 :	1;
	unsigned maskEPress3 :	1;
	unsigned  : 1;
	unsigned maskLowPower : 1;
	unsigned maskAbnormal :	1;
	unsigned maskCharging :	1;
	
	unsigned maskRssi :		1;
	unsigned maskGPS :		1;
	unsigned maskETempr1 :	1;
	unsigned maskETempr2 :	1;
	unsigned maskETempr3 :	1;
	unsigned maskBattery :	1;
	unsigned maskFlow :		1;
	unsigned maskLeak :		1;
} bluetooth_mask_t;

typedef union
{
	struct
	{
		unsigned sec : 6;
		unsigned min : 6;
		unsigned hour_L : 4;
		unsigned hour_H : 1;
		unsigned day : 5;
		unsigned mon : 4;
		unsigned year : 6;
	};
	uint32_t tm;
} bluetooth_timestamp_t;

typedef	union
{
	unsigned long long ll;
	struct
	{
		unsigned long l;
		unsigned long h;
	};
} longlong_mask_t;

typedef struct
{
	union
	{
		struct
		{
			unsigned sateCount : 5;		// gps可见卫星数量
			unsigned posState : 1;		// gps定位状态		（0-GPS未定位，1-GPS已定位）
			unsigned carState : 1;		// 车辆是否启动		（0-车辆未启动，1-车辆已启动）
			unsigned carEvent : 1;		// 车辆启动或停止事件（0-启动状态未改变，1-启动状态已改变）
		};
		uint8_t state;
	};
	bluetooth_timestamp_t 	time;	// 时间戳
	int32_t					latitude;
	int32_t					longitude;
	uint16_t 				speed;
} gps_data_t;

typedef struct	// size = 158
{
	uint32_t	sample_time;	// 采集时间：自启动以来经过的秒数
	data_dtu_t			dtuData;	// size = 36
	data_sample_t		sampleData; // size = 118
} gprs_data_t;

// 双向通讯的数据结构
typedef struct	// size = 120
{
	uint16_t	serverVer;	// 服务器参数版本号
	uint8_t		type;		// 储罐类型
	uint32_t	diameter;	// 内径
	uint32_t	len;		// 圆柱体长度
	uint32_t	lenExtra;	// 直边封头长度
	uint32_t	reserved_1[3];
	uint8_t		source;				// 液源
	uint32_t	density;			// 各液源的比重（kg/m3)
	uint16_t	fullPct;			// 满液位百分比
	uint16_t	priPct;				// 关键液位百分比
	uint16_t	orderPct;			// 订货液位百分比
	uint16_t	emptyPct;			// 空液位百分比
	uint32_t	planMount;			// 每日计划用量
	uint32_t	predictMount;		// 每日预测用量
	uint16_t	warnVolt;			// 电压报警低点: 10mV
	uint16_t	warnVoltH;			// 电压报警高点: 10mV
	uint16_t	warnPress;			// 压力报警低点: KPa
	uint16_t	warnPressH;			// 压力报警高点: KPa
	uint32_t	intervalTrans;		// 数据上报周期
	uint32_t	intervalSample;		// 数据采集周期
	uint32_t	intervalGPSTrans;	// 位置上报周期
	uint32_t	intervalGPS;		// 位置采集周期
	union
	{
		struct
		{
			char		gpsServer[20];		// 远传服务器	(只上传，不修改)
			int16_t		gpsPort;			// 远传端口		(只上传，不修改)
			char		pwd1[6];			// 储罐参数修改密码
		};
		struct
		{
			char		gprsServer[26];		// praxair：修改数据服务器地址
			int16_t		gprsPort;			// praxair: 修改数据服务器端口
		};
	};
	uint32_t	options;			// 参数开关
	union
	{
		uint8_t		reserved_2[12];
		struct
		{
			uint16_t floorLevel;								// praxair: 液量报警下限
			uint16_t span;											// praxair: 液量变化报警门限
			uint16_t spanPeriod;								// praxair: 液量变化报警时间
			unsigned floorLevelAssigned : 1;		// praxair: 参数中floorLevel是否有效
			unsigned spanAssigned : 1;					// praxair: 参数中span是否有效
			unsigned spanPeriodAssigned : 1;		// praxair: 参数中spanPeriod是否有效
			unsigned intervalTransAssigned : 1;	// praxair: 参数中intervalTrans是否有效
			unsigned gprsServerAssigned : 1;		// praxair: 参数中数据服务器地址是否有效
			unsigned gprsPortAssigned : 1;			// praxair: 参数中数据服务器端口是否有效
			unsigned : 2;
		};
	};
	uint32_t	ts;					// 参数时间戳
} param_data_t;

// 升级进度信息（存放在FRAM中，可断点续传）
typedef struct
{
	uint16_t	check;		// 标志，固定为0x55AA
	uint32_t	ver;		// 固件版本
	int32_t		fileSize;	// 固件总字节数
	uint16_t	fileCrc;	// 固件总的crc
	int32_t		offset;		// 本次固件偏移量
	int32_t 	len;		// 本次数据长度
	uint16_t	crc;		// 本记录的crc
} upgrade_info_t;

// 升级包接收记录
typedef struct
{
	uint32_t	ver;		// 固件版本
	int32_t		fileSize;	// 固件总字节数
	uint16_t	fileCrc;	// 固件总的crc
	int32_t		offset;		// 本次固件偏移量
	int32_t 	len;		// 本次数据长度
	uint8_t		data[UPGRADE_DATA_LEN];		// 本次数据
	uint16_t	crc;		// 本次数据的crc
} upgrade_frame_t;

// 升级文件头
typedef struct // size=12
{
	unsigned short check;			// 数据有效标志, 0x55AA表示有效 
	unsigned upgrade_request : 1;	// 升级请求标志，0-无升级，1-有升级
	unsigned upgrade_result : 3;	// 升级失败标志，0-成功，1-失败，其余保留
	unsigned encrypt_flag : 2;		// 加密标志， 0-无加密，其余保留
	unsigned compress_flag : 2;		// 压缩标志， 0-无压缩，1-有压缩，其余保留
	unsigned rerseved1 : 8;			// 保留，必须为0xFF
	
	unsigned long upgrade_length; 	// 升级文件长度
	
	unsigned rerseved2 : 8;			// 保留，必须为0xFF
	unsigned rerseved3 : 8;			// 保留，必须为0xFF
	unsigned short crc;				// 对前面内容的crc校验
} TUpgradeHeader;

// 阿里云密钥记录
typedef struct // size=76
{
	unsigned short check;			// 数据有效标志, 0x55AA表示有效
	uint8_t PSN[6];					// 获取密钥所用的PSN（如果PSN改变需重新获取）
	char product[12];				// 产品代码
	char device[21];				// 默认为cPSN
	char secret[33];				// 设备密钥
	unsigned short crc;				// 对前面内容的crc校验
} TAliyunSecret;

#define ALIYUN_SECRET_SIZE (66)

#pragma pack(pop)

// 阿里云密钥
TAliyunSecret aliyunSecret = {0};

// 升级包记录
upgrade_info_t upInfo = {0};

// GPS循环缓冲记录
loopbuff_t gpsBuff = {0};

// 存放GPRS记录的循环缓冲
loopbuff_t gprsBuff = {0};
loopbuff_t bd_gprsBuff = {0};
// GPRS记录读写缓冲
gprs_data_t gprsRWBuf;

void pack_param_DO23_data(param_data_t *param)
{
	memset(param, 0, sizeof(param_data_t));
	param->serverVer = htons(dcBuff.configBottle.serverVer);
	param->type = dcBuff.configBottle.type;
	param->diameter = htonl(dcBuff.configBottle.diameter);
	param->len = htonl(dcBuff.configBottle.len);
	param->lenExtra = htonl(dcBuff.configBottle.lenExtra);
	param->source = dcBuff.configBottle.source;
	param->density = htonl(Config_GetDensity(dcBuff.configBottle.source) * 1000);
	param->fullPct = htons(dcBuff.configBottle.fullPct);
	param->priPct = htons(dcBuff.configBottle.priPct);
	param->orderPct = htons(dcBuff.configBottle.orderPct);
	param->emptyPct = htons(dcBuff.configBottle.emptyPct);
	param->planMount = htonl(dcBuff.configBottle.planMount);
	param->predictMount = htonl(dcBuff.configBottle.predictMount);
	param->warnVolt = htons(dcBuff.configBottle.warnVolt);
	param->warnVoltH = htons(dcBuff.configBottle.warnVoltH);
	param->warnPress = htons(dcBuff.configBottle.warnPress);
	param->warnPressH = htons(dcBuff.configBottle.warnPressH);
	param->intervalTrans = htonl(dcBuff.configData.intervalTrans);
	param->intervalSample = htonl(dcBuff.configData.intervalSample);
	param->intervalGPSTrans = htonl(dcBuff.configData.intervalGPSTrans);
	param->intervalGPS = htonl(dcBuff.configData.intervalGPS);
	if(dcBuff.configBottle.serverVer != 3)
	{
		strcpy(param->gpsServer, dcBuff.configData.gpsServer);
		param->gpsPort = htons(dcBuff.configData.gpsPort);
		strcpy(param->pwd1, dcBuff.configDisplay.pwd1);
	}
	if(dcBuff.configBottle.dispMode == DISP_MODE_ALL)
		param->options |= 0x0003ul;
	else if(dcBuff.configBottle.dispMode == DISP_MODE_L)
		param->options |= 0x0001ul;
	else if(dcBuff.configBottle.dispMode == DISP_MODE_KG)
		param->options |= 0x0002ul;
	param->options = htonl(param->options);
	param->ts = htonl(dcBuff.configBottle.ts);
	
	// praxair
	memset(param->reserved_2, 0, sizeof(param->reserved_2));
	if(dcBuff.configBottle.serverVer == 3)
	{
		param->floorLevel = htons(dcBuff.configBottle.floorLevel);
		param->floorLevelAssigned = 1;
		param->span = htons(dcBuff.configBottle.span);
		param->spanAssigned = 1;
		param->spanPeriod = htons(dcBuff.configBottle.spanPeriod);
		param->spanPeriodAssigned = 1;
		param->intervalTransAssigned = 1;
		strcpy(param->gprsServer, dcBuff.configData.server);
		param->gprsServerAssigned = 1;
		param->gprsPort = htons(dcBuff.configData.port);
		param->gprsPortAssigned = 1;
	}
}

void parse_param_D021_data(param_data_t *param)
{
	int serverVer = ntohs(param->serverVer);
	dcBuff.configBottle.serverVer = serverVer;

	if(serverVer == 3)		// praxair
	{
		if(param->floorLevelAssigned)
			dcBuff.configBottle.floorLevel = ntohs(param->floorLevel);
		if(param->spanAssigned)
			dcBuff.configBottle.span = ntohs(param->span);
		if(param->spanPeriodAssigned)
			dcBuff.configBottle.spanPeriod = ntohs(param->spanPeriod);
		if(param->intervalTransAssigned)
			dcBuff.configData.intervalTrans = ntohl(param->intervalTrans);
		if(param->gprsServerAssigned)
		{
			strcpy(dcBuff.configData.server, param->gprsServer);
			strcpy(dcBuff.configData.upgServer, param->gprsServer);
			strcpy(dcBuff.configData.gpsServer, param->gprsServer);
		}
		if(param->gprsPortAssigned)
		{
			dcBuff.configData.port = ntohs(param->gprsPort);
			dcBuff.configData.upgPort = dcBuff.configData.port + 1;
			dcBuff.configData.gpsPort = dcBuff.configData.port + 2;
		}
	}
	else
	{
		dcBuff.configBottle.type = param->type;
		dcBuff.configBottle.diameter = ntohl(param->diameter);
		dcBuff.configBottle.len = ntohl(param->len);
		dcBuff.configBottle.lenExtra = ntohl(param->lenExtra);
		dcBuff.configBottle.source = param->source;
		Config_SetDensity(dcBuff.configBottle.source, ntohl(param->density) / 1000.0);
		dcBuff.configBottle.fullPct = ntohs(param->fullPct);
		dcBuff.configBottle.priPct = ntohs(param->priPct);
		dcBuff.configBottle.orderPct = ntohs(param->orderPct);
		dcBuff.configBottle.emptyPct = ntohs(param->emptyPct);
		dcBuff.configBottle.planMount = ntohl(param->planMount);
		dcBuff.configBottle.predictMount = ntohl(param->predictMount);
		dcBuff.configBottle.warnVolt = ntohs(param->warnVolt);
		dcBuff.configBottle.warnVoltH = ntohs(param->warnVoltH);
		dcBuff.configBottle.warnPress = ntohs(param->warnPress);
		dcBuff.configBottle.warnPressH = ntohs(param->warnPressH);
		dcBuff.configData.intervalTrans = ntohl(param->intervalTrans);
		dcBuff.configData.intervalSample = ntohl(param->intervalSample);
		
		// 以下参数只做上传，不做修改
//		dcBuff.configData.intervalGPSTrans = ntohl(param->intervalGPSTrans);
//		dcBuff.configData.intervalGPS = ntohl(param->intervalGPS);
//		strcpy(dcBuff.configData.gpsServer, param->gpsServer);
//		dcBuff.configData.gpsPort = ntohs(param->gpsPort);
//		strcpy(dcBuff.configDisplay.pwd1, param->pwd1);

		dcBuff.configBottle.options = ntohl(param->options);
		if((dcBuff.configBottle.options & 0x0003ul) == 0x0003ul)
			dcBuff.configBottle.dispMode = DISP_MODE_ALL;
		else if((dcBuff.configBottle.options & 0x0001ul) == 0x0001ul)
			dcBuff.configBottle.dispMode = DISP_MODE_L;
		else if((dcBuff.configBottle.options & 0x0002ul) == 0x0002ul)
			dcBuff.configBottle.dispMode = DISP_MODE_KG;
		else
			dcBuff.configBottle.dispMode = DISP_MODE_DPRESS;
		dcBuff.configBottle.ts = ntohl(param->ts);
	}
}

// 是否GPS定位
volatile uint8_t GPS_Locate = 1;
volatile uint8_t GPS_Located = 0;
volatile uint32_t GPS_waitTick = 0;
volatile uint8_t GPS_Waiting = 0;
// GPS定位超时
const uint8_t DTU_tmrLocate = 90;

// GPS发送数据
volatile uint32_t GPS_tranTick = 0;

// 保存上次数据的时间
bluetooth_timestamp_t GPS_LastTime = {0};

// 是否发送GPRS数据
uint8_t GPRS_Send_Task = 0;
uint32_t GPRS_Send_Time = 0;
// 是否保存GPRS数据
uint8_t GPRS_Save_Task = 0;
uint32_t GPRS_Save_Time = 0;

// 计算两个经纬度之间的距离
const double EARTH_RADIUS = 6378.137;
double rad(double d)
{
   return d * PI / 180.0;
}

double GetDistance(int32_t lat1, int32_t lng1, int32_t lat2, int32_t lng2)
{
   double radLat1 = rad(lat1 * 0.000001);
   double radLat2 = rad(lat2 * 0.000001);
   double a = radLat1 - radLat2;
   double b = rad(lng1 * 0.000001) - rad(lng2 * 0.000001);
   double s = 2 * asin(sqrt(pow(sin(a / 2), 2) +
			cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2)));
   s = s * EARTH_RADIUS;
   return s;
}

// 比较新数据的时间，是否晚于老数据的时间
int32_t GPS_IsLateThan(bluetooth_timestamp_t *pNewTime, bluetooth_timestamp_t *pOldTime)
{
	uint8_t newHour = (pNewTime->hour_H << 4) | pNewTime->hour_L;
	uint8_t oldHour = (pOldTime->hour_H << 4) | pOldTime->hour_L;
	
	if(pNewTime->year > pOldTime->year)
		return TRUE;
	if(pNewTime->year < pOldTime->year)
		return FALSE;
	if(pNewTime->mon > pOldTime->mon)
		return TRUE;
	if(pNewTime->mon < pOldTime->mon)
		return FALSE;
	if(pNewTime->day > pOldTime->day)
		return TRUE;
	if(pNewTime->day < pOldTime->day)
		return FALSE;
	if(newHour > oldHour)
		return TRUE;
	if(newHour < oldHour)
		return FALSE;
	if(pNewTime->min > pOldTime->min)
		return TRUE;
	if(pNewTime->min < pOldTime->min)
		return FALSE;
	
	return pNewTime->sec > pOldTime->sec;
}

// 计算两个时间间隔的秒数
uint32_t GPS_CalcInterval(bluetooth_timestamp_t *pNewTime, bluetooth_timestamp_t *pOldTime)
{
	// 计算从OldYear以来的秒数
	uint32_t newSeconds = Calc_SecondsFromYear(GPS_BASE_YEAR + pOldTime->year, pNewTime->year + GPS_BASE_YEAR, pNewTime->mon, 
		pNewTime->day, (pNewTime->hour_H << 4) | pNewTime->hour_L, pNewTime->min, pNewTime->sec);
	uint32_t oldSeconds = Calc_SecondsFromYear(GPS_BASE_YEAR + pOldTime->year, pOldTime->year + GPS_BASE_YEAR, pOldTime->mon, 
		pOldTime->day, (pOldTime->hour_H << 4) | pOldTime->hour_L, pOldTime->min, pOldTime->sec);
	
	return newSeconds - oldSeconds;
}

// 将一个数据加入队列
void GPS_PutToQueue(gps_data_t *gps)
{
	uint16_t nextPtr;
	
	// 如果要添加数据的时间大于上一条数据的时间
	if(GPS_LastTime.year == 0 || GPS_IsLateThan(&gps->time, &GPS_LastTime))
	{
		// 移动写指针
		nextPtr = LoopBuff_GetNextPtr(&gpsBuff, gpsBuff.info.wtPtr);
		
		// 如果队列已满
		if(nextPtr == gpsBuff.info.rdPtr)
		{
			// 移动读指针（丢弃第一条数据）
			gpsBuff.info.rdPtr = LoopBuff_GetNextPtr(&gpsBuff, gpsBuff.info.rdPtr);
		}

		// 将新数据加到最后
		FRAM_BufferWrite(LoopBuff_GetDataPos(&gpsBuff, gpsBuff.info.wtPtr), (uint8_t *) gps, sizeof(gps_data_t));
		gpsBuff.info.wtPtr = nextPtr;
		// 保存到铁电
		FRAM_SaveInfo(gpsBuff.info_base, (uint8_t *) &gpsBuff.info, sizeof(gpsBuff.info));

		GPS_LastTime = gps->time;
	}
}

// 将一个数据加入队列
void GPRS_PutToQueue(loopbuff_t *lpBuff, data_dtu_t *dtuData, data_sample_t *sampleData)
{
	uint16_t nextPtr;
    S_RTC_TIME_DATA_T sRTC;
	gprs_data_t *gprs;

	// 移动写指针
	nextPtr = LoopBuff_GetNextPtr(lpBuff, lpBuff->info.wtPtr);
	
	// 如果队列已满
	if(nextPtr == lpBuff->info.rdPtr)
	{
		// 移动读指针（丢弃第一条数据）
		lpBuff->info.rdPtr = LoopBuff_GetNextPtr(lpBuff, lpBuff->info.rdPtr);
	}

	// 将新数据加到最后
	gprs = &gprsRWBuf;
	// 获取当前时间
	RTC_GetDateAndTime(&sRTC);
	// 计算自上次gps定位以来的时间
	gprs->sample_time = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
			sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
	gprs->dtuData = *dtuData;
	gprs->sampleData = *sampleData;
	FRAM_BufferWrite(LoopBuff_GetDataPos(lpBuff, lpBuff->info.wtPtr), (uint8_t *) gprs, sizeof(gprs_data_t));
	
	lpBuff->info.wtPtr = nextPtr;
}

// 将前面几条数据移出队列
void GPS_MoveFromQueue(uint8_t count)
{
	LoopBuff_RemoveItems(&gpsBuff, count);
	// 保存到铁电
	FRAM_SaveInfo(gpsBuff.info_base, (uint8_t *) &gpsBuff.info, sizeof(gpsBuff.info));
}

// 查找队列前面的数据, 找出时间间隔相同的一组，最多max_count条
// 本函数在调用的地方加锁，因为这个函数返回以后接着要取数据
uint8_t GPS_LookData(uint8_t max_count, uint16_t *interval, uint8_t *done)
{
	uint8_t	count = 0;
	uint8_t i;
	uint16_t gps_count = 0, nextPtr;
	gps_data_t gps0, gps1;
	
	*interval = 0;
	*done = 1;
	
	if(max_count < 1)
		return 0;
	
	// 获取未发送记录条数
	gps_count = LoopBuff_GetCount(&gpsBuff);
	if(gps_count < 2)
		return gps_count;
	
	count = 2;
	FRAM_BufferRead(LoopBuff_GetDataPos(&gpsBuff, gpsBuff.info.rdPtr), (uint8_t *) &gps0, sizeof(gps_data_t));
	nextPtr = LoopBuff_GetNextPtr(&gpsBuff, gpsBuff.info.rdPtr);
	FRAM_BufferRead(LoopBuff_GetDataPos(&gpsBuff, nextPtr), (uint8_t *) &gps1, sizeof(gps_data_t));
	*interval = GPS_CalcInterval(&gps1.time, &gps0.time);
	for(i = 2; count < max_count && i < gps_count; i++)
	{
		// 如果后面的时间间隔不一样
		gps0 = gps1;
		nextPtr = LoopBuff_GetNextPtr(&gpsBuff, nextPtr);
		FRAM_BufferRead(LoopBuff_GetDataPos(&gpsBuff, nextPtr), (uint8_t *) &gps1, sizeof(gps_data_t));
		if(GPS_CalcInterval(&gps1.time, &gps0.time) != *interval)
			break;
		count++;
	}
	if(i < gps_count)
		*done = 0;
	return count;
}

// 将采集数据中的传感器状态转换为蓝牙协议中的状态
static uint8_t Bluetooth_ConvertStat(sensor_status_t *pStat)
{
	if(pStat->notConnect)
		return 3;
	if(pStat->overFlow)
		return 1;
	if(pStat->underFlow)
		return 2;
	return 0;
}

// GPS uart
void GPS_IRQHandler(USART_Handle *huart)
{
	uint8_t u8DTU = (uint8_t) huart->Instance->RDR;
		
//	printf("%c", u8DTU);
	// 直接处理
	DTU_Task0(u8DTU);	
}

// GSM uart
void GPRS_IRQHandler(USART_Handle *huart)
{
	uint8_t u8DTU = (uint8_t) huart->Instance->RDR;
	
	if(DTU_uartPrint)
	{
//		if(u8DTU == '\n')
//			printf("\\n\n");
//		else if(u8DTU == '\r')
//			printf("\\r");
//		else
			printf("%c", u8DTU);
	}
	// 加入缓冲
	LoopBuff_PutItem(&DTU_TaskM, &u8DTU);
}

void DTU_Init()
{	
    /* 配置GSM端口 */
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
  /**USART1 GPIO Configuration  
  PA9   ------> USART1_TX
  PA10   ------> USART1_RX 
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_9|LL_GPIO_PIN_10;
  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_7;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* 配置GPS端口: GPS和Debug共用一个串口，GPS用到输入，DEBUG用到输出 */
}

void DTU_Open()
{
  LL_USART_InitTypeDef USART_InitStruct = {0};

    // 分配扩展内存
//	DTU_gpsData[0] = (char *) SRAM_Alloc(DTU_GPSDATA_SIZE);
//	DTU_gpsData[1] = (char *) SRAM_Alloc(DTU_GPSDATA_SIZE);
//	DTU_recvBuff = (char *) SRAM_Alloc(DTU_RECVBUFF_SIZE);
//	Task_sendBuff = (uint8_t *) SRAM_Alloc(TASK_SENDBUFF_SIZE);
//	Task_recvBuff = (uint8_t *) SRAM_Alloc(TASK_RECVBUFF_SIZE);
	LoopBuff_Create(&gpsBuff, sizeof(gps_data_t), FRAM_GPS_DATA_COUNT, FRAM_GPS_INFO_BASE, FRAM_GPS_DATA_BASE);
	LoopBuff_Create(&gprsBuff, sizeof(gprs_data_t), FRAM_GPRS_DATA_COUNT, FRAM_GPRS_INFO_BASE, FRAM_GPRS_DATA_BASE);
	LoopBuff_Create(&bd_gprsBuff, sizeof(gprs_data_t), FRAM_BD_GPRS_DATA_COUNT, FRAM_GPRS_BD_INFO_BASE, FRAM_GPRS_BD_DATA_BASE);
	LoopBuff_Create(&DTU_TaskM, sizeof(uint8_t), DTU_TASKM_DATA_COUNT, 0, (uint32_t) DTU_TaskM_Data);

	huart1.RxISR = GPRS_IRQHandler;
	huart2.RxISR = GPS_IRQHandler;
  
  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
  
  /* USART1 interrupt Init */
  NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
  NVIC_EnableIRQ(USART1_IRQn);
  
  USART_InitStruct.BaudRate = 115200;
  USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
  USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
  USART_InitStruct.Parity = LL_USART_PARITY_NONE;
  USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
  USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
  USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
  LL_USART_Init(USART1, &USART_InitStruct);
  LL_USART_ConfigAsyncMode(USART1);

  SET_BIT(USART1->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
  LL_USART_Enable(USART1);

  /* 打开GPS端口: GPS和Debug共用一个串口，GPS用到输入，DEBUG用到输出 */
}

// 任务主体：采集GPS数据
void DTU_Task0(uint8_t c)
{
	static uint16_t RdIdx = 0;
	static uint8_t bufIdx = 0;
	static data_dtu_t sample = {0};
	static int32_t last_latitude, last_longitude;
	static uint8_t gps_flag = 0, motion_count = 0, motionless_count = 0;
	static uint32_t last_time = 0;
	gps_data_t gpsData;
	uint32_t time;

	if(c == '$' || RdIdx >= DTU_GPSDATA_SIZE)
		RdIdx = 0;
	
	if(RdIdx == 0 && c != '$')
		return;

	if(c != '\r' && c != '\n')
		DTU_gpsData[bufIdx][RdIdx++] = c;
	else
	{
		// 收到完整的一行
		DTU_gpsData[bufIdx][RdIdx] = 0;
		RdIdx = 0;
		
		// 解析一行数据
		if(parse_frame(&bufIdx, DTU_gpsData[bufIdx], &sample))
		{
			if(sample.sateCount > 0)
				printf("sateCount:\t%d\n", sample.sateCount);

			if(sample.posState)
			{
				time = Calc_SecondsFromYear(INITIAL_YEAR, sample.sysTime.year + 2000, sample.sysTime.month, 
						sample.sysTime.day, sample.sysTime.hour, sample.sysTime.minute, sample.sysTime.second);

				// 修正时间基准（可显示绝对时间）
				//if(RTC_offsetSeconds == 0 && time >= DTU_gpsTime)
				if(time >= DTU_gpsTime) // 每次成功定位都修正时间
					RTC_offsetSeconds = time - DTU_gpsTime;
				
				if(sample.sateCount >= 4)
				{
					if(time >= last_time + dcBuff.configData.intervalGPS)
					{
						last_time = time;
					
						// 如果没有硬件加速度计，则用软件方式判断
						if(dcBuff.configDisplay.op_SEND_GPS_DATA && Accelero_ID != ACCELERO_ID)
						{							
							if(sample.speed <= 3)
							{
								motion_count = 0;
								if(Motion_Status == 1 && ++motionless_count >= 3)
								{
									Motion_Status = 0;
									printf("\nSoft Motion status = 0\n");
								}
							}
							else
							{
								motionless_count = 0;
								if(Motion_Status == 0 && ++motion_count >= 3)
								{
									Motion_Status = 1;
									printf("\nSoft Motion status = 1\n");
								}
							}
						}
					
						printf("Latitude:\t%10.6f\n", sample.latitude * 0.000001);
						printf("Longitude:\t%10.6f\n", sample.longitude * 0.000001);
						printf("Speed:\t\t%d km/h\n", sample.speed);
						printf("GPS time:\t%d-%02d-%02d %02d:%02d:%02d\n", 
							sample.sysTime.year + 2000, sample.sysTime.month, sample.sysTime.day,
							sample.sysTime.hour, sample.sysTime.minute, sample.sysTime.second);

						// 计算和上次定位之间的距离，或者判断运动状态
						if(dcBuff.configDisplay.op_SEND_GPS_DATA && gps_flag == 1 && (
							!Motion_Status
//						 		|| (sample.speed < 5 && GetDistance(last_latitude, last_longitude, sample.latitude, sample.longitude) < 10)
						))
						{
							printf("\nCalibrate to last position\n");
							sample.latitude = last_latitude;
							sample.longitude = last_longitude;
						}
						else
						{
							gps_flag = 1;
							last_latitude = sample.latitude;
							last_longitude = sample.longitude;
						}

						// 写入全局缓冲
						dcBuff.dtuData.posState = sample.posState;
						dcBuff.dtuData.sateCount = sample.sateCount;
						dcBuff.dtuData.latitude = sample.latitude;
						dcBuff.dtuData.longitude = sample.longitude;
						dcBuff.dtuData.speed = sample.speed;
						dcBuff.dtuData.sysTime = sample.sysTime;
						// 最近定位成功
						dcBuff.dtuData.recentPosState = 1;
					
						if(dcBuff.configDisplay.op_SEND_GPS_DATA)
						{
							// 加入GPS数据队列，待发送
							if(sample.sateCount > 31)
								gpsData.sateCount = 31;
							else
								gpsData.sateCount = sample.sateCount;
							gpsData.posState = sample.posState;
							gpsData.carState = VCC_POWER_STATUS() ? 1: 0;
							gpsData.carEvent = bat_CurrentEvent;
							bat_CurrentEvent = 0;
							
							gpsData.time.year = sample.sysTime.year + 2000 - GPS_BASE_YEAR;
							gpsData.time.mon = sample.sysTime.month;
							gpsData.time.day = sample.sysTime.day;
							gpsData.time.hour_H = sample.sysTime.hour >> 4;
							gpsData.time.hour_L = sample.sysTime.hour & 0x0F;
							gpsData.time.min = sample.sysTime.minute;
							gpsData.time.sec = sample.sysTime.second;
							gpsData.latitude = sample.latitude;
							gpsData.longitude = sample.longitude;
							gpsData.speed = sample.speed;
							
							GPS_PutToQueue(&gpsData);
						}
						else
						{
							GPS_Located = 1;
							// 停止超时定时器
							GPS_Waiting = 0;
						}
					}
				}
			}
			// 清除数据
			memset(&sample, 0, sizeof(sample));
		}
	}
}

// 发送奥扬数据
uint16_t pack_aoyang_send_data(gprs_data_t *pGprs, uint32_t totalSeconds)
{
    S_RTC_TIME_DATA_T sRTC;
	char field[20];

	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	// PSN
	strcat((char *) Task_sendBuff, "{\"i\":");
	sprintf(field, "20%02d%02d%02d%02d%03d", 
		dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], dcBuff.configBottle.PSN[2],
		dcBuff.configBottle.PSN[3], (dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
	strcat((char *) Task_sendBuff, field);
	// 取数时间
	strcat((char *) Task_sendBuff, ",\"t\":");
	Wakeup_CalcUTCTime(pGprs->sample_time + RTC_offsetSeconds, &sRTC);
	sprintf(field, "%04d%02d%02d%02d%02d%02d", sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
		sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
	strcat((char *) Task_sendBuff, field);
	// 液位高度
	strcat((char *) Task_sendBuff, ",\"h\":");
	if(pGprs->sampleData.staDPress.status == SENSOR_STATUS_OVERFLOW)
	{
		// 短路
		sprintf(field, "%d", -1);
	}
	else if(pGprs->sampleData.staDPress.status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_UNDERFLOW)
	{
		// 断路
		sprintf(field, "%d", -2);
	}
	else
		sprintf(field, "%d", (uint16_t) pGprs->sampleData.height);
	strcat((char *) Task_sendBuff, field);
	// 液体体积
	strcat((char *) Task_sendBuff, ",\"v\":");
	if(pGprs->sampleData.staDPress.status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_OVERFLOW 
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_UNDERFLOW)
	{
		// 故障
		sprintf(field, "%d", -1);
	}
	else
		sprintf(field, "%d", pGprs->sampleData.volume);
	strcat((char *) Task_sendBuff, field);
	// 气瓶压力
	strcat((char *) Task_sendBuff, ",\"p\":");
	if(pGprs->sampleData.staPress.status == SENSOR_STATUS_OVERFLOW)
	{
		// 短路
		sprintf(field, "%d", -1);
	}
	else if(pGprs->sampleData.staPress.status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staPress.status == SENSOR_STATUS_UNDERFLOW)
	{
		// 断路
		sprintf(field, "%d", -2);
	}
	else
	{
		// 压力：KPa->MPa
		sprintf(field, "%f", pGprs->sampleData.pressure * 0.001);
	}
	strcat((char *) Task_sendBuff, field);
	// 经度
	strcat((char *) Task_sendBuff, ",\"x\":");
	if(!pGprs->dtuData.recentPosState || pGprs->dtuData.longitude == 0)
		sprintf(field, "%d", 200);
	else
		sprintf(field, "%.6f", pGprs->dtuData.longitude * 0.000001);
	strcat((char *) Task_sendBuff, field);
	// 纬度
	strcat((char *) Task_sendBuff, ",\"y\":");
	if(!pGprs->dtuData.recentPosState || pGprs->dtuData.latitude == 0)
		sprintf(field, "%d", 200);
	else
		sprintf(field, "%.6f", pGprs->dtuData.latitude * 0.000001);
	strcat((char *) Task_sendBuff, field);
	//结束符，多发送一个换行符('\n')
	strcat((char *) Task_sendBuff, "}\n");

	return strlen((char *) Task_sendBuff);	
}

// 发送巴西数据
uint16_t pack_brasil_send_data(gprs_data_t *pGprs, uint32_t totalSeconds)
{
    S_RTC_TIME_DATA_T sRTC;
	char field[40];

	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	// PSN
	strcat((char *) Task_sendBuff, "{\"psn\":");
	sprintf(field, "\"20%02d%02d%02d%02d%03d\"", 
		dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], dcBuff.configBottle.PSN[2],
		dcBuff.configBottle.PSN[3], (dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
	strcat((char *) Task_sendBuff, field);
	// 取数时间
	strcat((char *) Task_sendBuff, ",\"time\":");
	Wakeup_CalcUTCTime(pGprs->sample_time + RTC_offsetSeconds, &sRTC);
	sprintf(field, "\"%04d%02d%02d%02d%02d%02d\"", sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
		sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
	strcat((char *) Task_sendBuff, field);
	// 差压
	strcat((char *) Task_sendBuff, ",\"dp\":");
	if(pGprs->sampleData.staDPress.status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_OVERFLOW
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_UNDERFLOW)
	{
		// 故障
		sprintf(field, "%d", -300);
	}
	else
	{
		// mmWC
		sprintf(field, "%.0f", KPa2mmH2O(pGprs->sampleData.diff));
	}
	strcat((char *) Task_sendBuff, field);
	// 容积百分比
	strcat((char *) Task_sendBuff, ",\"pct\":");
	if(pGprs->sampleData.staDPress.status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_OVERFLOW
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_UNDERFLOW)
	{
		// 故障
		sprintf(field, "%d", 0);
	}
	else
	{
		// %
		sprintf(field, "%.1f", pGprs->sampleData.volumePct * 0.01);
	}
	strcat((char *) Task_sendBuff, field);
	// 液体体积
	strcat((char *) Task_sendBuff, ",\"v\":");
	if(pGprs->sampleData.staDPress.status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_OVERFLOW 
		|| pGprs->sampleData.staDPress.status == SENSOR_STATUS_UNDERFLOW)
	{
		// 故障
		sprintf(field, "%d", 0);
	}
	else
	{
		// L
		sprintf(field, "%d", pGprs->sampleData.volume);
	}
	strcat((char *) Task_sendBuff, field);
	// 压力
	strcat((char *) Task_sendBuff, ",\"p\":");
	if(pGprs->sampleData.staPress.status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staPress.status == SENSOR_STATUS_OVERFLOW
		|| pGprs->sampleData.staPress.status == SENSOR_STATUS_UNDERFLOW)
	{
		// 故障
		sprintf(field, "%d", -300);
	}
	else
	{
		// 压力：KPa->MPa
		sprintf(field, "%.2f", pGprs->sampleData.pressure * 0.001);
	}
	strcat((char *) Task_sendBuff, field);
	// 温度
	strcat((char *) Task_sendBuff, ",\"t\":");
	if(pGprs->sampleData.staExtTempr[0].status == SENSOR_STATUS_NOCONNECT
		|| pGprs->sampleData.staExtTempr[0].status == SENSOR_STATUS_OVERFLOW
		|| pGprs->sampleData.staExtTempr[0].status == SENSOR_STATUS_UNDERFLOW)
	{
		// 故障
		sprintf(field, "%d", -300);
	}
	else
	{
		// 温度：℃
		sprintf(field, "%d", pGprs->sampleData.extTempr[0]);
	}
	strcat((char *) Task_sendBuff, field);
	// 经度
	strcat((char *) Task_sendBuff, ",\"x\":");
	if(!pGprs->dtuData.recentPosState || pGprs->dtuData.longitude == 0)
		sprintf(field, "%d", -300);
	else
		sprintf(field, "%.6f", pGprs->dtuData.longitude * 0.000001);
	strcat((char *) Task_sendBuff, field);
	// 纬度
	strcat((char *) Task_sendBuff, ",\"y\":");
	if(!pGprs->dtuData.recentPosState || pGprs->dtuData.latitude == 0)
		sprintf(field, "%d", -300);
	else
		sprintf(field, "%.6f", pGprs->dtuData.latitude * 0.000001);
	strcat((char *) Task_sendBuff, field);
	// APN
	strcat((char *) Task_sendBuff, ",\"apn\":");
	sprintf(field, "\"%s\"", dcBuff.configDisplay.APN);
	strcat((char *) Task_sendBuff, field);
	// APN-User
	strcat((char *) Task_sendBuff, ",\"user\":");
	sprintf(field, "\"%s\"", dcBuff.configDisplay.User);
	strcat((char *) Task_sendBuff, field);
	// APN-Pwd
	strcat((char *) Task_sendBuff, ",\"pwd\":");
	sprintf(field, "\"%s\"", dcBuff.configDisplay.Pwd);
	strcat((char *) Task_sendBuff, field);
	// sim card
	strcat((char *) Task_sendBuff, ",\"sim\":");
	sprintf(field, "\"%s\"", dcBuff.powerInfo.simNumber);
	strcat((char *) Task_sendBuff, field);
	// type
	strcat((char *) Task_sendBuff, ",\"type\":");
	sprintf(field, "%d", dcBuff.configBottle.type);
	strcat((char *) Task_sendBuff, field);
	// diameter
	strcat((char *) Task_sendBuff, ",\"dia\":");
	sprintf(field, "%d", dcBuff.configBottle.diameter);
	strcat((char *) Task_sendBuff, field);
	// len
	strcat((char *) Task_sendBuff, ",\"len\":");
	sprintf(field, "%d", dcBuff.configBottle.len + dcBuff.configBottle.lenExtra);
	strcat((char *) Task_sendBuff, field);
	// liquid
	strcat((char *) Task_sendBuff, ",\"liquid\":");
	sprintf(field, "%d", dcBuff.configBottle.source);
	strcat((char *) Task_sendBuff, field);
	// density
	strcat((char *) Task_sendBuff, ",\"density\":");
	sprintf(field, "%d", (uint16_t) (Config_GetDensity(dcBuff.configBottle.source) * 1000));
	strcat((char *) Task_sendBuff, field);
	// send
	strcat((char *) Task_sendBuff, ",\"send\":");
	sprintf(field, "%d", dcBuff.configData.intervalTrans);
	strcat((char *) Task_sendBuff, field);
	// save
	strcat((char *) Task_sendBuff, ",\"save\":");
	sprintf(field, "%d", dcBuff.configData.intervalSample);
	strcat((char *) Task_sendBuff, field);
	// level1
	strcat((char *) Task_sendBuff, ",\"level1\":");
	sprintf(field, "%.2f", dcBuff.configBottle.priPct * 0.01);
	strcat((char *) Task_sendBuff, field);
	// level2
	strcat((char *) Task_sendBuff, ",\"level2\":");
	sprintf(field, "%.2f", dcBuff.configBottle.orderPct * 0.01);
	strcat((char *) Task_sendBuff, field);
	// level3
	strcat((char *) Task_sendBuff, ",\"level3\":");
	sprintf(field, "%.2f", dcBuff.configBottle.emptyPct * 0.01);
	strcat((char *) Task_sendBuff, field);
	// server
	strcat((char *) Task_sendBuff, ",\"server\":");
	sprintf(field, "\"%s\"", dcBuff.configData.server);
	strcat((char *) Task_sendBuff, field);
	// port
	strcat((char *) Task_sendBuff, ",\"port\":");
	sprintf(field, "%d", dcBuff.configData.port);
	strcat((char *) Task_sendBuff, field);
	
	//结束符，多发送一个换行符('\n')
	strcat((char *) Task_sendBuff, "}\n");

	return strlen((char *) Task_sendBuff);	
}

// 解析巴西数据
int parse_brasil_recv_data(char *recv, gprs_data_t *pGprs, uint32_t totalSeconds)
{
	char *src = recv;
	char psn[14], time[15];
    S_RTC_TIME_DATA_T sRTC;
	uint8_t i;
	uint8_t psnMatch = 0, timeMatch = 0;

	if(!JSON_Parse_Record(&src))
		return 0;

	for(i = 0; i < JSON_FIELD_COUNT; i++)
	{
		if(JSON_Record[i].type == JSON_TYPE_NULL)
			continue;
		if(JSON_Record[i].type == JSON_TYPE_INTEGER)
			printf("%s\t%s\t%ld\n", JSON_Record[i].name, "INTEGER", JSON_Record[i].i);
		else if(JSON_Record[i].type == JSON_TYPE_FLOAT)
			printf("%s\t%s\t%f\n", JSON_Record[i].name, "FLOAT", JSON_Record[i].f);
		else
			printf("%s\t%s\t%s\n", JSON_Record[i].name, "STRING", JSON_Record[i].s);
	}
	
	// PSN
	sprintf(psn, "20%02d%02d%02d%02d%03d", 
		dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], dcBuff.configBottle.PSN[2],
		dcBuff.configBottle.PSN[3], (dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
	// 取数时间
	Wakeup_CalcUTCTime(pGprs->sample_time + RTC_offsetSeconds, &sRTC);
	sprintf(time, "%04d%02d%02d%02d%02d%02d", sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
		sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);

	// 检查PSN和数据时间
	for(int i = 0; i < JSON_FIELD_COUNT; i++)
	{
		if(JSON_Record[i].type == JSON_TYPE_NULL)
			continue;
		if(strcmp(JSON_Record[i].name, "psn") == 0 && strcmp(psn, JSON_Record[i].s) == 0)
		{
			psnMatch = 1;
		}
		if(strcmp(JSON_Record[i].name, "time") == 0 && strcmp(time, JSON_Record[i].s) == 0)
		{
			timeMatch = 1;
		}
	}
	
	if(psnMatch && timeMatch)
		return 1;

	printf("psn or time NOT matched\n");
	return 0;
}

int save_brasil_issue_parameters()
{
	uint8_t i;
	int ret = 0;
	uint16_t f2i;
	
	for(i = 0; i < JSON_FIELD_COUNT; i++)
	{
		if(JSON_Record[i].type == JSON_TYPE_NULL)
			continue;
		if(strcmp(JSON_Record[i].name, "apn") == 0)
		{
			if(strlen(JSON_Record[i].s) >= 1 && strlen(JSON_Record[i].s) <= 23 
				&& strcmp(dcBuff.configDisplay.APN, JSON_Record[i].s) != 0)
			{
				printf("change apn to: %s\n", JSON_Record[i].s);
				strcpy(dcBuff.configDisplay.APN, JSON_Record[i].s);
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "user") == 0)
		{
			if(strlen(JSON_Record[i].s) <= 9 
				&& strcmp(dcBuff.configDisplay.User, JSON_Record[i].s) != 0)
			{
				printf("change user to: %s\n", JSON_Record[i].s);
				strcpy(dcBuff.configDisplay.User, JSON_Record[i].s);
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "pwd") == 0)
		{
			if(strlen(JSON_Record[i].s) <= 9 
				&& strcmp(dcBuff.configDisplay.Pwd, JSON_Record[i].s) != 0)
			{
				printf("change pwd to: %s\n", JSON_Record[i].s);
				strcpy(dcBuff.configDisplay.Pwd, JSON_Record[i].s);
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "type") == 0)
		{
			if(JSON_Record[i].i >= 0 && JSON_Record[i].i <= 1 
				&& dcBuff.configBottle.type != JSON_Record[i].i)
			{
				printf("change type to: %ld\n", JSON_Record[i].i);
				dcBuff.configBottle.type = JSON_Record[i].i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "dia") == 0)
		{
			if(JSON_Record[i].i >= 1 && JSON_Record[i].i <= 99999 
				&& dcBuff.configBottle.diameter != JSON_Record[i].i)
			{
				printf("change dia to: %ld\n", JSON_Record[i].i);
				dcBuff.configBottle.diameter = JSON_Record[i].i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "len") == 0)
		{
			if(JSON_Record[i].i >= 1 && JSON_Record[i].i <= 99999 
				&& dcBuff.configBottle.len != JSON_Record[i].i)
			{
				printf("change len to: %ld\n", JSON_Record[i].i);
				dcBuff.configBottle.len = JSON_Record[i].i;
				dcBuff.configBottle.lenExtra = 0;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "liquid") == 0)
		{
			if(JSON_Record[i].i >= 0 && JSON_Record[i].i <= 4 
				&& dcBuff.configBottle.source != JSON_Record[i].i)
			{
				printf("change liquid to: %ld\n", JSON_Record[i].i);
				dcBuff.configBottle.source = JSON_Record[i].i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "send") == 0)
		{
			if(JSON_Record[i].i >= 300 && JSON_Record[i].i <= 86400 
				&& dcBuff.configData.intervalTrans != JSON_Record[i].i)
			{
				printf("change send to: %ld\n", JSON_Record[i].i);
				dcBuff.configData.intervalTrans = JSON_Record[i].i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "save") == 0)
		{
			if(JSON_Record[i].i >= 300 && JSON_Record[i].i <= 86400 
				&& dcBuff.configData.intervalSample != JSON_Record[i].i)
			{
				printf("change save to: %ld\n", JSON_Record[i].i);
				dcBuff.configData.intervalSample = JSON_Record[i].i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "level1") == 0)
		{
			f2i = (uint16_t) (JSON_Record[i].f * 100);
			if(f2i >= 0 && f2i <= 100 * 100 
				&& dcBuff.configBottle.priPct != f2i)
			{
				printf("change level1 to: %f\n", JSON_Record[i].f);
				dcBuff.configBottle.priPct = f2i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "level2") == 0)
		{
			f2i = (uint16_t) (JSON_Record[i].f * 100);
			if(f2i >= 0 && f2i <= 100 * 100 
				&& dcBuff.configBottle.orderPct != f2i)
			{
				printf("change level2 to: %f\n", JSON_Record[i].f);
				dcBuff.configBottle.orderPct = f2i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "level3") == 0)
		{
			f2i = (uint16_t) (JSON_Record[i].f * 100);
			if(f2i >= 0 && f2i <= 100 * 100 
				&& dcBuff.configBottle.emptyPct != f2i)
			{
				printf("change level3 to: %f\n", JSON_Record[i].f);
				dcBuff.configBottle.emptyPct = f2i;
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "server") == 0)
		{
			if(strlen(JSON_Record[i].s) >= 1 && strlen(JSON_Record[i].s) <= 29 
				&& strcmp(dcBuff.configData.server, JSON_Record[i].s) != 0)
			{
				printf("change server to: %s\n", JSON_Record[i].s);
				strcpy(dcBuff.configData.server, JSON_Record[i].s);
				ret++;
			}
		}
		else if(strcmp(JSON_Record[i].name, "port") == 0)
		{
			if(JSON_Record[i].i >= 0 && JSON_Record[i].i <= 65535 
				&& dcBuff.configData.port != JSON_Record[i].i)
			{
				printf("change port to: %ld\n", JSON_Record[i].i);
				dcBuff.configData.port = JSON_Record[i].i;
				ret++;
			}
		}
	}
	
	// 最后再修改密度（因为要先确定介质）
	for(i = 0; i < JSON_FIELD_COUNT; i++)
	{
		if(JSON_Record[i].type == JSON_TYPE_NULL)
			continue;
		if(strcmp(JSON_Record[i].name, "density") == 0)
		{
			f2i = (uint16_t) (Config_GetDensity(dcBuff.configBottle.source) * 1000);
			
			if(JSON_Record[i].i >= 1 && JSON_Record[i].i <= 9999 
				&& f2i != JSON_Record[i].i)
			{
				printf("change density to: %ld\n", JSON_Record[i].i);
				Config_SetDensity(dcBuff.configBottle.source, JSON_Record[i].i * 0.001);
				ret++;
			}
		}
	}
	
	if(ret > 0)
	{
		printf("changed %d parameters\n", ret);
		return 1;
	}
	
	return 0;
}

uint8_t pack_gprs_send_data(gprs_data_t *pGprs, uint32_t totalSeconds)
{
	uint8_t i;
	bluetooth_sensor_t *pSensor;
	bluetooth_mask_t   *pMask;
	uint32_t relativeTime;
    S_RTC_TIME_DATA_T sRTC;
	uint16_t crc;	

	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	i = 0;
	// PSN
	memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
	printf("\nSend PSN: 20%02d%02d%02d%02d%03d\n", Task_sendBuff[i], Task_sendBuff[i + 1], Task_sendBuff[i + 2],
		Task_sendBuff[i+3], (Task_sendBuff[i + 4] << 8) | Task_sendBuff[i + 5]);
	
	i += 6;
	// 功能码
	Task_sendBuff[i++] = 0x10;
	// 数据长度：先预设为0，最后再修改，位置为Task_sendBuff[7]
	Task_sendBuff[i++] = 0;
	
	// 当前差压值
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.diff));
	i +=2 ;
	// 容积百分比
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.volumePct));
	i += 2;
	// 当前容积
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.volume));
	i += 4;
	// 重量
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.weight));
	i += 4;
	// 高度：mmWC
	if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR && !dcBuff.configDisplay.op_USE_HEIGHT_LEVEL && !dcBuff.configDisplay.op_USE_PCT_LEVEL)
		Int2ByteS(Task_sendBuff, i, htons((uint16_t) KPa2mmH2O(pGprs->sampleData.diff)));
	else
		Int2ByteS(Task_sendBuff, i, htons((uint16_t) pGprs->sampleData.height));
	i += 2;
	// 压力
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.pressure));
	i += 2;
#if 0								
	// 温度
	Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batTempr);
#else
	// 用温度表示自启动以来的时间分钟数，32767分钟
	Int2ByteS(Task_sendBuff, i, htons((totalSeconds % 1966080ul) / 60));
#endif
	i += 2;
	// 液源
	if(dcBuff.configBottle.source >= SOURCE_LNG && dcBuff.configBottle.source <= SOURCE_POPO)
		Task_sendBuff[i] = dcBuff.configBottle.source;
	i++;
	// 储罐类型
	if(dcBuff.configBottle.type == BOTTLE_TYPE_STAND)
		Task_sendBuff[i] = 0;
	else if(dcBuff.configBottle.type == BOTTLE_TYPE_LYING)
		Task_sendBuff[i] = 1;
	else if(dcBuff.configBottle.type == BOTTLE_TYPE_SPHERICAL)
		Task_sendBuff[i] = 2;
	i++;
	// 故障码
	pSensor = (bluetooth_sensor_t *) (Task_sendBuff + i);
	
	pSensor->staDiff = Bluetooth_ConvertStat(&pGprs->sampleData.staDPress);
	pSensor->staPress = Bluetooth_ConvertStat(&pGprs->sampleData.staPress);
	pSensor->staEPress1 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtPress[0]);
	pSensor->staEPress2 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtPress[1]);
	pSensor->staEPress3 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtPress[2]);
	pSensor->staETempr1 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtTempr[0]);
	pSensor->staETempr2 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtTempr[1]);
	pSensor->staETempr3 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtTempr[2]);
	i += 2;
	// 传感器状态
	pMask = (bluetooth_mask_t *) (Task_sendBuff + i);
	memset(pMask, 0xFF, 2);
	pMask->maskFlow = 1;
	pMask->maskLowPower = pGprs->dtuData.batLow;
	pMask->maskAbnormal = 0;
	pMask->maskCharging = pGprs->sampleData.charging;
	i += 2;
	
	// 版本号
	Task_sendBuff[i++] = dcBuff.powerInfo.protocolVer.minor;
	// rssi
	Task_sendBuff[i++] = pGprs->dtuData.rssi;
	if(pMask->maskGPS)
	{
		 // 经度
		if(pGprs->dtuData.recentPosState)
			Int2ByteL(Task_sendBuff, i, htonl(pGprs->dtuData.longitude));
		i += 4;
		
		// 纬度
		if(pGprs->dtuData.recentPosState)
			Int2ByteL(Task_sendBuff, i, htonl(pGprs->dtuData.latitude));
		i += 4;
	}
	// 扩展温度
	if(pMask->maskETempr1)
	{
		Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extTempr[0]));
		i += 2;
	}
	if(pMask->maskETempr2)
	{
		Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extTempr[1]));
		i += 2;
	}
	if(pMask->maskETempr3)
	{
#if 0
		// 扩展温度3
		Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extTempr[2]));
#else
		// 用扩展温度3表示硬件配置
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.powerInfo.hardVer.major));
#endif
		i += 2;
	}
	
	// 电池信息
	if(pMask->maskBattery)
	{
		// 电量百分比
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batPct));
		i += 2;
		// 电池内部温度
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batTempr));
		i += 2;
		// 电池当前电压
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batVoltage / 10));
		i += 2;
		// 电池容量
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batMaxCapa));
		i += 2;
		// 电池当前容量
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batCapa));
		i += 2;
#if 0									
		// 充电电流，电流的符号表示充放电状态
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batCurrent));
#else
		// 用电流的绝对值表示复位原因
		// 1-POR, 2-PIN, 4-WDT, 8-LVR, 16-BOD, 32-SYS, 128-CPU, 256-CPULK
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batCurrent > 0 ? SYS_RSTSTS : -SYS_RSTSTS));
#endif									
		i += 2;
		// 光照强度
		Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.sunLevel));
		i += 2;
	}
	
	// 流量计
	if(pMask->maskFlow)
	{
		// 天信MODBUS /A1 通信协议 (BCD码）
		// 标况体积总量
		memmove(Task_sendBuff + i, pGprs->sampleData.flow.nM3, 6);
		i += 6;
		// 标况流量
		memmove(Task_sendBuff + i, pGprs->sampleData.flow.nM3_h, 4);
		i += 4;
		// 工况流量
		memmove(Task_sendBuff + i, pGprs->sampleData.flow.M3_h, 4);
		i += 4;
		// 温度
		memmove(Task_sendBuff + i, pGprs->sampleData.flow.tempr, 4);
		i += 4;
		// 压力
		memmove(Task_sendBuff + i, pGprs->sampleData.flow.pressure, 4);
		i += 4;
	}
	
	// 泄露报警
	if(pMask->maskLeak)
	{
		// 类型
		Task_sendBuff[i++] = pGprs->sampleData.leak.typeLeak;
		// 状态、报警浓度
		if(pGprs->sampleData.leak.staLeak == LEAK_STATUS_FAULT || pGprs->sampleData.leak.staLeak == LEAK_STATUS_COMM_FAULT)
			Task_sendBuff[i] = 0x80;
		else
			Task_sendBuff[i] = (pGprs->sampleData.leak.concentrations & 0x7F);
		i++;
	}
	
	if(pMask->maskStamp)
	{
		if(dcBuff.powerInfo.protocolVer.minor == 107)
		{
			// 获取当前时间
			RTC_GetDateAndTime(&sRTC);
			// 计算自上次gps定位以来的时间
			relativeTime = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
					sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second) - pGprs->sample_time;
			Int2ByteL(Task_sendBuff, i, htonl(relativeTime));
		}
		// 时间
		i += 4;
		// 年月日
		i += 4;
	}
	
	// 扩展压力
	if(pMask->maskEPress1)
	{
		Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extPressure[0]));
		i += 2;
	}
	if(pMask->maskEPress2)
	{
		Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extPressure[1]));
		i += 2;
	}
	if(pMask->maskEPress3)
	{
#if 0
		// 扩展压力3
		Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extPressure[2]));
#else
		// 上传GPS调试信息: 闪断次数*100+卫星数
		// 如2105表示闪断21次，卫星数5颗
		Int2ByteS(Task_sendBuff, i, htons(GPS_BOD_COUNT * 100 + pGprs->dtuData.sateCount));
		printf("\nGPS_DEBUG_VAL: %d\n", ntohs(Byte2IntS(Task_sendBuff, i)));
#endif
		i += 2;
	}
	
	printf("\ndcBuff.powerInfo.hardVer.major = %d, dcBuff.powerInfo.softVer.minor = %d\n",
		dcBuff.powerInfo.hardVer.major, dcBuff.powerInfo.softVer.minor);
	// 硬件版本
	//Task_sendBuff[i++] = ((dcBuff.powerInfo.hardVer.minor / 10) << 4) + dcBuff.powerInfo.hardVer.minor % 10;
	Task_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor;
	// 软件版本
	//Task_sendBuff[i++] = ((dcBuff.powerInfo.softVer.minor / 10) << 4) + dcBuff.powerInfo.softVer.minor % 10;;
	Task_sendBuff[i++] = dcBuff.powerInfo.softVer.minor;
	
	// 真空传感器1
	if(pGprs->sampleData.vacuum[0].staVacuum == VACUUM_STATUS_FAULT || pGprs->sampleData.vacuum[0].staVacuum == VACUUM_STATUS_COMM_FAULT)
		Int2ByteS(Task_sendBuff, i, htons(0));
	else
		Int2ByteS(Task_sendBuff, i, htons(1));
	i += 2;
	// 使用年限
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.vacuum[0].lifeVacuum));
	i += 2;
	// 真空度
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.vacuum[0].vacuum * 100));
	i += 4;
	// 漏放气速率
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.vacuum[0].rateVacuum * 100));
	i += 4;
	// 船级社维持时间
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.ccsRemainDay));
	i += 2;
	// 算法版本
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.ccsVer));
	i += 4;
	// 保留
	i += 2;
	// 保留
	i += 4;
	
	// 气瓶容量
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.volumeTotal));
	i += 4;
	// 储罐封头直边长
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.lenExtra));
	i += 2;
	// 储罐筒长度
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.len));
	i += 4;
	// 储罐直径
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.diameter));
	i += 4;
	// 自动发送频率
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configData.intervalTrans / 60));
	i += 2;
	// 自动发送短信频率（实际发送采集频率）
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configData.intervalSample / 60));
	i += 2;
	
	// 修改数据长度
	Task_sendBuff[7] = i - 8;
	
	// 校验码
	crc = MODBUS_RTU_CRC16((uint8_t *) Task_sendBuff, i);
	Int2ByteS(Task_sendBuff, i, htons(crc));
	i += 2;
	// 结束符
	Task_sendBuff[i++] = 0x0d;
	Task_sendBuff[i++] = 0x0a;
	
	return i;
}

uint8_t pack_furui_send_data(gprs_data_t *pGprs, uint32_t *relativeTime)
{
	uint8_t i;
	uint32_t uVal32;
    S_RTC_TIME_DATA_T sRTC;
	uint16_t crc;	

	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	i = 0;

	// 起始符
	Task_sendBuff[i++] = 0x4C;
	
	// 总长度：先预设为0，最后再修改，位置为Task_sendBuff[1]
	Task_sendBuff[i++] = 0;	
	// 协议版本
	Task_sendBuff[i++] = 1;	
	// 硬件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor;
	// 软件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.softVer.minor;

	// PSN
	memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
	printf("\nSend PSN: 20%02d%02d%02d%02d%03d\n", Task_sendBuff[i], Task_sendBuff[i + 1], Task_sendBuff[i + 2],
		Task_sendBuff[i+3], (Task_sendBuff[i + 4] << 8) | Task_sendBuff[i + 5]);	
	i += 6;
	
	// 时间戳
	RTC_GetDateAndTime(&sRTC);
	*relativeTime = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
			sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second) - pGprs->sample_time;
	Int2ByteL(Task_sendBuff, i, htonl(*relativeTime));
	i += 4;
	
	// 传感器状态
	uVal32 = 0xFFFFFFFFul;
	// 连接状态
	if(!pGprs->sampleData.staDPress.notConnect)
		uVal32 &= ~(1ul << 0);
	if(!pGprs->sampleData.staPress.notConnect)
		uVal32 &= ~(1ul << 1);
	if(!pGprs->sampleData.staExtPress[0].notConnect)
		uVal32 &= ~(1ul << 2);
	if(!pGprs->sampleData.staExtTempr[0].notConnect)
		uVal32 &= ~(1ul << 3);
	if(!pGprs->sampleData.staExtTempr[1].notConnect)
		uVal32 &= ~(1ul << 4);
	if(!(pGprs->sampleData.vacuum[0].staVacuum == VACUUM_STATUS_COMM_FAULT))
		uVal32 &= ~(1ul << 5);
	if(1)	 // 流量计
		uVal32 &= ~(1ul << 6);
	if(!(pGprs->sampleData.leak.staLeak == LEAK_STATUS_COMM_FAULT))
		uVal32 &= ~(1ul << 7);
	// 故障状态
	if(!(pGprs->sampleData.staDPress.overFlow || pGprs->sampleData.staDPress.underFlow))
		uVal32 &= ~(1ul << 8);
	if(!(pGprs->sampleData.staPress.overFlow || pGprs->sampleData.staPress.underFlow))
		uVal32 &= ~(1ul << 9);
	if(!(pGprs->sampleData.staExtPress[0].overFlow || pGprs->sampleData.staExtPress[0].underFlow))
		uVal32 &= ~(1ul << 10);
	if(!(pGprs->sampleData.staExtTempr[0].overFlow || pGprs->sampleData.staExtTempr[0].underFlow))
		uVal32 &= ~(1ul << 11);
	if(!(pGprs->sampleData.staExtTempr[1].overFlow || pGprs->sampleData.staExtTempr[1].underFlow))
		uVal32 &= ~(1ul << 12);
	if(!(pGprs->sampleData.vacuum[0].staVacuum == VACUUM_STATUS_FAULT))
		uVal32 &= ~(1ul << 13);
	if(1) // 流量计
		uVal32 &= ~(1ul << 14);
	if(!(pGprs->sampleData.leak.staLeak == LEAK_STATUS_FAULT))
		uVal32 &= ~(1ul << 15);
	Int2ByteL(Task_sendBuff, i, htonl(uVal32));
	i += 4;
	
	// 当前差压值：mmWC
	if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR && !dcBuff.configDisplay.op_USE_HEIGHT_LEVEL && !dcBuff.configDisplay.op_USE_PCT_LEVEL)
		Int2ByteS(Task_sendBuff, i, htons((uint16_t) KPa2mmH2O(pGprs->sampleData.diff)));
	else
		Int2ByteS(Task_sendBuff, i, htons((uint16_t) pGprs->sampleData.height));
	i +=2 ;
	// 容积百分比
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.volumePct));
	i += 2;
	// 当前容积
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.volume));
	i += 4;
	// 重量
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.weight));
	i += 4;
	// 气瓶容量
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.volumeTotal));
	i += 4;
	// 压力1
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.pressure));
	i += 2;
	// 压力2
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extPressure[0]));
	i += 2;
	// 温度1
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extTempr[0]));
	i += 2;
	// 温度2
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extTempr[1]));
	i += 2;
	
	// 真空度
	Int2ByteS(Task_sendBuff, i, htons((uint16_t) (pGprs->sampleData.vacuum[0].vacuum * 100)));
	i += 2;
	// 真空计温度
	Int2ByteS(Task_sendBuff, i, htons((int16_t) pGprs->sampleData.vacuum[0].tempr));
	i += 2;
	
	// 天信MODBUS /A1 通信协议 (BCD码）
	// 标况体积总量
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.nM3, 6);
	i += 6;
	// 标况流量
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.nM3_h, 4);
	i += 4;
	// 工况流量
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.M3_h, 4);
	i += 4;
	// 流量计温度
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.tempr, 4);
	i += 4;
	// 流量计压力
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.pressure, 4);
	i += 4;

	// 泄露状态
	Task_sendBuff[i++] = (pGprs->sampleData.leak.staLeak == LEAK_STATUS_A2_ALARM ? 1 : 0);
	
	 // 经度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, htonl(pGprs->dtuData.longitude));
	i += 4;
	// 纬度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, htonl(pGprs->dtuData.latitude));
	i += 4;
	
	// rssi
	Task_sendBuff[i++] = pGprs->dtuData.rssi;

	// 电量百分比
	Task_sendBuff[i++] = pGprs->dtuData.batPct;
	// 电池当前电压
	Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batVoltage / 10));
	i += 2;
	// 供电状态
	Task_sendBuff[i++] = (pGprs->dtuData.batCurrent < 0 ? -1 : 1);
	
	// 液源
	if(dcBuff.configBottle.source >= SOURCE_LNG && dcBuff.configBottle.source <= SOURCE_POPO)
		Task_sendBuff[i] = dcBuff.configBottle.source;
	i++;	
	// 密度
	Int2ByteS(Task_sendBuff, i, htons(Config_GetDensity(dcBuff.configBottle.source) * 1000));
	i += 2;
	
	// 储罐类型
	if(dcBuff.configBottle.type == BOTTLE_TYPE_STAND)
		Task_sendBuff[i] = 0;
	else if(dcBuff.configBottle.type == BOTTLE_TYPE_LYING)
		Task_sendBuff[i] = 1;
	else if(dcBuff.configBottle.type == BOTTLE_TYPE_SPHERICAL)
		Task_sendBuff[i] = 2;
	i++;
	// 储罐直径
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.diameter));
	i += 4;
	// 储罐筒长度
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.len + dcBuff.configBottle.lenExtra * 2));
	i += 4;
	
	// 采集周期
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configData.intervalSample));
	i += 4;
	// 发送周期
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configData.intervalTrans));
	i += 4;
	
	// 满液位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.fullPct));
	i += 2;
	// 关键液位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.priPct));
	i += 2;
	// 订货位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.orderPct));
	i += 2;
	// 空液位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.emptyPct));
	i += 2;
	// 压力报警上限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnPressH));
	i += 2;
	// 压力报警下限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnPress));
	i += 2;
	// 温度报警上限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnTemprH));
	i += 2;
	// 温度报警下限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnTempr));
	i += 2;
	// 真空度报警上限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnVacuumH));
	i += 2;
	// 显示控制
	Task_sendBuff[i++] = dcBuff.configBottle.dispMode;
	
	// 修改数据长度
	Task_sendBuff[1] = i - 1 + 2;
	
	// 校验码
	crc = MODBUS_RTU_CRC16(Task_sendBuff + 1, i - 1);
	Int2ByteS(Task_sendBuff, i, htons(crc));
	i += 2;
	// 结束符
	Task_sendBuff[i++] = 0x53;
	
	return i;
}

uint8_t pack_huida_send_data(gprs_data_t *pGprs, uint32_t *relativeTime)
{
	uint8_t i;
	uint32_t uVal32;
    S_RTC_TIME_DATA_T sRTC;
	uint16_t crc;	

	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	i = 0;

	// 起始符
	Task_sendBuff[i++] = 0x4C;
	
	// 总长度：先预设为0，最后再修改，位置为Task_sendBuff[1]
	Task_sendBuff[i++] = 0;	
	// 协议版本
	Task_sendBuff[i++] = 1;	
	// 硬件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor;
	// 软件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.softVer.minor;

	// PSN
	memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
	printf("\nSend PSN: 20%02d%02d%02d%02d%03d\n", Task_sendBuff[i], Task_sendBuff[i + 1], Task_sendBuff[i + 2],
		Task_sendBuff[i+3], (Task_sendBuff[i + 4] << 8) | Task_sendBuff[i + 5]);	
	i += 6;
	
	// 时间戳
	RTC_GetDateAndTime(&sRTC);
	*relativeTime = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
			sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second) - pGprs->sample_time;
	Int2ByteL(Task_sendBuff, i, htonl(*relativeTime));
	i += 4;
	
	// 传感器状态
	uVal32 = 0xFFFFFFFFul;
	// 连接状态
	if(!pGprs->sampleData.staDPress.notConnect)
		uVal32 &= ~(1ul << 0);
	if(!pGprs->sampleData.staPress.notConnect)
		uVal32 &= ~(1ul << 1);
	if(!pGprs->sampleData.staExtTempr[0].notConnect)
		uVal32 &= ~(1ul << 2);
	if(!pGprs->sampleData.staExtTempr[1].notConnect)
		uVal32 &= ~(1ul << 3);
	if(!(pGprs->sampleData.vacuum[0].staVacuum == VACUUM_STATUS_COMM_FAULT))
		uVal32 &= ~(1ul << 6);
	if(!(pGprs->sampleData.leak.staLeak == LEAK_STATUS_COMM_FAULT))
		uVal32 &= ~(1ul << 7);
	// 故障状态
	if(!(pGprs->sampleData.staDPress.overFlow || pGprs->sampleData.staDPress.underFlow))
		uVal32 &= ~(1ul << 8);
	if(!(pGprs->sampleData.staPress.overFlow || pGprs->sampleData.staPress.underFlow))
		uVal32 &= ~(1ul << 9);
	if(!(pGprs->sampleData.staExtTempr[0].overFlow || pGprs->sampleData.staExtTempr[0].underFlow))
		uVal32 &= ~(1ul << 10);
	if(!(pGprs->sampleData.staExtTempr[1].overFlow || pGprs->sampleData.staExtTempr[1].underFlow))
		uVal32 &= ~(1ul << 11);
	if(!(pGprs->sampleData.vacuum[0].staVacuum == VACUUM_STATUS_FAULT))
		uVal32 &= ~(1ul << 14);
	if(!(pGprs->sampleData.leak.staLeak == LEAK_STATUS_FAULT))
		uVal32 &= ~(1ul << 15);
	Int2ByteL(Task_sendBuff, i, htonl(uVal32));
	i += 4;
	
	// 当前差压值：mmWC
	if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR && !dcBuff.configDisplay.op_USE_HEIGHT_LEVEL && !dcBuff.configDisplay.op_USE_PCT_LEVEL)
		Int2ByteS(Task_sendBuff, i, htons((uint16_t) KPa2mmH2O(pGprs->sampleData.diff)));
	else
		Int2ByteS(Task_sendBuff, i, htons((uint16_t) pGprs->sampleData.height));
	i +=2 ;
	// 容积百分比
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.volumePct));
	i += 2;
	// 当前容积
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.volume));
	i += 4;
	// 重量
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.weight));
	i += 4;
	// 气瓶容量
	Int2ByteL(Task_sendBuff, i, htonl(pGprs->sampleData.volumeTotal));
	i += 4;
	// 压力1
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.pressure));
	i += 2;
	// 温度1
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extTempr[0]));
	i += 2;
	// 温度2
	Int2ByteS(Task_sendBuff, i, htons(pGprs->sampleData.extTempr[1]));
	i += 2;
	// 温度3
	i += 2;
	// 温度4
	i += 2;
	
	// 真空度
	Int2ByteS(Task_sendBuff, i, htons((uint16_t) (pGprs->sampleData.vacuum[0].vacuum * 100)));
	i += 2;
	// 真空计温度
	Int2ByteS(Task_sendBuff, i, htons((int16_t) pGprs->sampleData.vacuum[0].tempr));
	i += 2;
	
#if 0	
	// 天信MODBUS /A1 通信协议 (BCD码）
	// 标况体积总量
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.nM3, 6);
	i += 6;
	// 标况流量
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.nM3_h, 4);
	i += 4;
	// 工况流量
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.M3_h, 4);
	i += 4;
	// 流量计温度
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.tempr, 4);
	i += 4;
	// 流量计压力
	memmove(Task_sendBuff + i, pGprs->sampleData.flow.pressure, 4);
	i += 4;
#endif

	// 泄露状态
	Task_sendBuff[i++] = (pGprs->sampleData.leak.staLeak == LEAK_STATUS_A2_ALARM ? 1 : 0);
	
	 // 经度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, htonl(pGprs->dtuData.longitude));
	i += 4;
	// 纬度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, htonl(pGprs->dtuData.latitude));
	i += 4;
	
	// rssi
	Task_sendBuff[i++] = pGprs->dtuData.rssi;

	// 电量百分比
	Task_sendBuff[i++] = pGprs->dtuData.batPct;
	// 电池当前电压
	Int2ByteS(Task_sendBuff, i, htons(pGprs->dtuData.batVoltage / 10));
	i += 2;
	// 供电状态
	Task_sendBuff[i++] = (pGprs->dtuData.batCurrent < 0 ? -1 : 1);
	
	// 液源
	if(dcBuff.configBottle.source >= SOURCE_LNG && dcBuff.configBottle.source <= SOURCE_POPO)
		Task_sendBuff[i] = dcBuff.configBottle.source;
	i++;	
	// 密度
	Int2ByteS(Task_sendBuff, i, htons(Config_GetDensity(dcBuff.configBottle.source) * 1000));
	i += 2;
	
	// 储罐类型
	if(dcBuff.configBottle.type == BOTTLE_TYPE_STAND)
		Task_sendBuff[i] = 0;
	else if(dcBuff.configBottle.type == BOTTLE_TYPE_LYING)
		Task_sendBuff[i] = 1;
	else if(dcBuff.configBottle.type == BOTTLE_TYPE_SPHERICAL)
		Task_sendBuff[i] = 2;
	i++;
	// 储罐直径
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.diameter));
	i += 4;
	// 储罐筒长度
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.len + dcBuff.configBottle.lenExtra * 2));
	i += 4;
	
	// 采集周期
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configData.intervalSample));
	i += 4;
	// 发送周期
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configData.intervalTrans));
	i += 4;
	
	// 满液位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.fullPct));
	i += 2;
	// 关键液位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.priPct));
	i += 2;
	// 订货位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.orderPct));
	i += 2;
	// 空液位百分比
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.emptyPct));
	i += 2;
	// 压力报警上限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnPressH));
	i += 2;
	// 压力报警下限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnPress));
	i += 2;
	// 温度报警上限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnTemprH));
	i += 2;
	// 温度报警下限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnTempr));
	i += 2;
	// 真空度报警上限
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnVacuumH));
	i += 2;
	// 显示控制
	Task_sendBuff[i++] = dcBuff.configBottle.dispMode;
	
	// 修改数据长度
	Task_sendBuff[1] = i - 1 + 2;
	
	// 校验码
	crc = MODBUS_RTU_CRC16(Task_sendBuff + 1, i - 1);
	Int2ByteS(Task_sendBuff, i, htons(crc));
	i += 2;
	// 结束符
	Task_sendBuff[i++] = 0x53;
	
	return i;
}

uint8_t pack_chaoyang_send_data(gprs_data_t *pGprs, uint32_t *relativeTime)
{
	uint8_t i;
	uint32_t uVal32;

	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	i = 0;

	// IMSI
	memmove(Task_sendBuff + i, dcBuff.powerInfo.simNumber, strlen(dcBuff.powerInfo.simNumber));
	i += 15;
	
	//  压力状态、压力值
	if(pGprs->sampleData.staPress.notConnect || pGprs->sampleData.staPress.underFlow || pGprs->sampleData.staPress.overFlow)
	{
		Task_sendBuff[i++] = '0';
		sprintf((s8 *) Task_sendBuff + i, "%05d", 0);
	}
	else
	{
		Task_sendBuff[i++] = '1';
		sprintf((s8 *) Task_sendBuff + i, "%05d", pGprs->sampleData.pressure / 10); // 0.1MPa
	}
	i += 5;

	//  液位状态、液量值
	if(pGprs->sampleData.staDPress.notConnect || pGprs->sampleData.staDPress.underFlow || pGprs->sampleData.staDPress.overFlow)
	{
		Task_sendBuff[i++] = '0';
		sprintf((s8 *) Task_sendBuff + i, "%05d", 0);
	}
	else
	{
		Task_sendBuff[i++] = '1';
		sprintf((s8 *) Task_sendBuff + i, "%05d", pGprs->sampleData.volume / 10); // 0.1m3
	}
	i += 5;

	//  电池电压
	Task_sendBuff[i++] = '1';
	sprintf((s8 *) Task_sendBuff + i, "%05d", pGprs->dtuData.batVoltage / 10);	// 0.1v
	i += 5;

	//  充电状态
	Task_sendBuff[i++] = '1';
	sprintf((s8 *) Task_sendBuff + i, "%05d", VCC_POWER_STATUS() ? 1 * 100 : 0);
	i += 5;
	
	// 结束符
	sprintf((s8 *) Task_sendBuff + i, "\r\n");
	i += 2;
	
	return i;
}

uint8_t parse_furui_recv_data(uint8_t PSN[6], uint32_t relativeTime, uint16_t recvLen)
{
	uint8_t i, j, len, protocol;
	uint32_t mask, uVal32;
	uint16_t uVal16;
	int16_t val16;
	uint8_t saveConfig = 0;
 
	i = 0;	
	// 检查起始符、结束符
	if(Task_recvBuff[i++] != 0x4C || Task_recvBuff[recvLen - 1] != 0x53)
		return 0;
	// 检查数据长度和CRC
	len = Task_recvBuff[i++];	
	if(len != recvLen - 2 || MODBUS_RTU_CRC16(Task_recvBuff + 1, len) != 0)
		return 0;
	// 检查协议版本
	protocol = Task_recvBuff[i++];
	if(protocol != 1)
		return 0;
	// 检查PSN
	if(memcmp(Task_recvBuff + i, PSN, 6) != 0)
		return 0;
	i += 6;
	// 检查时间戳
	if(ntohl(Byte2IntL(Task_recvBuff, i)) != relativeTime)
		return 0;
	i += 4;
	// 参数更新标志
	mask = ntohl(Byte2IntL(Task_recvBuff, i));
	i += 4;
	
	j = 0;
	// 介质
	if(mask & (1ul << (j++)))
	{
		printf("modify source\r\n");
		if(dcBuff.configBottle.source != Task_recvBuff[i])
		{
			dcBuff.configBottle.source = Task_recvBuff[i];
			saveConfig = 1;
		}
	}
	i++;
	
	// 密度
	if(mask & (1ul << (j++)))
	{
		printf("modify density\r\n");
		uVal16 = ntohs(Byte2IntS(Task_recvBuff, i));
		if(Config_GetDensity(dcBuff.configBottle.source) * 1000 != uVal16)
		{
			Config_SetDensity(dcBuff.configBottle.source, uVal16 / 1000.0);
			saveConfig = 1;
		}
	}
	i += 2;

	// 储罐类型
	if(mask & (1ul << (j++)))
	{
		printf("modify type\r\n");
		if(dcBuff.configBottle.type != Task_recvBuff[i])
		{
			dcBuff.configBottle.type = Task_recvBuff[i];
			saveConfig = 1;
		}
	}
	i++;
	// 储罐直径
	if(mask & (1ul << (j++)))
	{
		printf("modify diameter\r\n");
		uVal32 = ntohl(Byte2IntL(Task_recvBuff, i));
		if(dcBuff.configBottle.diameter != uVal32)
		{
			dcBuff.configBottle.diameter = uVal32;
			saveConfig = 1;
		}
	}
	i += 4;
	// 储罐筒长度
	if(mask & (1ul << (j++)))
	{
		printf("modify len\r\n");
		uVal32 = ntohl(Byte2IntL(Task_recvBuff, i));
		if(dcBuff.configBottle.lenExtra != 0 || dcBuff.configBottle.len != uVal32)
		{
			dcBuff.configBottle.lenExtra = 0;
			dcBuff.configBottle.len = uVal32;
			saveConfig = 1;
		}
	}
	i += 4;
	
	// 采集周期
	if(mask & (1ul << (j++)))
	{
		printf("modify intervalSample\r\n");
		uVal32 = ntohl(Byte2IntL(Task_recvBuff, i));
		if(dcBuff.configData.intervalSample != uVal32)
		{
			dcBuff.configData.intervalSample = uVal32;
			saveConfig = 1;
		}
	}
	i += 4;
	// 发送周期
	if(mask & (1ul << (j++)))
	{
		printf("modify intervalTrans\r\n");
		uVal32 = ntohl(Byte2IntL(Task_recvBuff, i));
		if(dcBuff.configData.intervalTrans != uVal32)
		{
			dcBuff.configData.intervalTrans = uVal32;
			saveConfig = 1;
		}
	}
	i += 4;
	
	// 满液位百分比
	if(mask & (1ul << (j++)))
	{
		printf("modify fullPct\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		if(dcBuff.configBottle.fullPct != uVal16)
		{
			dcBuff.configBottle.fullPct = uVal16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 关键液位百分比
	if(mask & (1ul << (j++)))
	{
		printf("modify priPct\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		if(dcBuff.configBottle.priPct != uVal16)
		{
			dcBuff.configBottle.priPct = uVal16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 订货位百分比
	if(mask & (1ul << (j++)))
	{
		printf("modify orderPct\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		if(dcBuff.configBottle.orderPct != uVal16)
		{
			dcBuff.configBottle.orderPct = uVal16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 空液位百分比
	if(mask & (1ul << (j++)))
	{
		printf("modify emptyPct\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		if(dcBuff.configBottle.emptyPct != uVal16)
		{
			dcBuff.configBottle.emptyPct = uVal16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 压力报警上限
	if(mask & (1ul << (j++)))
	{
		printf("modify warnPressH\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		if(dcBuff.configBottle.warnPressH != uVal16)
		{
			dcBuff.configBottle.warnPressH = uVal16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 压力报警下限
	if(mask & (1ul << (j++)))
	{
		printf("modify warnPress\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		if(dcBuff.configBottle.warnPress != uVal16)
		{
			dcBuff.configBottle.warnPress = uVal16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 温度报警上限
	if(mask & (1ul << (j++)))
	{
		printf("modify warnTemprH\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		memmove(&val16, &uVal16, 2);
		if(dcBuff.configBottle.warnTemprH != val16)
		{
			dcBuff.configBottle.warnTemprH = val16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 温度报警下限
	if(mask & (1ul << (j++)))
	{
		printf("modify warnTempr\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		memmove(&val16, &uVal16, 2);
		if(dcBuff.configBottle.warnTempr != val16)
		{
			dcBuff.configBottle.warnTempr = val16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 真空度报警上限
	if(mask & (1ul << (j++)))
	{
		printf("modify warnVacuumH\r\n");
		uVal16= ntohs(Byte2IntS(Task_recvBuff, i));
		if(dcBuff.configBottle.warnVacuumH != uVal16)
		{
			dcBuff.configBottle.warnVacuumH = uVal16;
			saveConfig = 1;
		}
	}
	i += 2;
	// 显示控制
	if(mask & (1ul << (j++)))
	{
		printf("modify dispMode\r\n");
		if(dcBuff.configBottle.dispMode != Task_recvBuff[i])
		{
			dcBuff.configBottle.dispMode = Task_recvBuff[i];
			saveConfig = 1;
		}
	}
	i++;
	
	// 保存参数
	if(saveConfig)
		Config_SaveConfig();
	
	return 1;
}

uint8_t parse_huida_recv_data(uint8_t PSN[6], uint32_t relativeTime, uint16_t recvLen)
{
	return parse_furui_recv_data(PSN, relativeTime, recvLen);
}

////////////////////////////////////////////////////////////////////////////////////////
uint8_t pack_rf_send_data(gprs_data_t *pGprs, uint32_t totalSeconds)
{
	uint8_t i;
	rf_sensor_t *pSensor;
    S_RTC_TIME_DATA_T sRTC;
	
	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	i = 0;

	// PSN
	printf("\nRf PSN: 20%02d%02d%02d%02d%03d\n", dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], 
		dcBuff.configBottle.PSN[2], dcBuff.configBottle.PSN[3],
		(dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
	
	// 差压测量：差压值 *100(KPa)，称重测量：容积百分比*100，电容测量：液位高度（mm）
	if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
	{		
		if(dcBuff.configBottle.measureType == 0)
			Int2ByteS(Task_sendBuff, i, pGprs->sampleData.diff * 100);
		else
			Int2ByteS(Task_sendBuff, i, pGprs->sampleData.volumePct);
	}
	else	
		Int2ByteS(Task_sendBuff, i, pGprs->sampleData.height);	
	i += 2;
	
	// 压力
	Int2ByteS(Task_sendBuff, i, pGprs->sampleData.pressure);
	i += 2;
	
	// 温度
	Int2ByteS(Task_sendBuff, i, pGprs->sampleData.extTempr[0]);
	i += 2;
	
	// 液源/贮罐类型/故障码/测量方式
	pSensor = (rf_sensor_t *) (Task_sendBuff + i);
	
	pSensor->staDiff = Bluetooth_ConvertStat(&pGprs->sampleData.staDPress);
	pSensor->staPress = Bluetooth_ConvertStat(&pGprs->sampleData.staPress);
	pSensor->staETempr1 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtTempr[0]);
	pSensor->charging = pGprs->sampleData.charging;
	pSensor->bat_low = pGprs->dtuData.batLow;
	if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
		pSensor->measure_type = dcBuff.configBottle.measureType;
	else
		pSensor->measure_type = 2;
	pSensor->bottle_type = dcBuff.configBottle.type;
	pSensor->L_source = dcBuff.configBottle.source;
	i += 2;
	
	// 密度
	Int2ByteS(Task_sendBuff, i, Config_GetDensity(dcBuff.configBottle.source) * 1000);
	i += 2;
	 // 经度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, pGprs->dtuData.longitude);
	i += 4;
	// 纬度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, pGprs->dtuData.latitude);
	i += 4;
	
	// 电池当前电压
	Int2ByteS(Task_sendBuff, i, pGprs->dtuData.batVoltage / 10);
	i += 2;
	
	// 电量百分比
	Task_sendBuff[i++] = pGprs->dtuData.batPct;
#if 0									
	// 充电电流，电流的符号表示充放电状态
	if(pGprs->dtuData.batCurrent < -128)
		Task_sendBuff[i] = -128;
	else if(pGprs->dtuData.batCurrent > 127)
		Task_sendBuff[i] = 127;
	else
		Task_sendBuff[i] = pGprs->dtuData.batCurrent;
#else
	// 用电流的绝对值表示复位原因
	// 1-POR, 2-PIN, 4-WDT, 8-LVR, 16-BOD, 32-SYS
	Task_sendBuff[i] = SYS_RSTSTS & 0x7F;
	if(pGprs->dtuData.batCurrent < 0)
		Task_sendBuff[i] = -Task_sendBuff[i];
#endif
	i++;

	// 获取当前时间
	RTC_GetDateAndTime(&sRTC);
	Int2ByteL(Task_sendBuff, i, Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
				sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second) - pGprs->sample_time);
	i += 4;

	printf("\ndcBuff.powerInfo.hardVer.major = %d, dcBuff.powerInfo.softVer.minor = %d\n",
		dcBuff.powerInfo.hardVer.major, dcBuff.powerInfo.softVer.minor);
	// 硬件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor;
	// 软件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.softVer.minor;
	
	// 储罐筒长度
	Int2ByteL(Task_sendBuff, i, dcBuff.configBottle.len + dcBuff.configBottle.lenExtra * 2);
	i += 4;
	// 储罐直径
	Int2ByteL(Task_sendBuff, i, dcBuff.configBottle.diameter);
	i += 4;
	// 充装比
	Task_sendBuff[i++] = dcBuff.configBottle.chargePct;
	
	return i;
}
////////////////////////////////////////////////////////////////////////////////////////
uint8_t pack_bd_send_data(gprs_data_t *pGprs, uint32_t totalSeconds)
{
	uint8_t i;
	rf_sensor_t *pSensor;
    S_RTC_TIME_DATA_T sRTC;
	
	// 打包上报数据（按modbus从机响应的格式）
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	i = 0;

	// PSN
	printf("\nBD PSN: 20%02d%02d%02d%02d%03d\n", dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], 
		dcBuff.configBottle.PSN[2], dcBuff.configBottle.PSN[3],
		(dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
	
	// 差压
	Int2ByteS(Task_sendBuff, i, pGprs->sampleData.diff);
	i += 2;

	// 容积百分比
	Int2ByteS(Task_sendBuff, i, pGprs->sampleData.volumePct);
	i += 2;

	// 当前容积
	Int2ByteL(Task_sendBuff, i, pGprs->sampleData.volume);
	i += 4;

	// 重量
	Int2ByteL(Task_sendBuff, i, pGprs->sampleData.weight);
	i += 4;

	// 压力
	Int2ByteS(Task_sendBuff, i, pGprs->sampleData.pressure);
	i += 2;

	// 温度-扩展温度1
	Int2ByteS(Task_sendBuff, i, pGprs->sampleData.extTempr[0]);
	i += 2;

	// 温度-调试信息：标识北斗短信
	Int2ByteS(Task_sendBuff, i, 2);	
	i += 2;

	// 液源/贮罐类型/故障码/测量方式
	pSensor = (rf_sensor_t *) (Task_sendBuff + i);
	
	pSensor->staDiff = Bluetooth_ConvertStat(&pGprs->sampleData.staDPress);
	pSensor->staPress = Bluetooth_ConvertStat(&pGprs->sampleData.staPress);
	pSensor->staETempr1 = Bluetooth_ConvertStat(&pGprs->sampleData.staExtTempr[0]);
	pSensor->charging = pGprs->sampleData.charging;
	pSensor->bat_low = pGprs->dtuData.batLow;
	if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR)
		pSensor->measure_type = dcBuff.configBottle.measureType;
	else
		pSensor->measure_type = 2;	
	pSensor->bottle_type = dcBuff.configBottle.type;
	pSensor->L_source = dcBuff.configBottle.source;
	i += 2;
	
	// 经度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, pGprs->dtuData.longitude);
	i += 4;

	// 纬度
	if(pGprs->dtuData.recentPosState)
		Int2ByteL(Task_sendBuff, i, pGprs->dtuData.latitude);
	i += 4;
	
	// 电池当前电压
	Int2ByteS(Task_sendBuff, i, pGprs->dtuData.batVoltage / 10);
	i += 2;

	// 电量百分比
	Task_sendBuff[i++] = pGprs->dtuData.batPct;
	
#if 0									
	// 充电电流，电流的符号表示充放电状态
	if(pGprs->dtuData.batCurrent < -128)
		Task_sendBuff[i] = -128;
	else if(pGprs->dtuData.batCurrent > 127)
		Task_sendBuff[i] = 127;
	else
		Task_sendBuff[i] = pGprs->dtuData.batCurrent;
#else
	// 用电流的绝对值表示复位原因
	// 1-POR, 2-PIN, 4-WDT, 8-LVR, 16-BOD, 32-SYS
	Task_sendBuff[i] = SYS_RSTSTS & 0x7F;
	if(pGprs->dtuData.batCurrent < 0)
		Task_sendBuff[i] = -Task_sendBuff[i];
#endif									
	i++;

	// 获取当前时间
	RTC_GetDateAndTime(&sRTC);
	Int2ByteL(Task_sendBuff, i, Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
				sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second) - pGprs->sample_time);
	i += 4;

	printf("\ndcBuff.powerInfo.hardVer.major = %d, dcBuff.powerInfo.softVer.minor = %d\n",
		dcBuff.powerInfo.hardVer.major, dcBuff.powerInfo.softVer.minor);
	
	// 硬件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor;
	
	// 软件版本
	Task_sendBuff[i++] = dcBuff.powerInfo.softVer.minor;
	
	// 气瓶容量
	Int2ByteL(Task_sendBuff, i, pGprs->sampleData.volumeTotal);
	i += 4;
	
	// 储罐筒长度
	Int2ByteL(Task_sendBuff, i, dcBuff.configBottle.len + dcBuff.configBottle.lenExtra * 2);
	i += 4;
	
	// 储罐直径
	Int2ByteL(Task_sendBuff, i, dcBuff.configBottle.diameter);
	i += 4;
	
	return i;
}
////////////////////////////////////////////////////////////////////////////////////////
uint16_t pack_json_send_data(gprs_data_t *pGprs, uint32_t totalSeconds)
{
	char psn[14], utc[21];
	S_RTC_TIME_DATA_T sRTC;
	
#if 0
	unsigned long long ll = 0; 
	ll = dcBuff.configBottle.PSN[0] * 1000000000ll + dcBuff.configBottle.PSN[1] * 10000000ll
		+ dcBuff.configBottle.PSN[2] * 100000ll + dcBuff.configBottle.PSN[3] * 1000ll
		+ ((dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
	sprintf(psn, "%010llX", ll); 
#else
	sprintf(psn, "20%02d%02d%02d%02d%03d", dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], 
		dcBuff.configBottle.PSN[2], dcBuff.configBottle.PSN[3],
		(dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]); 
#endif
	
	Wakeup_CalcUTCTime(pGprs->sample_time + RTC_offsetSeconds, &sRTC);
	sprintf(utc, "%04d-%02d-%02dT%02d:%02d:%02dZ", sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
		sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
	
	json_initialize();
	json_new_object();
		json_new_array("assets");
			json_new_object();
				json_new_stringValue("customerReference", "PRAXAIR-GOLD-CN-PROD");
				json_new_stringValue("assetIntegrationId", "0");
				json_new_array("channels");
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Level");
						json_new_stringValue("channelNumber", "1");
						json_new_stringValue("scaledUnitName", "mm WC");
						json_new_array("readings");
							json_new_object();
								if(!dcBuff.configDisplay.op_USE_CAPACITY_SENSOR && !dcBuff.configDisplay.op_USE_HEIGHT_LEVEL && !dcBuff.configDisplay.op_USE_PCT_LEVEL)
									json_new_doubleValue("scaledMeasurement", KPa2mmH2O(pGprs->sampleData.diff));
								else
									json_new_doubleValue("scaledMeasurement", pGprs->sampleData.height);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();
					if(!dcBuff.configDisplay.op_LEVEL_SENSOR_ONLY){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Pressure");
						json_new_stringValue("channelNumber", "2");
						json_new_stringValue("scaledUnitName", "BAR");
						json_new_array("readings");
							json_new_object();
								json_new_doubleValue("scaledMeasurement", pGprs->sampleData.pressure * 0.01);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
					if(!dcBuff.configDisplay.op_LEVEL_SENSOR_ONLY && !dcBuff.configDisplay.op_DOL_VER){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Temperature");
						json_new_stringValue("channelNumber", "3");
						json_new_stringValue("scaledUnitName", "Celsius");
						json_new_array("readings");
							json_new_object();
								json_new_intValue("scaledMeasurement", pGprs->sampleData.extTempr[0]);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Gps");
						json_new_stringValue("channelNumber", "4");
						json_new_array("readings");
							json_new_object();
								json_new_intValue("scaledMeasurement", 0);
								if(pGprs->dtuData.recentPosState)
								{
									json_new_doubleValue("longitude", pGprs->dtuData.longitude * 0.000001);
									json_new_doubleValue("latitude", pGprs->dtuData.latitude * 0.000001);
								}
								else
								{
									json_new_doubleValue("longitude", 0);
									json_new_doubleValue("latitude", 0);
								}
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "BatVoltage");
						json_new_stringValue("channelNumber", "5");
						json_new_stringValue("scaledUnitName", "V");
						json_new_array("readings");
							json_new_object();
								json_new_doubleValue("scaledMeasurement", pGprs->dtuData.batVoltage * 0.001);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();
					if(0){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Diagnostic");
						json_new_stringValue("channelNumber", "6");
						json_new_array("readings");
							json_new_object();
								json_new_intValue("scaledMeasurement", dcBuff.powerInfo.hardVer.major);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
					if(0){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Diagnostic");
						json_new_stringValue("channelNumber", "7");
						json_new_array("readings");
							json_new_object();
								json_new_intValue("scaledMeasurement", dcBuff.powerInfo.hardVer.minor);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
					if(0){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Diagnostic");
						json_new_stringValue("channelNumber", "8");
						json_new_array("readings");
							json_new_object();
								json_new_intValue("scaledMeasurement", dcBuff.powerInfo.softVer.minor);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
					if(0){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Diagnostic");
						json_new_stringValue("channelNumber", "9");
						json_new_array("readings");
							json_new_object();
								// 自启动以来的时间分钟数，32767分钟
								json_new_intValue("scaledMeasurement", totalSeconds % 1966080ul / 60);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
					if(0){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Diagnostic");
						json_new_stringValue("channelNumber", "10");
						json_new_array("readings");
							json_new_object();
								// 启动代码，充放电
								json_new_intValue("scaledMeasurement", pGprs->dtuData.batCurrent > 0 ? SYS_RSTSTS : -SYS_RSTSTS);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
					if(0){
					json_new_object();
						json_new_stringValue("deviceId", psn);
						json_new_stringValue("channelType", "Diagnostic");
						json_new_stringValue("channelNumber", "11");
						json_new_array("readings");
							json_new_object();
								// 上传GPS调试信息: 闪断次数*100+卫星数, 如2105表示闪断21次，卫星数5颗
								json_new_intValue("scaledMeasurement", GPS_BOD_COUNT * 100 + pGprs->dtuData.sateCount);
								json_new_stringValue("timestamp", utc);
							json_end_object();
						json_end_array();
					json_end_object();}
				json_end_array();
			json_end_object();
		json_end_array();
	json_end_object();
	json_finish();
	
	return strlen(JSON_data());
}
////////////////////////////////////////////////////////////////////////////////////////
// 填写双向通讯的固定字段
uint16_t fill_biDir_fixFields(uint16_t cmd, uint16_t len)
{
	bluetooth_send_t *pSend = (bluetooth_send_t *) Task_sendBuff;
	uint16_t crc;

	pSend->mark = CONFIG_MARK_LS;
	pSend->ver = htons(dcBuff.powerInfo.protocolVer.major);
	pSend->trans = 0;
	pSend->len = htons(len - sizeof(bluetooth_send_t) + 2);
	pSend->cmd = htons(cmd);
	crc = MODBUS_RTU_CRC16((uint8_t *) Task_sendBuff, len);
	Int2ByteS(Task_sendBuff, len, htons(crc));
	
	return len + 2;
}

uint16_t pack_ldms_info_Ext_data(uint32_t dataTime, uint32_t totalSeconds)
{
	uint16_t i = 0;
	S_RTC_TIME_DATA_T sRTC;
	bluetooth_timestamp_t t;
	
	memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
	
	// 头信息（最后再填内容）
	i += sizeof(bluetooth_send_t);
	// PSN
	memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
	i += 6;
	Task_sendBuff[i++] = dcBuff.powerInfo.hardVer.major;
	Task_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor;
	Task_sendBuff[i++] = dcBuff.powerInfo.softVer.major;
	Task_sendBuff[i++] = dcBuff.powerInfo.softVer.minor;
	// 软件日期：yyyymmdd
	Int2ByteL(Task_sendBuff, i, htonl((2000 + dcBuff.powerInfo.softDate.year) * 10000 + dcBuff.powerInfo.softDate.month * 100 + dcBuff.powerInfo.softDate.day));
	i += 4;
	// Report format
	Task_sendBuff[i++] = dcBuff.powerInfo.protocolVer.major;
	Task_sendBuff[i++] = dcBuff.powerInfo.protocolVer.minor;
	// Config format
	Task_sendBuff[i++] = dcBuff.configBottle.header.ver.major;
	Task_sendBuff[i++] = dcBuff.configBottle.header.ver.minor;

	// 运行时间：分钟
	Int2ByteL(Task_sendBuff, i, htonl(totalSeconds / 60));
	i += 4;
	Int2ByteS(Task_sendBuff, i, htons(SYS_RSTSTS));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.dtuData.batCurrent));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.dtuData.batVoltage / 10));
	i += 2;
	Task_sendBuff[i++] = dcBuff.dtuData.batPct;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.dtuData.batCapa));
	i += 4;
	if(bat_veryLow)
		Task_sendBuff[i] = 2;
	else if(dcBuff.dtuData.batLow)
		Task_sendBuff[i] = 1;
	else
		Task_sendBuff[i] = 0;
	i++;
	if(dcBuff.dtuData.posState)
		Int2ByteL(Task_sendBuff, i, htonl(dcBuff.dtuData.latitude));
	i += 4;
	if(dcBuff.dtuData.posState)
		Int2ByteL(Task_sendBuff, i, htonl(dcBuff.dtuData.longitude));
	i += 4;

	// 定位时间
	if(dcBuff.dtuData.posState && dcBuff.dtuData.sysTime.year)
	{
		t.year = dcBuff.dtuData.sysTime.year + 2000 - 2010;
		t.mon = dcBuff.dtuData.sysTime.month;
		t.day = dcBuff.dtuData.sysTime.day;
		t.hour_H = dcBuff.dtuData.sysTime.hour >> 4;
		t.hour_L = dcBuff.dtuData.sysTime.hour & 0x0F;
		t.min = dcBuff.dtuData.sysTime.minute;
		t.sec = dcBuff.dtuData.sysTime.second;
		Int2ByteL(Task_sendBuff, i, htonl(t.tm));
	}
	i += 4;
	// 卫星数量
	Task_sendBuff[i++] = dcBuff.dtuData.sateCount;
	// 数据时间
	Wakeup_CalcUTCTime(dataTime + RTC_offsetSeconds, &sRTC);
	t.year = sRTC.u32Year - 2010;
	t.mon = sRTC.u32Month;
	t.day = sRTC.u32Day;
	t.hour_H = sRTC.u32Hour >> 4;
	t.hour_L = sRTC.u32Hour & 0x0F;
	t.min = sRTC.u32Minute;
	t.sec = sRTC.u32Second;
	Int2ByteL(Task_sendBuff, i, htonl(t.tm));
	i += 4;
	// 信号强度
	Task_sendBuff[i++] = dcBuff.dtuData.rssi;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.powerInfo.gprsSuccCount));
	i += 4;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.powerInfo.gprsSendCount - dcBuff.powerInfo.gprsSuccCount));
	i += 4;
	if(dcBuff.powerInfo.gprsSendCount > 0)
		Task_sendBuff[i] = dcBuff.powerInfo.gprsSuccCount * 100 / dcBuff.powerInfo.gprsSendCount;
	i++;
	memmove(Task_sendBuff + i, dcBuff.powerInfo.gprsFailCode, strlen(dcBuff.powerInfo.gprsFailCode));
	i += 6;
	memmove(Task_sendBuff + i, dcBuff.powerInfo.simNumber, strlen(dcBuff.powerInfo.simNumber));
	i += 24;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.powerInfo.bdNumber));
	i += 4;
	
	// 储罐类型
	Task_sendBuff[i++] = dcBuff.configBottle.type;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.diameter));
	i += 4;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.len));
	i += 4;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.lenExtra));
	i += 4;
	Int2ByteL(Task_sendBuff, i, htonl(Theoretical_Param.v));
	i += 4;
	Task_sendBuff[i++] = dcBuff.configBottle.chargePct;
	Task_sendBuff[i++] = dcBuff.configBottle.source;
	Int2ByteS(Task_sendBuff, i, htons(Config_GetDensity(dcBuff.configBottle.source) * 1000));
	i += 2;
	Task_sendBuff[i++] = dcBuff.configBottle.dispMode | (dcBuff.configBottle.hideVacu << 2);
	if(dcBuff.configDisplay.L_Unit == UNIT_KPA)
		Task_sendBuff[i] = 0;
	else if(dcBuff.configDisplay.L_Unit == UNIT_KG)
		Task_sendBuff[i] = 1;
	else if(dcBuff.configDisplay.L_Unit == UNIT_L)
		Task_sendBuff[i] = 2;
	else if(dcBuff.configDisplay.L_Unit == UNIT_MMH2O)
		Task_sendBuff[i] = 4;
	else
		Task_sendBuff[i] = 3;
	i++;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.serverVer));
	i += 2;
	memmove(Task_sendBuff + i, dcBuff.configData.server, strlen(dcBuff.configData.server));
	i += 30;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configData.port));
	i += 2;
	memmove(Task_sendBuff + i, dcBuff.configData.gpsServer, strlen(dcBuff.configData.gpsServer));
	i += 30;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configData.gpsPort));
	i += 2;
	memmove(Task_sendBuff + i, dcBuff.configData.upgServer, strlen(dcBuff.configData.upgServer));
	i += 30;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configData.upgPort));
	i += 2;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configData.intervalTrans));
	i += 4;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configData.intervalSample));
	i += 4;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configData.intervalGPSTrans));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configData.intervalGPS));
	i += 2;
	Task_sendBuff[i++] = dcBuff.configData.timeLag;
	strcpy((char *) Task_sendBuff + i, DTU_DecideAPN());
	i += 24;
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configDisplay.bdCommander));
	i += 4;
	
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnPress));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnPressH));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.fullPct));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.priPct));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.orderPct));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.emptyPct));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnVolt));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.warnVoltH));
	i += 2;
	strcpy((char *) Task_sendBuff + i, DTU_DecideAPNUser());
	i += 10;
	strcpy((char *) Task_sendBuff + i, DTU_DecideAPNPwd());
	i += 10;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.floorLevel));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.span));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configBottle.spanPeriod));
	i += 2;

	// 测量方式
	Task_sendBuff[i++] = dcBuff.configDisplay.op_USE_CAPACITY_SENSOR ? 2 : dcBuff.configBottle.measureType;
	Task_sendBuff[i++] = 0;
	Task_sendBuff[i++] = dcBuff.configDisplay.op_USE_PT100_SENSOR ? 0 : 1;

	// 差压传感器参数
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorDPress.lowRange));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorDPress.highRange));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorDPress.zeroValue));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorDPress.fullValue));
	i += 2;
	// 电容传感器参数
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorCap.baseC));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorCap.refC));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorCap.c1ADC));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorCap.c2ADC));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(CAP_K_C1));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(CAP_K_C2));
	i += 2;
	// 称重传感器参数
//	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configSensor.sensorWeight.lowRange));
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.sampleData.adDPress));
	i += 4;
//	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configSensor.sensorWeight.highRange));
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.sampleData.adPress));
	i += 4;
//	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configSensor.sensorWeight.zeroValue));
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.sampleData.adExtTempr[0]));
	i += 4;
//	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configSensor.sensorWeight.fullValue));
	Int2ByteL(Task_sendBuff, i, htonl(dcBuff.sampleData.adExtTempr[1]));
	i += 4;
	// 压力传感器参数
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPress.lowRange));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPress.highRange));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPress.zeroValue));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPress.fullValue));
	i += 2;
	// 扩展压力传感器1参数
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorEPress[0].lowRange));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorEPress[0].highRange));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorEPress[0].zeroValue));
	i += 2;
	Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorEPress[0].fullValue));
	i += 2;
	if(dcBuff.configDisplay.op_USE_PT100_SENSOR)
	{
		// 扩展温度传感器1参数
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[0].calibrateT));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[0].calibrateR));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[0].zeroValue));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[0].fullValue));
		i += 2;
		// 扩展温度传感器2参数
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[1].calibrateT));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[1].calibrateR));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[1].zeroValue));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorPTempr[1].fullValue));
		i += 2;
	}
	else
	{
		// 扩展温度传感器1参数
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[0].lowRange));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[0].highRange));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[0].zeroValue));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[0].fullValue));
		i += 2;
		// 扩展温度传感器2参数
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[1].lowRange));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[1].highRange));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[1].zeroValue));
		i += 2;
		Int2ByteS(Task_sendBuff, i, htons(dcBuff.configSensor.sensorMTempr[1].fullValue));
		i += 2;
	}
	
	// 填写固定字段
	return fill_biDir_fixFields(0xD045, i);
}

#define D046_PARAM_SIZE (268)
uint8_t parse_param_D046_data(uint8_t *param, uint8_t *reset)
{
	longlong_mask_t mask;
	uint16_t i = 0, shift = 0;
	
	// 参数有效标志位（用一个无符号长整数表示, 共63项可选配置（bit 0~62）, 最高位（bit 63）代表复位命令）
	// 网络字节序： 12 34 56 78 90 ab cd ef
	// h = 0x78563412, l = 0xefcdab90 （网络字节序）
	// h = 0x12345678, l = 0x90abcdef （本机字节序)
	// mask = 0x1234567890abcdef
	mask.h = ntohl(Byte2IntL(param, i));
	i += 4;
	mask.l = ntohl(Byte2IntL(param, i));
	i += 4;
	
	printf("\nmask = %016llX\n", mask.ll);
	
	// 储罐类型
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.type = param[i];
	i++;
	// 直径
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.diameter = ntohl(Byte2IntL(param, i));
	i += 4;
	// 长度
	if(mask.ll & (1ull << (shift++)))
	{
		dcBuff.configBottle.len = ntohl(Byte2IntL(param, i));
		dcBuff.configBottle.lenExtra = 0;
	}
	i += 4;
	// 充装比
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.chargePct = param[i];
	i++;
	// 介质
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.source = param[i];
	i++;
	// 密度
	if(mask.ll & (1ull << (shift++)))
		Config_SetDensity(dcBuff.configBottle.source, ntohs(Byte2IntS(param, i)) / 1000.0);
	i += 2;
	// 显示模式
	if(mask.ll & (1ull << (shift++)))
	{
		dcBuff.configBottle.dispMode = param[i] & 0x03;
		dcBuff.configBottle.hideVacu = (param[i] >> 2) & 0x01;

		dcBuff.configBottle.options &= ~0x0003ul;
		if(dcBuff.configBottle.dispMode == DISP_MODE_ALL)
			dcBuff.configBottle.options |= 0x0003ul;
		else if(dcBuff.configBottle.dispMode == DISP_MODE_L)
			dcBuff.configBottle.options |= 0x0001ul;
		else if(dcBuff.configBottle.dispMode == DISP_MODE_KG)
			dcBuff.configBottle.options |= 0x0002ul;
	}
	i++;
	// 显示单位
	if(mask.ll & (1ull << (shift++)))
	{
		if(param[i] == 0)
			dcBuff.configDisplay.L_Unit = UNIT_KPA;
		else if(param[i] == 1)
			dcBuff.configDisplay.L_Unit = UNIT_KG;
		else if(param[i] == 2)
			dcBuff.configDisplay.L_Unit = UNIT_L;
		else if(param[i] == 4)
			dcBuff.configDisplay.L_Unit = UNIT_MMH2O;
		else
			dcBuff.configDisplay.L_Unit = UNIT_PCT;
	}
	i++;

	// 服务器版本
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.serverVer = ntohs(Byte2IntS(param, i));
	i += 2;
	// 远传服务器
	if(mask.ll & (1ull << (shift++)))
		strcpy(dcBuff.configData.server, (char *) param + i);
	i += 30;
	// 远传端口
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.port = ntohs(Byte2IntS(param, i));
	i += 2;
	// 远传服务器
	if(mask.ll & (1ull << (shift++)))
		strcpy(dcBuff.configData.gpsServer, (char *) param + i);
	i += 30;
	// 远传端口
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.gpsPort = ntohs(Byte2IntS(param, i));
	i += 2;
	// 远传服务器
	if(mask.ll & (1ull << (shift++)))
		strcpy(dcBuff.configData.upgServer, (char *) param + i);
	i += 30;
	// 远传端口
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.upgPort = ntohs(Byte2IntS(param, i));
	i += 2;
	// 发送频率
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.intervalTrans = ntohl(Byte2IntL(param, i));
	i += 4;
	// 采集频率
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.intervalSample = ntohl(Byte2IntL(param, i));
	i += 4;
	// 发送频率
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.intervalGPSTrans = ntohs(Byte2IntS(param, i));
	i += 2;
	// 采集频率
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.intervalGPS = ntohs(Byte2IntS(param, i));
	i += 2;
	// 时差
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configData.timeLag = param[i];
	i++;
	// APN
	if(mask.ll & (1ull << (shift++)))
		strcpy(dcBuff.configDisplay.APN, (char *) param + i);
	i += 24;
	// 北斗指挥机卡号
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configDisplay.bdCommander = ntohl(Byte2IntL(param, i));
	i += 4;

	// 压力报警点低: KPa
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.warnPress = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力报警点高: KPa
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.warnPressH = ntohs(Byte2IntS(param, i));
	i += 2;
	// 满液位报警点: 0.01%
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.fullPct = ntohs(Byte2IntS(param, i));
	i += 2;
	// 关键液位报警点: 0.01%
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.priPct = ntohs(Byte2IntS(param, i));
	i += 2;
	// 订货液位报警点: 0.01%
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.orderPct = ntohs(Byte2IntS(param, i));
	i += 2;
	// 空液位报警点: 0.01%
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.emptyPct = ntohs(Byte2IntS(param, i));
	i += 2;
	// 电压报警低点: mV
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.warnVolt = ntohs(Byte2IntS(param, i));
	i += 2;
	// 电压报警高点: mV
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.warnVoltH = ntohs(Byte2IntS(param, i));
	i += 2;
	// APN-User
	if(mask.ll & (1ull << (shift++)))
		strcpy(dcBuff.configDisplay.User, (char *) param + i);
	i += 10;
	// APN-Pwd
	if(mask.ll & (1ull << (shift++)))
		strcpy(dcBuff.configDisplay.Pwd, (char *) param + i);
	i += 10;
	// TTS-空液位报警点: 0.01%
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.floorLevel = ntohs(Byte2IntS(param, i));
	i += 2;
	// TTS-变化量报警点: 0.01%
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.span = ntohs(Byte2IntS(param, i));
	i += 2;
	// TTS-变化量检测时间: 秒
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configBottle.spanPeriod = ntohs(Byte2IntS(param, i));
	i += 2;
	
	// 差压传感器量程: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorDPress.lowRange = ntohs(Byte2IntS(param, i));
	i += 2;
	// 差压传感器量程: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorDPress.highRange = ntohs(Byte2IntS(param, i));
	i += 2;
	// 差压传感器标定: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorDPress.zeroValue = ntohs(Byte2IntS(param, i));
	i += 2;
	// 差压传感器标定: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorDPress.fullValue = ntohs(Byte2IntS(param, i));
	i += 2;
	// 电容传感器量程: 底电容
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorCap.baseC = ntohs(Byte2IntS(param, i));
	i += 2;
	// 电容传感器量程: 增长电容
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorCap.refC = ntohs(Byte2IntS(param, i));
	i += 2;
 	// 电容传感器标定: C1ADC
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorCap.c1ADC = ntohs(Byte2IntS(param, i));
	i += 2;
	// 电容传感器标定: C2ADC
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorCap.c2ADC = ntohs(Byte2IntS(param, i));
	i += 2;
	// 称重传感器量程: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorWeight.lowRange = ntohl(Byte2IntL(param, i));
	i += 4;
	// 称重传感器量程: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorWeight.highRange = ntohl(Byte2IntL(param, i));
	i += 4;
	// 称重传感器标定: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorWeight.zeroValue = ntohl(Byte2IntL(param, i));
	i += 4;
	// 称重传感器标定: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorWeight.fullValue = ntohl(Byte2IntL(param, i));
	i += 4;
	// 压力传感器1量程: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorPress.lowRange = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力传感器1量程: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorPress.highRange = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力传感器1标定: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorPress.zeroValue = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力传感器1标定: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorPress.fullValue = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力传感器2量程: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorEPress[0].lowRange = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力传感器2量程: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorEPress[0].highRange = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力传感器2标定: 低
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorEPress[0].zeroValue = ntohs(Byte2IntS(param, i));
	i += 2;
	// 压力传感器2标定: 高
	if(mask.ll & (1ull << (shift++)))
		dcBuff.configSensor.sensorEPress[0].fullValue = ntohs(Byte2IntS(param, i));
	i += 2;
	if(dcBuff.configDisplay.op_USE_PT100_SENSOR)
	{
		// 温度传感器1量程: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[0].calibrateT = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器1量程: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[0].calibrateR = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器1标定: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[0].zeroValue = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器1标定: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[0].fullValue = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2量程: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[1].calibrateT = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2量程: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[1].calibrateR = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2标定: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[1].zeroValue = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2标定: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorPTempr[1].fullValue = ntohs(Byte2IntS(param, i));
		i += 2;
	}
	else
	{
		// 温度传感器1量程: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[0].lowRange = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器1量程: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[0].highRange = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器1标定: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[0].zeroValue = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器1标定: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[0].fullValue = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2量程: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[1].lowRange = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2量程: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[1].highRange = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2标定: 低
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[1].zeroValue = ntohs(Byte2IntS(param, i));
		i += 2;
		// 温度传感器2标定: 高
		if(mask.ll & (1ull << (shift++)))
			dcBuff.configSensor.sensorMTempr[1].fullValue = ntohs(Byte2IntS(param, i));
		i += 2;
	}
	
	*reset = ((mask.ll & (1ull << shift)) != 0);
	
	return ((mask.ll & ~(1ull << shift)) != 0);
}

#define D048_CONFIG_SIZE (82)
uint8_t parse_config_D048_data(uint8_t *param)
{
	uint16_t i = 0;
	
	// 服务器版本
	dcBuff.configBottle.serverVer = ntohs(Byte2IntS(param, i));
	i += 2;
	// 远传服务器
	strcpy(dcBuff.configData.server, (char *) param + i);
	i += 30;
	// 远传端口
	dcBuff.configData.port = ntohs(Byte2IntS(param, i));
	i += 2;
	// 远传服务器
	strcpy(dcBuff.configData.gpsServer, (char *) param + i);
	i += 30;
	// 远传端口
	dcBuff.configData.gpsPort = ntohs(Byte2IntS(param, i));
	i += 2;
	// 发送频率
	dcBuff.configData.intervalTrans = ntohl(Byte2IntL(param, i));
	i += 4;
	// 采集频率
	dcBuff.configData.intervalSample = ntohl(Byte2IntL(param, i));
	i += 4;

	// 硬件版本
	dcBuff.configDisplay.op_HARDWARE_VER_MAJOR = param[i++];
	// 只显示毫米水柱
	dcBuff.configDisplay.op_DISP_MMWC_ONLY = param[i++];
	// 罐箱版本
	dcBuff.configDisplay.op_BOX_VER = param[i++];
	// 基站定位、不定位
	dcBuff.configDisplay.op_CELL_LOCATION = param[i] & 1;
	dcBuff.configDisplay.op_NO_LOCATION = (param[i] >> 1) & 1;
	i++;
	// 发送轨迹
	dcBuff.configDisplay.op_SEND_GPS_DATA = param[i++];
	// 通信方式
	dcBuff.configDisplay.op_SERVER_PROTOCOL = param[i++];
	// URL索引
	dcBuff.configDisplay.op_SERVER_INDEX = param[i++];
	// 单向通信
	dcBuff.configDisplay.op_UNIDIR_COMM = param[i++];
	
	return 1;
}

// 从服务器获取时间
void DTU_setOffsetSecondsFromServer()
{
	bluetooth_send_t *pRecv = (bluetooth_send_t *) Task_recvBuff;
	S_RTC_TIME_DATA_T sRTC;
	uint32_t totalSeconds1, totalSeconds2;
	int16_t zz;
	uint16_t i, recvLen;

	// 从服务器获取当前时间
	printf("\nGet time from server ...\n");
	// 连接升级服务器
	if(DTU_Connect(0, dcBuff.configData.upgServer, dcBuff.configData.upgPort))
	{
		memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
		
		i = sizeof(bluetooth_send_t);								
		// 填写固定字段
		i = fill_biDir_fixFields(0xD03B, i);

		// 发送i个字节到服务器，至少接收10个字节
		recvLen = sizeof(bluetooth_recv_t) + 2;
		if(DTU_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
		{
			if(recvLen >= sizeof(bluetooth_recv_t) + 2
				&& MODBUS_RTU_CRC16(Task_recvBuff, recvLen) == 0)
			{
				if(recvLen >= sizeof(bluetooth_recv_t) + 11
					&& pRecv->cmd == ntohs(0x003B)
					&& MODBUS_RTU_CRC16(Task_recvBuff, sizeof(bluetooth_recv_t) + 11) == 0)
				{
					// 获取当前时间
					RTC_GetDateAndTime(&sRTC);
					totalSeconds1 = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
							sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
					
					// UTC日期
					i = sizeof(bluetooth_recv_t);

					// 年
					sRTC.u32Year = ntohs(Byte2IntS(Task_recvBuff, i));
					i += 2;
					// 月
					sRTC.u32Month = Task_recvBuff[i++];
					// 日
					sRTC.u32Day = Task_recvBuff[i++];
					// 时
					sRTC.u32Hour = Task_recvBuff[i++];
					// 分
					sRTC.u32Minute = Task_recvBuff[i++];
					// 秒
					sRTC.u32Second = Task_recvBuff[i++];
					// 时差（按1/4小时, 带符号）
					recvLen = ntohs(Byte2IntS(Task_recvBuff, i));
					memmove(&zz, &recvLen, 2);
					
					printf("\n%04d-%02d-%02d %02d:%02d:%02d %d\n", sRTC.u32Year, sRTC.u32Month, sRTC.u32Day, 
							sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second, zz);
					
					totalSeconds2 = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
							sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);

					// 将UTC时间转换为GMT时间（时差为0）
					totalSeconds2 -= zz * 900;
					// 将GMT时间转换为UTC时间（按配置的时差）
					totalSeconds2 += dcBuff.configData.timeLag * 3600;

					if(RTC_offsetSeconds == 0)
						RTC_offsetSeconds = totalSeconds2 - totalSeconds1;
				}
			}
		}
		// 关闭和服务器的连接
		DTU_Close(0);
	}
}

char pakistan_data[400];
uint16_t Pack_Pakistan_Json_Data(void)
{
  uint16_t len = 0;
	#if 0
  len = sprintf(pakistan_data,"{\"PSN\":20%02d%02d%02d%02d%03d,\"Tank_Pressure\":%.2f,\"Tank_Level\":%.2f,\
\"Manf_Pressure\":%d,\"Tank_Pressure_High\":%.2f,\"Tank_Pressure_Low\":%.2f,\"Tank_Level_High\":%.2f,\
\"Tank_Level_Low\":%.2f,\"Tank_Level_Reorder\":%d,\"Manf_Pressure_High\":%d,\
\"Manf_Pressure_Low\":%d,\"Interval\":%d}",
  dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], 
	dcBuff.configBottle.PSN[2], dcBuff.configBottle.PSN[3],
	(dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5],
  (float)dcBuff.sampleData.pressure * 0.01f,
  KPa2mmH2O(dcBuff.sampleData.diff), 0,
  dcBuff.configBottle.warnPressH * 0.01f,
  dcBuff.configBottle.warnPress * 0.01f,
  dcBuff.configBottle.fullPct * 0.01f,
  dcBuff.configBottle.emptyPct * 0.01f, 0,0,0, dcBuff.configData.intervalTrans / 60);
  #else
	  len = sprintf(pakistan_data,"{\"PSN\":20%02d%02d%02d%02d%03d,\"Tank_Pressure\":%.2f,\"Tank_Level\":%.2f,\
\"Manf_Pressure\":%.2f,\"Manf_Pressure_High\":%.2f,\"Manf_Pressure_Low\":%.2f,\"Tank_Pressure_High\":%.2f,\"Tank_Pressure_Low\":%.2f,\"Tank_Level_High\":%.2f,\
\"Tank_Level_Low\":%.2f,\"Tank_Level_Reorder\":%d,\"Interval\":%d}",
  dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], 
	dcBuff.configBottle.PSN[2], dcBuff.configBottle.PSN[3],
	(dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5],
  (float)dcBuff.sampleData.pressure * 0.01f,
  KPa2mmH2O(dcBuff.sampleData.diff), 
	
	(float)dcBuff.sampleData.extPressure[0]*0.01f,
		dcBuff.configBottle.warnPressH2 * 0.01f,
  dcBuff.configBottle.warnPress2 * 0.01f,	
  dcBuff.configBottle.warnPressH * 0.01f,
  dcBuff.configBottle.warnPress * 0.01f,

  dcBuff.configBottle.fullPct * 0.01f,
  dcBuff.configBottle.emptyPct * 0.01f, 0, dcBuff.configData.intervalTrans / 60);
	#endif
  return(len);
}

////////////////////////////////////////////////////////////////////////////////////////

// 任务主体：发送运行数据和GPS数据，读取网络信号强度等
void DTU_Task(void *p_arg)
{
	bluetooth_send_t *pSend = (bluetooth_send_t *) Task_sendBuff;
	bluetooth_send_t *pRecv = (bluetooth_send_t *) Task_recvBuff;
	uint16_t i, j, k;
	uint8_t gpsCount, gpsDone;
	uint16_t gpsInterval;
	uint32_t totalSeconds;
	uint32_t relativeTime;
    S_RTC_TIME_DATA_T sRTC;
	gprs_data_t *pGprs;
	uint8_t try_count;
	uint16_t recvLen;
	uint8_t upgrade;
	uint8_t ackUpgrade;
	uint8_t downloadParam;
	uint8_t ackParam;
	uint8_t downloadConfig;
	uint8_t ackConfig;
	uint8_t reset = 0;
	param_data_t *pParam;
	TUpgradeHeader upHeader;
	upgrade_frame_t *pFrame;
	gps_data_t gps;
	uint16_t nextPtr;
	uint8_t write_count;
	uint8_t rf_fail_count = 0;
	uint8_t semSync, semGPRS, semGPS;
	uint8_t recentLocate;

	uint32_t tick;

	// 从FRAM读取阿里云密钥信息
	FRAM_LoadInfo(FRAM_ALIYUN_SECRET_BASE, (uint8_t *) &aliyunSecret, sizeof(aliyunSecret));

	// 从FRAM读取GPS信息
	FRAM_LoadInfo(gpsBuff.info_base, (uint8_t *) &gpsBuff.info, sizeof(gpsBuff.info));
	if(gpsBuff.info.rdPtr > gpsBuff.maxItemCount || gpsBuff.info.wtPtr > gpsBuff.maxItemCount)
		memset(&gpsBuff.info, 0, sizeof(gpsBuff.info));
	
	// 船级社维持时间算法初始化
	//CCS_Init();
	
	// 清除数据
	memset(&dcBuff.dtuData, 0, sizeof(dcBuff.dtuData));
	
	// 读取其它板子的配置数据

	// 启动定时器
	GPS_tranTick = GetDelayTick(dcBuff.configData.intervalGPSTrans * 1000);
	
	if(dcBuff.configDisplay.op_BOX_VER)
	{
		// 检查是否有BD模块
		BD_PowerOn();
		BD_PowerOff();
	}
	
//	// 检查是否有RF模块
//	RF_PowerOn();
//	RF_PowerOff();
	if(RF_initStatus && dcBuff.configDisplay.op_LNG_LORA)
		RF_PowerOn();
	
	// 打开槽车充液泵
	if(dcBuff.configDisplay.op_SEND_GPS_DATA)
		KZ_PUMP_ON();
	
	// 上电运行一次任务
	DTU_semSync = 1;
	DTU_semGPRS = 1;
	DTU_semGPS = 1;

	while(1)
	{
		// 获取当前时间
		RTC_GetDateAndTime(&sRTC);
		// 计算自上次gps定位以来的时间
		totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
				sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
		// 刚开始运行的时候，回退到刚启动的时间（忽略系统初始化时间）
		if(totalSeconds < 10)
			totalSeconds = 0;

		// 打开或关闭槽车的RF接收
		if(dcBuff.configDisplay.op_SEND_GPS_DATA && RF_initStatus && !dcBuff.configDisplay.op_LNG_LORA)
		{
			if(VCC_POWER_STATUS())
				RF_PowerOn();
			else
				RF_PowerOff();
		}
		
		// 槽车充液泵控制
		if(dcBuff.configDisplay.op_SEND_GPS_DATA && !IS_PUMP_ON())
		{
			// 等待30分钟，或者离开5分钟
			if(totalSeconds >= Pump_Stop_Time + 1800 || (totalSeconds >= Pump_Stop_Time + 300 && rf_is_truck_leave()))
				KZ_PUMP_ON();
		}

		// 读取信号量
		semSync = DTU_semSync;
		DTU_semSync = 0;
		semGPRS = DTU_semGPRS;
		DTU_semGPRS = 0;
		semGPS = DTU_semGPS;
		DTU_semGPS = 0;
		
		// 本地显示：无4G模块
		if(dcBuff.configDisplay.op_LOCAL_DISP)
		{
			if(semGPS || semSync)
			{
				// 先清除信号量
				GPRS_semSampled = 0;
				// 采集数据
				Sample_Notify();
				tick = GetDelayTick(3000);
				while(!GPRS_semSampled && !IsTickOut(tick))
				{
				}
			}
			
			// 休眠
			Wakeup_Powerdown();				
			continue;
		}
		
		// 默认不保存、不发送
		GPRS_Send_Task = 0;
		GPRS_Save_Task = 0;			
	
		// 是否强制上传
		if(DTU_dataConn)
		{
			DTU_dataConn = 0;
			GPRS_Send_Task = 1;
		}
		
		// 是否强制定位
		if(GPS_Locate)
		{
			GPS_Locate = 0;
		
			// 强制定位：保存和发送
			GPRS_Send_Task = 1;
			GPRS_Save_Task = 1;

			// 设置超时定时器
			if(!dcBuff.configDisplay.op_NO_LOCATION)
			{
				GPS_waitTick = GetDelayTick(DTU_tmrLocate * 1000);
				GPS_Waiting = 1;
			}
		}

		// GPS发送周期：检查电池电量
		if(semGPS || semSync)
		{
			delay_ms(200);

			// 先清除信号量
			GPRS_semSampled = 0;
			// 采集数据
			Sample_Notify();
			tick = GetDelayTick(3000);
			while(!GPRS_semSampled && !IsTickOut(tick))
			{
			}

			// 根据电量设置工作模式
			Wakeup_SetWorkMode();
		}

		// 检测唤醒同步信号
		if(semGPRS || semSync)
		{
			printf("\n*** dcBuff.sampleData.warnning = %d ***\n", dcBuff.sampleData.warnning);				
			if(dcBuff.sampleData.warnning)
			{
				GPRS_Send_Task = 1;
				dcBuff.sampleData.warnning = 0;
			}
			
			// 判断是否发送周期
			// 如果发送时间到了，或者队列中的数据够了，则发送数据（为了工程测试方便，刚开始几次按照不大于5分钟的频率发送）
			if(dcBuff.configDisplay.op_SEND_GPS_DATA)
			{
				// 发送间隔最小值
				if(totalSeconds + 3 >= GPRS_Send_Time + (dcBuff.configData.intervalTrans > 300 ? 300 : dcBuff.configData.intervalTrans))
					GPRS_Send_Task = 1;
			}
			else 
			{
				if(((SYS_RSTSTS & 0x13) && !(SYS_RSTSTS & 0x04) && // 上电或手动复位, 非看门狗复位
					totalSeconds < INITIAL_TRAN_COUNT * (dcBuff.configData.intervalSample > 300 ? 300 : dcBuff.configData.intervalSample))
					|| totalSeconds + 3 >= GPRS_Send_Time + dcBuff.configData.intervalTrans 
//					|| LoopBuff_GetCount(&gprsBuff) >= dcBuff.configData.intervalTrans / dcBuff.configData.intervalSample - 1
				)
//////			if(LoopBuff_GetCount(&gprsBuff) >= 11)
				{
					// 发送间隔最小值
					if(totalSeconds + 3 >= GPRS_Send_Time + (dcBuff.configData.intervalTrans > 300 ? 300 : dcBuff.configData.intervalTrans))
						GPRS_Send_Task = 1;
				}
//				else if(Config_CheckUpdate(&dcBuff))
//				{
//					GPRS_Send_Task = 1;
//				}
			}			
				
			// 判断是否保存周期
			if(GPRS_Send_Task || totalSeconds + 3 >= GPRS_Save_Time + dcBuff.configData.intervalSample) 
				GPRS_Save_Task = 1;	

			if(GPRS_Send_Task && ((dcBuff.configDisplay.op_BOX_VER && (Motion_Detected || Motion_Status))
				|| (dcBuff.configDisplay.op_SEND_GPS_DATA && Wakeup_GetWorkMode() == WORK_MODE_NORMAL)))
			{
				GPS_Located = 0;
				
				// 设置超时定时器
				if(!dcBuff.configDisplay.op_NO_LOCATION)
				{
					GPS_waitTick = GetDelayTick(DTU_tmrLocate * 1000);
					GPS_Waiting = 1;
				}
			}
		}
		
		// 运行数据发送周期：检测信号强度
		if(semGPRS || semSync)
		{
			if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPRS_Send_Task)
			{
				delay_ms(200);
				
				// 打开DTU（开始定位）
				dcBuff.dtuData.networked = 0;
				
				if(RF_initStatus && dcBuff.configDisplay.op_BOX_VER && !dcBuff.configDisplay.op_LNG_LORA)
				{
					// 打开射频模块
					RF_PowerOn();
					// 检查中继器是否存在
					rf_check_gateway();
					// 关闭射频模块
					RF_PowerOff();
				}
				
				if(!rf_has_gateway() || GPS_Waiting || dcBuff.configDisplay.op_SEND_GPS_DATA)
				{
					DTU_PowerOn();
					// 重新开始定位计时，保证足够定位时间
					GPS_waitTick = GetDelayTick(DTU_tmrLocate * 1000);
					
					// 采集信号强度和注册信息
					Sim808_ReadGPRS();
					printf("\ndcBuff.dtuData.networked: %d\n", dcBuff.dtuData.networked);
					
					// 如果有GPRS但是信号很弱
					if(rf_has_gateway() && dcBuff.dtuData.rssi < 30)
						dcBuff.dtuData.networked = 0;
					if(!dcBuff.dtuData.networked)
						dcBuff.dtuData.rssi = 0;
				}
			}

			// 每小时保存1条数据
			if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPRS_Save_Task)
			{
				if(GPRS_Send_Task)
				{
					// GPRS拨号和GPS定位同时进行，以节省时间
					if(dcBuff.dtuData.networked)
						Sim808_GPRSDial();

					// 如果不发送轨迹数据，则等待定位完成再发送运行数据
					recentLocate = (!dcBuff.configDisplay.op_SEND_GPS_DATA && Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPS_Waiting);
					while(!dcBuff.configDisplay.op_SEND_GPS_DATA && Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPS_Waiting)
					{
						delay_ms(200);
					}

					if(!dcBuff.configDisplay.op_SEND_GPS_DATA)
					{
						// 关闭GPS
						DTU_DisableGPS();
					}
					
					// 获取基站定位数据
					if(recentLocate)
					{
						if(DTU_model == DTU_MODEL_LIERDA && Sim808_GetCellLocPosition())
						{
							dcBuff.dtuData.posState = 1;
							dcBuff.dtuData.recentPosState = 1;
							// 没有卫星定位或者卫星定位的坐标离基站太远（3000米），直接用基站定位坐标
							if(!GPS_Located || GetDistance(dcBuff.dtuData.latitude, dcBuff.dtuData.longitude, DTU_latitude, DTU_longitude) >= 3000)
							{
								dcBuff.dtuData.longitude = DTU_longitude;
								dcBuff.dtuData.latitude = DTU_latitude;
							}
						}
						else if(!GPS_Located)
							dcBuff.dtuData.recentPosState = 0;
					}
					
					// 本次定位结束
					GPS_Located = 1;
					// 下次有运动才定位（罐箱）
					Motion_Detected = 0;

					// 先清除信号量
					GPRS_semSampled = 0;
					// 采集数据
					Sample_Notify();
					tick = GetDelayTick(3000);
					while(!GPRS_semSampled && !IsTickOut(tick))
					{
					}
					// 记录本次发送的时间
					GPRS_Send_Time = totalSeconds;
				}
				
				// 船级社维持时间计算
				//CCS_Predict();
				// 加入队列，待发送
				printf("\nPut gprs data to queue...\n");
				if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_CHAOYANG)
					LoopBuff_Clear(&gprsBuff);
				GPRS_PutToQueue(&gprsBuff, &dcBuff.dtuData, &dcBuff.sampleData);
				// 每条记录，北斗发送2次
				if(BD_initStatus)
				{
					GPRS_PutToQueue(&bd_gprsBuff, &dcBuff.dtuData, &dcBuff.sampleData);
					GPRS_PutToQueue(&bd_gprsBuff, &dcBuff.dtuData, &dcBuff.sampleData);
				}
				// 记录本次保存的时间
				GPRS_Save_Time = totalSeconds;
			}
		}

		// 用北斗发送数据
		if(BD_initStatus && (semGPRS || semSync))
		{
			// 每采集1条就发送1条
			if(LoopBuff_GetCount(&bd_gprsBuff) > 0)
			{
				if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL)
				{
					// 打开北斗模块
					BD_PowerOn();

					if(BD_initStatus)
					{
						FRAM_BufferRead(LoopBuff_GetDataPos(&bd_gprsBuff, bd_gprsBuff.info.rdPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
						pGprs = &gprsRWBuf;

						// 打包上报数据（按北斗精简报文的格式）
						i = pack_bd_send_data(pGprs, totalSeconds);
					
						bd_rf_app_send_data(i, Task_sendBuff);						

						delay_ms(200);
					}
					
					// 关闭北斗模块
					BD_PowerOff();
				}
				
				// 不管是否发送成功，都移除记录（因为1分钟发送一次，没有重发机制）
				LoopBuff_RemoveItems(&bd_gprsBuff, 1);
			}
		}
		
		// 优先用射频发送数据
		if(rf_has_gateway() && (semGPRS || semSync))
		{
			if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPRS_Send_Task)
			{
				// 关闭GPRS
				DTU_PowerOff();

				// 打开射频模块
				RF_PowerOn();

				k = LoopBuff_GetCount(&gprsBuff);
				while(k--)
				{
					FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, gprsBuff.info.rdPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
					pGprs = &gprsRWBuf;

					// 打包上报数据（按RF精简报文的格式）
					i = pack_rf_send_data(pGprs, totalSeconds);
				
					try_count = 3;
					while(try_count--)
					{
						j = rf_app_send_data(i, Task_sendBuff);
						if(j == 1)
						{
							rf_fail_count = 0;
							LoopBuff_RemoveItems(&gprsBuff, 1);
							break;
						}
					}
					if(j == 0)
					{
						rf_fail_count++;
						if(rf_fail_count >= 3)
						{
							// 清除网关信息
							rf_fail_count = 0;
							rf_clear_gateway();
						}
						// 下次再来
						break;
					}
				}
							
				// 关闭射频模块
				RF_PowerOff();
			}
		}
		
		// 如果没有卡，或者没有注册进网络，采集以后休眠
		if(!dcBuff.dtuData.networked)
		{
			// 检查是否进入掉电模式
			Wakeup_Powerdown();				
			continue;
		}
		
		// 检测发送采集数据的信号
		if(semGPRS || semSync)
		{			
			if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPRS_Send_Task)
			{ 
				// 是否下载参数：数据服务器
				downloadParam = 0;
				ackParam = 0;
				dcBuff.configDisplay.op_SERVER_PROTOCOL =SERVER_PROTOCOL_PAKISTAN;	
				if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_HTTPS)
				{
					try_count = 2;
					while((try_count--) && LoopBuff_GetCount(&gprsBuff) > 0)
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;

						if(Sim808_Connect(1, dcBuff.configData.server, dcBuff.configData.port))
						{
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
								i = pack_json_send_data(pGprs, totalSeconds);							
								sprintf((char *) Task_sendBuff, http_header_fmt, SERVER_URLs[dcBuff.configDisplay.op_SERVER_INDEX], dcBuff.configData.server, i);
							
								//printf("\n\n%s%s\n", Task_sendBuff, JSON_data());

								recvLen = 0;		// 发送HTTP头，完了直接返回，不等结果
								if(!Sim808_SendAndRecv(1, Task_sendBuff, strlen((char *) Task_sendBuff), &recvLen, Task_recvBuff, sizeof(Task_recvBuff)))
									break;
								recvLen = 15;		// 发送数据，完了等结果
								if(!Sim808_SendAndRecv(1, (uint8_t *) JSON_data(), i, &recvLen, Task_recvBuff, sizeof(Task_recvBuff)))
									break;

								printf("\n\n%s\n", Task_recvBuff);
								if(!strstr((char *) Task_recvBuff, "HTTP/1.1 200 OK"))
								{
									strcpy(dcBuff.powerInfo.gprsFailCode, "HTTP");
									break;
								}
								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);
								
							// 关闭和服务器的连接
							DTU_Close(1);
						}
					}
				}
        if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_PAKISTAN)
				{
					try_count = 2;
					while((try_count--) && LoopBuff_GetCount(&gprsBuff) > 0)
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;

            char *Pakistan_url = "/workflows/1d1d3a530dea461f88c0333ab0a0102a/triggers/manual/paths\
/invoke?api-version=2016-10-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&\
sig=dFgP23aabJi6dMl7X2wf8JBfexlMB4xO7Zy6Gkxb2CI";
            char *Pakistan_server = "prod-68.eastus.logic.azure.com";
            uint16_t Pakistan_port = 443;
            
//						if(Sim808_Connect(1, dcBuff.configData.server, dcBuff.configData.port))
            if(Sim808_Connect(1, Pakistan_server, Pakistan_port))
						{
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
//								i = pack_json_send_data(pGprs, totalSeconds);		
//                char *Pakistan_example = "{\"PSN\":2456548901234,\"Tank_Pressure\":12,\"Tank_Level\":400.55,\
//\"Manf_Pressure\":8,\"Tank_Pressure_High\":10,\"Tank_Pressure_Low\":2,\"Tank_Level_High\":600.45,\
//\"Tank_Level_Low\":200.00,\"Tank_Level_Reorder\":350.00,\"Manf_Pressure_High\":5,\
//\"Manf_Pressure_Low\":1,\"Interval\":45}";              
//                i = strlen(Pakistan_example);
                i = Pack_Pakistan_Json_Data();
								sprintf((char *) Task_sendBuff, http_header_fmt, Pakistan_url, Pakistan_server, i);
							
							//	printf("\n\n%s%s\n", Task_sendBuff, pakistan_data);

								recvLen = 0;		// 发送HTTP头，完了直接返回，不等结果
								if(!Sim808_SendAndRecv(1, Task_sendBuff, strlen((char *) Task_sendBuff), &recvLen, Task_recvBuff, sizeof(Task_recvBuff)))
									break;
								recvLen = 15;		// 发送数据，完了等结果
								if(!Sim808_SendAndRecv(1, (uint8_t *) pakistan_data, i, &recvLen, Task_recvBuff, sizeof(Task_recvBuff)))
									break;
//if(!Sim808_SendAndRecv(1, (uint8_t *) Pakistan_example, i, &recvLen, Task_recvBuff, sizeof(Task_recvBuff)))
//								break;
								
								
								//printf("\n\n%s\n", Task_recvBuff);
//								if(!strstr((char *) Task_recvBuff, "HTTP/1.1 200 OK"))
//								{
//									strcpy(dcBuff.powerInfo.gprsFailCode, "HTTP");
//									break;
//								}
								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);
								
							// 关闭和服务器的连接
							DTU_Close(1);
						}
					}
				}
				else if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_MQTT)
				{
					// 检查阿里云密钥是否有效，如无效则下载
					try_count = 2;
					while((try_count--) &&
						(aliyunSecret.check != 0x55AA || memcmp(aliyunSecret.PSN, dcBuff.configBottle.PSN, 6) != 0))
					{
						// 连接升级服务器
						if(Sim808_Connect(0, dcBuff.configData.upgServer, dcBuff.configData.upgPort))
						{
							printf("\nDownload aliyun secret ...\n");

							memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
										
							i = sizeof(bluetooth_send_t);
							
							// PSN
							memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
							i += 6;
							
							// 填写固定字段
							i = fill_biDir_fixFields(0xD037, i);
					
							// 发送i个字节到服务器，至少接收10个字节
							// 如果失败，下次再发送
							recvLen = sizeof(bluetooth_recv_t) + 2;
							if(Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
							{
								if(recvLen >= sizeof(bluetooth_recv_t) + 2
									&& MODBUS_RTU_CRC16(Task_recvBuff, recvLen) == 0)
								{
									if(recvLen >= sizeof(bluetooth_recv_t) + ALIYUN_SECRET_SIZE + 2
										&& pRecv->cmd == ntohs(0x0037)
										&& MODBUS_RTU_CRC16(Task_recvBuff, sizeof(bluetooth_recv_t) + ALIYUN_SECRET_SIZE + 2) == 0)
									{
										// 保存参数
										memmove(aliyunSecret.PSN, dcBuff.configBottle.PSN, 6);
										strcpy(aliyunSecret.product, (char *) Task_recvBuff + sizeof(bluetooth_recv_t));
										strcpy(aliyunSecret.device, (char *) Task_recvBuff + sizeof(bluetooth_recv_t) + sizeof(aliyunSecret.product));
										strcpy(aliyunSecret.secret, (char *) Task_recvBuff + sizeof(bluetooth_recv_t) + sizeof(aliyunSecret.product) + sizeof(aliyunSecret.device));
										FRAM_SaveInfo(FRAM_ALIYUN_SECRET_BASE, (uint8_t *) &aliyunSecret, sizeof(aliyunSecret));
									}
								}
							}
\
							// 关闭和服务器的连接
							DTU_Close(0);
						}
					}
					
					try_count = 2;
					while((try_count--) && aliyunSecret.check == 0x55AA 
						&& memcmp(aliyunSecret.PSN, dcBuff.configBottle.PSN, 6) == 0
						&& LoopBuff_GetCount(&gprsBuff) > 0)
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;

						if(Sim808_MqttConnect(SERVER_URLs[dcBuff.configDisplay.op_SERVER_INDEX], dcBuff.configData.port, aliyunSecret.product, aliyunSecret.device, aliyunSecret.secret))
						{
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
								i = pack_gprs_send_data(pGprs, totalSeconds);

								if(!Sim808_MqttPublish(Task_sendBuff, i, aliyunSecret.product, aliyunSecret.device))
									break;
								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);
								
							// 关闭和服务器的连接
							MQTT_Close();
						}
					}
				}
				else if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_TCP)
				{
					try_count = 2;
					while((try_count--) && (LoopBuff_GetCount(&gprsBuff) > 0 // || Config_CheckUpdate(&dcBuff) 
						|| downloadParam || ackParam))
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;
						
						if(Sim808_Connect(0, dcBuff.configData.server, dcBuff.configData.port))
						{
							// 普莱克斯、林德、宝钢的不再上传
							if(dcBuff.configBottle.serverVer != 3 && dcBuff.configBottle.serverVer != 4 && 
								dcBuff.configBottle.serverVer != 5
								&& !dcBuff.configDisplay.op_UNIDIR_COMM && Config_CheckUpdate(&dcBuff))
							{
								printf("\nUpload parameters ...\n");

								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								// 参数时间戳
								Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.ts));
								i += 4;
								// 打包参数
								pParam = (param_data_t *) (Task_sendBuff + i);
								pack_param_DO23_data(pParam);
								i += sizeof(param_data_t);
								
								// 填写固定字段
								i = fill_biDir_fixFields(0xD023, i);
						
								// 发送i个字节到服务器，至少接收10个字节
								// 如果失败，下次再发送
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									if(recvLen >= sizeof(bluetooth_recv_t) + 2 
										&& pRecv->cmd == ntohs(0x0023)
										&& MODBUS_RTU_CRC16(Task_recvBuff, sizeof(bluetooth_recv_t) + 2) == 0)
									{
										// 清除更新标志，保存参数
										dcBuff.configBottle.updateFlag = 0;
										Config_SaveConfig();
//										Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_BOTTLE_CONFIG, &display_modifi);
									}
								}
								else
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
							}
							
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
								i = pack_gprs_send_data(pGprs, totalSeconds);
							
								recvLen = 2;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
									break;
								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;

								// 从GPRS切换到RF，需要重新搜索网关
								rf_fail_count = 0;
								rf_clear_gateway();
								
								if(!dcBuff.configDisplay.op_UNIDIR_COMM)
								{
									if(recvLen >= 2 && Task_recvBuff[0] == 0xFF && Task_recvBuff[1] == 0x0F)
									{
										// 普莱克斯、林德的不再下载
										if(dcBuff.configBottle.serverVer != 3 && dcBuff.configBottle.serverVer != 4)
											downloadParam = 1;
									}
								}
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);

							// 下载参数
							if(downloadParam)
							{
								printf("\nDownload parameters ...\n");

								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								
								// 宝钢版本：用D046替代D021, 因为服务器端没有完整的参数信息，只能修改个别参数
								if(dcBuff.configBottle.serverVer == 5)
								{
									// 填写固定字段
									i = fill_biDir_fixFields(0xD046, i);
								}
								else 
								{
									// 参数时间戳
									Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.ts));
									i += 4;
									// 填写固定字段
									i = fill_biDir_fixFields(0xD021, i);
								}
								// 发送i个字节到服务器，至少接收10个字节
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									if(recvLen >= sizeof(bluetooth_recv_t) + 2
										&& MODBUS_RTU_CRC16(Task_recvBuff, recvLen) == 0)
									{
										downloadParam = 0;
										
										if(recvLen >= sizeof(bluetooth_recv_t) + sizeof(param_data_t) + 2
											&& pRecv->cmd == ntohs(0x0021)
											&& MODBUS_RTU_CRC16(Task_recvBuff, sizeof(bluetooth_recv_t) + sizeof(param_data_t) + 2) == 0)
										{
											// 解析参数
											pParam = (param_data_t *) (Task_recvBuff + sizeof(bluetooth_recv_t));
											parse_param_D021_data(pParam);												
											// 清除更新标志，
											dcBuff.configBottle.updateFlag = 0;
										}
										else if(recvLen >= sizeof(bluetooth_recv_t) + D046_PARAM_SIZE + 2
											&& pRecv->cmd == ntohs(0x0046)
											&& MODBUS_RTU_CRC16(Task_recvBuff, sizeof(bluetooth_recv_t) + D046_PARAM_SIZE + 2) == 0)
										{
											// 保存参数
											parse_param_D046_data(Task_recvBuff + sizeof(bluetooth_recv_t), &reset);
										}
										// 保存参数
										Config_SaveConfig();
//										Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_BOTTLE_CONFIG, &display_modifi);
//										Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_SENSOR_CONFIG, &display_modifi);
//										Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_DATA_CONFIG, &display_modifi);
										
										ackParam = 1;
									}
								}
								else
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
							}
							
							// 确认参数
							if(ackParam)
							{
								printf("\nConfirm download parameters ...\n");

								// 发送确认
								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								// 参数时间戳
								Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.ts));
								i += 4;
								
								// 填写固定字段
								i = fill_biDir_fixFields(0xD022, i);
						
								// 发送i个字节到服务器，至少接收10个字节
								// 如果失败，下次再发送
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
								ackParam = 0;
							}
							
							// 关闭和服务器的连接
							DTU_Close(0);
						}
					}
				}
				else if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_AOYANG)
				{
					try_count = 2;
					while((try_count--) && LoopBuff_GetCount(&gprsBuff) > 0)
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;
						
						if(Sim808_Connect(0, dcBuff.configData.server, dcBuff.configData.port))
						{
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
								i = pack_aoyang_send_data(pGprs, totalSeconds);
								printf("\ni=%d:%s\n", i, (char *) Task_sendBuff);

								recvLen = 7;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
									break;
								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;

								// 从GPRS切换到RF，需要重新搜索网关
								rf_fail_count = 0;
								rf_clear_gateway();
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);

							// 关闭和服务器的连接
							DTU_Close(0);
						}
					}
				}
				else if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_BRASIL)
				{
					try_count = 2;
					while((try_count--) && LoopBuff_GetCount(&gprsBuff) > 0)
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;
						
						if(Sim808_Connect(0, dcBuff.configData.server, dcBuff.configData.port))
						{
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
								i = pack_brasil_send_data(pGprs, totalSeconds);
								printf("\ni=%d:%s\n", i, (char *) Task_sendBuff);

								recvLen = 47;
								memset(Task_recvBuff, 0, sizeof(Task_recvBuff));
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE - 1))
									break;								
								if(!parse_brasil_recv_data((char *) Task_recvBuff, pGprs, totalSeconds))
									continue;
								if(save_brasil_issue_parameters())
								{
									// 保存参数
									Config_SaveConfig();
//									Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_BOTTLE_CONFIG, &display_modifi);
//									Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_SENSOR_CONFIG, &display_modifi);
//									Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_DATA_CONFIG, &display_modifi);
								}

								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;

								// 从GPRS切换到RF，需要重新搜索网关
								rf_fail_count = 0;
								rf_clear_gateway();
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);

							// 关闭和服务器的连接
							DTU_Close(0);
						}
					}
				}
				else if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_FURUI 
					 || dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_HUIDA)
				{
					try_count = 2;
					while((try_count--) && LoopBuff_GetCount(&gprsBuff) > 0)
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;
						
						if(Sim808_Connect(0, dcBuff.configData.server, dcBuff.configData.port))
						{
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
								if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_FURUI)
									i = pack_furui_send_data(pGprs, &relativeTime);
								else
									i = pack_huida_send_data(pGprs, &relativeTime);

								printf("\nSend %d bytes to server:\n", i);
								for(j = 0; j < i; j++)
									printf("%02X ", Task_sendBuff[j]);
								printf("\n");
								
								recvLen = 6;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
									break;
								if((dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_FURUI && !parse_furui_recv_data(dcBuff.configBottle.PSN, relativeTime, recvLen))
									|| (dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_HUIDA && !parse_huida_recv_data(dcBuff.configBottle.PSN, relativeTime, recvLen)))
								{
									break;
								}
								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;

								// 从GPRS切换到RF，需要重新搜索网关
								rf_fail_count = 0;
								rf_clear_gateway();
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);

							// 关闭和服务器的连接
							DTU_Close(0);
						}
					}
				}
				else if(dcBuff.configDisplay.op_SERVER_PROTOCOL == SERVER_PROTOCOL_CHAOYANG)
				{
					try_count = 2;
					while((try_count--) && LoopBuff_GetCount(&gprsBuff) > 0)
					{
						// 第一条记录，连接就开始计数
						if(LoopBuff_GetCount(&gprsBuff) > 0)
							dcBuff.powerInfo.gprsSendCount++;
						
						if(Sim808_Connect(0, dcBuff.configData.server, dcBuff.configData.port))
						{
							nextPtr = gprsBuff.info.rdPtr;
							for(k = 0; k < LoopBuff_GetCount(&gprsBuff); k++)
							{
								if(k > 0) // 第一条发送计数在连接之前
									dcBuff.powerInfo.gprsSendCount++;

								FRAM_BufferRead(LoopBuff_GetDataPos(&gprsBuff, nextPtr), (uint8_t *) &gprsRWBuf, sizeof(gprs_data_t));
								pGprs = &gprsRWBuf;

								nextPtr = LoopBuff_GetNextPtr(&gprsBuff, nextPtr);
								
								// 打包上报数据（按modbus从机响应的格式）
								i = pack_chaoyang_send_data(pGprs, &relativeTime);

								printf("\nSend %d bytes to server:\n", i);
								for(j = 0; j < i; j++)
									printf("%c", Task_sendBuff[j]);
								printf("\n");
								
								recvLen = 0;	// 服务器无应答
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
									break;
								dcBuff.powerInfo.gprsSuccCount++;

								// 最近一条上传数据的采集时间
								DTU_dataTime = pGprs->sample_time;

								// 从GPRS切换到RF，需要重新搜索网关
								rf_fail_count = 0;
								rf_clear_gateway();
							}
							
							// 移除已成功发送的数据
							if(k > 0)
								LoopBuff_RemoveItems(&gprsBuff, k);

							// 关闭和服务器的连接
							DTU_Close(0);
						}
					}
				}
				
				// 是否连接维护平台：每隔12小时一次（普莱克斯、林德的每次连接）
				if(dcBuff.configBottle.serverVer == 3 || dcBuff.configBottle.serverVer == 4 ||
					(!dcBuff.configDisplay.op_UNIDIR_COMM && 
					(totalSeconds < INITIAL_TRAN_COUNT * (dcBuff.configData.intervalSample > 300 ? 300 : dcBuff.configData.intervalSample) 
						|| totalSeconds + 3 >= DTU_ldmsTime + 43200 || DTU_ldmsConn)))
				{
					// 清除强制连接维护平台标志
					DTU_ldmsConn = 0;
					
					// 保存连接维护平台时间（刚复位时连续上传6次，但只保存第一次）
					if(totalSeconds >= 3600)
						DTU_ldmsTime = totalSeconds;
					
					// 是否升级或下载参数：维护平台
					upgrade = 0;
					ackUpgrade = 0;
					downloadParam = 0;
					ackParam = 0;
					downloadConfig = 0;
					ackConfig = 0;
					reset = 0;
					k = 1;	// 发送1条诊断信息

					try_count = 2;
					while((try_count--) && (k || upgrade || ackUpgrade || downloadParam || ackParam || downloadConfig || ackConfig))
					{
						// 连接升级服务器
						strcpy(dcBuff.configData.upgServer, "extra.cd-ls.cn");
						dcBuff.configData.upgPort=7006;
						if(Sim808_Connect(0, dcBuff.configData.upgServer, dcBuff.configData.upgPort))
						{
							if(k)
							{
								// 发送诊断信息，至少接收12个字节
								i = pack_ldms_info_Ext_data(DTU_dataTime, totalSeconds);
								recvLen = sizeof(bluetooth_recv_t) + 2 + 2;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
								if(recvLen >= sizeof(bluetooth_recv_t) + 2 + 2 && MODBUS_RTU_CRC16(Task_recvBuff, recvLen) == 0
									&& pRecv->cmd == ntohs(0x0045))
								{
									upgrade = Task_recvBuff[sizeof(bluetooth_recv_t)];
									downloadParam = Task_recvBuff[sizeof(bluetooth_recv_t) + 1];
									downloadConfig = Task_recvBuff[sizeof(bluetooth_recv_t) + 2];
									k--;	// 发送成功
								}
							}

							// 下载参数
							if(downloadParam)
							{
								printf("\nDownload parameters ...\n");

								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								
								// 填写固定字段
								i = fill_biDir_fixFields(0xD046, i);
						
								// 发送i个字节到服务器，至少接收10个字节
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									if(recvLen >= sizeof(bluetooth_recv_t) + 2
										&& MODBUS_RTU_CRC16(Task_recvBuff, recvLen) == 0)
									{
										downloadParam = 0;
										
										if(recvLen >= sizeof(bluetooth_recv_t) + D046_PARAM_SIZE + 2
											&& pRecv->cmd == ntohs(0x0046)
											&& MODBUS_RTU_CRC16(Task_recvBuff, sizeof(bluetooth_recv_t) + D046_PARAM_SIZE + 2) == 0)
										{
											// 保存参数
											if(parse_param_D046_data(Task_recvBuff + sizeof(bluetooth_recv_t), &reset))
											{
												// 保存参数
												Config_SaveConfig();
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_BOTTLE_CONFIG, &display_modifi);
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_SENSOR_CONFIG, &display_modifi);
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_DATA_CONFIG, &display_modifi);
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_DISPLAY_CONFIG, &display_modifi);
											}
											ackParam = 1;
										}
									}
								}
								else
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
							}
							
							// 确认参数
							if(ackParam)
							{
								printf("\nConfirm download parameters ...\n");

								// 发送确认
								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								// 参数时间戳
								Int2ByteL(Task_sendBuff, i, htonl(dcBuff.configBottle.ts));
								i += 4;
								
								// 填写固定字段
								i = fill_biDir_fixFields(0xD022, i);
						
								// 发送i个字节到服务器，至少接收10个字节
								// 如果失败，下次再发送
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
								ackParam = 0;
							}

							// 下载配置
							if(downloadConfig)
							{
								printf("\nDownload configuration ...\n");

								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								
								// 填写固定字段
								i = fill_biDir_fixFields(0xD048, i);
						
								// 发送i个字节到服务器，至少接收10个字节
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									if(recvLen >= sizeof(bluetooth_recv_t) + 2
										&& MODBUS_RTU_CRC16(Task_recvBuff, recvLen) == 0)
									{
										downloadConfig = 0;
										
										if(recvLen >= sizeof(bluetooth_recv_t) + D048_CONFIG_SIZE + 2
											&& pRecv->cmd == ntohs(0x0048)
											&& MODBUS_RTU_CRC16(Task_recvBuff, sizeof(bluetooth_recv_t) + D048_CONFIG_SIZE + 2) == 0)
										{
											// 保存参数
											if(parse_config_D048_data(Task_recvBuff + sizeof(bluetooth_recv_t)))
											{
												// 保存参数
												Config_SaveConfig();
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_BOTTLE_CONFIG, &display_modifi);
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_SENSOR_CONFIG, &display_modifi);
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_DATA_CONFIG, &display_modifi);
//												Can_Write(CONFIG_BOARD_SAMPLE,CAN_DC_DISPLAY_CONFIG, &display_modifi);
											}
											ackConfig = 1;
										}
									}
								}
								else
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
							}
							
							// 确认配置
							if(ackConfig)
							{
								printf("\nConfirm download configuration ...\n");

								// 发送确认
								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								
								// 填写固定字段
								i = fill_biDir_fixFields(0xD039, i);
						
								// 发送i个字节到服务器，至少接收10个字节
								// 如果失败，下次再发送
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
								ackConfig = 0;
								// 配置改变，需要复位
								reset = 1;
							}

							// 升级
							if(upgrade)
							{
								printf("\nUpgrade software ...\n");

								// 从FRAM读取初始进度
								FRAM_LoadInfo(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo));

								if(upInfo.fileSize == 0)
								{
									// 从头开始升级
									memset(&upInfo, 0, sizeof(upInfo));
									// 保存到铁电
									for(write_count = 0; write_count < 2; write_count++)
									{
										FRAM_SaveInfo(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo));
										if(FRAM_BufferVerify(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo)))
											break;
										printf("**** Verify FRAM failed at: 0x%08X, %d bytes\n", FRAM_UPGRADE_INFO_BASE, sizeof(upInfo));
										delay_ms(200);
									}
								}

								// 下载数据
								while(upInfo.fileSize == 0 || upInfo.offset < upInfo.fileSize)
								{
									memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
												
									i = sizeof(bluetooth_send_t);
									
									// PSN
									memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
									i += 6;
									// 当前固件号
									Int2ByteL(Task_sendBuff, i, htonl(upInfo.ver));
									i += 4;
									// 文件偏移量
									Int2ByteL(Task_sendBuff, i, htonl(upInfo.offset));
									i += 4;
									// 请求数据长度
									Int2ByteL(Task_sendBuff, i, htonl(UPGRADE_DATA_LEN));
									i += 4;
									
									// 填写固定字段
									i = fill_biDir_fixFields(0xD0E0, i);
							
									// 发送i个字节到服务器，至少接收10个字节
									// 如果失败，下次再升级
									recvLen = sizeof(bluetooth_recv_t) + 2;
									if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
										break;
									
									if(recvLen >= sizeof(bluetooth_recv_t) + 2 && MODBUS_RTU_CRC16(Task_recvBuff, recvLen) == 0)
									{
										if(pRecv->cmd == ntohs(0x00E0))
										{
											pFrame = (upgrade_frame_t *) (Task_recvBuff + sizeof(bluetooth_recv_t));
											if(MODBUS_RTU_CRC16(pFrame->data, ntohl(pFrame->len) + 2) == 0)
											{
												// 升级内容下载成功，允许继续升级
												try_count = 2;

												// 如果升级包有变化
												if(upInfo.fileSize > 0 && (upInfo.fileSize != ntohl(pFrame->fileSize) || upInfo.fileCrc != pFrame->fileCrc
													|| upInfo.offset > ntohl(pFrame->fileSize) || upInfo.ver != ntohl(pFrame->ver)))
												{
													// 从头开始升级
													memset(&upInfo, 0, sizeof(upInfo));
													// 保存到铁电
													for(write_count = 0; write_count < 2; write_count++)
													{
														FRAM_SaveInfo(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo));
														if(FRAM_BufferVerify(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo)))
															break;
														printf("**** Verify FRAM failed at: 0x%08X, %d bytes\n", FRAM_UPGRADE_INFO_BASE, sizeof(upInfo));
														delay_ms(200);
													}
													continue;
												}
												// 保存下载信息
												// 如果只是网络通信失败，会断点续传
												upInfo.ver = ntohl(pFrame->ver);
												upInfo.fileSize = ntohl(pFrame->fileSize);
												upInfo.offset = ntohl(pFrame->offset);
												upInfo.len = ntohl(pFrame->len);
												upInfo.fileCrc = pFrame->fileCrc;
												printf("\nfileSize = %d, offset = %d, len = %d\n", 
													upInfo.fileSize, upInfo.offset, upInfo.len);
									
												// 如果是第一个包，先将升级请求改为0，以免意外重启导致boot-loader解压
												// 待全部下载完以后，再改为1
												if(upInfo.offset == 0)
													((TUpgradeHeader *) pFrame->data)->upgrade_request = 0;
#if UPGRADE_DATA_LEN >= SFLASH_ERASE_SIZE
												// 直接写入flash
												for(write_count = 0; write_count < 2; write_count++)
												{
													SFlash_BufferWrite(SFLASH_UPGRADE_BASE + upInfo.offset, pFrame->data, upInfo.len);
													if(SFlash_BufferVerify(SFLASH_UPGRADE_BASE + upInfo.offset, pFrame->data, upInfo.len))
														break;
													printf("**** Verify SFlash failed at: 0x%08X, %d bytes\n", SFLASH_UPGRADE_BASE + upInfo.offset, upInfo.len);
													delay_ms(200);
												}
												upInfo.offset += upInfo.len;
#else												
												// 为了减少flash的多次擦写，又节约收发缓冲
												// 先把数据拷到flash页缓冲
												for(write_count = 0; write_count < 2; write_count++)
												{
													FRAM_BufferWrite(FRAM_UPGRADE_DATA_BASE + upInfo.offset % SFLASH_ERASE_SIZE, pFrame->data, upInfo.len);
													if(FRAM_BufferVerify(FRAM_UPGRADE_DATA_BASE + upInfo.offset % SFLASH_ERASE_SIZE, pFrame->data, upInfo.len))
														break;
													printf("**** Verify FRAM failed at: 0x%08X, %d bytes\n", FRAM_UPGRADE_DATA_BASE + upInfo.offset % SFLASH_ERASE_SIZE, upInfo.len);
													delay_ms(200);
												}
												upInfo.offset += upInfo.len;
												
												// 够一页了，或者下载完了就从铁电写入flash
												if(upInfo.offset % SFLASH_ERASE_SIZE == 0)
												{
													FRAM_BufferRead(FRAM_UPGRADE_DATA_BASE, Task_recvBuff, SFLASH_ERASE_SIZE);
													for(write_count = 0; write_count < 2; write_count++)
													{
														SFlash_BufferWrite(SFLASH_UPGRADE_BASE + (upInfo.offset - SFLASH_ERASE_SIZE), Task_recvBuff, SFLASH_ERASE_SIZE);
														if(SFlash_BufferVerify(SFLASH_UPGRADE_BASE + (upInfo.offset - SFLASH_ERASE_SIZE), Task_recvBuff, SFLASH_ERASE_SIZE))
															break;
														printf("**** Verify SFlash failed at: 0x%08X, %d bytes\n", SFLASH_UPGRADE_BASE + (upInfo.offset - SFLASH_ERASE_SIZE), SFLASH_ERASE_SIZE);
														delay_ms(200);
													}

												}
												else if(upInfo.offset == upInfo.fileSize)
												{
													FRAM_BufferRead(FRAM_UPGRADE_DATA_BASE, Task_recvBuff, upInfo.offset % SFLASH_ERASE_SIZE);
													for(write_count = 0; write_count < 2; write_count++)
													{
														SFlash_BufferWrite(SFLASH_UPGRADE_BASE + (upInfo.offset - upInfo.offset % SFLASH_ERASE_SIZE), Task_recvBuff, upInfo.offset % SFLASH_ERASE_SIZE);
														if(SFlash_BufferVerify(SFLASH_UPGRADE_BASE + (upInfo.offset - upInfo.offset % SFLASH_ERASE_SIZE), Task_recvBuff, upInfo.offset % SFLASH_ERASE_SIZE))
															break;
														printf("**** Verify SFlash failed at: 0x%08X, %d bytes\n", SFLASH_UPGRADE_BASE + (upInfo.offset - upInfo.offset % SFLASH_ERASE_SIZE), upInfo.offset % SFLASH_ERASE_SIZE);
														delay_ms(200);
													}
												}
#endif
												for(write_count = 0; write_count < 2; write_count++)
												{
													// 保存到铁电
													FRAM_SaveInfo(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo));
													if(FRAM_BufferVerify(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo)))
														break;
													printf("**** Verify FRAM failed at: 0x%08X, %d bytes\n", FRAM_UPGRADE_INFO_BASE, sizeof(upInfo));
													delay_ms(200);
												}
											}
										}
										else // 命令返回错误
										{
											// 取消本次升级
											upInfo.fileSize = 0;
											// 保存到铁电
											for(write_count = 0; write_count < 2; write_count++)
											{
												FRAM_SaveInfo(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo));
												if(FRAM_BufferVerify(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo)))
													break;
												printf("**** Verify FRAM failed at: 0x%08X, %d bytes\n", FRAM_UPGRADE_INFO_BASE, sizeof(upInfo));
												delay_ms(200);
											}
											
											upgrade = 0;
											break;
										}
									}
								}
								
								if(upInfo.fileSize > 0 && upInfo.offset == upInfo.fileSize)
								{
									SFlash_BufferRead(SFLASH_UPGRADE_BASE, (uint8_t *) &upHeader, sizeof(upHeader));
									// 将升级请求改为1
									upHeader.upgrade_request = 1;
									if(upHeader.check == 0x55AA
										&& do_crc_16(0, (uint8_t *) &upHeader, sizeof(upHeader)) == 0
										&& do_sflash_crc(SFLASH_UPGRADE_BASE + sizeof(upHeader), upHeader.upgrade_length) == 0)
									{
										// 校验通过
										printf("\nUpgrade package confirm passed\n");
										// 发送确认
										ackUpgrade = 1;
									}
									else
									{
										// 校验未通过
										printf("\n****** Upgrade package confirm failed\n");
										// 从头开始
										upInfo.fileSize = 0;
										// 保存到铁电
										for(write_count = 0; write_count < 2; write_count++)
										{
											FRAM_SaveInfo(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo));
											if(FRAM_BufferVerify(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo)))
												break;
											printf("**** Verify FRAM failed at: 0x%08X, %d bytes\n", FRAM_UPGRADE_INFO_BASE, sizeof(upInfo));
											delay_ms(200);
										}
									}
								}
								else
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 继续
									continue;
								}
							}
						
							// 确认升级成功
							if(ackUpgrade)
							{
								printf("\nConfirm upgrade software ...\n");


								// 发送确认
								memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
											
								i = sizeof(bluetooth_send_t);
								
								// PSN
								memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
								i += 6;
								// 当前固件号
								Int2ByteL(Task_sendBuff, i, htonl(upInfo.ver));
								i += 4;
								// 固件的CRC16
								Int2ByteS(Task_sendBuff, i, upInfo.fileCrc);
								i += 2;
								
								// 填写固定字段
								i = fill_biDir_fixFields(0xD0E1, i);
						
								// 发送i个字节到服务器，至少接收10个字节
								// 如果失败，下次再发送
								recvLen = sizeof(bluetooth_recv_t) + 2;
								if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
								{
									// 关闭和服务器的连接
									DTU_Close(0);
									// 重连
									continue;
								}
								if(recvLen == sizeof(bluetooth_recv_t) + 2 && pRecv->cmd == ntohs(0x00E1))
								{
									// 将升级请求改为1
									SFlash_BufferRead(SFLASH_UPGRADE_BASE, (uint8_t *) &upHeader, sizeof(upHeader));
									upHeader.upgrade_request = 1;
									for(write_count = 0; write_count < 2; write_count++)
									{
										SFlash_BufferWrite(SFLASH_UPGRADE_BASE, (uint8_t *) &upHeader, sizeof(upHeader));
										if(SFlash_BufferVerify(SFLASH_UPGRADE_BASE, (uint8_t *) &upHeader, sizeof(upHeader)))
											break;
										printf("**** Verify SFlash failed at: 0x%08X, %d bytes\n", SFLASH_UPGRADE_BASE, sizeof(upHeader));
										delay_ms(200);
									}
									
									// 下次再升级从头开始
									upInfo.fileSize = 0;
									// 保存到铁电
									for(write_count = 0; write_count < 2; write_count++)
									{
										FRAM_SaveInfo(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo));
										if(FRAM_BufferVerify(FRAM_UPGRADE_INFO_BASE, (uint8_t *) &upInfo, sizeof(upInfo)))
											break;
										printf("**** Verify FRAM failed at: 0x%08X, %d bytes\n", FRAM_UPGRADE_INFO_BASE, sizeof(upInfo));
										delay_ms(200);
									}
									// 关闭和服务器的连接
									DTU_Close(0);

									// 关闭DTU电源
									VCC_GSM_OFF();
									delay_ms(200);
									
									// 将LDROM映射到地址0x0
//									FMC_Open();
//									FMC_SetVectorPageAddr(LDROM_BASE);
//									FMC_Close();
									// 复位以后执行Bootloader，将升级包解压
									//WDT_Close(); // 先关看门狗，免得bootloader复位
									NVIC_SystemReset();
								}
							}
							
							// 关闭和服务器的连接
							DTU_Close(0);

							// 确认参数以后才执行复位命令（避免反复复位）
							if(reset && !ackParam)
							{
								VCC_GSM_OFF();
								delay_ms(200);
								NVIC_SystemReset();
							}
						}
					}
				}
			}
			
			// 刚处理完，清除等待的信号。等下一个周期再执行（如果有报警必须立即上传）
			if(dcBuff.sampleData.warnning == 0)
				DTU_semGPRS = 0;
		}
		
		// 检测发送GPS定位信号
		if(semGPS || semSync)
		{
			if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL)
			{
				if(dcBuff.configDisplay.op_SEND_GPS_DATA && Sim808_Connect(0, dcBuff.configData.gpsServer, dcBuff.configData.gpsPort))
				{
					// 如果有待发送数据
					do
					{
						// 根据发送缓冲区的大小，决定一次最多发几条数据
						// 每条记录占12个字节，另外有24个字节的固定字段，比如头信息、PSN、crc等
						// 如果没有合法的记录，发送一条空记录
						gpsCount = GPS_LookData((TASK_SENDBUFF_SIZE - 24) / 12, &gpsInterval, &gpsDone);
						if(gpsCount > 0)
						{
							nextPtr = gpsBuff.info.rdPtr;
							FRAM_BufferRead(LoopBuff_GetDataPos(&gpsBuff, nextPtr), (uint8_t *) &gps, sizeof(gps_data_t));
						}
						
						memset(Task_sendBuff, 0, TASK_SENDBUFF_SIZE);
									
						i = sizeof(bluetooth_send_t);
						
						// PSN
						memmove(Task_sendBuff + i, dcBuff.configBottle.PSN, 6);
						i += 6;
						// 坐标个数
						if(gpsCount > 0)
							Int2ByteS(Task_sendBuff, i, htons(gpsCount));
						else
							Int2ByteS(Task_sendBuff, i, htons(1));
						i += 2;
						// 起始时间戳
						if(gpsCount > 0)
							Int2ByteL(Task_sendBuff, i, htonl(gps.time.tm));
						i += 4;
						// 时间戳增量
						if(gpsCount > 0)
							Int2ByteS(Task_sendBuff, i, htons(gpsInterval));
						i += 2;
						for(j = 0; j < (gpsCount ? gpsCount : 1); j++)
						{
							 // 状态
							if(gpsCount > 0)
								Task_sendBuff[i] = gps.state;
							else
							{
								// 车辆是否启动（根据充电状态决定）
								if(VCC_POWER_STATUS())
									Task_sendBuff[i] |= (1 << 6);
								// 车辆启动状态是否改变）
								Task_sendBuff[i] |= (bat_CurrentEvent << 7);
								bat_CurrentEvent = 0;
							}
							i++;
							// 保留
							i++;
							 // 经度
							if(gpsCount > 0)
								Int2ByteL(Task_sendBuff, i, htonl(gps.longitude));
							i += 4;
							// 纬度
							if(gpsCount > 0)
								Int2ByteL(Task_sendBuff, i, htonl(gps.latitude));
							i += 4;
							// 速度
							if(gpsCount > 0)
								Int2ByteS(Task_sendBuff, i, htons(gps.speed * 100));
							i += 2;
							
							nextPtr = LoopBuff_GetNextPtr(&gpsBuff, nextPtr);
							FRAM_BufferRead(LoopBuff_GetDataPos(&gpsBuff, nextPtr), (uint8_t *) &gps, sizeof(gps_data_t));
						}
						
						// 填写固定字段
						i = fill_biDir_fixFields(0xD010, i);
						
						// 发送i个字节到服务器，至少接收10个字节
						// 如果失败，下次再发送
						recvLen = sizeof(bluetooth_recv_t) + 2;
						if(!Sim808_SendAndRecv(0, Task_sendBuff, i, &recvLen, Task_recvBuff, TASK_RECVBUFF_SIZE))
							break;

						if(gpsCount > 0)
						{
							// 将这几条记录移除
							GPS_MoveFromQueue(gpsCount);
							
							if(gpsDone)
							{
								GPS_Located = 1;
								// 停止超时定时器
								GPS_Waiting = 0;
							}
						}
					} while(!gpsDone);
				}

				// 无论如何，关闭和服务器的连接
				DTU_Close(0);

				// 刚处理完，清除等待的信号。等下一个周期再执行
				DTU_semGPS = 0;
			}
		}

		if(semSync)
		{
			// 刚处理完，清除等待的信号。等下一个周期再执行
			DTU_semSync = 0;
		}
		// 检查是否进入掉电模式
		Wakeup_Powerdown();	
	}
}
