[连载]《C#通讯(串口和网络)框架的设计与实现》- 8.总体控制器的设计

目       录

第八章           总体控制器的设计... 2

8.1           总控制器的职能... 2

8.2           组装和释放部件... 3

8.3           事件响应... 5

8.4           小结... 9

第八章     总体控制器的设计

有了IO部分、设备驱动部分、显示部分、数据导出部分和服务组件部分等,在这些已经存在的接口上构建一个集成各部分的总控制器,协调各部分有序工作、事件响应和控制数据流向。

另外,这个总控制器还负责与宿主程序进行交互,可以这样理解:总控制器是宿主程序与IO部分、设备驱动部分、显示部分、数据导出部分和服务组件部分之间交互的载体,并且是唯一的。结构示意图如下:

8.1    总控制器的职能

总控制器(IDeviceController)的职能包括:增加和删除设备驱动、增加导出数据实例、增加图形显示实例、增加服务组件实例、单击服务事件、释放控制器资源等等。接口定义如下图:

8.2    组装和释放部件

DeviceController是总控制器的实例体类,继承自IDeviceController接口。通过构造函数来完成对总控制器的初始化,代码如下:

public DeviceController()
{
       _devList = DeviceManager.GetInstance();
       _ioController = IOControllerManager.GetInstance();
       _runContainer = RunContainerForm.GetRunContainer();
       _runContainer.MouseRightContextMenuHandler += RunContainer_MouseRightContextMenuHandler;
       _dataShowController = new GraphicsShowController();
       _exportController = new ExportDataController();
       _appServiceManager = new AppServiceManager();
}

通过ReleaseDeviceController接口来完成对总控制器的资源释放,代码如下:

public void ReleaseDeviceController()
{
       _ioController.RemoveAllController();
       _runContainer.RemoveAllDevice();
       _runContainer.MouseRightContextMenuHandler -= RunContainer_MouseRightContextMenuHandler;
       _exportController.RemoveAll();
       _dataShowController.RemoveAll();
       _appServiceManager.RemoveAll();
       IEnumerator<IRunDevice> devList = _devList.GetEnumerator();
       while (devList.MoveNext())
       {
              devList.Current.ExitDevice();
       }
       _devList.RemoveAllDevice();
}

软件退出时释放资源要比软件启动时加载资源要复杂的多,这块涉及到两方面问题:(1)释放资源顺序,如果资源提前释放,那么往往会造成后边代码在执行过程中出现无法引用对象资源的现象,造成意想不到的结果,所以一定要对实例的可用性进行判断。(2)事务性的线程无法正常退出,造成软件界面已经关闭,但是后台进程却一直存在。特别是对线程退出的处理,框架平台采用了统一的线程退出机制,代码如下:

public void StartThead()
{
       if (_RunThread == null || !_RunThread.IsAlive)
       {
              this._IsExit = false;
              this._RunThread = new Thread(new ThreadStart(RunThead));
              this._RunThread.IsBackground = true; //该线程为后台线程
              this._RunThread.Name = "RunThread";
              this._RunThread.Start();
       }
}

private void RunThead()
{
       while (!_IsExit)
       {
              if(_IsExit)         //如果标识为true,则退出循环,退出线程
              {
                     break;
              }
              //事务处理
       }
}

public void StopThead()
{
       if (this._RunThread != null && this._RunThread.IsAlive)
       {
              this._IsExit = true;       //标识当前线程为可退出线程。
              this._RunThread.Join(1000);//阻塞调用线程,直到某个线程终止或经过了指定时间为止
              try
              {
                     _RunThread.Abort();    //为了防止线程没有退出,进行强行终止,有可能造成文件损坏
              }
              catch
              {
              }
       }
}

8.3    事件响应

增加和删除设备驱动都会对设备的事件进行绑定和解绑。代码如下:

dev.DeviceRuningLogHandler += new DeviceRuningLogHandler(DeviceRuningLogHandler);
dev.UpdateContainerHandler += new UpdateContainerHandler(UpdateContainerHandler);
dev.DeviceObjectChangedHandler += new DeviceObjectChangedHandler(DeviceObjectChangedHandler);
dev.ReceiveDataHandler += new ReceiveDataHandler(ReceiveDataHandler);
dev.SendDataHandler += new SendDataHandler(SendDataHandler);
dev.COMParameterExchangeHandler += new COMParameterExchangeHandler(COMParameterExchangeHandler);
dev.DeleteDeviceHandler += new DeleteDeviceHandler(DeleteDeviceHandler);

具体含义请参见《第3章 设备驱动的设计》中的“3.12 事件响应设计”,COMParameterExchangeHandler改变串口参数事件响应代码如下:

