您的位置:首页 > 其它

DMS结构化数据订阅设计思考

2016-04-03 11:02 288 查看

1背景

本文主要讲述SSIP(Signaling SCADA Integration Platform)人机界面与DMS信息之间的订阅问题。主要包括实时数据库表定义,怎样使用protobuf结构化数据作为订阅的单元?
在SCADA实时监控系统中,图形组态时可以按照常规的模拟量和数字量订阅方式。但是我们也会面临这样的实时结构化的数据,订阅时需要作为整体,那该怎么办呢。
本文将使用一个DMS例子,构思这样的特殊订阅过程。

2 DMS结构定义

序号
内容
字节数
内容说明
1
帧类型
1
0x07
2
ATP时间
4
UNIX时间
3
服务器时间
4
UNIX时间
4
机车号
2
WORD型
5
机车型号
2
WORD型
6
车次
8
字符串直接显示
7
司机号
2
WORD型
8
副司机号
2
WORD型
9
输入交路号
1
10
实际交路号
1
11
车站号
2
WORD型,TMIS号,全路统一且唯一
12
机车运行方向
1
1:上行
2:下行
13
常用制动速度
2
WORD型
14
紧急制动速度
2
WORD型
15
目标速度
2
WORD型
16
目标距离
2
WORD型
17
最大限制速度
2
WORD型
18
允许速度
2
WORD型
19
临时限速速度
2
WORD型
20
ATP等级
1
1:CTCS-0
LKJ控车
2:CTCS-1
LKJ控车
3:CTCS-2
ATP控车
其他值预留
21
ATP模式
1
1:FS【完全监控】
2:PS【部分监控】
3:R0【反向运行】
4:C0【引导】
5:OS【目视】
6:SH【调车】
7:SL休眠模式
8:SB【备用】
9:TR【冒进】
10:PT【冒后】
11:SF【系统故障】
12:IS【隔离】
其他值预留
22
制动信息
1
1:一级常用制动
2:四级常用制动
3:七级常用制动
4:施加紧急制动
5:缓解紧急制动
6:施加常用制动
7:缓解常用制动
其他预留
23
DMI文本信息长度
1
24
DMI文本信息
n
字符串
25
司机对DMI操作信息长度
1
26
司机对DMI操作信息
n
既有线CTCS-2:
包含司机对DMI的操作信息、隔离开关的状态信息、牵引手柄的位置信息和方向手柄的位置信息。
客运专线CTCS-3:
包含司机输入数据信息、司机对列车数据的确认信息。
27
牵引手柄信息
1
1:牵引
2:零位
3:制动
4:异常
其他预留
28
方向手柄信息
1
1:向前
2:向后
其他:预留
29
轨道电路区段名称长度
1
30
轨道电路区段名称
n
31
入口电压
2
WORD型
32
出口电压
2
WORD型
33
最低电压
2
WORD型
34
最高电压
2
WORD型
35
载频编码
1
36
低频编码
1
37
载频
2
载频×10 (Hz)(0xFFFF为未知)
38
低频
2
低频×10(Hz)(0xFFFF为未知)
39
幅度
2
幅度×10(mv)(0xFFFF为未知)
40
RBC报文信息
1
41
RBC报文信息
n
42
经度
4
GPS经度
43
纬度
4
GPS纬度
44
当前速度
2
GPS速度,WORD型
45
动车编号
2
WORD型
46
里程
4
动车组当前运行位置的公里标信息,浮点数FLOAT32
47
线路编号
2
当前运行的线路,全路统一且惟一
48
线路名称长度
1
49
线路名称
N
50
线路行别
1
1上行;2下行
51
前方车站
2
WORD型
52
停发车信息
1
1:区间停车
2:区间发车
3:站内停车
4:站内发车
5:非正常发车
其他:预留
53
信号机种类制式
1
1:进出站
2:出站
3:进站
4:通过
5:预告
6:容许
7:分割
9:第1预告
10:第2预告
其他:预留
54
信号机编号
2
WORD型
55
信号机灯位
2
Bit8=1:闪光
Bit7=1:白
Bit6=1:红
Bit5=1:红黄
Bit4=1:双黄
Bit3=1:黄2
Bit2=1:黄
Bit1=1:绿黄
Bit0=1:绿
56
前方信号种类制式
1
1:进出站
2:出站
3:进站
4:通过
5:预告
6:容许
7:分割
9:第1预告
10:第2预告
其他:预留
57
前方信号机编号
2
WORD型
58
前方信号机灯位
1
Bit7=1:白
Bit6=1:红
Bit5=1:红黄
Bit4=1:双黄
Bit3=1:黄2
Bit2=1:黄
Bit1=1:绿黄
Bit0=1:绿
59
距前方信号机距离
2
WORD型,单位m
60
应答器编号
2
WORD型
61
应答器报文信息长度
1
62
应答器报文信息
n
63
应答器监测结果
1
1:OK
0:为异常
其他:预留
64
应有电容
4
FLOAT32
65
实有电容
4
FLOAT32
66
电容是否失效
1
1:失效
2:正常
其他:预留

