一、   引子

之前都在讲网关,不少网友关注如何实现界面。想了解下位机变量变化,是怎样一步步触发人机界面动画的。

这个步步触发,实质上是变量组(Group)的批量数据变化(DataChange)事件,引发了变量(Tag)的值更新(ValueChanged)事件,最终触发了图元的动画脚本(Action)。这是一个连锁反应。

简言之,界面是一批叫Tag乘客,从网关坐TLV协议的列车,到了上位机车站下车,在ClientService这个舞台上,用各自的乐器(ITagReader)演奏了一出交响乐。

二、   承上启下的核心对象:Tag

Tag(标签或者叫变量)是整个项目的核心对象。所谓核心对象,就是它无所不在,是动态的,流动的,就像血液融汇贯通。

实质上,Tag对下位机,就是一个个传感器的数据、一个个开关信号;对上位机,就是一个个按钮、仪表盘、电机。

Tag在变量管理器(TagConfig)产生,在系统初始化时分配,存在于人机界面程序和网关服务的各个角落,它们的值和时间戳在不断的变化。

对上位机设计者,用到的是Tag的名字、Tag的数据类型;对下位机设计者,看到的是Tag的地址、Tag的长度。对变量报警和数据归档,需要知道Tag的时间戳。

所有的Tag继承于ITag接口。Tag的类型就是数据的类型,有FloatTag(浮点型)、BoolTag(逻辑型)、还有整型、字符型。不同类型Tag的读写对应IReaderWriter接口的ReadXXX/WriteXXX方法。

Tag可以主动去读(Read)写(Write),也可以被动的刷新(Update),强制刷新(Refresh)。

Tag的Read方法是调用所属Group、最终是调用所属IDriver的ReadXXX方法从下位机读入数据。但Tag的主要应用场景是被动刷新触发ValueChanged事件,以驱动人机界面。

三、   上下位机连接的纽带:TLV协议

前文已经阐述了网关如何通过轮询下位机、推送批量数据给上位机。上位机需要将推送来的数据流解析为一堆变化的Tag,以驱动整个人机界面和控制逻辑。

网关和上位机之间通讯,我这里使用了一个自定义的简单的TLV协议(Tag-Length-Value),承载于Socket。

这个协议包括两部分:

  • 数据推送:将网关一端变化的Tag打包封装,传输给客户端;客户端拆包,还原为一堆Tag。具体流程为:
  1. 网关的DataChange事件调用SendData方法,将变化的Tag打包为HistoryData数组(包含变量ID、值、时间戳);
  2. Socket将HistoryData数组转换为字节流推送给客户端;
  3. 客户端的ClientDriver 包含ReciveData方法,将字节流还原为HistoryData数组并触发客户端DataChange事件;
  4. 客户端的DataChange事件将HistoryData数组转换为Tag数组,并调用Tag的Update,触发ValueChanging和ValueChanged事件。
  • 指令:客户端主动向网关发送指令,一般用来读、写特定变量或一批变量,还可以查询历史归档、查询报警等。指令格式如下:

指令码FCTCOMMAND:包含各种命令;

参数:如读入时间段内所有归档数据,则需要起始时间、结束时间;读入变量,则需要变量ID。

返回值:网关接收指令并返回数据,也是字节流。

    public class FCTCOMMAND
{
public const byte fctHead = 0xAB;//报头可加密,如报头不符,则不进行任何操作;客户端Socket发送报警请求,封装于Server
public const byte fctHdaIdRequest = ;//按变量ID读入历史数据
public const byte fctHdaRequest = ;//读时间段内所有历史数据
public const byte fctAlarmRequest = ;//读报警数据
public const byte fctOrderChange = ;//读订单
public const byte fctReset = ;//重置指令,一般用来释放网关套接字
public const byte fctXMLHead = 0xEE;//xml协议
public const byte fctReadSingle = ;//读单一变量
public const byte fctReadMultiple = ;//读多个变量
public const byte fctWriteSingle = ;//写单一变量
public const byte fctWriteMultiple = ;//写多个变量
}

四、   人机界面的驱动引擎:ClientService