private void COMParameterExchangeHandler(object source, COMParameterExchangeArgs e)
{
       if (e == null)
       {
              return;
       }
       IRunDevice dev = this._devList.GetDevice(e.DeviceID.ToString());
       if (dev != null)
       {
              if (dev.CommunicationType == CommunicationType.COM)
              {
                     if (e.OldCOM != e.NewCOM)
                     {
                            //--------------对旧串口进行处理----------------//
                            IRunDevice[] oldCOMDevList = this._devList.GetDevices(e.OldCOM.ToString(), CommunicationType.COM);
                            //---------------检测当前串口设备数------------//
                            int existCOMCount = 0;
                            for (int i = 0; i < oldCOMDevList.Length; i++)
                            {
                                   if (oldCOMDevList[i].GetHashCode() != dev.GetHashCode())
                                   {
                                          existCOMCount++;
                                   }
                            }
                            //------------------------------------------//
                            if (existCOMCount <= 0)//该串口没有可用的设备
                            {
                                   IIOController oldCOMController = IOControllerManager.GetInstance().GetController(SessionCom.FormatKey(e.OldCOM));
                                   if (oldCOMController != null)
                                   {
                                          _ioController.CloseController(oldCOMController.Key);
                                   }

                                   else
                                   {
                                          DeviceMonitorLog.WriteLog(e.DeviceName, "该设备的串口控制器为空");
                                   }
                            }
                            //--------------对新串口进行处理----------------//
                            bool newCOMControllerExist = IOControllerManager.GetInstance().ContainController(SessionCom.FormatKey(e.NewCOM));
                            if (!newCOMControllerExist)
                            {
                                   IIOController newCOMController = _ioController.BuildController(e.NewCOM.ToString(), e.NewBaud.ToString(), CommunicationType.COM);
                                   if (newCOMController != null)
                                   {
                                          newCOMController.StartService();
                                        _ioController.AddController(newCOMController.Key.ToString(), newCOMController);
                                   }
                                   else
                                   {
                                          DeviceMonitorLog.WriteLog(e.DeviceName, "创建该设备的串口控制器失败");
                                   }
                            }
                            DeviceMonitorLog.WriteLog(e.DeviceName, String.Format("串口从{0}改为{1}", e.OldCOM.ToString(), e.NewCOM.ToString()));

                     }
                     else
                     {
                            if (e.OldBaud != e.NewBaud)
                            {
                                   ISessionCom comIO = (ISessionCom)SessionComManager.GetInstance().GetIO(SessionCom.FormatKey(e.OldCOM));
                                   if (comIO != null)
                                   {
                                          bool success = comIO.IOSettings(e.NewBaud);
                                          if (success)
                                          {
                                                 DeviceMonitorLog.WriteLog(e.DeviceName, String.Format("串口{0}的波特率从{1}改为{2}成功", e.OldCOM.ToString(), e.OldBaud.ToString(), e.NewBaud.ToString()));
                                          }
                                          else
                                          {
                                                 DeviceMonitorLog.WriteLog(e.DeviceName, String.Format("串口 {0} 的波特率从 {1} 改为 {2} 失败", e.OldCOM.ToString(), e.OldBaud.ToString(), e.NewBaud.ToString()));
                                          }
                                   }
                            }
                     }
              }
              else
              {
                     DeviceMonitorLog.WriteLog(e.DeviceName, "不是串口类型的设备");
              }
       }
}

同时,还包括GraphicsShowClosedHandler和MouseRightContextMenuHandler两个事件。当关闭显示视图的时候会触发GraphicsShowClosedHandler事件,把当前视图从管理器中移除,并释放资源;当右键单击显示视图会触发MouseRightContextMenuHandler事件,以调用相应设备的上下文菜单。

8.4    小结

总体控制器不是必须的,宿主程序完全可以直接与IO部分、设备驱动部分、显示部分、数据导出部分和服务组件部分进行交互。但是,为了结构清晰、方便扩展,在中间加了一层进行总体协调。

作者:唯笑志在

Email:[email protected]

QQ:504547114

.NET开发技术联盟:54256083

文档下载:http://pan.baidu.com/s/1pJ7lZWf

官方网址:http://www.bmpj.net

时间: 2024-11-15 19:32:05

[连载]《C#通讯(串口和网络)框架的设计与实现》- 8.总体控制器的设计的相关文章

[连载]《C#通讯(串口和网络)框架的设计与实现》- 0.前言

                              目       录 前言 前言 刚参加工作,使用过VB.VC开发软件,随着C#的崛起,听说是C++++,公司决定以后开发软件使用C#,凭借在书市5块钱买C#编程入门书籍,开始了职业生涯.开发C/S.B/S结构的软件是必不可少的,又涉及到Remoting.WebService.线程.异步等不知所云的技术.到现在为止,不敢妄称精通,却也使用熟练:研读Framework源代码,不敢说全部搞懂,却对技术提高有很大帮助. 身在传统行业,确实感觉到

