水文行业是近些来兴起的行业之一,其着眼于民生安全,水文工程是利国利民的工程。在这个领域,主要工作内容围绕“水域“展开,如大江、大河、雨水、水蒸汽、泥石流、等等。水文观测和预警涉及人们生命安全,具有不可忽视的重要性。
水文行业观测目前正在进行数字化、自动化转变。其观测具有范围广,面积大,监测点多、分布式等特点。为了实现监测数据的统一管理以及历史备案,水文行业引入了中心服务器这和集中式数据管理方式。所以监测点的数据通过某种协议利用互联网媒介把数据传到中心站,然后数据统一调配统一分析。目前所用的报文方式有实时数据报文和密集数据报文两种方式。
实时数据报文和密集数据报文具有不同的形工,实时报文仅发送某一时间点的观测数据,而密集数据报文则可以一次性发送一组历史观测数据。这对于利用GPRS或卫星信号方式传输信息的应用而言,可以大大减小发送信息量。以下就时实数据报的结构及其编程实现进行叙述。
实时数据报文的帧结构[取自:《公共数据平台实时数据上传协议V2.0》]:
数据段名 | 数据 | 说明 |
起始段 | $AAA |
|
设备编号 | ID | 设备的唯一编号 |
口令段 | Password | 中心站的数据接入口令 |
单位名段 | 单位名 | 观测单位名称 |
测站名段 | 站点名 | 观测站点名称 |
时间段 | 年-月-日 时:分:秒 | 报文发生的观测时间 |
数据段 | 数据1,数据2……数据n | 观测到的数据 |
数据说明段 | 说明1,说明2……说明n | 与数报对应的描述 |
结束段 | $END |
|
在上表中,一个完整的数据报文包含以上9个数据段,数据段与数据段之间用“;”符号隔开,数据段内的并行数据之间用“,”符号隔开,数据报文按ASCII方式发送,中文发送其GB2312编码。以下为一个完整的数据报文示例:
$AAA;46005;11223344;福建水文;建阳站;2010-09-2011:15:00;12.34,12,10,26.7;水位(m),电池电压(V),设备温度(℃);$END
注意以上的符号全部使用半角状态下的英文符号。在数据段与数据说明段,两者必须一一对应,说明段也可以留空使用:
$AAA;46005;11223344;福建水文;建阳站;2010-09-2011:15:00;12.34,12,10,26.7;,,;$END
数据段与数据说明段一一对应,数据个数和保留精度没有做明确规定,这里建议保留到小数点后第二位。
报文的软件实现。在WRTOS平台上,以下根据报文定义实时数据数据结构:
#defineDATA_MAX_LENGTH 5
typedef struct
{
uint8 StartFlag[5]; //$AAA
uint32 DeviceSerNum; //设备编号
uint32 PassWord; //数据中心口令
uint8 *Company; //单位名称
uint8 *Station; //站名称
f32 Datas[DATA_MAX_LENGTH]; //数据区
uint8 DataLength; //数据个数
void *DataExplain[DATA_MAX_LENGTH]; //数据说明
uint8 EndFlag[5]; //$END
}RealtimePacket;
在以上数据结构中,定义了DATA_MAX_LENGTH这样一个参数,用于确定应用中可能出现的最大数据个数,数据统一按浮点处理。
以下为报文的创建方法:
voidRealtimeData_Create(RealtimePacket *NewRTData,uint32 DeviceNum,uint32PassWord,uint8 *Company,uint8 *Station)
{
TTS_StringCopy(NewRTData->StartFlag,"$AAA");
NewRTData->DeviceSerNum=DeviceNum;
NewRTData->PassWord=PassWord;
NewRTData->Company=Company;
NewRTData->Station=Station;
NewRTData->DataLength=0;
TTS_StringCopy(NewRTData->EndFlag,"$END");
}
创建报文之后可以向报文之后可以初始化报文的说明字段,这个字段也可以不做任何说明,但必须和数据个数相对应,这点由报文生成方法保证。
报文的打包方法:
uint16RealtimeData_Packet(RealtimePacket *CurRTData,uint8 *Buffer)
{
uint8 i;
uint8 Tbuffer[20];
uint16 StrLength;
*Buffer = '\0';
TTS_StringAppend(Buffer,CurRTData->StartFlag);
TTS_StringAppend(Buffer,";");
TTS_StringFromNumber(Tbuffer,CurRTData->DeviceSerNum,'D',0); //0~4294967295
TTS_StringAppend(Buffer,Tbuffer);
TTS_StringAppend(Buffer,";");
TTS_StringFromNumber(Tbuffer,CurRTData->PassWord,'D',0);
TTS_StringAppend(Buffer,Tbuffer);
TTS_StringAppend(Buffer,";");
TTS_StringAppend(Buffer,CurRTData->Company);
TTS_StringAppend(Buffer,";");
TTS_StringAppend(Buffer,CurRTData->Station);
TTS_StringAppend(Buffer,";");
TTS_StringFromDataTime1(Tbuffer,&DateTimeNow,'-',':');
TTS_StringAppend(Buffer,Tbuffer);
TTS_StringAppend(Buffer,";");
for(i=0;i<CurRTData->DataLength;i++)
{
TTS_StringFromNumber(Tbuffer,CurRTData->Datas[i],'D',2); //两个数据
if(i>0)TTS_StringAppend(Buffer,",");
TTS_StringAppend(Buffer,Tbuffer);
}
TTS_StringAppend(Buffer,";");
for(i=0;i<CurRTData->DataLength;i++)
{
if(i>0)TTS_StringAppend(Buffer,",");
TTS_StringAppend(Buffer,CurRTData->DataExplain[i]); //解释说明段
}
TTS_StringAppend(Buffer,";");
TTS_StringAppend(Buffer,CurRTData->EndFlag);
StrLength = TTS_StringLenth(Buffer);
return StrLength;
}
使用示例,以下为具体用法:
Void TaskSystem(void*Tags)
{
Uint8 TxBuffer[50];
Uint16 RL;
RealtimePacket RT;
RealtimeData_Create(&RT,0x124334,0x343333,(uint8*)(“测试单位”),(uint8 *)(“测试站点”));
RT. DataExplain[0]=”水位(m)”;
RT. DataExplain[1]=”温度(℃)”;
RT. DataExplain[2]=”电压(V)”;
……
While(1){
Wrtos_TaskSuspend();
……
RT.Datas[0]=Cur_WL;
RT.Datas[1]=Cur_Temper;
RT.Datas[2]=Cur_Voltage;
RL=RealtimeData_Packet(&RT,TxBuffer);
USART1_WriteDatas(TxBuffer,RL,0);
……
}
}