人机界面客户端的 ClientService与网关的DAService如出一辙:都具有相类似的结构,继承了IDataServer, IAlarmServer,都从同一个数据库加载驱动、组、变量、报警:

客户端的:

public sealed class DAServer : IDataServer, IAlarmServer, IHDAServer

网关的:

public class DAService : IDataExchangeService, IDataServer, IAlarmServer

只是多了一个IHDAServer,具有查询历史数据的功能,而历史数据归档是网关的功能。

因此,ClientService也带有自己的驱动ClientDriver,ClientDriver也带有自己的组ClientGroup。

注意的是,ClientDriver是上位机唯一的Driver,ClientGroup也是ClientDriver唯一的Group。这是因为上位机无需和各类型下位机打交道,与它打交道的唯一对象就是网关本身。

因此,人机界面的各类操作指令,如按按钮、读归档数据、查询报警等,最终都反映成TLV协议指令发送给网关,并得到反馈。

而人机界面图元的动画,都是来自网关推送的Tag,触发ValueChanged事件;事件的订阅者,就是图元对应的ITagReader,图元动画的幕后指挥。

五、   图元动画的幕后指挥:ITagReader

ITagReader接口为所有图元组件继承,它的功能就是将Tag与动画绑定。先看下结构:

    public interface ITagReader : ITagLink
{
string TagReadText { get; set; }
string[] GetActions();
Action SetTagReader(string key, Delegate tagChanged);
IList<ITagLink> Children { get; }
}

TagReadText属性,就是与图元动画关联的变量表达式:形如Tag1*2+Tag2*5>10。我实现了一个自定义表达式编译器Eval,可以解析表达式语法,分离出Tag1和Tag2。这段代码在Example-WindowHelper-BindingControl。

接着,图元组件订阅Tag1和Tag2的ValueChanged事件。

如果值发生变化,这个事件内部会执行SetTagReader,计算表达式的结果,如满足条件,将向界面发送指令。

例如变量表达式为Tag1*2+Tag2*5>10,此时若Tag1=1,Tag2=2,满足条件,最终会触发一个动画脚本:Action。这个Action可以是让电机报警,颜色变为闪烁的红色;也可以是点亮一盏灯,或打开一座阀门。下文会详细阐述。

从网关到人机界面流程:

六、   下面的计划

写一系列帖子,把架构、原理讲清楚。大致如下:

  • 网关层接口概述
  • 上下位机通讯原理
  • 如何实现一个设备驱动
  • 从网关到人机界面
  • 如何设计图元
  • VS插件模块及原理
  • 归档模块及文件格式
  • 如何进行功能扩展
  • 组态变量表达式实现

github地址:https://github.com/GavinYellow/SharpSCADA。QQ群:102486275

