本设计不通用,只针对特定的一类问题。
如果系统经常和多种端口打交道,例如:COM,TCP,UDP,短信,打印机等等外接端口通讯,那么可以这样设计。
每种通讯方式都是类似,连接,打开端口,接收和发送数据,解析数据给系统。
所以可以统一起来进行设计,这样扩充端口更加容易。
使用C#语言描述
public delegate void GameEventDelegate(object sender, Action action);
//
public class Action : EventArgs
{
public PlayPort Receiver = PlayPort.Logic;
public Action(PlayPort sender, ICommand command)
{
Sender = sender;
Receiver = PlayPort.Logic;
Command = command;
}
public Action(PlayPort sender, PlayPort receiver, ICommand command)
{
Sender = sender;
Receiver = receiver;
Command = command;
}
public PlayPort Sender { get; set; }
public ICommand Command { get; set; }
}
//端口服务接口
public interface IPortService
{
event GameEventDelegate OnPort;
void Write(Action action);
}
Write函数:向设备写入数据
OnPort事件接收数据,并通知系统接收数据
Java代码和上面类似!
扩展接口可以这样
public class ControlPanelPort : IPortService
{
private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private ConfigManager config;
private ControlPanelExecutor executor = new ControlPanelExecutor();
ControlPanelPortQueueManager controlPanelPortQueueManager = new ControlPanelPortQueueManager();
private IPersistService persistService;
public event EventHandler DataArrived;
public IDataParser Parser
{
set
{
controlPanelPortQueueManager.Parser = value;
controlPanelPortQueueManager.Start();
}
}
public Queue<byte[]> DataQueue = new Queue<byte[]>();
public ControlPanelPort(IPersistService persistService)
{
this.persistService = persistService;
config = ConfigManager.Instance(persistService.LoadConfig());
Init();
}
public SerialPort ControlPanelSerialPort { get; set; }
#region IPortService Members
public event GameEventDelegate OnPort;
/// <summary>
/// action中的data格式必须为int[]
/// </summary>
/// <param name="action"></param>
public void Write(Action action)
{
try
{
if (action.Receiver != PlayPort.ControlPanel) return;
if (ControlPanelSerialPort != null && ControlPanelSerialPort.IsOpen)
executor.Execute(this, action);
}
catch (IOException ex)
{
log.Error(ex.Message,ex);
if(ControlPanelSerialPort!=null)
ControlPanelSerialPort.Close();
}
}
#endregion
//
private void Init()
{
try
{
ControlPanelSerialPort = new SerialPort("control panel");
ControlPanelSerialPort.PortName = config[ConfigKey.控制面板串口];
ControlPanelSerialPort.BaudRate = 57600;
ControlPanelSerialPort.Handshake = Handshake.None;
ControlPanelSerialPort.DataBits = 8;
ControlPanelSerialPort.StopBits = StopBits.One;
ControlPanelSerialPort.Parity = Parity.None;
ControlPanelSerialPort.ReceivedBytesThreshold = 2;
ControlPanelSerialPort.WriteTimeout = SerialPort.InfiniteTimeout;
ControlPanelSerialPort.ReadTimeout = SerialPort.InfiniteTimeout;
ControlPanelSerialPort.DataReceived += controlPanelPort_DataReceived;
ControlPanelSerialPort.Open();
ControlPanelSerialPort.DiscardInBuffer();
ControlPanelSerialPort.DiscardOutBuffer();
//
controlPanelPortQueueManager.ControlPort = this;
}
catch (Exception ex)
{
log.Error("控制面板端口初始化失败!" + ex.Message);
}
}
private void controlPanelPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (OnPort != null)
{
if (ControlPanelSerialPort == null) return;
Application.DoEvents();
Thread.Sleep(50);
byte[] data = new byte[ControlPanelSerialPort.BytesToRead];
ControlPanelSerialPort.Read(data, 0, data.Length);
log.Warn("<<<<接收控制面板信息,length:" + data.Length);
DataQueue.Enqueue(data);
if (DataArrived != null)
{
DataArrived(this, null);
}
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
}
public void FireOnPort(Action action)
{
if(OnPort!=null)
{
OnPort(this, action);
}
}
}
其他所有的端口扩展都是类似的
在接受端口数据后,将数据直接放到处理队列里面,不要直接将处理代码放到这里,否则影响端口的继续工作,接收数据。不可以认为数据一次性都直接收完毕,数据可能是多次才能接受完成,所以处理的时候都要将数据放到队列里面,然后通过另一个线程处理。
数据接收函数
controlPanelPort_DataReceived
将数据放到队列中
DataQueue.Enqueue(data);
处理完毕后,触发事件,通知订阅者
OnPort(this, action);
Write数据到端口的执行者:ControlPanelExecutor
处理队列数据的管理者:ControlPanelPortQueueManager
持久化服务:IPersistService
其他端口都是类似处理!!!
下面将所有端口统一起来
public class PortProxy : IPortService
PortProxy类型是向前端表露的统一端口代理
他统一了所有端口的访问方式,这里使用了Proxy模式
public class PortProxy : IPortService
{
private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IPortService communicationPortService1;
private IPortService monitorPortService;
private IPortService controlPanelPortService1;
private IPortService printPortService1;
private IPortService tcpPortService1;
private IPortService sMSPortService;
public IPortService CommunicationPortService
{
set
{
communicationPortService1 = value;
communicationPortService1.OnPort += Event_OnPort;
}
}
public IPortService MonitorPortService
{
set
{
monitorPortService = value;
monitorPortService.OnPort += Event_OnPort;
}
}
public IPortService PrintPortService
{
set
{
printPortService1 = value;
printPortService1.OnPort += Event_OnPort;
}
}
public IPortService ControlPanelPortService
{
set
{
controlPanelPortService1 = value;
controlPanelPortService1.OnPort += Event_OnPort;
}
}
public IPortService TcpPortService
{
set
{
tcpPortService1 = value;
tcpPortService1.OnPort += Event_OnPort;
}
}
public IPortService SMSPortService
{
set
{
sMSPortService = value;
sMSPortService.OnPort += Event_OnPort;
}
}
#region IPortService Members
public event GameEventDelegate OnPort;
public void Write(Action action)
{
switch (action.Receiver)
{
case PlayPort.ControlPanel:
{
controlPanelPortService1.Write(action);
}
break;
case PlayPort.Printer:
{
printPortService1.Write(action);
}
break;
case PlayPort.Udp:
{
communicationPortService1.Write(action);
}
break;
case PlayPort.Tcp:
{
tcpPortService1.Write(action);
}
break;
case PlayPort.SMS:
{
sMSPortService.Write(action);
}
break;
case PlayPort.Monitor:
{
monitorPortService.Write(action);
}
break;
default:
Event_OnPort(this, action);
break;
}
}
#endregion
private void Event_OnPort(object sender, Action action)
{
if (OnPort != null)
OnPort(sender, action);
}
}
他代理了所有的端口,另外值得说明的是他充当了一个逻辑接口,该接口是一个虚拟的系统之间通信的接口,并不代表一个实际存在的接口,该接口的存在大大减少了系统模块之间的耦合性
应用的时候通过注入将可以将Port实例注入了
public abstract class AbstractGameState : IGameState
{
protected IPortService logic;
//
protected const PlayPort LOGIC_PORT = PlayPort.Logic;
protected const PlayPort CONTROL_PANEL_PORT = PlayPort.ControlPanel;
protected const PlayPort PRINTER_PORT = PlayPort.Printer;
protected const PlayPort SMS_PORT = PlayPort.SMS;
protected const PlayPort UDP_PORT = PlayPort.Udp;
#region IGameState Members
public IPortService PortService
{
set
{
logic = value;
logic.OnPort += Logic_OnPortEvent;
}
get
{
return logic;
}
}
protected abstract void Logic_OnPortEvent(object sender, Action action);
}
这里面的logic即使端口,他代表了所有的端口服务,通过它可以访问所有的端口,端口服务的客户访问大大简化,也与所有的具体端口松耦合,维护上大为简化
访问方法:
SingleCommand command = SingleCommand.Instance[CommandCode.指令];
command.Data = printParams;
logic.Write(new Action(PlayPort.Logic, PlayPort.Printer, command));
表示逻辑端口想打印机发送指令,进行打印
数据接收会触发OnPort事件
客户可以通过该事件进行程序处理
public abstract class AbstractSingleGameState:AbstractGameState
{
protected override void Logic_OnPortEvent(object sender, Action action)
{
//
if(GameContext.GameState==null) return;
if (GameContext.GameState.CurrentState == CurrentState)
{
try
{
ActionChainNode stateListener = ActionLockStateManager.Instance;
if (stateListener.Process(this, action)) return;
ThreadPool.QueueUserWorkItem(new WaitCallback(Doo),action);
OnPortEvent(sender, action);
}
catch (Exception ex)
{
log.Error(ex.Message,ex);
}
}
}
private static ActionChainNode globalChain = GlobalActionChainFactory.GetChain();
protected void Doo(object state)
{
//将不是立即执行的命令填出gamestate栈中,等到actionFilterChain的调用
ActionChainNode stackChain = GlobalActionStackFactory.GetChain();
stackChain.Process(this, (Action) state);
//
globalChain.Process(this, (Action)state);
}
protected virtual void OnPortEvent(object sender, Action action)
{
}
}
程序通过Logic_OnPortEvent处理程序进行接受指令的处理
这里使用了职责链模式进行所有的指令处理,下一节将写出该模式的设计
该处理函数既可以处理全局指令,也可以处理当前状态指令,并将事件进行传递。
传递到具体的处理类
public class StepWaitingState : AbstractSingleGameState
{
public override GameState CurrentState
{
get { return GameState.StepWaiting; }
}
public StepWaitingState()
{
}
public override object Enter(Action action)
{
}
protected override void OnPortEvent(object sender, Action action)
{
Doo(action);
}
private void Doo(object state)
{
Action action = (Action) state;
ActionChainNode controlPanelActionChain = WatingActionChainFactory.GetChain();
controlPanelActionChain.Process(this, action);
}
public override IGameState Transit(Action action)
{
if (GameContext.GameState.CurrentState == CurrentState)
GameContext.SetState(StateFactory.StepPost, action);
return GameContext.GameState;
}
}
如果接受的指令数据传递到当前状态后,通过该状态的职责链进行处理
ActionChainNode controlPanelActionChain = WatingActionChainFactory.GetChain();
整体就是这样了!
端口代理的实例化
<object id="PortProxy" type="Single.Core.PortProxy,Single.Core">
<property name="CommunicationPortService" ref="UdpPort"/>
<property name="PrintPortService" ref="PrintPort"/>
<property name="ControlPanelPortService" ref="ControlPanelPort"/>
<property name="TcpPortService" ref="TcpPort"/>
<property name="SMSPortService" ref="SMSPort"/>
<property name="MonitorPortService" ref="UdpMonitorPort"/>
</object>
PortProxy的注入
<object id="AbstractStateBase" abstract="true">
<property name="PortService" ref="PortProxy"/>
<property name="PersistService" ref="SinglePersistService"/>
</object>
综上,这样设计之后,客户在使用的过程中所有的细节都没有接触,只是统一通过PortProxy进行通信,所有的端口扩展也都通过ProtProxy进行扩充,不影响客户使用,扩展也更容易,端口的扩展继承统一的PortService,扩展方式统一!
原始链接
http://qixin000.iteye.com/blog/1425135
分享到:
相关推荐
【有源配电网多端口统一电能质量控制器】是一种针对现代电力系统中电压质量问题而设计的高级解决方案。随着分布式电源(Distributed Generation, DG)在配电网中的广泛应用,电压波动和偏差问题日益突出,这对供电质量...
### TMS320F28335及其最小应用系统设计 #### 一、引言 TMS320F28335是一款由德州仪器(TI)生产的高性能浮点数字信号处理器(Digital Signal Processor, DSP),属于TMS320C28x系列。相较于传统的定点DSP,这款处理器...
在本研究中,设计了一种适用于水温水位监控系统的RTOS,并扩展了设备管理功能,实现了设备驱动系统的统一管理。 在单片机的选择上,文中提到了基于8位单片机的设计,这是因为8位单片机成本低、性能稳定且便于控制。...
Java统一认证中心(Single Sign-On, SSO)是一种在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统的技术。在这个项目中,我们拥有一个开箱即用的SSO系统源码,名为"smart-sso"。这个系统允许...
32位操作系统为了提高安全性,通常会对用户态的应用程序进行限制,不允许其直接访问系统底层资源,包括硬件中断(IRQ)、DMA(Direct Memory Access)以及I/O端口等。这种限制虽然增强了系统的安全性,但也给硬件...
本文介绍了一种基于面向对象的电力系统网络拓扑分析模块设计方法,该方法通过面向对象思想,在网络图形平台上将电网中电力图元设计为统一的元件模型,并用统一的数据结构进行存储。该方法提出了一个利用递归搜索的...
计算机端口是计算机网络中不可或缺的一部分,通过了解端口的工作原理和相关协议,可以帮助我们更好地设计和实现高效稳定的网络应用。无论是硬件端口还是软件端口,它们都在计算机与外部世界的交互中发挥着关键作用。
- **Winsock接口**:它是Windows环境下实现网络通信的核心API集,为应用程序提供了一个统一的、标准的网络编程接口,使得开发者无需关心底层网络协议的具体细节,即可实现复杂的数据交换。 - **TCP与UDP协议**:TCP...
本文将详细介绍如何测试数据库连接和端口号是否被占用,以及提供一个小程序——TestConnet,帮助你高效完成这项任务。 首先,数据库连接涉及的主要元素包括数据库服务器地址(通常是IP或域名)、数据库端口号、...
在本设计中,PLC控制系统使用了四个输入口和五个输出口,因此选择了一个具有更多输入输出端口的PLC,即FPO系列C16T型可编程控制器。 在实际操作中,多种液体混合控制装置按照以下工作流程执行:初始状态下,所有...
《SystemC片上系统设计》是一本深入探讨SystemC在片上系统(SoC)设计中的应用的专业书籍,徐宁仪老师的课件则为学习这一主题提供了宝贵的辅助资源。SystemC是一种高级的硬件描述语言(HDL),它扩展了C++,使得系统...
作者刘芳来自新余学院数学与计算机科学学院,专注于嵌入式系统在智能家居设计中的应用研究,其研究成果不仅提高了智能家居系统的功能性,也为后续的智能家居系统设计和实现提供了专业指导和参考文献。
因此,设计一种简单独立的气缸控制系统以满足就地运行控制的要求,显得尤为必要。 2. STC单片机的应用 本系统采用STC单片机作为控制模块的核心,利用其高速、低功耗、强抗干扰能力等特性。STC89C52单片机作为本设计...
本文介绍了一种基于现场可编程门阵列(Field-Programmable Gate Array,FPGA)的分布式动态时隙交换系统的设计,该设计旨在实现一种高效的中小型数字程控交换机。 ### 标题和描述中知识点 1. **数字程控交换机**:...
为应对这一挑战,一种基于C/S(客户端/服务器)模式与完成端口技术的路灯监控软件设计应运而生,它旨在构建大规模、统一的监控体系,提高数据传输的效率和可靠性。 C/S模式在传统意义上,由于客户端数量的限制,...
7. 设计与调试:学习如何设计一个完整的字符设备驱动程序,包括模块化设计、代码组织,以及如何使用gdb等工具进行调试。 在实际操作中,学生可能会参考现有的字符设备驱动程序,如键盘或串口驱动,进行修改和扩展,...
在探讨单片机技术在多机通信系统设计中的应用之前,我们先要了解单片机的基本概念。单片机,又称为微控制器或微处理器,是一种集成电路芯片,包含了一个完整的微型计算机系统,包括运算器、控制器、输入/输出接口等...