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 |
3.2 dms_tempdata数据表
id | 列车编号 | char(8) |
data | 数据区 | blob(512) |
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总结
省略。相关文章推荐
- Linux系统日志
- 位运算实现两个数的加法
- .vimrc
- bzoj 3676 [Apio2014]回文串(Manacher+SAM)
- MUI跨域请求数据的例子:
- 在centos7下安装python3.4的scrapy包
- .NET+Jquery+jquery.ztree 实现树状角色权限设置
- 基于在线评分的协同过滤算法---Slope One算法
- 点到直线的距离
- hdu 3572(最大流)
- 2. Add Two Numbers----LeetCode
- Java类的初始化1
- AngularJs 基础(60分钟入门) (转)
- JavaPersistenceWithHibernate第二版笔记Getting started with ORM-001用JPA和Hibernate实现HellowWorld(JTA、Bitronix)
- MySQL命令行下执行.sql脚本详解
- 小兔与小猫
- #工作两年后的总结
- ZOJ 3875 Lunch Time(结构体排序)
- 十进制到十六进制转换
- CentOS 7 更改默认登陆界面为字符界面