开源纯C#工控网关+组态软件(五)从网关到人机界面的更多相关文章

  1. 开源纯C#工控网关+组态软件

    一.   前言 在园子潜水也七八年了.说来惭愧,这么多年虽然一直自称.NET铁杆粉丝,然仅限于回几个不痛不痒的贴,既没有发布过代码,也没有写过文章. 看着.NET和C#在国外风生水起,国内却日趋没落, ...

  2. 开源纯C#工控网关+组态软件(七)数据采集与归档

    一.   引子 在当前自动化.信息化.智能化的时代背景下,数据的作用日渐凸显.而工业发展到如今,科技含量和自动化水平均显著提高,但对数据的采集.利用才开始起步. 对工业企业而言,数据采集日益受到重视, ...

  3. 开源纯C#工控网关+组态软件(八)表达式编译器

    一.   引子 监控画面的主要功能之一就是跟踪下位机变量变化,并将这些变化展现为动画.大部分时候,界面上一个图元组件的某个状态,与单一变量Tag绑定,比如电机的运行态,绑定一个MotorRunning ...

  4. 开源纯C#工控网关+组态软件(九)定制Visual Studio

    一.   引子 因为最近很忙(lan),很久没发博了.不少朋友对那个右键弹出菜单和连线的功能很感兴趣,因为VS本身是不包含这种功能的.   大家想这是什么鬼,怎么我的设计器没有,其实这是一个微软黑科技 ...

  5. 开源纯C#工控网关+组态软件(十)移植到.NET Core

    一.   引子 写这个开源系列已经十来篇了.自从十年前注册博客园以来,关注了张善友.老赵.xiaotie.深蓝色右手等一众大牛,也围观了逗比的吉日嘎啦.精密顽石等形形色色的园友.然而整整十年一篇文章都 ...

  6. 开源纯C#工控网关+组态软件(二)工控网关的实现

    一.   工控网关是什么 网关是物联网和工控系统的核心组件.网关起的是承上启下的作用.上即上位机,电脑/触屏监控系统.MES这些:下即下位机,包括PLC.传感器.嵌入式芯片等. 不同厂家的下位机,往往 ...

  7. 开源纯C#工控网关+组态软件(三)加入一个新驱动:西门子S7

    一.   引子 首先感谢博客园:第一篇文章.第一个开源项目,算是旗开得胜.可以看到,项目大部分流量来自于博客园,码农乐园,名不虚传^^. 园友给了我很多支持,并提出了很好的改进意见.现加入屏幕分辨率自 ...

  8. 开源纯C#工控网关+组态软件(四)上下位机通讯原理

    一.   网关的功能:承上启下 最近有点忙,更新慢了.感谢园友们给予的支持,现在github上已经有.目标是最好的开源组态,看来又近一步^^ 之前有提到网关是物联网的关键环节,它的作用就是承上启下. ...

  9. 开源纯C#工控网关+组态软件(六)图元组件

    一.   图元概述 图元是构成人机界面的基本单元.如一个个的电机.设备.数据显示.仪表盘,都是图元.构建人机界面的过程就是铺排.挪移.定位图元的过程. 图元设计是绘图和编码的结合.因为图元不仅有显示和 ...

随机推荐

  1. markdown编辑器的学习

    markdown编辑器的学习 1 标题 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 2列表 无序列表 1 2 3 4 有序列表 1 2 3 4 3引用 这里是引用,哈哈我也不知道到我引 ...

  2. WebService的简单介绍与入门使用

    WebService是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布式 ...

  3. RabbitMQ消息队列之二:消费者和生产者

    在使用RabbitMQ之前,需要了解RabbitMQ的工作原理. RabbitMQ的工作原理 RabbitMQ是消息代理.从本质上说,它接受来自生产者的信息,并将它们传递给消费者.在两者之间,它可以根 ...

  4. Azure SQL Database (25) Azure SQL Database创建只读用户

    <Windows Azure Platform 系列文章目录> 本文将介绍如何在Azure SQL Database创建只读用户. 请先按照笔者之前的文章:Azure SQL Databa ...

  5. PHP中isset和empty的区别(最后总结)

    PHP的isset()函数 一般用来检测变量是否设置 格式:bool isset ( mixed var [, mixed var [, ...]] ) 功能:检测变量是否设置 返回值: 若变量不存在 ...

  6. Valgrind检测内存泄露简介

    原文地址: Valgrind 概述 体系结构 Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合.Valgrind由内核(core)以及基于内核的其他调试工具组成.内核 ...

  7. Struts2的核心运行流程,原理图解

    感觉很有必要制定一个计划,这样盲目的想到哪里写到哪里,不符合我大程序员的思维逻辑呀~~~嗯...那就从基本的开始吧,循循渐进,今天想到的先写上,不能浪费了,哈哈哈................... ...

  8. VC++:创建,调用Win32动态链接库

    VC++:创建,调用Win32动态链接库 概述 DLL(Dynamic Linkable Library)动态链接库,Dll可以看作一种仓库,仓库中包含了可以直接使用的变量,函数或类.仓库的发展史经历 ...

  9. Ansible(三) - playbook简介

    Ⅰ. Playbook介绍 Playbook其实就是ansible的一个任务列表,各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个.在顺序运行某playb ...

  10. Java面向对象 正则表达式

     Java面向对象 正则表达式 知识概要:                (1)正则表达式的特点 (2)正则表达的匹配 (3)正则表达式的切割,替换,获取 (4)正则表达式的练习 正则表达式:符合 ...