[连载]《C#通讯(串口和网络)框架的设计与实现》-3.设备驱动的设计

目       录 第三章           设备驱动的设计... 2 3.1           初始化设备... 4 3.2           运行设备接口设计... 4 3.3           虚拟设备接口设计... 6 3.4           协议驱动设计... 7 3.5           命令缓存设计... 17 3.6           数据持久化设计... 24 3.7           IO数据交互设计... 26 3.8           通讯状态设计..

教你写Android网络框架之请求配置与Response缓存

前言 在教你写Android网络框架的前三篇文章中,我们从基本结构到代码实现,剖析了一个简单的网络框架应该是怎样运作的,以及在面对各式各样的需求时应该如何对代码做出处理,在深入了解网络框架的同时学习到一些简单的面向对象设计原则.正如第一篇博文所说,SimpleNet框架参照的是Volley实现,甚至有一些类名也是一样的.我们的目标并不是要重新发明轮子,而是以学习轮子制作的过程来达到提升自我的目的.SimpleNet只是一个简单的网络框架实现,没有经过严格的测试以及市场检验,不建议大家在项目中使用

《连载 | 物联网框架ServerSuperIO教程》-4.如开发一套设备驱动,同时支持串口和网络通讯。附:将来支持Windows 10 IOT

感谢唯笑志在分享 原博主原地址:http://www.cnblogs.com/lsjwq/ 注:ServerSuperIO有可能被移植到Windows 10 IOT上,那么将来有可能开发一套设备驱动,可以支行在服务端.嵌入式设备中,将形成完整的解决方案.       现在已经调试通过部分代码,还得需要一段时间,一般都是晚上干,时间也有限.如下图: 目       录 4.如开发一套设备驱动,同时支持串口和网络通讯... 2 4.1           概述... 2 4.2          

[连载]《C#通讯(串口和网络)框架的设计与实现》-4.设备驱动管理器的设计

目       录 第四章           设备驱动管理器的设计... 2 4.1           接口定义... 2 4.2           设备容器... 7 4.3           生成设备ID.. 7 4.4           对设备容器操作的互斥... 8 4.5           获得设备列表... 8 4.6           设备计数器的特殊用处... 8 4.7           小结... 10 第四章     设备驱动管理器的设计 设备驱动管理器是对

上门洗车APP --- Android客户端开发 之 网络框架封装(二)

上门洗车APP --- Android客户端开发 之 网络框架封装(二) 前几篇博文中给大家介绍了一下APP中的基本业务及开发本项目使用的网络架构: 上门洗车APP --- Android客户端开发 前言及业务简介 上门洗车APP --- Android客户端开发 之 网络框架封装介绍(一) 本篇接着给大家分享网络框架封装,相信感兴趣的朋友已经对上篇博文中的一些开源项目有了些许了解,这里继续为大家介绍关于GenericDataManager 通用网络管理类中的 dataRequest 方法 和

家庭洗车APP --- Androidclient开展 之 网络框架包介绍(一)

家庭洗车APP --- Android客户端开发 之 网络框架包介绍(一) 上篇文章中给大家简单介绍了一些业务.上门洗车APP --- Android客户端开发 前言及业务简单介绍,本篇文章给大家介绍下网络框架.之前也了解过一些开源网络通讯架构.也大概看了一部分源代码.比方Afinal.Volley.AndBase.Android-async-http等,感觉各自都有各自的优劣,自己也曾封装过一些简单的网络架构,感觉有非常多地方须要注意和优化.这里就不贴出来献丑了,感兴趣的朋友能够去查阅学习上面

ym—— Android网络框架Volley(体验篇)

<a target=_blank href="https://android.googlesource.com/platform/frameworks/volley" style="font-family: Arial, Helvetica, sans-serif; box-sizing: border-box; background-image: initial; background-attachment: initial; background-color: rg

上门洗车APP --- Androidclient开发 之 网络框架封装介绍(二)

上门洗车APP --- Androidclient开发 之 网络框架封装介绍(二) 前几篇博文中给大家介绍了一下APP中的基本业务及开发本项目使用的网络架构: 上门洗车APP --- Androidclient开发 前言及业务简单介绍 上门洗车APP --- Androidclient开发 之 网络框架封装介绍(一) 本篇接着给大家分享网络框架封装.相信感兴趣的朋友已经对上篇博文中的一些开源项目有了些许了解.这里继续为大家介绍关于GenericDataManager 通用网络管理类中的 data