在工控系统开发中,随着项目和业务量的增加,接触到了各种各样的设备,上位工控系统要与设备通过串口、网口、PCI访问,等各种方式实现设备指令的调用。
各种设备指令,在业务调用层被映射到了各种功能调用和视图表现。因为新设备每个项目都在增加,客户也需要对设备的监控或控制的粒度各不同,底层的设备驱动层则要封装大量的功能函数。每次随着新设备的引入,业务场景为了对设备的调用功能更好的描述,也需要更改对应的业务调用。初期采用弱类型,通过在业务层反射类型并识别设备业务调用功能,虽然弱类型实现了设备驱动与业务层的解耦,但是由于是弱依赖,对二次开发人员,进行逻辑开发时,造成了重重的困难,主要是定位问题点不容易,因为弱类型很多时候在运行时进行业务关联。
为了解决设备增加,在软件产品版本中带来的冲击,采用过弱类型设计方案,也采用过公共指令集方式,等等,但是都会在其应用场景中带来很多不便因素。
参阅一些物联网工业标准,例如AllJoyn,其中也会出现大量的设备,而且各种设备也是预先无法界定的,但是其框架的通用性在于,设备只要具备AllJoyn中的接口,就可以实现插入AllJoyn网络的目的。因此在新的版本产品开发中,也引入了基于接口的业务剥离,大量的接口托管,通过其对应的接口容器来托管,设备驱动在实现时,按照框架接口实现,并且业务调用,仅仅支持接口调用,通过设备驱动构建时,注册到接口容器,实现设备实例到接口的关联。基于此思路之后,初期接口数量会随着设备的功能描述,大量增加,随着接口的逐步完善,后续新的设备引入时,不会再出现接口的增加,可能有几百个接口,就可以同时支撑几万种设备的应用了,业务层的开发,也会随着接口的调用,与驱动层完成了剥离。
接口容器类:
/// <summary>
/// 容器接口服务
/// </summary>
interface IDockerService
{
/// <summary>
/// 根据键取消某一个设备注册
/// </summary>
/// <param name="key"></param>
void CancelRegister(string key);
/// <summary>
/// 取消所有注册
/// </summary>
void CancelRegisterAll();
/// <summary>
/// 注册设备到容器
/// </summary>
/// <param name="key">键</param>
/// <param name="device">设备</param>
void RegisterDevice(string key, object device);
}
接口容器基类:
/// <summary>
/// 容器服务基类
/// </summary>
public abstract class BaseDockerService<T> : IDockerService where T : class
{
public BaseDockerService()
{
this.dicMapDictionary = new Dictionary<string,T>();
}
/// <summary>
/// 锁
/// </summary>
protected object syncLock = new object();
/// <summary>
/// 打开映射表
/// </summary>
protected Dictionary<string, T> dicMapDictionary = null;
/// <summary>
/// 注册设备
/// </summary>
/// <param name="key">唯一键</param>
/// <param name="device">设备实例</param>
public virtual void RegisterDevice(string key, object device)
{
if (device is T)
{
lock (syncLock)
{
if (dicMapDictionary == null)
{
dicMapDictionary = new Dictionary<string, T>();
}
if (dicMapDictionary.ContainsKey(key) == false)
{
dicMapDictionary.Add(key, (T)device);
}
}
}
}
/// <summary>
/// 取消注册,清理服务
/// </summary>
public virtual void CancelRegisterAll()
{
lock (syncLock)
{
if (dicMapDictionary != null)
{
dicMapDictionary.Clear();
}
}
}
/// <summary>
/// 取消注册,清理服务
/// </summary>
public virtual void CancelRegister(string key)
{
lock (syncLock)
{
if (dicMapDictionary != null)
{
if (dicMapDictionary.ContainsKey(key))
{
dicMapDictionary.Remove(key);
}
}
}
}
}
日志容器示例实现:
/// <summary>
/// 容器接收日志服务
/// </summary>
public class DockerReceiveLogService : BaseDockerService<IReceiveLog>
{
/// <summary>
/// 日志触发事件
/// </summary>
public event EventHandler<LogEventArgs> OnLogReceived;
/// <summary>
/// 注册设备
/// </summary>
/// <param name="key">唯一键</param>
/// <param name="device">设备实例</param>
public override void RegisterDevice(string key, object device)
{
if (device is IReceiveLog)
{
lock (syncLock)
{
if (dicMapDictionary == null)
{
dicMapDictionary = new Dictionary<string, IReceiveLog>();
}
if (dicMapDictionary.ContainsKey(key) == false)
{
((IReceiveLog)device).OnLogReceived += DockerReceiveLogService_OnLogReceived;
dicMapDictionary.Add(key, (IReceiveLog)device);
}
}
}
}
/// <summary>
/// 日志接收
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void DockerReceiveLogService_OnLogReceived(object sender, LogEventArgs e)
{
if (OnLogReceived != null)
{
OnLogReceived(sender, e);
}
}
}
设备驱动实现基类:
/// <summary>
/// 基础驱动基类服务
/// </summary>
public abstract class BasicDriveService<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse> : IOpen, IClose, IReceiveLog, ISendLog,
IInfoReceived, IConnectSessionInfo
where TRequest : BaseRequestData
where TResponse : BaseResponseData
where TInputMessageFilter : BaseInPutMessageFilter<TRequest>
where TOutputMessageFilter : BaseOutPutMessageFilter<TRequest, TResponse>
{
/// <summary>
/// 连接
/// </summary>
protected ICommunication<TRequest, TResponse> iCommunication;
/// <summary>
/// 启动状态
/// </summary>
public virtual bool IsOpen
{
get
{
if (iCommunication != null)
{
return iCommunication.IsOpen;
}
return false;
}
}
/// <summary>
/// 启动
/// </summary>
/// <param name="isAsyncOpen"></param>
public virtual void Open(bool isAsyncOpen)
{
BaseCommunicationParameters receivePa = this.CreateCommunicationParameters();
if (iCommunication == null)
{
iCommunication = CommunicationFactory<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>.Create(receivePa);
iCommunication.OnResponseInfo += iReceiveCommunication_OnResponseInfo;
iCommunication.OnOperateStaus += iReceiveCommunication_OnOperateStaus;
iCommunication.OnSessionAdded += iReceiveCommunication_OnSessionAdded;
iCommunication.OnSessionRemoved += iReceiveCommunication_OnSessionRemoved;
iCommunication.OnResponseBuffer += iReceiveCommunication_OnResponseBuffer;
}
if (iCommunication.IsOpen == false)
{
iCommunication.Open();
}
}
/// <summary>
/// 构建设备通信参数
/// </summary>
/// <returns></returns>
protected abstract BaseCommunicationParameters CreateCommunicationParameters();
/// <summary>
/// 关闭
/// </summary>
public virtual void Close()
{
if (iCommunication != null)
{
if (iCommunication.IsOpen == true)
{
iCommunication.Close();
}
iCommunication = null;
}
}
/// <summary>
/// 应答处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected abstract void iReceiveCommunication_OnResponseBuffer(object sender, TResponse e);
/// <summary>
/// 连接会话断开
/// </summary>
/// <param name="info"></param>
protected virtual void iReceiveCommunication_OnSessionRemoved(SessionInfo info)
{
if (OnConnectSession != null)
{
ConnectSessionDataEventArgs args=new ConnectSessionDataEventArgs();
OnConnectSession(this, args);
}
}
/// <summary>
/// 连接会话建立
/// </summary>
/// <param name="info"></param>
protected virtual void iReceiveCommunication_OnSessionAdded(SessionInfo info)
{
if (OnConnectSession != null)
{
ConnectSessionDataEventArgs args = new ConnectSessionDataEventArgs();
OnConnectSession(this, args);
}
}
/// <summary>
/// 操作状态反馈
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void iReceiveCommunication_OnOperateStaus(object sender, OperateStatus e)
{
if (e == OperateStatus.Opening)
{
if (OnInfoDataReceived != null)
{
InfoData infoData = new InfoData("请求启动");
InfoDataEventArgs args = new InfoDataEventArgs(infoData);
OnInfoDataReceived(this, args);
}
}
else if (e == OperateStatus.Opened)
{
if (OnInfoDataReceived != null)
{
InfoData infoData = new InfoData("启动成功");
InfoDataEventArgs args = new InfoDataEventArgs(infoData);
OnInfoDataReceived(this, args);
}
}
else if (e == OperateStatus.Closing)
{
if (OnInfoDataReceived != null)
{
InfoData infoData = new InfoData("请求关闭");
InfoDataEventArgs args = new InfoDataEventArgs(infoData);
OnInfoDataReceived(this, args);
}
}
else if (e == OperateStatus.Closed)
{
if (OnInfoDataReceived != null)
{
InfoData infoData = new InfoData("关闭成功");
InfoDataEventArgs args = new InfoDataEventArgs(infoData);
OnInfoDataReceived(this, args);
}
}
}
/// <summary>
/// 消息应答
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void iReceiveCommunication_OnResponseInfo(object sender, ResponseInfo e)
{
if (e.ResponseInfoType == ResponseInfoType.NotifyInfo)
{
if (OnInfoDataReceived != null)
{
InfoData infoData = new InfoData(e.Message);
InfoDataEventArgs args = new InfoDataEventArgs(infoData);
OnInfoDataReceived(this, args);
}
}
else if (e.ResponseInfoType == ResponseInfoType.Exception)
{
}
else if (e.ResponseInfoType == ResponseInfoType.ReceiveLog)
{
if (OnLogReceived != null)
{
LogData logData = new LogData(e.Message);
LogEventArgs args = new LogEventArgs(logData);
OnLogReceived(this, args);
}
}
else if (e.ResponseInfoType == ResponseInfoType.SendLog)
{
if (OnLogSended != null)
{
LogData logData = new LogData(e.Message);
LogEventArgs args = new LogEventArgs(logData);
OnLogSended(this, args);
}
}
}
/// <summary>
/// 接收日志
/// </summary>
public event EventHandler<Base.DriveData.LogEventArgs> OnLogReceived;
/// <summary>
/// 发送日志
/// </summary>
public event EventHandler<Base.DriveData.LogEventArgs> OnLogSended;
/// <summary>
/// 底层的消息通知
/// </summary>
public event EventHandler<InfoDataEventArgs> OnInfoDataReceived;
/// <summary>
/// 会话连接建立断开触发事件
/// </summary>
public event EventHandler<ConnectSessionDataEventArgs> OnConnectSession;
}
驱动实现,此处是一个简单的RMI实现过程,通过透明代理实现元数据的反射实现,此部分为服务器端的连接会话上的调用实现部分:
/// <summary>
/// 调用测试Demo
/// </summary>
public class PDAScanDataService : BasicDriveService<PDAScanDataInputFilter, PDAScanDataOutputFilter, PDAScanDataRequest, PDAScanDataResponse>
{
/// <summary>
/// 创建通信参数
/// </summary>
/// <returns></returns>
protected override BaseCommunicationParameters CreateCommunicationParameters()
{
throw new NotImplementedException();
}
/// <summary>
/// 应答处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected override void iReceiveCommunication_OnResponseBuffer(object sender, PDAScanDataResponse e)
{
if (e.ResponseException != null)
{
if (iCommunication != null && iCommunication.IsOpen == true)
{
PDAScanDataRequest request = new PDAScanDataRequest();
request.ServerSend(e.ResponseException, e.ReturnTypeFullName);
iCommunication.Request(e.SessionID, request);
}
return;
}
try
{
object obj = e.Invoke();
if (iCommunication != null && iCommunication.IsOpen == true)
{
PDAScanDataRequest request = new PDAScanDataRequest();
request.ServerSend(obj, e.ReturnTypeFullName);
iCommunication.Request(e.SessionID, request);
}
}
catch (Exception ex)
{
if (iCommunication != null && iCommunication.IsOpen == true)
{
PDAScanDataRequest request = new PDAScanDataRequest();
request.ServerSend(ex.InnerException, e.ReturnTypeFullName);
iCommunication.Request(e.SessionID, request);
}
}
}
public virtual PDAScanData[] SearchAll(int a)
{
PDAScanData[] list = new PDAScanData[a];
for (int i = 0; i < a; i++)
{
PDAScanData p = new PDAScanData();
p.Id = i;
p.Now = DateTime.Now;
p.Status = STatus.正常;
p.Str = i.ToString("0000000");
list[i] = p;
}
return list;
}
public virtual PDAScanData[] FindAll()
{
PDAScanData[] list = new PDAScanData[30];
for (int i = 0; i < 30; i++)
{
PDAScanData p = new PDAScanData();
p.Id = i;
p.Now = DateTime.Now;
p.Status = STatus.正常;
p.Str = i.ToString("0000000");
list[i] = p;
}
return list;
}
public virtual PDAScanData[] SaveAll(PDAScanData[] collection)
{
for (int i = 0; i < collection.Length; i++)
{
PDAScanData p = collection[i];
int id = p.Id;
}
return collection;
}
public virtual void Save(PDAScanData[] collection)
{
throw new Exception("保存数据失败");
}
}
RMI客户端的调用部分,通信采用TCP,底层基于Json进行序列化和反序列化,此处为客户端Stub:
/// <summary>
/// 测试Demo部分,与服务器端的定义一致
/// </summary>
public class PDAScanDataService : ClientProxy
{
public PDAScanDataService()
: base("Trace.Drive.Service.PDAScanDataService, Trace.Drive.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
{
}
public virtual PDAScanData[] SearchAll(int i)
{
Func<int,PDAScanData[]> tempAction = new Func<int, PDAScanData[]>(SearchAll);
return (PDAScanData[])ClientSend(tempAction, new object[] { i });
}
public virtual PDAScanData[] FindAll()
{
Func<PDAScanData[]> tempAction = new Func<PDAScanData[]>(FindAll);
return (PDAScanData[])ClientSend(tempAction, new object[] { });
}
public virtual PDAScanData[] SaveAll(PDAScanData[] collection)
{
Func<PDAScanData[],PDAScanData[]> tempAction = new Func<PDAScanData[],PDAScanData[]>(SaveAll);
return (PDAScanData[])ClientSend(tempAction, new object[] { collection });
}
public virtual void Save(PDAScanData[] collection)
{
Action<PDAScanData[]> tempAction = new Action<PDAScanData[]>(Save);
ClientSend(tempAction, new object[] { collection });
}
}