3实时库定义

3.1 dms_data数据表

id
列车编号
char(8)
atp_time
ATP时间
uint32
server_time
服务器时间
uint32
train_id
机车号
uint16
train_type
机车型号
uint16
train_number
车次
char(8)
pilot_no
司机号
uint16
copilot_no
副司机号
uint16
input_crossroadno
输入交路号
uint8
real_crossroadno
实际交路号
uint8
station_no
车站号
uint16
dir
机车运行方向
uint8
normalspeed
常用制动速度
uint16
breakspeed
紧急制动速度
uint16
targetspeed
目标速度
uint16
targetdistance
目标距离
uint16
maxspeed
最大限制速度
uint16
permitspeed
允许速度
uint16
tempspeed
临时限速速度
uint16
atp_priority
ATP等级
uint8
atp_mode
ATP模式
uint8
break_info
制动信息
uint8
dmitextlen
DMI文本信息长度
uint8
dmitext
DMI文本信息
char(32)
driverdmilen
司机对DMI操作信息长度
uint8
driverdmitext
司机对DMI操作信息
char(32)
pullhandle
牵引手柄信息
uint8
pullhandle2
方向手柄信息
uint8
trackregionnamelen
轨道电路区段名称长度
uint8
trackregionname
轨道电路区段名称
char(32)
involtage
入口电压
uint16
outvoltage
出口电压
uint16
lowvoltage
最低电压
uint16
maxvoltage
最高电压
uint16
carryfrequencycode
载频编码
uint8
lowfrequencycode
低频编码
uint8
carryfrequency
载频
uint16
lowfrequency
低频
uint16
scope
幅度
uint16
rbc_text
RBC报文信息
uint8
rbc_text2
RBC报文信息
char(32)
longitude
经度
int32
latitude
纬度
int32
currentspeed
当前速度
uint16
runcarcno
动车编号
uint16
mileage
里程
float32
lineno
线路编号
uint16
linenamelen
线路名称长度
uint8
linename
线路名称
char(32)
linelevel
线路行别
uint16
forwardstation
前方车站
uint16
stopcartext
停发车信息
uint8
signaltype
信号机种类制式
uint8
signalno
信号机编号
uint16
signallampposition
信号机灯位
uint16
forwardsignaltype
前方信号种类制式
uint8
forwardsignalno
前方信号机编号
uint16
forwardlampposition
前方信号机灯位
uint8
forwardsignaldistance
距前方信号机距离
uint16
apno
应答器编号
uint16
apgramlen
应答器报文信息长度
uint8
apgramtext
应答器报文信息
char(32)
propercap
应有电容
float32
apresult
应答器监测结果
uint16
realcap
实有电容
float32
capenable
电容是否失效
uint8
注:id主键。

3.2 dms_tempdata数据表

id
列车编号
char(8)
data
数据区
blob(512)
注:id主键。

4 protobuf接口定义

package SSIP;

