当前位置: 首页 > news >正文

网站备案法律海口网站建设网页制作公司

网站备案法律,海口网站建设网页制作公司,九江市网站建设,智慧团建手机版前言 由于近期我做了好几个客户的接入工厂Mes系统的需求。但是每个客户的Mes都有不同程度的定制需求#xff0c;原有的代码复用难度其实很大。所以打算将整个接入Mes系统的框架单独拿出来作为一个项目使用#xff0c;同时因为不同的设备接入同一个Mes系统#xff0c;所以代…前言 由于近期我做了好几个客户的接入工厂Mes系统的需求。但是每个客户的Mes都有不同程度的定制需求原有的代码复用难度其实很大。所以打算将整个接入Mes系统的框架单独拿出来作为一个项目使用同时因为不同的设备接入同一个Mes系统所以代码的迁移规范同样非常重要。 1.需求分析 这部分的需求分析主要来自于我在接入不同客户Mes系统时发现的一些问题和解决方案同时也了解过工厂Mes系统供应商的朋友们。列举了一些比较实际的功能主要是代码方面的。 需要有同一个的接入方式方便接入不同客户的Mes系统。需要有全局的参数列表。只允许存在一个Mes系统的入口。保证数据统一性在多线程访问设备不同轨道运行时数据需要做区分。尽可能的减少后续的代码修改。UI上不同的客户的选项卡要做区分但是只显示一个选项卡。所有关于Mes的操作需要独立于设备内容方便在不同设备软件上迁移设备软件只做传入数据的功能。需要考虑由Mes控制设备的功能 2.设计项目内容 首先会有一个MesApp的入口用来访问整个Mes系统但是这个入口只能有一个所有MesApp应当使用单例模式。不同的客户需要继承于同一个接口根据客户的名称信息去访问指定的客户类所以MesApp应当具有工厂模式通过工厂生产客户类。根据全局参数列表需要一个可通过MesApp访问的全局静态类Const和枚举类保证数据做好区分但是又保证数据统一性所以Mes需要全部公用一个数据类对象并且可以在外部写入参数并作为类对象进行传参UI上面仍然使用MVVM框架去实现同时使用Visibility的binding的形式来控制在选项卡中显示UI根据实际情况可以选择公用选项卡或者多选项卡的形式考虑数据的通用性所以数据应到以类对象的形式存在类型为String的Name类型为Object的Value需要独立的数据存储部分通讯方式需要独立在MesApp中需要由一个队列跟软件的框架进行通讯用来控制软件执行某些内容 3.代码内容 3.1MesApp入口 首先MesApp是整个项目的入口除了数据结构类以外全部数据都应该从MesApp的端口中进入。所以MesApp有一个单例的入口。其中包含config配置文件const在软件运行时的不用存储的变量IMesSend接口与Mes交互的主要代码Enum需要使用的枚举值。同时在进入Mes前需要根据不同的客户去选择我们需要的使用的Mes内容所以有一个创建mes的函数。同时还有保存配置和获取配置的部分 namespace Mes {public class MesApp{#region 单例部分private static MesApp _instance null;private static readonly object Lock new object();private MesConst _Const new MesConst();private IMesSend _Mes null;private MesEnum _MesEnum new MesEnum();private MyMesConfig _MesConfig new MyMesConfig();private string EnvironmentAddress Path.Combine(Environment.CurrentDirectory, Config);private string ConfigPath Path.Combine(Environment.CurrentDirectory, Config\\MesConfig.txt);//mes接收控制软件的队列public QueueMesProcessData MesQueueAccept new QueueMesProcessData();//mes接收控制软件结束后的反馈队列public QueueMesProcessData MesQueueSend new QueueMesProcessData();public MyMesConfig MyMesConfig{get _MesConfig;set _MesConfig value;}public MesEnum MesEnum{get _MesEnum;}public MesConst Const{get _Const;set _Const value;}public IMesSend Mes{get _Mes;set _Mes value;}public static MesApp Instance{get{if (_instance null){lock (Lock){if (_instance null){_instance new MesApp();}}}return _instance;}}#endregion/// summary/// 创建Mes对象/// /summarypublic bool CreatMes(){try{MesEnum.MesCustomer customer new MesEnum.MesCustomer();customer MesEnum.GetEnumValueFromDescriptionMesEnum.MesCustomer(MesApp.Instance.MyMesConfig.SelectCustomer);if (!MesApp.Instance.MyMesConfig.IsEnableMes){customer MesEnum.MesCustomer.None;}switch (customer){case MesEnum.MesCustomer.CustomerA:Mes new CustomerA();break;default:Mes new DefaultMes();break;}return true;}catch (Exception){return false;}}public bool SaveMesConfig(){// 检查 config 文件夹是否存在if (!Directory.Exists(EnvironmentAddress)){try{// 创建 config 文件夹Directory.CreateDirectory(EnvironmentAddress);string json JsonConvert.SerializeObject(MesApp.Instance.MyMesConfig, Formatting.Indented);File.WriteAllText(ConfigPath, json);return true;}catch (Exception ex){MesLog.Error(配置参数序列化失败: ex.ToString());return false;}}else{string json JsonConvert.SerializeObject(MesApp.Instance.MyMesConfig, Formatting.Indented);File.WriteAllText(ConfigPath, json);return true;}}public bool GetMesConfig(){if (Directory.Exists(EnvironmentAddress)){try{string json File.ReadAllText(ConfigPath);MesApp.Instance.MyMesConfig MesJson.DeserializeObjectMyMesConfig(json);}catch (Exception ex){MesLog.Error(配置参数反序列化失败: ex.ToString());}}else{return false;}return true;}} } 3.2IMesSend接口 IMesSend接口是项目主要的内容在创建Mes时会使用工厂模式通过IMesSend接口去生产指定的客户类客户类通常包含我们自有设备通常需要上传的函数方法。同时包含一个动态接口因为在某些客户需要定制一些独特的功能但是大部分客户都是没有的可以使用这个Task Dynamic(MesDynamic dynamic);的接口。 using System.Threading.Tasks;namespace Mes {public interface IMesSend{/// summary/// 用户登录/// /summary/// returns/returnsTaskMesProcessData MesLogin(MesDynamic dynamic);/// summary/// 上报拿板情况/// /summaryTaskbool RemovePCB(MesDynamic data);/// summary/// 上传工艺参数/// /summaryvoid ProcessParameters();/// summary/// 上传整板测试结果/// /summaryTaskbool Result(MesDynamic dynamic);/// summary/// Mes启用/// /summary/// returns/returnsbool MesEnable();/// summary/// 上传报警信息,/// /summary/// param namemessage/param/// param nameLevel级别1为警告黄灯2为红灯报警/paramTaskbool AlarmInformation(string message, int Level);/// summary/// 消除报警信息/// /summary/// param namemessage/paramTaskbool CancelAlarmInformation(string message);/// summary/// 发送设备状态/// /summaryTaskbool ProcessStop(MesEnum.MachineState on);/// summary/// 切换程序/// /summaryvoid SwitchPrograms();/// summary/// 过站检测/// /summary/// param nameBoardCode/param/// returns/returnsTaskbool CheckBoard(MesDynamic dynamic);/// summary/// 设备出板/// /summary/// returns/returnsTaskbool OutBoard(MesDynamic dynamic);/// summary/// 关闭Mes/// /summaryvoid CloseMes();/// summary/// 动态接口用于在特殊情况下调用的接口/// /summary/// param namedynamic/param/// returns/returnsTaskMesProcessData Dynamic(MesDynamic dynamic);} } 3.3通讯类 通讯类所需要做的内容并不是很多需要有创建通讯的步骤发送数据监听端口关闭通讯就可以了。 using JOJO.Mes.Log; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks;namespace JOJO.Mes.CommModel {internal class MesHttp{public string MesUrlAddress { get; set; } http:\\Send;public string AccessInterface { get; set; } ;public string MesUrlAcceptAddress { get; set; } http:\\Accept;public int MesUrlTimeOut { get; set; } 5000;public bool UseToken { get; set; } false;public string Token { get; set; } ;private string url { get; set; } ;public TimeSpan CtsTimeOut TimeSpan.FromSeconds(10);HttpClient Client;HttpListener Listener;public Queuestring GetHttpQueue new Queuestring();public Queuestring ResponseHttpQueue new Queuestring();public bool CreatHttpClient(){Client new HttpClient();Client.Timeout TimeSpan.FromSeconds(MesUrlTimeOut);Listener new HttpListener();Listener.Prefixes.Add(MesUrlAcceptAddress); // 监听的 URL 前缀Listener.Start();return true;}public async Taskstring MesUrlSendAndAccept(string obj){try{string dataOut ;url MesUrlAddress / AccessInterface;MesLog.Info(当前访问的URL地址: url);// 创建 HTTP 客户端实例if (UseToken){Client.DefaultRequestHeaders.Add(token, Token);}// 构造要发送的内容var content new StringContent(obj, Encoding.UTF8, application/json);MesLog.Info(MesUrl数据上传 obj);// 发送POST请求var response await Client.PostAsync(url, content);// 确保响应成功if (response.IsSuccessStatusCode){dataOut await response.Content.ReadAsStringAsync().ConfigureAwait(false);MesLog.Info(Mes数据接受 dataOut);}content null;response null;return dataOut;}catch (Exception ex){MesLog.Error(发送Http数据失败: ex.ToString());return null;}}public async void AcceptHttp(){while (true){HttpListenerContext context await Listener.GetContextAsync();HttpListenerRequest request context.Request;HttpListenerResponse response context.Response;if (request.HttpMethod POST){using (StreamReader reader new StreamReader(request.InputStream, request.ContentEncoding)){string requestContent await reader.ReadToEndAsync();GetHttpQueue.Enqueue(requestContent);string responseString ;//等待内容响应try{Task ResponseTask Task.Run(async () {while (true){if (ResponseHttpQueue.Count 0){responseString ResponseHttpQueue.Dequeue();break;}await Task.Delay(10);}}, new CancellationTokenSource(CtsTimeOut).Token);}catch (Exception ex){MesLog.Error(Http接收响应失败 ex.ToString());MesApp.Instance.Const.SetMachineLog(Http接收响应失败);return;}byte[] buffer Encoding.UTF8.GetBytes(responseString);response.ContentLength64 buffer.Length;using (Stream output response.OutputStream){await output.WriteAsync(buffer, 0, buffer.Length);}}}else{response.StatusCode (int)HttpStatusCode.MethodNotAllowed;response.Close();}}}public void Close(){Client.Dispose();}} } using JOJO.Mes.Log; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks;namespace JOJO.Mes.CommModel {internal class MesSocket{private readonly byte[] buffer new byte[1024 * 1024 * 100];public Socket listener;public Socket handler;public int Point 8888;public string Address 192.168.8.88;public Queuestring SocketQueue new Queuestring();public bool CreatSocket(){listener new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);long address new long();try{IPAddress ipAddress IPAddress.Parse(Address);address BitConverter.ToInt32(ipAddress.GetAddressBytes(), 0);IPEndPoint localEndPoint new IPEndPoint(address, Point);listener.Bind(localEndPoint);listener.Listen(10);}catch (FormatException){return false;}MesLog.Info(Socket,等待客户端连接...);// 开始异步接受客户端连接listener.BeginAccept(AcceptCallback, listener);return true;}private void AcceptCallback(IAsyncResult ar){Socket listener (Socket)ar.AsyncState;// 完成接受客户端连接handler listener.EndAccept(ar);MesLog.Info($连接Socket成功: handler.AddressFamily);// 开始异步接收数据handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, handler); 继续监听新的连接listener.BeginAccept(AcceptCallback, listener);}private void ReceiveCallback(IAsyncResult ar){Socket handler (Socket)ar.AsyncState;try{int bytesRead handler.EndReceive(ar);if (bytesRead 0){byte[] data new byte[bytesRead];Array.Copy(buffer, data, bytesRead);string message System.Text.Encoding.UTF8.GetString(data);MesLog.Info($接收Socket数据: {message});SocketQueue.Enqueue(message);handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, handler);}}catch (SocketException e){MesLog.Warn($接收Socket数据出错: {e.Message});}finally{handler.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, handler);}}public async void SendObject(string SendString){try{if (!handler.Connected){MesApp.Instance.Const.SetMachineLog(Mes所在的Socket端口未连接无法发送数据);return;}byte[] SendBytes Encoding.UTF8.GetBytes(SendString);await Task.Run(() {// 通过Socket发送数据handler.Send(SendBytes, 0, SendBytes.Length, SocketFlags.None);});}catch (Exception ex){MesLog.Error(发送不带反馈的Socket数据失败 ex.ToString());}}public void Close(){try{handler.Shutdown(SocketShutdown.Both);//listener.Shutdown(SocketShutdown.Both);handler.Close();listener.Close();}catch (Exception){}}} } 3.4日志类 using System; using System.IO; using System.Threading.Tasks;namespace Mes.Log {internal static class MesLog{public enum LogLevel{Trace,Debug,Info,Warn,Error,Fatal}private static string logBasePath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, log, Meslog);private static long maxFileSize 5 * 1024 * 1024; // 5MBprivate static LogLevel minimumLevel LogLevel.Trace;static MesLog(){if (!Directory.Exists(logBasePath)){Directory.CreateDirectory(logBasePath);}}private static string GetLogFilePath(){string date DateTime.Now.ToString(yyyy-MM-dd);return Path.Combine(logBasePath, ${date}.txt);}private static async Task AppendTextAsync(string text, string filePath){var fileOptions FileOptions.Asynchronous;using (var fileStream new FileStream(filePath,FileMode.Append, // 使用FileMode.Append以追加模式打开文件FileAccess.Write,FileShare.ReadWrite,bufferSize: 4096 * 10,fileOptions)){using (var streamWriter new StreamWriter(fileStream)){// 异步写入文本到文件await streamWriter.WriteAsync(text);}}}public static async void Write(LogLevel level, string message){if (level minimumLevel){return;}string timestamp DateTime.Now.ToString(yyyy - MM - dd HH:mm:ss);string logMessage ${timestamp} [{level}]: {message}{Environment.NewLine};string filePath GetLogFilePath();if (File.Exists(filePath) new FileInfo(filePath).Length maxFileSize){filePath Path.Combine(logBasePath, ${DateTime.Now.ToString(yyyyMMddHHmmss)}.txt);}await AppendTextAsync(logMessage, filePath);}public static void Trace(string message){Write(LogLevel.Trace, message);}public static void Debug(string message){ #if DEBUGWrite(LogLevel.Debug, message); #endif}public static void Info(string message){Write(LogLevel.Info, message);}public static void Warn(string message){Write(LogLevel.Warn, message);}public static void Error(string message){Write(LogLevel.Error, message);}public static void Fatal(string message){Write(LogLevel.Fatal, message);}} } 3.5配置参数类使用Json格式 using System; using System.Windows;namespace Mes.Config {[Serializable]public class MyMesConfig{/// summary/// 是否需要Mes控制软件不需要情况下减少线程开辟/// /summarypublic bool IsMesControMachine { get; set; } false;/// summary/// 是否显示选择客户页面/// /summarypublic string IsShowSelectCustomer { get; set; } Visibility.Visible.ToString();/// summary/// 是否开启Mes/// /summarypublic bool IsEnableMes { get; set; } false;/// summary/// Mes超时时间/// /summarypublic int MesTimeOut { get; set; } 5000;public string EquipmentID { get; set; } SMT01;public string MesAddress { get; set; } 192.168.1.1;/// summary/// 选择客户选项卡的ID/// /summarypublic int SelectedTabIndex { get; set; } 0;/// summary/// 是否显示客户页面/// /summarypublic string IsShowCustomer { get; set; } Visibility.Collapsed.ToString();/// summary/// 选择的客户名称/// /summarypublic string SelectCustomer { get; set; } 选择Mes客户;public CustomerConfig.CustomerA CustomerA { get; set; } new CustomerConfig.CustomerA();public CustomerConfig.CustomerB CustomerB { get; set; } new CustomerConfig.CustomerB();} } 3.6实际使用的用户类参考 using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml;namespace Mes.Client {/// summary/// 客户A/// /summarypublic class CustomerA : IMesSend{private readonly byte[] buffer new byte[1024 * 1024 * 100];private MesSocket socket new MesSocket();private static readonly object _lockObject new object();private Dictionarystring, CustomerARec _recDic new Dictionarystring, CustomerARec();private Dictionarystring, CustomerARec RecDic{get _recDic;set{lock (_lockObject){_recDic value;}}}DateTime HeartTime DateTime.Now;private bool CustomerAIsConnect false;private bool IsAlarm false;private string Heade { get; } Header;public CustomerA(){socket.Address MesApp.Instance.MyMesConfig.MesAddress;socket.Point MesApp.Instance.MyMesConfig.CustomerA.Port;socket.CreatSocket();Receive();HeartTimeAndIsConnect();}private object lockObj new object();private void Receive(){Task MesContralMachine Task.Run(async () {while (true){lock (lockObj){if (socket.SocketQueue.Count 0){string message socket.SocketQueue.Dequeue();MesLog.Info($接收客户AMes数据: {message});MesProcessData ProcessData MesXml.DeserializeXml(message);string MesInterface ProcessData.FindValueByPath(new string[] { Header, MESSAGENAME }, 0).ToString();switch (MesInterface){case EAP_LinkTest_Request:EAP_LinkTest_Request_Accept(ProcessData);break;case DATE_TIME_CALIBREATION_COMMAND:ChangeTime(ProcessData);break;case ALARM_REPORT_R:case EQP_STATUS_REPORT_R:case JOB_RECEIVE_REPORT_R:case JOB_SEND_REPORT_R:case EDC_REPORT_R:case JOB_REMOVE_RECOVERY_REPORT_R:CheckSend(ProcessData);break;case 123://预留Mes控制设备部分MesApp.Instance.MesQueueAccept.Enqueue(ProcessData); break;default:break;}}}// 等待一段时间避免忙等待await Task.Delay(10);}});}public bool MesEnable(){return MesApp.Instance.MyMesConfig.IsEnableMes socket.handler.Connected;}public async Taskbool AlarmInformation(string message, int Level){ListMesProcessData datas new ListMesProcessData();datas.Add(new MesProcessData { MesName EquipmentID, MesValue MesApp.Instance.MyMesConfig.EquipmentID });datas.Add(new MesProcessData { MesName AlarmStatus, MesValue 0 });datas.Add(new MesProcessData { MesName AlarmLevel, MesValue 0 });datas.Add(new MesProcessData { MesName AlarmCode, MesValue 00 });datas.Add(new MesProcessData { MesName AlarmText, MesValue message });MesDynamic dynamic new MesDynamic();dynamic.AddressInterface ALARM_REPORT;IsAlarm true;return await MesSend(datas, dynamic);}public void ProcessParameters(){return;}/// summary/// 过站检查/// /summary/// param nameBoardCode/param/// returns/returnspublic async Taskbool CheckBoard(MesDynamic dynamic){ListMesProcessData datas new ListMesProcessData();if (dynamic.BoardCode || dynamic.BoardCode null){dynamic.BoardCode MesApp.Instance.Const.NowTimeF;}datas.Add(new MesProcessData { MesName EquipmentID, MesValue MesApp.Instance.MyMesConfig.EquipmentID });datas.Add(new MesProcessData { MesName JobID, MesValue dynamic.BoardCode });dynamic.AddressInterface JOB_RECEIVE_REPORT;bool result await MesSend(datas, dynamic);return result;}/// summary/// 发送设备状态/// /summary/// param nameon/parampublic async Taskbool ProcessStop(MesEnum.MachineState on){if (!MesApp.Instance.Mes.MesEnable()){return true;}int EquipmentStatus -1;switch (on){case MesEnum.MachineState.stop:EquipmentStatus 3;break;case MesEnum.MachineState.start:EquipmentStatus 1;break;case MesEnum.MachineState.RedLight:EquipmentStatus 2;break;case MesEnum.MachineState.AwaitEnterBoard:EquipmentStatus 4;break;case MesEnum.MachineState.AwaitOutBoard:EquipmentStatus 5;break;default:EquipmentStatus 2;break;}ListMesProcessData datas new ListMesProcessData();datas.Add(new MesProcessData { MesName EquipmentID, MesValue MesApp.Instance.MyMesConfig.EquipmentID });ListMesProcessData StationInfoList new ListMesProcessData();ListMesProcessData StationInfo new ListMesProcessData();StationInfo.Add(new MesProcessData { MesName Station, MesValue MesApp.Instance.MyMesConfig.CustomerA.CustomerAStatueName });StationInfo.Add(new MesProcessData { MesName EquipmentStatus, MesValue EquipmentStatus });StationInfoList.Add(new MesProcessData { MesName StationInfo, MesValue StationInfo.ToArray() });datas.Add(new MesProcessData { MesName StationInfoList, MesValue StationInfoList.ToArray() });MesDynamic dynamic new MesDynamic();dynamic.AddressInterface EQP_STATUS_REPORT;return await MesSend(datas, dynamic);}public async Taskbool RemovePCB(MesDynamic data){if (!MesApp.Instance.Mes.MesEnable()){return true;}ListMesProcessData datas new ListMesProcessData();datas.Add(new MesProcessData { MesName EquipmentID, MesValue MesApp.Instance.MyMesConfig.EquipmentID });datas.Add(new MesProcessData { MesName JobID, MesValue data.BoardCode });datas.Add(new MesProcessData { MesName RemoveFlag, MesValue 0 });data.AddressInterface JOB_REMOVE_RECOVERY_REPORT;return await MesSend(datas, data);}public async Taskbool Result(MesDynamic data){if (!MesApp.Instance.Mes.MesEnable()){return true;}ListMesProcessData datas new ListMesProcessData();datas.Add(new MesProcessData { MesName EquipmentID, MesValue MesApp.Instance.MyMesConfig.EquipmentID.ToString() });datas.Add(new MesProcessData { MesName JobID, MesValue data.BoardCode.ToString() });datas.Add(new MesProcessData { MesName ProcessTime, MesValue data.TimeCost.ToString() });datas.Add(new MesProcessData { MesName ProcessStartTime, MesValue data.ProcessStartTime.ToString() });datas.Add(new MesProcessData { MesName ProcessEndTime, MesValue data.ProcessEndTime.ToString() });ListMesProcessData MesProcessDataList new ListMesProcessData();ListMesProcessData ProcessData1 new ListMesProcessData();ProcessData1.Add(new MesProcessData { MesName Station, MesValue MesApp.Instance.MyMesConfig.CustomerA.CustomerAStatueName.ToString() });ProcessData1.Add(new MesProcessData { MesName Name, MesValue TotalResult });ProcessData1.Add(new MesProcessData { MesName value, MesValue int.Parse(data.VerifiedBoardResult) 0 ? NG : OK });ListMesProcessData ProcessData2 new ListMesProcessData();ProcessData2.Add(new MesProcessData { MesName Station, MesValue MesApp.Instance.MyMesConfig.CustomerA.CustomerAStatueName.ToString() });ProcessData2.Add(new MesProcessData { MesName Name, MesValue ProductCode });ProcessData2.Add(new MesProcessData { MesName value, MesValue data.BoardCode.ToString() });ListMesProcessData ProcessData3 new ListMesProcessData();ProcessData3.Add(new MesProcessData { MesName Station, MesValue MesApp.Instance.MyMesConfig.CustomerA.CustomerAStatueName.ToString() });ProcessData3.Add(new MesProcessData { MesName Name, MesValue ProcessName });ProcessData3.Add(new MesProcessData { MesName value, MesValue data.ProduceName.ToString() });ListMesProcessData ProcessData4 new ListMesProcessData();ProcessData4.Add(new MesProcessData { MesName Station, MesValue MesApp.Instance.MyMesConfig.CustomerA.CustomerAStatueName.ToString() });ProcessData4.Add(new MesProcessData { MesName Name, MesValue PartNum });ProcessData4.Add(new MesProcessData { MesName value, MesValue data.TPNumber.ToString() });ListMesProcessData ProcessData5 new ListMesProcessData();ProcessData5.Add(new MesProcessData { MesName Station, MesValue MesApp.Instance.MyMesConfig.CustomerA.CustomerAStatueName.ToString() });ProcessData5.Add(new MesProcessData { MesName Name, MesValue NGNum });ProcessData5.Add(new MesProcessData { MesName value, MesValue data.NGTPNumber.ToString() });JArray Detailes new JArray();foreach (var item in data.TPNGs){string codeName string.Join(,, item.NGCodeName);JObject Detailedata new JObject{{Code, item.SubBoardCode},{Results, NG},{TEST_ITEM, item.TagNumber},{Result, codeName},{PartName, item.PartNumber}};Detailes.Add(Detailedata);}ListMesProcessData ProcessData6 new ListMesProcessData();ProcessData6.Add(new MesProcessData { MesName Station, MesValue MesApp.Instance.MyMesConfig.CustomerA.CustomerAStatueName });ProcessData6.Add(new MesProcessData { MesName Name, MesValue Details });ProcessData6.Add(new MesProcessData { MesName value, MesValue Detailes.ToString() });MesProcessDataList.Add(new MesProcessData { MesName ProcessData, MesValue ProcessData1.ToArray() });MesProcessDataList.Add(new MesProcessData { MesName ProcessData, MesValue ProcessData2.ToArray() });MesProcessDataList.Add(new MesProcessData { MesName ProcessData, MesValue ProcessData3.ToArray() });MesProcessDataList.Add(new MesProcessData { MesName ProcessData, MesValue ProcessData4.ToArray() });MesProcessDataList.Add(new MesProcessData { MesName ProcessData, MesValue ProcessData5.ToArray() });MesProcessDataList.Add(new MesProcessData { MesName ProcessData, MesValue ProcessData6.ToArray() });datas.Add(new MesProcessData { MesName ProcessDataList, MesValue MesProcessDataList.ToArray() });MesDynamic dynamic new MesDynamic{AddressInterface EDC_REPORT};return await MesSend(datas, dynamic, true); ;}public void SwitchPrograms(){return;}private static DateTime _lastCallTime DateTime.MinValue;/// summary/// 发送客户A数据/// /summary/// param namedatas数据源/param/// param namedynamic接口/param/// returns/returnspublic async Taskbool MesSend(ListMesProcessData datas, MesDynamic dynamic, bool IsUseFix false){Random random new Random();int number GetUniqueFiveDigitNumber();ListMesProcessData Message new ListMesProcessData();ListMesProcessData Head new ListMesProcessData();Head.Add(new MesProcessData { MesName MESSAGENAME, MesValue dynamic.AddressInterface });Head.Add(new MesProcessData { MesName TRANSACTIONID, MesValue MesApp.Instance.Const.NowTime.ToString(yyyyMMddHHmmssffff) number });Head.Add(new MesProcessData { MesName MESSAGEID, MesValue number.ToString() });Head.Add(new MesProcessData { MesName REPLYSUBJECTNAME, MesValue MesApp.Instance.MyMesConfig.MesAddress : MesApp.Instance.MyMesConfig.CustomerA.Port });Message.Add(new MesProcessData { MesName Header, MesValue Head.ToArray() });Message.Add(new MesProcessData { MesName Body, MesValue datas.ToArray() });ListMesProcessData MessageReturn new ListMesProcessData();MessageReturn.Add(new MesProcessData { MesName ReturnCode, MesValue });MessageReturn.Add(new MesProcessData { MesName ReturnMessage, MesValue });Message.Add(new MesProcessData { MesName Return, MesValue MessageReturn.ToArray() });MesProcessData Top new MesProcessData();Top.MesName Message;Top.MesValue Message.ToArray();if ((DateTime.Now - _lastCallTime).TotalMilliseconds 500){_lastCallTime DateTime.Now;MesSend_Accept(Top);}return await AwaitReceive(Top);}/// summary/// 发送数据后将参数存储到字典中等待超时和反馈信号/// /summary/// param namemesData/param/// returns/returnsprivate async Taskbool AwaitReceive(MesProcessData Data){CancellationTokenSource cts1 new CancellationTokenSource();CustomerARec meiDiRec new CustomerARec();string Time DateTime.Now.ToString();meiDiRec.Cts cts1;string MESSAGEID Data.FindValueByPath(new string[] { Heade, MESSAGEID }).ToString();RecDic.Add(MESSAGEID, meiDiRec);bool Result false;Task task1 Task.Run(async () {int timeoutCount 0;while (true){try{Task.Delay(TimeSpan.FromMilliseconds(MesApp.Instance.MyMesConfig.MesTimeOut), cts1.Token).Wait(cts1.Token);}catch (OperationCanceledException ex){if (ex.CancellationToken cts1.Token){if (RecDic[MESSAGEID].Result){RecDic.Remove(MESSAGEID);MesLog.Info(MESSAGEID return true);Result true;return;}RecDic.Remove(MESSAGEID);Result false;return;}timeoutCount;if (timeoutCount MesApp.Instance.MyMesConfig.CustomerA.CustomerAReNumber){RecDic.Remove(MESSAGEID);MesLog.Error(Mes重新发送3次失败。接口为 Data.FindValueByPath(new string[] { Heade, MESSAGENAME }).ToString() 时间为 Time 随机ID为 MESSAGEID);CustomerAIsConnect false;MesApp.Instance.Const.SetMachinAlarm();break;}else{MesSend_Accept(Data);continue;}}await Task.Delay(5000 * 100);}Result false;return;}, cts1.Token);await task1;return Result;}private void CheckSend(MesProcessData data){string MESSAGEID data.FindValueByPath(new string[] { Header, MESSAGEID }).ToString();if (RecDic.ContainsKey(MESSAGEID)){if (!data.FindValueByPath(new string[] { Return, ReturnCode }).ToString().Contains(1)){MesLog.Error(Mes执行失败。 接口为 data.FindValueByPath(new string[] { Header, MESSAGENAME }).ToString());}RecDic[MESSAGEID].Result true;RecDic[MESSAGEID].Cts.Cancel();}else{MesLog.Error(Mes没有此发送数据);}}public void MesSend_Accept(MesProcessData Data){string data MesXml.SerializeToXml(Data);data Regex.Replace(data, \?.*?\?, );//整理XMl的缩进XmlDocument xmlDoc new XmlDocument();xmlDoc.LoadXml(data);StringBuilder sb new StringBuilder();XmlWriterSettings settings new XmlWriterSettings();settings.Indent true; // 设置缩进为 truesettings.IndentChars ; // 设置缩进字符这里使用两个空格using (XmlWriter writer XmlWriter.Create(sb, settings)){xmlDoc.Save(writer);}data sb.ToString();if (!socket.handler.Connected){MesApp.Instance.Const.SetMachineLog(客户AMes 没有连接);MesApp.Instance.Const.SetMachinAlarm();return;}socket.SendObject(data);}/// summary/// 接收心跳,反馈接收的心跳/// /summarypublic void EAP_LinkTest_Request_Accept(MesProcessData Data){HeartTime DateTime.Now;Data Data.ModifyValueByPath(new string[] { Header, MESSAGENAME }, EAP_LinkTest_Request_R);Data Data.ModifyValueByPath(new string[] { Header, REPLYSUBJECTNAME }, MesApp.Instance.MyMesConfig.MesAddress : MesApp.Instance.MyMesConfig.CustomerA.Port);Data Data.ModifyValueByPath(new string[] { Return, ReturnCode }, 01);Data Data.ModifyValueByPath(new string[] { Return, ReturnMessage }, 指令执行成功);MesSend_Accept(Data);}public bool AwaitHeartTime(TimeSpan time){if (HeartTime time DateTime.Now){return false;}return true;}public async Taskbool OutBoard(MesDynamic dynamic){ListMesProcessData datas new ListMesProcessData();if (dynamic.BoardCode || dynamic.BoardCode null){dynamic.BoardCode MesApp.Instance.Const.NowTimeF;}datas.Add(new MesProcessData { MesName EquipmentID, MesValue MesApp.Instance.MyMesConfig.EquipmentID });datas.Add(new MesProcessData { MesName JobID, MesValue dynamic.BoardCode });dynamic.AddressInterface JOB_SEND_REPORT;bool result await MesSend(datas, dynamic);return result;}/// summary/// Mes校准系统时间/// /summary/// param namedata/parampublic void ChangeTime(MesProcessData data){data data.ModifyValueByPath(new string[] { Header, MESSAGENAME }, DATE_TIME_CALIBREATION_COMMAND_R);data data.ModifyValueByPath(new string[] { Header, REPLYSUBJECTNAME }, MesApp.Instance.MyMesConfig.MesAddress : MesApp.Instance.MyMesConfig.CustomerA.Port);try{string input data.FindValueByPath(new string[] { Body, DateTime }).ToString();string format yyyyMMddHHmmss;DateTime result DateTime.ParseExact(input, format, null);DateTime dt result;bool r UpdateTime.SetDate(dt);if (r){data data.ModifyValueByPath(new string[] { Return, ReturnCode }, 01);data data.ModifyValueByPath(new string[] { Return, ReturnMessage }, 指令执行成功);}else{data data.ModifyValueByPath(new string[] { Return, ReturnCode }, 02);data data.ModifyValueByPath(new string[] { Return, ReturnMessage }, 指令执行失败);}}catch (Exception ex){data data.ModifyValueByPath(new string[] { Return, ReturnCode }, 02);data data.ModifyValueByPath(new string[] { Return, ReturnMessage }, 指令执行失败);MesLog.Error(Mes矫正时间失败: ex.Message);}MesSend_Accept(data);}private static Random _random new Random();private static HashSetint _uniqueNumbers new HashSetint();/// summary/// 获取五位的随机数/// /summary/// returns/returnsstatic int GetUniqueFiveDigitNumber(){int fiveDigitNumber;do{fiveDigitNumber _random.Next(10000, 100000);} while (!_uniqueNumbers.Add(fiveDigitNumber));return fiveDigitNumber;}public async Taskbool CancelAlarmInformation(string message){if (!IsAlarm){return true;}IsAlarm false;message 报警已消除;ListMesProcessData datas new ListMesProcessData();datas.Add(new MesProcessData { MesName EquipmentID, MesValue MesApp.Instance.MyMesConfig.EquipmentID });datas.Add(new MesProcessData { MesName AlarmStatus, MesValue 1 });datas.Add(new MesProcessData { MesName AlarmLevel, MesValue 0 });datas.Add(new MesProcessData { MesName AlarmCode, MesValue 10 });datas.Add(new MesProcessData { MesName AlarmText, MesValue message });MesDynamic dynamic new MesDynamic();dynamic.AddressInterface ALARM_REPORT;return await MesSend(datas, dynamic);}/// summary/// 监听心跳/// /summaryprivate void HeartTimeAndIsConnect(){Task task1 Task.Run(() {while (true){if (!AwaitHeartTime(MesApp.Instance.MyMesConfig.CustomerA.HeartTime)){MesLog.Error(Mes心跳异常);MesApp.Instance.Const.SetMachinAlarm();CloseMes();break;}}});}public void CloseMes(){socket.Close();}public async TaskMesProcessData MesLogin(MesDynamic dynamic){ListMesProcessData resultList1 new ListMesProcessData();resultList1.Add(new MesProcessData { MesName IsEnable, MesValue true });return new MesProcessData { MesValue resultList1.ToArray() };}public TaskMesProcessData Dynamic(MesDynamic dynamic){throw new NotImplementedException();}public class CustomerARec{public CancellationTokenSource Cts { get; set; } new CancellationTokenSource();public bool Result { get; set; } false;}} } 3.7框架整体解析 如下图所示整体框架包含7个部分。 1Client客户类。由于每个客户都有独特的定制需求所以所有的客户定制的内容都存放再Client中便于管理 2CommModel通讯类。存放每种不同通讯方式的方法通常最常使用的是Http和Socket如果有另外特殊的通讯模式还可以单独编写。 3Config配置文件类。推荐使用可读的Json格式。一开始编写Mes时候就有一个客户是在登陆工程师级别账户时要求Mes通讯同意但是由于客户Mes在升级无法通讯所有软件登陆不了工程师级别无法关闭Mes造成需要软件重新配置参数。所以需要在特殊情况下可以手动配置Mes参数。不同的客户Mes配置也是单独做出区分即可在打开软件时将json反序列化到MesApp下面的Config字段中即可全局使用。 4.Const参数类。MesConst用于存放软件中需要使用但是不需要保存的配置参数。MesData用于存放自定义的数据结构。MesDynamic一个动态数据结构类这个类存在的意义在于所有的接口传入传出都可以使用这个类对象所有的数据都可以在这个类中建立新的字段这个是考虑在某些定制的客户中一些框架满足不了的需求可以在这里做新增内容。MesEnum枚举类用来存入Mes的枚举例如客户枚举设备状态代码等。其中包含访问Description参数的方法。 5.Log日志类将mes的日志与原有的软件日志做区分防止单日的日志过多。 6.Model方法类这里存放着Json和Xml的序列化和反序列化的方法类就暂时来说客户的序列化都是Json或者Xml的形式。 7.接口类和MesApp的单例入口 3.8举例部分方法使用方式 报警和取消报警的调用 public async void Alarm(bool enable, int emgLight -1, string message Alarm) {ChangeEMGLight(enable ? MachineConsts.EMG_ERROR : emgLight -1 ? MachineConsts.EMG_RUNNING : emgLight);if (MesApp.Instance.Mes.MesEnable() !enable){MesApp.Instance.Const.ProcessState MesEnum.MachineState.GreenLight;if (!await MesApp.Instance.Mes.CancelAlarmInformation(message)){LogController.Instance.Error(上传Mes取消报警信息失败);}}if (MesApp.Instance.Mes.MesEnable() enable){MesApp.Instance.Const.ProcessState MesEnum.MachineState.RedLight;if (!await MesApp.Instance.Mes.AlarmInformation(message, 2)){LogController.Instance.Error(上传Mes报警信息失败);}}_machine.EnableBuzzer(enable); }3.9UI部分 由于我使用的WPF框架对winformQT的框架并不是很熟悉所以这里只使用WPF框架的内容作为参考 1.选择厂商的UI。WPF的UI其实编写很简单核心在于Visibility“{Binding }”的使用例如在选择厂商前需要将选择厂商的选项卡显示厂商选项卡隐藏那么将选择厂商选项卡的binding设置为显示其他全部厂商选项卡设置为隐藏。同理选择完厂商后就将指定厂商的选项卡显示即可。 2.参数的Binding如果是需要保存在配置文件中的可以使用Binding的Value指向Config的类即可。 3.由于UI部分难度不高并且大家UI都是不一样的所以这里仅说一下我是怎么使用UI的 TabItemWidth200Height24FontSize15Header请选择Mes厂商Style{StaticResource OverrideMaterialDesignNavigationRailTabItem}Visibility{Binding IsShowSelectCustomer}Grid IsEnabled{Binding Source{x:Static service:ApplicationStateService.Instance}, PathLoginUser.UserGroupKey, Converter{StaticResource LoginUserAuthorityToIsEnableConverter}, ConverterParameter{x:Static enums:AuthorityKeys.SoftwareOptions}}Grid.RowDefinitionsRowDefinition Heightauto /RowDefinition Heightauto //Grid.RowDefinitionsStackPanelGrid Margin8Grid.ColumnDefinitionsColumnDefinition Width200 /ColumnDefinition Width* //Grid.ColumnDefinitionsTextBlockHorizontalAlignmentRightVerticalAlignmentCenterText选择需要使用的Mes系统: /ComboBoxName客户名称Grid.Column1Height30Margin0,0,8,0CursorIBeamItemsSource{Binding PathCustomerName}Style{DynamicResource MaterialDesignComboBox}Text{Binding SelectCustomer, UpdateSourceTriggerPropertyChanged} //GridButtonMargin5HorizontalAlignmentCenterVerticalAlignmentCenterCommand{Binding OpenMesUI}CommandParameterALMContent开启Mes配置界面 //StackPanel/Grid /TabItem4.总结 整个标准Mes框架并不是很难。难点只有一个是如果将数据灵活应用在常见编写Mes时由于每个客户的数据结构都是不一样的每个客户都需要单独开多个数据结构类去序列化和反序列化当然这个并没有错只是这样子会导致代码冗杂量非常大而且维护难度大代码命名混乱的问题。所以标准框架主要还是提供一个如何解决数据灵活性的思路而已。除去这个以外其他内容并不是很难剩下的就是如何规范后续客户的扩展性和如何高效的实现解耦和代码迁移。 最后如果有什么想法可以持续交流。有时间的话这个标准接口框架还会随着我接入Mes的次数而优化。
文章转载自:
http://www.morning.cpwmj.cn.gov.cn.cpwmj.cn
http://www.morning.hdnd.cn.gov.cn.hdnd.cn
http://www.morning.dpmkn.cn.gov.cn.dpmkn.cn
http://www.morning.sqqdy.cn.gov.cn.sqqdy.cn
http://www.morning.zmwd.cn.gov.cn.zmwd.cn
http://www.morning.zrfwz.cn.gov.cn.zrfwz.cn
http://www.morning.jqsyp.cn.gov.cn.jqsyp.cn
http://www.morning.c7491.cn.gov.cn.c7491.cn
http://www.morning.stph.cn.gov.cn.stph.cn
http://www.morning.tkgjl.cn.gov.cn.tkgjl.cn
http://www.morning.pycpt.cn.gov.cn.pycpt.cn
http://www.morning.dmjhp.cn.gov.cn.dmjhp.cn
http://www.morning.kwdfn.cn.gov.cn.kwdfn.cn
http://www.morning.tnmmp.cn.gov.cn.tnmmp.cn
http://www.morning.bxbkq.cn.gov.cn.bxbkq.cn
http://www.morning.nwljj.cn.gov.cn.nwljj.cn
http://www.morning.hqlnp.cn.gov.cn.hqlnp.cn
http://www.morning.pcngq.cn.gov.cn.pcngq.cn
http://www.morning.fyxr.cn.gov.cn.fyxr.cn
http://www.morning.kwnbd.cn.gov.cn.kwnbd.cn
http://www.morning.mjbkp.cn.gov.cn.mjbkp.cn
http://www.morning.fmqng.cn.gov.cn.fmqng.cn
http://www.morning.nzsx.cn.gov.cn.nzsx.cn
http://www.morning.wjtwn.cn.gov.cn.wjtwn.cn
http://www.morning.fjscr.cn.gov.cn.fjscr.cn
http://www.morning.rmxgk.cn.gov.cn.rmxgk.cn
http://www.morning.lwsct.cn.gov.cn.lwsct.cn
http://www.morning.ypqwm.cn.gov.cn.ypqwm.cn
http://www.morning.qsmch.cn.gov.cn.qsmch.cn
http://www.morning.yzxhk.cn.gov.cn.yzxhk.cn
http://www.morning.pmsl.cn.gov.cn.pmsl.cn
http://www.morning.rtsx.cn.gov.cn.rtsx.cn
http://www.morning.rgrdd.cn.gov.cn.rgrdd.cn
http://www.morning.rhzzf.cn.gov.cn.rhzzf.cn
http://www.morning.pdghl.cn.gov.cn.pdghl.cn
http://www.morning.rklgm.cn.gov.cn.rklgm.cn
http://www.morning.mzhjx.cn.gov.cn.mzhjx.cn
http://www.morning.bmyrl.cn.gov.cn.bmyrl.cn
http://www.morning.zkgpg.cn.gov.cn.zkgpg.cn
http://www.morning.ssglh.cn.gov.cn.ssglh.cn
http://www.morning.djpgc.cn.gov.cn.djpgc.cn
http://www.morning.lqffg.cn.gov.cn.lqffg.cn
http://www.morning.wjtwn.cn.gov.cn.wjtwn.cn
http://www.morning.kxrld.cn.gov.cn.kxrld.cn
http://www.morning.nwbnt.cn.gov.cn.nwbnt.cn
http://www.morning.pqbkk.cn.gov.cn.pqbkk.cn
http://www.morning.sbdqy.cn.gov.cn.sbdqy.cn
http://www.morning.tzpqc.cn.gov.cn.tzpqc.cn
http://www.morning.qxmnf.cn.gov.cn.qxmnf.cn
http://www.morning.rkhhl.cn.gov.cn.rkhhl.cn
http://www.morning.syynx.cn.gov.cn.syynx.cn
http://www.morning.jlmrx.cn.gov.cn.jlmrx.cn
http://www.morning.dwgcx.cn.gov.cn.dwgcx.cn
http://www.morning.cmqrg.cn.gov.cn.cmqrg.cn
http://www.morning.ghrhb.cn.gov.cn.ghrhb.cn
http://www.morning.nbhft.cn.gov.cn.nbhft.cn
http://www.morning.fykrm.cn.gov.cn.fykrm.cn
http://www.morning.rpfpx.cn.gov.cn.rpfpx.cn
http://www.morning.rchsr.cn.gov.cn.rchsr.cn
http://www.morning.zgqysw.cn.gov.cn.zgqysw.cn
http://www.morning.fbpyd.cn.gov.cn.fbpyd.cn
http://www.morning.nwcgj.cn.gov.cn.nwcgj.cn
http://www.morning.mlnbd.cn.gov.cn.mlnbd.cn
http://www.morning.ppllj.cn.gov.cn.ppllj.cn
http://www.morning.nkkr.cn.gov.cn.nkkr.cn
http://www.morning.jkzjs.cn.gov.cn.jkzjs.cn
http://www.morning.lonlie.com.gov.cn.lonlie.com
http://www.morning.synlt.cn.gov.cn.synlt.cn
http://www.morning.yzmzp.cn.gov.cn.yzmzp.cn
http://www.morning.dmjhp.cn.gov.cn.dmjhp.cn
http://www.morning.yhyqg.cn.gov.cn.yhyqg.cn
http://www.morning.lzqnj.cn.gov.cn.lzqnj.cn
http://www.morning.rjrlx.cn.gov.cn.rjrlx.cn
http://www.morning.msbct.cn.gov.cn.msbct.cn
http://www.morning.lzqtn.cn.gov.cn.lzqtn.cn
http://www.morning.wfjyn.cn.gov.cn.wfjyn.cn
http://www.morning.yaqi6.com.gov.cn.yaqi6.com
http://www.morning.fengnue.com.gov.cn.fengnue.com
http://www.morning.xzrbd.cn.gov.cn.xzrbd.cn
http://www.morning.clxpp.cn.gov.cn.clxpp.cn
http://www.tj-hxxt.cn/news/258861.html