message dmsData
{
required string id = 1;
optional int32 atp_time = 2;
optional int32 server_time = 3;
optional int32 train_id = 4;
optional int32 train_type = 5;
optional string train_number = 6;
optional int32 pilot_no = 7;
optional int32 copilot_no = 8;
optional uint32 input_crossroadno = 9;
optional uint32 real_crossroadno = 10;
optional int32 station_no = 11;
optional uint32 dir = 12;
optional int32 normalspeed = 13;
optional int32 breakspeed = 14;
optional int32 targetspeed = 15;
optional int32 targetdistance = 16;
optional int32 maxspeed = 17;
optional int32 permitspeed = 18;
optional int32 tempspeed = 19;
optional uint32 atp_priority = 20;
optional uint32 atp_mode = 21;
optional uint32 break_info = 22;
optional string dmitext = 23;
optional string driverdmitext = 24;
optional uint32 pullhandle = 25;
optional uint32 pullhandle2 = 26;
optional string trackregionname = 27;
optional int32 involtage = 28;
optional int32 outvoltage = 29;
optional int32 lowvoltage = 30;
optional int32 maxvoltage = 31;
optional uint32 carryfrequencycode = 32;
optional uint32 lowfrequencycode = 33;
optional int32 carryfrequency = 34;
optional int32 lowfrequency = 35;
optional int32 scope = 36;
optional string rbc_text = 37;
optional int32 longitude = 38;
optional int32 latitude = 39;
optional int32 currentspeed = 40;
optional int32 runcarcno = 41;
optional float mileage = 42;
optional int32 lineno = 43;
optional string linename = 44;
optional uint32 linelevel = 45;
optional int32 forwardstation = 46;
optional uint32 stopcartext = 47;
optional uint32 signaltype = 48;
optional int32 signalno = 49;
optional int32 signallampposition = 50;
optional uint32 forwardsignaltype = 51;
optional int32 forwardsignalno = 52;
optional uint32 forwardlampposition = 53;
optional int32 forwardsignaldistance = 54;
optional int32 apno = 55;
optional string apgramtext = 56;
optional int32 apresult = 57;
optional float propercap = 58;
optional float realcap = 59;
optional uint32 capenable = 60;
}

message dmsDataSet
{
repeated dmsData dms = 1;
}

5构造dms_tempdata数据区

表“dms_tempdata”的字段id与表“dms_data”的字段成一一映射关系。表“dms_tempdata”的字段data主要由两块组成:header+body。Header包含当前data数据体的长度,类型以及描述;body是由表“dms_data”中的字段组合,使用protobuf序列成数据体。



下面的过程为实时库表dms_data结构,序列化到dmsDataSet接口中。

::SSIP::dmsDataSet dms;
::SSIP::dmsData* data = dms.add_dms();
data->set_dms_id(d.dms_id);
data->set_atp_time(d.atp_time);
data->set_server_time(d.server_time);
data->set_train_id(d.train_id);
data->set_train_type(d.train_type);
data->set_train_number(d.train_number);
data->set_pilot_no(d.pilot_no);
data->set_copilot_no(d.copilot_no);
data->set_input_crossroadno(d.input_crossroadno);
data->set_real_crossroadno(d.real_crossroadno);
data->set_station_no(d.station_no);
data->set_dir(d.dir);
data->set_normalspeed(d.normalspeed);
data->set_breakspeed(d.breakspeed);
data->set_targetspeed(d.targetspeed);
data->set_targetdistance(d.targetdistance);
data->set_maxspeed(d.maxspeed);
data->set_permitspeed(d.permitspeed);
data->set_tempspeed(d.tempspeed);
data->set_atp_priority(d.atp_priority);
data->set_atp_mode(d.atp_mode);
data->set_break_info(d.break_info);
data->set_dmitext(d.dmitext);
data->set_driverdmitext(d.driverdmitext);
data->set_pullhandle(d.pullhandle);
data->set_pullhandle2(d.pullhandle2);
data->set_trackregionname(d.trackregionname);
data->set_involtage(d.involtage);
data->set_outvoltage(d.outvoltage);
data->set_lowvoltage(d.lowvoltage);
data->set_maxvoltage(d.maxvoltage);
data->set_carryfrequencycode(d.carryfrequencycode);
data->set_lowfrequencycode(d.lowfrequencycode);
data->set_carryfrequency(d.carryfrequency);
data->set_lowfrequency(d.lowfrequency);
data->set_scope(d.scope);
data->set_rbc_text(d.rbc_text);
data->set_longitude(d.longitude);
data->set_latitude(d.latitude);
data->set_currentspeed(d.currentspeed);
data->set_runcarcno(d.runcarcno);
data->set_mileage(d.mileage);
data->set_lineno(d.lineno);
data->set_linename(d.linename);
data->set_linelevel(d.linelevel);
data->set_forwardstation(d.forwardstation);
data->set_stopcartext(d.stopcartext);
data->set_signaltype(d.signaltype);
data->set_signalno(d.station_no);
data->set_signallampposition(d.signallampposition);
data->set_forwardsignaltype(d.forwardsignaltype);
data->set_forwardsignalno(d.forwardsignalno);
data->set_forwardlampposition(d.forwardlampposition);
data->set_forwardsignaldistance(d.forwardsignaldistance);
data->set_apno(d.apno);
data->set_apgramtext(d.apgramtext);
data->set_apresult(d.apresult);
data->set_propercap(d.propercap);
data->set_realcap(d.realcap);
data->set_capenable(d.capenable);