相关文章:

  • 简述dw网站开发流程唐山快速建站的公司
  • 常州建网站编程网站项目做哪个比较好
  • 平安建设宣传音频免费下载网站网站接入商
  • 有一个域名做网站苏州关键词优化软件
  • 兰州网站排名优化服务wordpress安装错误310
  • 最新站长seo网站外链发布平台深圳做网站乐云seo费用优惠
  • 国外网站有备案吗网站内容侵权 怎么做
  • 郑州企业网站快速优化多少钱wordpress黑页
  • 前端怎么在猪八戒网站接单做wordpress app下载
  • 电影题材网页设计欣赏相关搜索优化软件
  • 网站建立需要什么条件wordpress系统怎么样
  • 合水口网站建设东莞网站建设 手机壳
  • 南通网站制作哪个好厦门电商网站建设
  • 怎么做一个国外网站芜湖企业做网站
  • 华企在线网站建设app 软件开发
  • 有哪些搜索引擎网站青岛网站建设服务平台
  • wordpress无需代码建站wordpress 关于我们
  • 宿州金融网站建设做跨境的网站
  • js网页设计大作业源代码新乡网站自然优化
  • 单页网站制作 在线 支付电子商务网站建设选择
  • 新建网站多少钱网店美工课程总结
  • 下列哪一项不属于电子商务网站建设网站建设人员分工表
  • 网站建设推广服务合同范本开源社区源码
  • 怎样注册个人网站广州网站推广模板
  • 加若格网站做么样深圳网站建设评价
  • 哈尔滨站建好了吗wordpress 如何登陆地址
  • 学做网站论坛vip账户网站建设推荐网
  • 视频网站如何做wordpress mip 插件
  • 网站开发什么语言做网站都需要用到什么
  • 网站开发属于软件吗源码建站之网站建设