std::string strOut = dms.SerializeAsString();
int nlen = dms.ByteSize();

BLOB_HEADER hd;
hd.type = NET_BITS_PROTOBUF;
hd.len = strOut.length();
strncpy(hd.desc,"SSIP.dmsDataSet",sizeof(hd.desc));
。。。

dms_tempdata d;
memset(&d, 0,sizeof(tempdata));
strncpy(d.id, d.dms_id.c_str(),sizeof(d.id));
assert(strOut.length() <= (sizeof(d.data) -sizeof(BLOB_HEADER)));
memcpy(d.data, &hd,sizeof(BLOB_HEADER));
memcpy(d.data +sizeof(BLOB_HEADER), strOut.c_str(), strOut.length());
。。。
这里的strOut就是表“dms_tempdata”的protobuf,nlen就是Header信息体的长度。毫无疑问Protobuf结构化数据已经跨平台了,BLOB_HEADER定义的结构也应考虑跨平台封装。

6订阅dms_tempdata数据

订阅规则表达式:
1) key [a-z0-9A-Z]模拟量和数字量
2) key@table.field.type 自定义表和字段
3) key@table.field.type[;field.type]适用blob少量字段分解
4) key@table.field.type[field.xml] 适用blob批量字段分解
当1003列车信息数据产生变化,data数据将主动把这块数据(blob)推送给人机界面。然后HMI使用一个标准动态链接库解析器接口,把data元素进行相应的分解。在这里我们将封装一个接口程序,这个解析器可以回调人机界面处理函数,也可以使用getValue接口分别调用处理。
例:
1003@dms_tempdata.data.blob[;atp_time.uint32;server_time.uint32]
列车编号:1003
实时库表:dms_tempdata
字段域:data
类型:blob
考虑软件工程中的封闭开放原则,能够集成不同的业务范围,不影响整个HMI软件重构。因此,我们使用动态链接库封装此接口—显示调用方式。随着业务范围的变化,我们可以对libblob.dll扩展业务功能,而不需要编译HMI软件。

l libblob.dll接口

extern"C"__declspec(dllexport)

bool

parserBlob(void* buf,constint& type,const
int& len,

const std::string& typedesc, LPFUNC_PARSELUA lpfnPaser)

{

。。。

}

extern"C"__declspec(dllexport)

bool

getValue(const std::string& object, CBaseValue& value)

{

。。。

}

l HMI调用接口
typedefbool (*LPFUNC_PARSELUA)(const
std::string& data);
typedefbool (*PARSEBLOB)(void*
buf,constint& type,const
int& len,

const std::string& desc, LPFUNC_PARSELUA lpfnParser);
typedefbool (*GETVALUE)(const
std::string& object, CBaseValue& value);
PARSEBLOB lpfnParseBlob;
GETVALUE lpfnGetValue;

hInst = LoadLibrary(_T("libblob.dll"));

lpfnParseBlob = (PARSEBLOB)GetProcAddress(hInst,"parserBlob");
lpfnGetValue = (GETVALUE)GetProcAddress(hInst,"getValue");
。。。
FreeLibrary(hInst);

l HMI订阅接口
。。。

int nBlobSize;

void* lpBlobData;

CBaseValue value;

LPFUNC_PARSELUA lpfnParser = (LPFUNC_PARSELUA)parser;

。。。

if (nBlobSize >
sizeof(BLOB_HEADER))

{

BLOB_HEADER* hd = (BLOB_HEADER*)lpBlobData;

if (hd->len <= (nBlobSize -
sizeof(BLOB_HEADER)))

{

void* buf = (char*)lpBlobData +
sizeof(BLOB_HEADER);

if (lpfnParseBlob && lpfnGetValue)

{

(*lpfnParseBlob)(buf, hd->type, hd->len, hd->desc, lpfnParser);

//下面可能循环处理,把data分解的内容释放到不同的动画对象中。

。。。

(*lpfnGetValue)(data->obj, value);

。。。

}

}

}
。。。

7总结

省略。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: