From 3daf4392ed4b720d67067180c51d986cef806bbe Mon Sep 17 00:00:00 2001 From: kazelee <1847801760@qq.com> Date: 星期三, 25 六月 2025 17:27:50 +0800 Subject: [PATCH] 完善TcpClient方式与产线设备交互、托盘下线的轮询和Debug测试逻辑 --- device/ModbusFactory.cs | 516 ++++++++++++++++++++++++++++--- api/DebugController.cs | 112 ------ Program.cs | 6 core/Monitor.cs | 103 ------ .vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/7b233932-2148-476d-a58f-024f6cac6202.vsidx | 0 /dev/null | 0 .vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f9a252f3-6694-4ab8-a204-0ccfbf239beb.vsidx | 0 .vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/d454431d-5ff0-4870-b58b-659457d9dd0a.vsidx | 0 core/WCSCore.cs | 203 ++++++++++++ .vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/754396c7-eaff-48c1-966a-0bbb85008292.vsidx | 0 10 files changed, 669 insertions(+), 271 deletions(-) diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/140a3f27-91f0-4f76-83cb-8a8da5896f2a.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/140a3f27-91f0-4f76-83cb-8a8da5896f2a.vsidx deleted file mode 100644 index 4477ac6..0000000 --- a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/140a3f27-91f0-4f76-83cb-8a8da5896f2a.vsidx +++ /dev/null Binary files differ diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/51f15dd6-39b1-4e8d-8d5a-7cdebd5ca9d8.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/51f15dd6-39b1-4e8d-8d5a-7cdebd5ca9d8.vsidx deleted file mode 100644 index 8e0418e..0000000 --- a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/51f15dd6-39b1-4e8d-8d5a-7cdebd5ca9d8.vsidx +++ /dev/null Binary files differ diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/754396c7-eaff-48c1-966a-0bbb85008292.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/754396c7-eaff-48c1-966a-0bbb85008292.vsidx new file mode 100644 index 0000000..3dd4cca --- /dev/null +++ b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/754396c7-eaff-48c1-966a-0bbb85008292.vsidx Binary files differ diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/7b233932-2148-476d-a58f-024f6cac6202.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/7b233932-2148-476d-a58f-024f6cac6202.vsidx new file mode 100644 index 0000000..febf7e4 --- /dev/null +++ b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/7b233932-2148-476d-a58f-024f6cac6202.vsidx Binary files differ diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/c349b9a0-3c00-4a74-bcf5-5ba46f79eacb.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/c349b9a0-3c00-4a74-bcf5-5ba46f79eacb.vsidx deleted file mode 100644 index 783f818..0000000 --- a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/c349b9a0-3c00-4a74-bcf5-5ba46f79eacb.vsidx +++ /dev/null Binary files differ diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/d454431d-5ff0-4870-b58b-659457d9dd0a.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/d454431d-5ff0-4870-b58b-659457d9dd0a.vsidx new file mode 100644 index 0000000..d99f720 --- /dev/null +++ b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/d454431d-5ff0-4870-b58b-659457d9dd0a.vsidx Binary files differ diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f3ed8dde-3902-4d3f-824a-8f00db530827.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f3ed8dde-3902-4d3f-824a-8f00db530827.vsidx deleted file mode 100644 index 6ceab82..0000000 --- a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f3ed8dde-3902-4d3f-824a-8f00db530827.vsidx +++ /dev/null Binary files differ diff --git a/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f9a252f3-6694-4ab8-a204-0ccfbf239beb.vsidx b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f9a252f3-6694-4ab8-a204-0ccfbf239beb.vsidx new file mode 100644 index 0000000..c2a52b7 --- /dev/null +++ b/.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f9a252f3-6694-4ab8-a204-0ccfbf239beb.vsidx Binary files differ diff --git a/Program.cs b/Program.cs index 0601b18..c88fd1c 100644 --- a/Program.cs +++ b/Program.cs @@ -10,6 +10,7 @@ using Task = System.Threading.Tasks.Task; using Monitor = HH.WCS.Mobox3.DSZSH.core.Monitor; +using System.Net.Sockets; namespace HH.WCS.Mobox3.DSZSH { internal class Program @@ -20,7 +21,7 @@ // 1.0 寮�惎api Startup(); // 2.0 寮�惎tcp - StartTcp(); + //StartTcp(); // 3.0 寮�惎S7 //StartS7(); // 4.0 寮�惎Modbus @@ -28,6 +29,7 @@ // TCP娴嬭瘯 //TcpClientHelper.Link("127.0.0.1", 8550); + Task.Run(() => { WCSCore.StartServer(); }); // 5.0 寮�惎绾跨▼ var rc = HostFactory.Run(x => { @@ -156,5 +158,7 @@ return task; } } + + } } diff --git a/api/DebugController.cs b/api/DebugController.cs index c7524f5..e6b697f 100644 --- a/api/DebugController.cs +++ b/api/DebugController.cs @@ -222,117 +222,7 @@ [HttpPost] [Route("AddInboundTask")] public string AddInboundTask(AddInboundTaskInfo model) { - var db = new SqlHelper<object>().GetInstance(); - var info = ""; - - const string taskName = TaskName.T鎵樼洏_婊℃墭涓嬬嚎鍏ュ簱; - const string startAreaName = AreaName.B鍖呰鍖� - const string endAreaName = AreaName.M婊℃墭璐ф灦鍖� - const string cntrType = "鎵樼洏"; - - try { - var cntrCode = model.CntrCode; - var startLocCode = model.StartLoc; - - var startLoc = db.Queryable<TN_Location>() - .Where(l => l.S_CODE == startLocCode) - .Where(l => Settings.AreaMap[startAreaName].Contains(l.S_AREA_CODE)) - .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "鏃� && l.C_ENABLE == "Y") - .Where(l => l.N_CURRENT_NUM == 0) // 缁戝畾鍓�- .First(); - - if (startLoc == null) { - info = $"鍦�{startAreaName}'涓病鏈夋壘鍒拌捣鐐硅揣浣�{startLocCode}'锛屾垨涓嶆弧瓒宠姹傦細鏈笂閿併�褰撳墠瀹瑰櫒鏁伴噺=0"; - LogHelper.Info(info); - return info; - } - - var locCntrRelOld = db.Queryable<TN_Loc_Container>() - .Where(c => c.S_CNTR_CODE == cntrCode).First(); - - // 缁戝畾璐т綅鍜屽鍣ㄥ彿 - var locCntrRel = new TN_Loc_Container { - S_LOC_CODE = startLocCode, - S_CNTR_CODE = cntrCode, - S_CNTR_TYPE = cntrType, - }; - - startLoc.N_CURRENT_NUM = 1; // 缁戝畾鍚�- - var endLoc = db.Queryable<TN_Location>() - .Where(a => Settings.AreaMap[endAreaName].Contains(a.S_AREA_CODE)) - .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "鏃� && a.C_ENABLE == "Y") // 绛涢�锛氭湭涓婇攣 - .Where(a => a.N_CURRENT_NUM == 0) // 绛涢�锛氱┖璐т綅 - .OrderBy(l => l.N_LAYER) - .First(); - - if (endLoc == null) { - info = $"鍦ㄧ粓鐐硅揣鍖�{endAreaName}'涓紝娌℃湁鎵惧埌鍚堥�鐨勩�缁堢偣璐т綅銆戯紝闇�婊¤冻瑕佹眰锛氭湭涓婇攣銆佸綋鍓嶅鍣ㄦ暟閲�0"; - LogHelper.Info(info); - return info; - } - - var cntId = locCntrRel.S_CNTR_CODE; - var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); - - LocationHelper.LockStartLoc(ref startLoc); // 璧风偣鍑哄簱閿�- LocationHelper.LockEndLoc(ref endLoc); // 缁堢偣鍏ュ簱閿�- - using (var tran = db.Ado.UseTran()) { - if (locCntrRelOld != null) { - if (db.Deleteable<TN_Loc_Container>(locCntrRelOld).ExecuteCommand() <= 0 && - db.Updateable<TN_Location>().SetColumns(l => l.N_CURRENT_NUM == 0).Where(l => l.S_CODE == locCntrRelOld.S_LOC_CODE).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鍒犻櫎鏃ц揣浣嶅鍣ㄥ叧绯昏〃澶辫触锛氳揣浣嶇紪鐮亄locCntrRelOld.S_LOC_CODE}锛屽鍣ㄧ紪鐮亄locCntrRelOld.S_CNTR_CODE}"; - LogHelper.Info(info); - return info; - } - } - - if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鎻掑叆璐т綅瀹瑰櫒鍏崇郴琛ㄥけ璐ワ細璐т綅缂栫爜{locCntrRel.S_LOC_CODE}锛屽鍣ㄧ紪鐮亄locCntrRel.S_CNTR_CODE}"; - LogHelper.Info(info); - return info; - } - - if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM }).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛氭洿鏂拌捣鐐硅揣浣峽startLoc.S_CODE}閿佺姸鎬佸け璐�; - LogHelper.Info(info); - return info; - } - - if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { - it.N_LOCK_STATE, - it.S_LOCK_STATE, - it.S_LOCK_OP, - it.T_MODIFY - }).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛氭洿鏂扮粓鐐硅揣浣峽endLoc.S_CODE}閿佺姸鎬佸け璐�; - LogHelper.Info(info); - return info; - } - - if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛屽鍣ㄥ彿{cntId}锛岃捣鐐箋startLoc.S_CODE}锛岀粓鐐硅揣鏋秢endLoc.S_CODE}"; - LogHelper.Info(info); - return info; - } - - tran.CommitTran(); - info = $"鐢熸垚浠诲姟'{taskName}'鎴愬姛锛屽鍣ㄥ彿{cntId}锛岃捣鐐箋startLoc.S_CODE}锛岀粓鐐硅揣鏋秢endLoc.S_CODE}"; - LogHelper.Info(info); - return info; - } - - } - catch (Exception ex) { - LogHelper.InfoEx(ex); - return ex.Message; - } + return WCSCore.CreateInboundTask(model.StartLoc, model.CntrCode).Content; } /// <summary> diff --git a/core/Monitor.cs b/core/Monitor.cs index b24ff54..2204e35 100644 --- a/core/Monitor.cs +++ b/core/Monitor.cs @@ -24,11 +24,6 @@ var db = new SqlHelper<object>().GetInstance(); var info = ""; - const string taskName = TaskName.T鎵樼洏_婊℃墭涓嬬嚎鍏ュ簱; - const string startAreaName = AreaName.B鍖呰鍖� - const string endAreaName = AreaName.M婊℃墭璐ф灦鍖� - const string cntrType = "鎵樼洏"; - try { // 鏌ヤ骇绾挎槸鍚︽湁鐗╂枡淇℃伅 foreach (var prod in Settings.ProductionLines) { @@ -65,103 +60,7 @@ var startLocCode = prod.OffLoc[0]; // 鐢ㄤ簬娴嬭瘯 //var startLocCode = "CX01"; // 鐢ㄤ簬娴嬭瘯 - var startLoc = db.Queryable<TN_Location>() - .Where(l => l.S_CODE == startLocCode) - .Where(l => Settings.AreaMap[startAreaName].Contains(l.S_AREA_CODE)) - .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "鏃� && l.C_ENABLE == "Y") - //.Where(l => l.N_CURRENT_NUM == 0) // 缁戝畾鍓�- .First(); - - if (startLoc == null) { - info = $"鍦�{startAreaName}'涓病鏈夋壘鍒拌捣鐐硅揣浣�{startLocCode}'锛屾垨涓嶆弧瓒宠姹傦細鏈笂閿併�褰撳墠瀹瑰櫒鏁伴噺=0"; - LogHelper.Info(info); - } - - var locCntrRelOld = db.Queryable<TN_Loc_Container>() - .Where(c => c.S_CNTR_CODE == cntrCode).First(); - - // 缁戝畾璐т綅鍜屽鍣ㄥ彿 - var locCntrRel = new TN_Loc_Container { - S_LOC_CODE = startLocCode, - S_CNTR_CODE = cntrCode, - S_CNTR_TYPE = cntrType, - }; - - startLoc.N_CURRENT_NUM = 1; // 缁戝畾鍚�- - var endLoc = db.Queryable<TN_Location>() - .Where(a => Settings.AreaMap[endAreaName].Contains(a.S_AREA_CODE)) - .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "鏃� && a.C_ENABLE == "Y") // 绛涢�锛氭湭涓婇攣 - .Where(a => a.N_CURRENT_NUM == 0) // 绛涢�锛氱┖璐т綅 - .OrderBy(l => l.N_LAYER) - .First(); - - if (endLoc == null) { - info = $"鍦ㄧ粓鐐硅揣鍖�{endAreaName}'涓紝娌℃湁鎵惧埌鍚堥�鐨勩�缁堢偣璐т綅銆戯紝闇�婊¤冻瑕佹眰锛氭湭涓婇攣銆佸綋鍓嶅鍣ㄦ暟閲�0"; - LogHelper.Info(info); - } - - var cntId = locCntrRel.S_CNTR_CODE; - var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); - - LocationHelper.LockStartLoc(ref startLoc); // 璧风偣鍑哄簱閿�- LocationHelper.LockEndLoc(ref endLoc); // 缁堢偣鍏ュ簱閿�- - using (var tran = db.Ado.UseTran()) { - if (locCntrRelOld != null) { - if (db.Deleteable<TN_Loc_Container>(locCntrRelOld).ExecuteCommand() <= 0 && - db.Updateable<TN_Location>().SetColumns(l => l.N_CURRENT_NUM == 0).Where(l => l.S_CODE == locCntrRelOld.S_LOC_CODE).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鍒犻櫎鏃ц揣浣嶅鍣ㄥ叧绯昏〃澶辫触锛氳揣浣嶇紪鐮亄locCntrRelOld.S_LOC_CODE}锛屽鍣ㄧ紪鐮亄locCntrRelOld.S_CNTR_CODE}"; - LogHelper.Info(info); - continue; - } - } - - if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鎻掑叆璐т綅瀹瑰櫒鍏崇郴琛ㄥけ璐ワ細璐т綅缂栫爜{locCntrRel.S_LOC_CODE}锛屽鍣ㄧ紪鐮亄locCntrRel.S_CNTR_CODE}"; - LogHelper.Info(info); - continue; - } - - if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { - it.N_LOCK_STATE, - it.S_LOCK_STATE, - it.S_LOCK_OP, - it.T_MODIFY, - it.N_CURRENT_NUM, // 璧风偣璐т綅缁戝畾鍚庯紝灏嗚揣浣嶇姸鎬佹洿鏂�- }).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛氭洿鏂拌捣鐐硅揣浣峽startLoc.S_CODE}閿佺姸鎬佸け璐�; - LogHelper.Info(info); - continue; - } - - if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { - it.N_LOCK_STATE, - it.S_LOCK_STATE, - it.S_LOCK_OP, - it.T_MODIFY, - }).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛氭洿鏂扮粓鐐硅揣浣峽endLoc.S_CODE}閿佺姸鎬佸け璐�; - LogHelper.Info(info); - continue; - } - - if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { - tran.RollbackTran(); - info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛屼换鍔″彿={task.S_CODE}锛屽鍣ㄥ彿={cntId}锛岃捣鐐�{startLoc.S_CODE}锛岀粓鐐�{endLoc.S_CODE}"; - LogHelper.Info(info); - continue; - } - - tran.CommitTran(); - info = $"鐢熸垚浠诲姟'{taskName}'鎴愬姛锛屼换鍔″彿={task.S_CODE}锛屽鍣ㄥ彿={cntId}锛岃捣鐐�{startLoc.S_CODE}锛岀粓鐐�{endLoc.S_CODE}"; - LogHelper.Info(info); - continue; - } + WCSCore.CreateInboundTask(startLocCode, cntrCode); } } diff --git a/core/WCSCore.cs b/core/WCSCore.cs index 6423042..d72bf4b 100644 --- a/core/WCSCore.cs +++ b/core/WCSCore.cs @@ -1,6 +1,8 @@ 锘縰sing System; using System.Collections.Generic; using System.Linq; +using System.Net; +using System.Net.Sockets; using System.Text; using System.Threading.Tasks; @@ -12,6 +14,8 @@ using HH.WCS.Mobox3.DSZSH.wms; using Newtonsoft.Json; + +using Swashbuckle.Swagger; using static HH.WCS.Mobox3.DSZSH.api.ApiModel; @@ -449,5 +453,204 @@ LogHelper.Info("鏆傛棤浠诲姟"); } } + + // TCP 闈炶疆璇㈡柟寮�妯℃嫙浜х嚎涓嬬嚎鐨勫皾璇�+ + public static void StartServer() { + var ListenPort = 6000; + TcpListener listener = new TcpListener(IPAddress.Any, ListenPort); + listener.Start(); + Console.WriteLine($"鍚庡彴鏈嶅姟宸插惎鍔紝鐩戝惉绔彛 {ListenPort}..."); + + while (true) { + try { + // 鎺ュ彈浜х嚎杩炴帴 + System.Net.Sockets.TcpClient client = listener.AcceptTcpClient(); + Console.WriteLine($"浜х嚎瀹㈡埛绔凡杩炴帴: {client.Client.RemoteEndPoint}"); + + // 澶勭悊瀹㈡埛绔姹傦紙浣跨敤Task閬垮厤闃诲涓荤嚎绋嬶級 + Task.Run(() => HandleClientRequest(client)); + } + catch (Exception ex) { + Console.WriteLine($"鏈嶅姟绔紓甯� {ex.Message}"); + } + } + } + + public static void HandleClientRequest(System.Net.Sockets.TcpClient client) { + var db = new SqlHelper<object>().GetInstance(); + using (client) + using (NetworkStream stream = client.GetStream()) { + try { + // 璇诲彇浜х嚎娑堟伅 + byte[] buffer = new byte[1024]; + int bytesRead = stream.Read(buffer, 0, buffer.Length); + string jsonMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead); + + // 瑙f瀽娑堟伅 + var message = JsonConvert.DeserializeObject<ProductCompletedMessage>(jsonMessage); + //Console.WriteLine($"鏀跺埌浜у搧瀹屾垚閫氱煡 - 鐗╂枡锛歿message.ItemCode}锛涙壒娆″彿锛歿message.BatchNo}锛涘鍣ㄥ彿锛歿message.CntrCode}"); + LogHelper.Info($"鏀跺埌浜у搧涓嬬嚎閫氱煡锛�+message); + + string startLocCode = ""; + + // A. 濡傛灉鏄崟涓骇绾縋LC锛岄�杩嘥CP浼犳挱锛岄渶瑕佷紶閫掍骇绾縄D锛屾牴鎹甀D璁$畻璧风偣璐т綅 + //startLocCode = Settings.ProductionLines[message.Id].OffLoc[0]; // 鐞嗚涓婂簲璇ュ彧鏈�涓狾ffLoc锛屽惁鍒欏簲璇ユ敞鏄庢槸鍝竴涓�+ + // B. 濡傛灉鏄瘡鏉′骇绾垮悇涓�釜瀹㈡埛绔紝鏇寸畝鍗曪紝鐩存帴鏍规嵁IP鍦板潃纭畾缁堢偣璐т綅 + // TODO 鍏蜂綋閫昏緫寰呭悗缁‘瀹氭椂琛ュ畬 + + var success = CreateInboundTask(startLocCode, message.CntrCode).Value; + + // 鍙戦�鍝嶅簲 + string response = success ? "ACK: 鏈哄櫒浜哄凡璋冨害" : "NAK: 璋冨害澶辫触"; + byte[] responseData = Encoding.UTF8.GetBytes(response); + stream.Write(responseData, 0, responseData.Length); + } + catch (Exception ex) { + Console.WriteLine($"澶勭悊瀹㈡埛绔姹傚紓甯� {ex.Message}"); + } + } + } + + /// <summary> + /// 鍏ュ簱浣滀笟鍒涘缓鍙帴鏀惰捣鐐硅揣浣嶅拰瀹瑰櫒鍙凤紙鐗╂枡淇℃伅寰呭畾銆侀�杩囦骇绾垮彿璁$畻璧风偣鐨勯�杈戞斁鍦ㄦ柟娉曞锛�+ /// </summary> + /// <param name="startLocCode"></param> + /// <param name="cntrCode"></param> + /// <returns></returns> + public static Result<bool> CreateInboundTask(string startLocCode, string cntrCode) { + var db = new SqlHelper<object>().GetInstance(); + var info = ""; + + const string taskName = TaskName.T鎵樼洏_婊℃墭涓嬬嚎鍏ュ簱; + const string startAreaName = AreaName.B鍖呰鍖� + const string endAreaName = AreaName.M婊℃墭璐ф灦鍖� + const string cntrType = "鎵樼洏"; + + try { + var startLoc = db.Queryable<TN_Location>() + .Where(l => l.S_CODE == startLocCode) + .Where(l => Settings.AreaMap[startAreaName].Contains(l.S_AREA_CODE)) + .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "鏃� && l.C_ENABLE == "Y") + //.Where(l => l.N_CURRENT_NUM == 0) // 缁戝畾鍓�+ .First(); + + if (startLoc == null) { + info = $"鍦�{startAreaName}'涓病鏈夋壘鍒拌捣鐐硅揣浣�{startLocCode}'锛屾垨涓嶆弧瓒宠姹傦細鏈笂閿併�褰撳墠瀹瑰櫒鏁伴噺=0"; + LogHelper.Info(info); + return new Result<bool>(false, info); + } + + var locCntrRelOld = db.Queryable<TN_Loc_Container>() + .Where(c => c.S_CNTR_CODE == cntrCode).First(); + + // 缁戝畾璐т綅鍜屽鍣ㄥ彿 + var locCntrRel = new TN_Loc_Container { + S_LOC_CODE = startLocCode, + S_CNTR_CODE = cntrCode, + S_CNTR_TYPE = cntrType, + }; + + startLoc.N_CURRENT_NUM = 1; // 缁戝畾鍚�+ + var endLoc = db.Queryable<TN_Location>() + .Where(a => Settings.AreaMap[endAreaName].Contains(a.S_AREA_CODE)) + .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "鏃� && a.C_ENABLE == "Y") // 绛涢�锛氭湭涓婇攣 + .Where(a => a.N_CURRENT_NUM == 0) // 绛涢�锛氱┖璐т綅 + .OrderBy(l => l.N_LAYER) + .First(); + + if (endLoc == null) { + info = $"鍦ㄧ粓鐐硅揣鍖�{endAreaName}'涓紝娌℃湁鎵惧埌鍚堥�鐨勩�缁堢偣璐т綅銆戯紝闇�婊¤冻瑕佹眰锛氭湭涓婇攣銆佸綋鍓嶅鍣ㄦ暟閲�0"; + LogHelper.Info(info); + return new Result<bool>(false, info); + } + + var cntId = locCntrRel.S_CNTR_CODE; + var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); + + LocationHelper.LockStartLoc(ref startLoc); // 璧风偣鍑哄簱閿�+ LocationHelper.LockEndLoc(ref endLoc); // 缁堢偣鍏ュ簱閿�+ + using (var tran = db.Ado.UseTran()) { + if (locCntrRelOld != null) { + if (db.Deleteable<TN_Loc_Container>(locCntrRelOld).ExecuteCommand() <= 0 && + db.Updateable<TN_Location>().SetColumns(l => l.N_CURRENT_NUM == 0).Where(l => l.S_CODE == locCntrRelOld.S_LOC_CODE).ExecuteCommand() <= 0) { + tran.RollbackTran(); + info = $"鍒犻櫎鏃ц揣浣嶅鍣ㄥ叧绯昏〃澶辫触锛氳揣浣嶇紪鐮亄locCntrRelOld.S_LOC_CODE}锛屽鍣ㄧ紪鐮亄locCntrRelOld.S_CNTR_CODE}"; + LogHelper.Info(info); + return new Result<bool>(false, info); + } + } + + if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { + tran.RollbackTran(); + info = $"鎻掑叆璐т綅瀹瑰櫒鍏崇郴琛ㄥけ璐ワ細璐т綅缂栫爜{locCntrRel.S_LOC_CODE}锛屽鍣ㄧ紪鐮亄locCntrRel.S_CNTR_CODE}"; + LogHelper.Info(info); + return new Result<bool>(false, info); + } + + if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { + it.N_LOCK_STATE, + it.S_LOCK_STATE, + it.S_LOCK_OP, + it.T_MODIFY, + it.N_CURRENT_NUM, // 璧风偣璐т綅缁戝畾鍚庯紝灏嗚揣浣嶇姸鎬佹洿鏂�+ }).ExecuteCommand() <= 0) { + tran.RollbackTran(); + info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛氭洿鏂拌捣鐐硅揣浣峽startLoc.S_CODE}閿佺姸鎬佸け璐�; + LogHelper.Info(info); + return new Result<bool>(false, info); + } + + if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { + it.N_LOCK_STATE, + it.S_LOCK_STATE, + it.S_LOCK_OP, + it.T_MODIFY, + }).ExecuteCommand() <= 0) { + tran.RollbackTran(); + info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛氭洿鏂扮粓鐐硅揣浣峽endLoc.S_CODE}閿佺姸鎬佸け璐�; + LogHelper.Info(info); + return new Result<bool>(false, info); + } + + if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { + tran.RollbackTran(); + info = $"鐢熸垚浠诲姟'{taskName}'澶辫触锛屼换鍔″彿={task.S_CODE}锛屽鍣ㄥ彿={cntId}锛岃捣鐐�{startLoc.S_CODE}锛岀粓鐐�{endLoc.S_CODE}"; + LogHelper.Info(info); + return new Result<bool>(false, info); + } + + tran.CommitTran(); + info = $"鐢熸垚浠诲姟'{taskName}'鎴愬姛锛屼换鍔″彿={task.S_CODE}锛屽鍣ㄥ彿={cntId}锛岃捣鐐�{startLoc.S_CODE}锛岀粓鐐�{endLoc.S_CODE}"; + LogHelper.Info(info); + return new Result<bool>(true, info); + } + } + catch (Exception ex) { + LogHelper.InfoEx(ex); + return new Result<bool>(false, ex.Message); + } + } + + } + + public class ProductCompletedMessage { + public int Id { get; set; } + //public string ItemCode { get; set; } + //public string BatchNo { get; set; } + public string CntrCode { get; set; } + } + + public class Result<T> { + public T Value { get; set; } + public string Content { get; set; } + + public Result(T value, string content) { + Value = value; + Content = content; + } } } diff --git a/device/ModbusFactory.cs b/device/ModbusFactory.cs index 28578f8..83a15ae 100644 --- a/device/ModbusFactory.cs +++ b/device/ModbusFactory.cs @@ -8,6 +8,7 @@ using System.Linq; using TcpClient = System.Net.Sockets.TcpClient; +using System.IO; namespace HH.WCS.Mobox3.DSZSH.device { // 瀹氫箟Modbus閫氳鎺ュ彛 @@ -48,13 +49,31 @@ /// <returns></returns> int[] ReadInputRegisters(int startingAddress, int quantity); /// <summary> - /// + /// 鍐欏叆鍗曚釜绾垮湀 /// </summary> /// <param name="coilAddress"></param> /// <param name="value"></param> bool WriteSingleCoil(int coilAddress, bool value); + /// <summary> + /// 鍐欏叆鍗曚釜瀵勫瓨鍣ㄦ暟鎹�+ /// </summary> + /// <param name="registerAddress"></param> + /// <param name="value"></param> + /// <returns></returns> bool WriteSingleRegister(int registerAddress, ushort value); + /// <summary> + /// 鍐欏叆澶氫釜绾垮湀 + /// </summary> + /// <param name="startingAddress"></param> + /// <param name="values"></param> + /// <returns></returns> bool WriteMultipleCoils(int startingAddress, bool[] values); + /// <summary> + /// 鍐欏叆澶氫釜瀵勫瓨鍣ㄦ暟鎹�+ /// </summary> + /// <param name="startingAddress"></param> + /// <param name="values"></param> + /// <returns></returns> bool WriteMultipleRegisters(int startingAddress, int[] values); } @@ -80,7 +99,15 @@ } static void Test() { - var communicator = ModbusFactory.CreateCommunicator(ModbusCommunicationType.TcpSocket); + try { + var communicator = ModbusFactory.CreateCommunicator(ModbusCommunicationType.TcpSocket); + + communicator.Link("127.0.0.1", 502); + var read = communicator.ReadInputRegisters(0, 5); + } + catch (Exception ex) { + LogHelper.InfoEx(ex); + } } } @@ -134,16 +161,19 @@ public bool[] ReadCoils(int startingAddress, int quantity) { bool[] res = new bool[0]; + var client = _modbusClient; if (_modbusClient != null && IsConnected) { + var ip = client.IPAddress; + var port = client.Port; try { res = _modbusClient.ReadCoils(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 - LogHelper.Info($"璇诲彇鎴愬姛锛歊eadCoils"); + LogHelper.Info($"璇诲彇鎴愬姛锛歊eadCoils:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 - LogHelper.Info($"璇诲彇澶辫触锛歊eadCoils"); + LogHelper.Info($"璇诲彇澶辫触锛歊eadCoils:IP:{ip},Port:{port}"); } } catch (Exception ex) { @@ -151,23 +181,26 @@ } } else { - LogHelper.Info($"璁惧鏈繛鎺ワ紝璇诲彇澶辫触锛歊eadCoils"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } public bool[] ReadDiscreteInputs(int startingAddress, int quantity) { bool[] res = new bool[0]; + var client = _modbusClient; if (_modbusClient != null && IsConnected) { + var ip = client.IPAddress; + var port = client.Port; try { res = _modbusClient.ReadDiscreteInputs(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 - LogHelper.Info($"璇诲彇鎴愬姛锛歊eadDiscreteInputs"); + LogHelper.Info($"璇诲彇鎴愬姛锛歊eadDiscreteInputs:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 - LogHelper.Info($"璇诲彇澶辫触锛歊eadDiscreteInputs"); + LogHelper.Info($"璇诲彇澶辫触锛歊eadDiscreteInputs:IP:{ip},Port:{port}"); } } catch (Exception ex) { @@ -175,7 +208,7 @@ } } else { - LogHelper.Info($"璁惧鏈繛鎺ワ紝璇诲彇澶辫触锛歊eadDiscreteInputs"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } @@ -183,26 +216,28 @@ public int[] ReadHoldingRegisters(int startingAddress, int quantity) { int[] res = new int[0]; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { //涓�釜瀵勫瓨鍣ㄦ槸16浣嶏紝杩斿洖2涓猧nt绫诲瀷 res = client.ReadHoldingRegisters(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 + LogHelper.Info($"璇诲彇鎴愬姛锛歊eadHoldingRegisters:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 + LogHelper.Info($"璇诲彇澶辫触锛歊eadHoldingRegisters:IP:{ip},Port:{port}"); } } catch (Exception ex) { //濡傛灉璇锋眰鏁伴噺瓒呭嚭淇濇寔瀵勫瓨鍣ㄧ殑鏈�ぇ鏁版嵁琛屾暟锛屼細鎶ラ敊 - LogHelper.Info($"鍙戠敓浜嗗紓甯�{ex.Message},IP:{ip},Port:{port}", "Error"); + LogHelper.InfoEx(ex); } } else { - LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄:IP:{ip},Port:{port}"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } @@ -210,24 +245,26 @@ public int[] ReadInputRegisters(int startingAddress, int quantity) { int[] res = new int[0]; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { res = client.ReadInputRegisters(startingAddress, quantity); if (res.Length != 0) { //璇诲彇鎴愬姛 + LogHelper.Info($"璇诲彇鎴愬姛锛歊eadInputRegisters:IP:{ip},Port:{port}"); } else { //璇诲彇澶辫触 + LogHelper.Info($"璇诲彇澶辫触锛歊eadInputRegisters:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } @@ -235,25 +272,27 @@ public bool WriteSingleCoil(int coilAddress, bool value) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { client.WriteSingleCoil(coilAddress, value); res = value == client.ReadCoils(coilAddress, 1)[0]; if (res) { //鍐欏叆鎴愬姛 + LogHelper.Info($"鍐欏叆鎴愬姛锛歐riteSingleCoil:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触锛歐riteSingleCoil:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } @@ -261,25 +300,27 @@ public bool WriteSingleRegister(int registerAddress, ushort value) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { client.WriteSingleRegister(registerAddress, value); res = value == client.ReadHoldingRegisters(registerAddress, 1)[0]; if (res) { //鍐欏叆鎴愬姛 + LogHelper.Info($"鍐欏叆鎴愬姛锛歐riteSingleRegister:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触锛歐riteSingleRegister:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } @@ -287,26 +328,28 @@ public bool WriteMultipleCoils(int startingAddress, bool[] values) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; try { client.WriteMultipleCoils(startingAddress, values); var dataRead = client.ReadCoils(startingAddress, values.Length); res = values.SequenceEqual(dataRead); if (res) { //鍐欏叆鎴愬姛 + LogHelper.Info($"鍐欏叆鎴愬姛锛歐riteMultipleCoils:IP:{ip},Port:{port}"); } else { //鍐欏叆澶辫触 + LogHelper.Info($"鍐欏叆澶辫触锛歐riteMultipleCoils:IP:{ip},Port:{port}"); } } catch (Exception ex) { - + LogHelper.InfoEx(ex); } } else { - + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } @@ -314,33 +357,34 @@ public bool WriteMultipleRegisters(int startingAddress, int[] values) { var res = false; var client = _modbusClient; - var ip = client.IPAddress; - var port = client.Port; - var log = string.Join(",", values.Select(x => x.ToString())); if (client != null && client.Connected) { + var ip = client.IPAddress; + var port = client.Port; + var log = string.Join(",", values.Select(x => x.ToString())); try { client.WriteMultipleRegisters(startingAddress, values); var dataRead = client.ReadHoldingRegisters(startingAddress, values.Length); res = values.SequenceEqual(dataRead); if (res) { - LogHelper.Info($"鍐欏叆鎴愬姛,IP:{ip},Port:{port},{log}"); + LogHelper.Info($"鍐欏叆鎴愬姛,WriteMultipleRegisters:IP:{ip},Port:{port},{log}"); } else { - LogHelper.Info($"鍐欏叆澶辫触,IP:{ip},Port:{port},{log}"); + LogHelper.Info($"鍐欏叆澶辫触,WriteMultipleRegisters:IP:{ip},Port:{port},{log}"); } } catch (Exception ex) { - LogHelper.Info($"鍙戠敓浜嗗紓甯�{ex.Message},IP:{ip},Port:{port},{log}", "Error"); + LogHelper.InfoEx(ex); } } else { - LogHelper.Info($"鏈厤缃殑璁惧淇℃伅,IP:{ip},Port:{port},{log}"); + LogHelper.Info($"鏈壘鍒癕odbus璁惧瀹炰緥瀵硅薄锛屾垨瀵硅薄鏈垚鍔熻繛鎺�); } return res; } public void Dispose() { //_modbusClient?.Dispose(); + GC.SuppressFinalize(_modbusClient); } } @@ -348,9 +392,10 @@ public class TcpSocketCommunicator : IModbusCommunicator { private System.Net.Sockets.TcpClient _tcpClient; private NetworkStream _networkStream; + private byte unitIdentifier = 1; // 榛樿鍗曞厓鏍囪瘑绗� - //public bool IsConnected => _tcpClient?.Connected ?? false; - public bool IsConnected { get { if (_tcpClient != null) { return true; } else { return false; } } } + public bool IsConnected => _tcpClient?.Connected ?? false; + //public bool IsConnected { get { if (_tcpClient != null) { return _tcpClient.Connected; } else { return false; } } } public void Link(string ipAddress, int port) { _tcpClient = new System.Net.Sockets.TcpClient(); @@ -372,50 +417,407 @@ } } - // 浠ヤ笅鏂规硶闇�鏍规嵁浣犵殑Modbus TCP鍗忚鍏蜂綋瀹炵幇 public bool[] ReadCoils(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇绾垮湀 - throw new NotImplementedException(); + if (quantity < 1 || quantity > 2000) + throw new ArgumentException("Quantity must be between 1 and 2000"); + + // 鏋勫缓璇锋眰鎶ユ枃锛�2瀛楄妭锛�+ byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺傦紙绀轰緥鍊硷級 + request[2] = 0x00; // 鍗忚ID楂樺瓧鑺傦紙鍥哄畾0锛�+ request[3] = 0x00; // 鍗忚ID浣庡瓧鑺傦紙鍥哄畾0锛�+ request[4] = 0x00; // 闀垮害楂樺瓧鑺傦紙鍚庣画6瀛楄妭锛�+ request[5] = 0x06; // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; // 鍗曞厓鏍囪瘑绗�+ request[7] = 0x01; // 鍔熻兘鐮侊紙璇荤嚎鍦堬級 + request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲澶达紙8瀛楄妭锛�+ byte[] responseHeader = new byte[8]; + int bytesRead = _networkStream.Read(responseHeader, 0, 8); + if (bytesRead != 8) + throw new Exception("Invalid response header length"); + + // 鏍¢獙浜嬪姟ID銆佸崗璁甀D銆佸崟鍏冩爣璇嗙 + if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || + responseHeader[2] != 0x00 || responseHeader[3] != 0x00 || + responseHeader[6] != unitIdentifier) + throw new Exception("Invalid response header"); + + // 妫�煡寮傚父鍝嶅簲锛堝姛鑳界爜 + 0x80锛�+ if (responseHeader[7] == 0x81) { + int errorCode = _networkStream.ReadByte(); + throw new Exception($"Modbus error. Code: {errorCode}"); + } + else if (responseHeader[7] != 0x01) + throw new Exception("Invalid function code in response"); + + // 璇诲彇鏁版嵁閮ㄥ垎锛堝瓧鑺傛暟 + 瀹為檯鏁版嵁锛�+ byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + bytesRead = _networkStream.Read(responseData, 0, byteCount); + if (bytesRead != byteCount) + throw new Exception("Invalid response data length"); + + // 瑙f瀽绾垮湀鐘舵�锛堟瘡涓綅琛ㄧず涓�釜绾垮湀锛�+ bool[] coils = new bool[quantity]; + for (int i = 0; i < quantity; i++) { + int byteIndex = i / 8; + int bitIndex = i % 8; + coils[i] = (responseData[byteIndex] & (1 << bitIndex)) != 0; + } + + return coils; } public bool[] ReadDiscreteInputs(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇绂绘暎杈撳叆 - throw new NotImplementedException(); + // 鎶ユ枃缁撴瀯涓嶳eadCoils鍑犱箮鐩稿悓锛屼粎鍔熻兘鐮佹敼涓�x02 + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺傦紙绀轰緥鍊硷級 + request[2] = 0x00; // 鍗忚ID楂樺瓧鑺傦紙鍥哄畾0锛�+ request[3] = 0x00; // 鍗忚ID浣庡瓧鑺傦紙鍥哄畾0锛�+ request[4] = 0x00; // 闀垮害楂樺瓧鑺傦紙鍚庣画6瀛楄妭锛�+ request[5] = 0x06; // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; + request[7] = 0x02; // 鍔熻兘鐮侊細璇荤鏁h緭鍏�+ request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ + _networkStream.Write(request, 0, request.Length); + + // 鍝嶅簲澶勭悊閫昏緫涓嶳eadCoils涓�嚧 + byte[] responseHeader = new byte[8]; + _networkStream.Read(responseHeader, 0, 8); + + // 鏍¢獙鍜屽紓甯稿鐞嗭紙鍙傝�ReadCoils锛�+ if (responseHeader[7] == 0x82) // 寮傚父鍝嶅簲 + { + int errorCode = _networkStream.ReadByte(); + throw new Exception($"Modbus error. Code: {errorCode}"); + } + + byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + _networkStream.Read(responseData, 0, byteCount); + + // 瑙f瀽绂绘暎杈撳叆鐘舵� + bool[] inputs = new bool[quantity]; + for (int i = 0; i < quantity; i++) { + int byteIndex = i / 8; + int bitIndex = i % 8; + inputs[i] = (responseData[byteIndex] & (1 << bitIndex)) != 0; + } + + return inputs; } public int[] ReadHoldingRegisters(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇淇濇寔瀵勫瓨鍣�- throw new NotImplementedException(); + if (quantity < 1 || quantity > 125) + throw new ArgumentException("Quantity must be between 1 and 125"); + + // 鏋勫缓璇锋眰鎶ユ枃锛�2瀛楄妭锛�+ byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺傦紙绀轰緥鍊硷級 + request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�+ request[2] = 0x00; // 鍗忚ID楂樺瓧鑺傦紙鍥哄畾0锛�+ request[3] = 0x00; // 鍗忚ID浣庡瓧鑺傦紙鍥哄畾0锛�+ request[4] = 0x00; // 闀垮害楂樺瓧鑺傦紙鍚庣画6瀛楄妭锛�+ request[5] = 0x06; // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; // 鍗曞厓鏍囪瘑绗�+ request[7] = 0x03; // 鍔熻兘鐮侊紙璇讳繚鎸佸瘎瀛樺櫒锛�+ request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲澶达紙8瀛楄妭锛�+ byte[] responseHeader = new byte[8]; + int bytesRead = _networkStream.Read(responseHeader, 0, 8); + if (bytesRead != 8) + throw new Exception("Invalid response header length"); + + // 鏍¢獙浜嬪姟ID銆佸崗璁甀D銆佸崟鍏冩爣璇嗙 + if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || + responseHeader[2] != 0x00 || responseHeader[3] != 0x00 || + responseHeader[6] != unitIdentifier) + throw new Exception("Invalid response header"); + + // 妫�煡寮傚父鍝嶅簲锛堝姛鑳界爜 + 0x80锛�+ if (responseHeader[7] == 0x83) { + int errorCode = _networkStream.ReadByte(); + throw new Exception($"Modbus error. Code: {errorCode}"); + } + else if (responseHeader[7] != 0x03) + throw new Exception("Invalid function code in response"); + + // 璇诲彇鏁版嵁閮ㄥ垎锛堝瓧鑺傛暟 + 瀹為檯鏁版嵁锛�+ byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + bytesRead = _networkStream.Read(responseData, 0, byteCount); + if (bytesRead != byteCount) + throw new Exception("Invalid response data length"); + + // 瑙f瀽瀵勫瓨鍣ㄥ�锛堝ぇ绔簭锛�+ int[] registers = new int[quantity]; + for (int i = 0; i < quantity; i++) { + int offset = i * 2; + registers[i] = (ushort)((responseData[offset] << 8) | responseData[offset + 1]); + } + + return registers; } public int[] ReadInputRegisters(int startingAddress, int quantity) { - // 瀹炵幇TCP鏂瑰紡璇诲彇杈撳叆瀵勫瓨鍣�- throw new NotImplementedException(); + if (quantity < 1 || quantity > 125) + throw new ArgumentException("Quantity must be between 1 and 125"); + + // 鏋勫缓Modbus TCP璇锋眰鎶ユ枃 + byte[] request = new byte[12]; + + // 浜嬪姟鏍囪瘑绗︼紙鍙互绠�崟閫掑锛�+ request[0] = 0x00; + request[1] = 0x01; + + // 鍗忚鏍囪瘑绗︼紙Modbus鍥哄畾涓�锛�+ request[2] = 0x00; + request[3] = 0x00; + + // 闀垮害瀛楁锛堝悗闈㈣繕鏈�瀛楄妭锛�+ request[4] = 0x00; + request[5] = 0x06; + + // 鍗曞厓鏍囪瘑绗�+ request[6] = unitIdentifier; + + // 鍔熻兘鐮侊紙4琛ㄧず璇昏緭鍏ュ瘎瀛樺櫒锛�+ request[7] = 0x04; + + // 璧峰鍦板潃 + request[8] = (byte)(startingAddress >> 8); + request[9] = (byte)startingAddress; + + // 瀵勫瓨鍣ㄦ暟閲�+ request[10] = (byte)(quantity >> 8); + request[11] = (byte)quantity; + + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 鎺ユ敹鍝嶅簲 + byte[] responseHeader = new byte[8]; + int bytesRead = _networkStream.Read(responseHeader, 0, 8); + + if (bytesRead != 8) + throw new Exception("Invalid response header length"); + + // 妫�煡浜嬪姟ID鍜屽崗璁甀D鏄惁鍖归厤 + if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || + responseHeader[2] != 0x00 || responseHeader[3] != 0x00) + throw new Exception("Invalid response header"); + + // 妫�煡鍗曞厓鏍囪瘑绗﹀拰鍔熻兘鐮�+ if (responseHeader[6] != unitIdentifier) + throw new Exception("Unit identifier mismatch"); + + if (responseHeader[7] != 0x04 && responseHeader[7] != 0x84) + throw new Exception("Invalid function code in response"); + + // 妫�煡寮傚父鍝嶅簲 + if (responseHeader[7] == 0x84) { + byte errorCode = responseHeader[8]; + throw new Exception($"Modbus error response. Error code: {errorCode}"); + } + + // 璇诲彇鍓╀綑鍝嶅簲鏁版嵁 + byte byteCount = responseHeader[8]; + byte[] responseData = new byte[byteCount]; + bytesRead = _networkStream.Read(responseData, 0, byteCount); + + if (bytesRead != byteCount) + throw new Exception("Invalid response data length"); + + // 瑙f瀽瀵勫瓨鍣ㄥ� + int[] registers = new int[quantity]; + for (int i = 0; i < quantity; i++) { + int offset = i * 2; + registers[i] = (ushort)((responseData[offset] << 8) | responseData[offset + 1]); + } + + return registers; } - public bool WriteSingleCoil(int coilAddress, bool value) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆鍗曚釜绾垮湀 - throw new NotImplementedException(); + public bool WriteSingleCoil(int address, bool value) { + // 璇锋眰鎶ユ枃鍥哄畾闀垮害12瀛楄妭 + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID + request[1] = 0x01; + request[2] = 0x00; // 鍗忚ID + request[3] = 0x00; + request[4] = 0x00; // 闀垮害 + request[5] = 0x06; + request[6] = unitIdentifier; + request[7] = 0x05; // 鍔熻兘鐮�+ request[8] = (byte)(address >> 8); // 鍦板潃楂樺瓧鑺�+ request[9] = (byte)address; // 鍦板潃浣庡瓧鑺�+ request[10] = (byte)(value ? 0xFF : 0x00); // ON=0xFF00, OFF=0x0000 + request[11] = 0x00; + + _networkStream.Write(request, 0, request.Length); + + // 鍝嶅簲搴斾笌璇锋眰瀹屽叏涓�嚧锛堝洖鏄撅級 + byte[] response = new byte[12]; + int bytesRead = _networkStream.Read(response, 0, 12); + if (bytesRead != 12) + throw new Exception("Invalid response length"); + + // 鏍¢獙鍥炴樉鎶ユ枃 + for (int i = 0; i < 12; i++) { + if (response[i] != request[i]) + throw new Exception("Response does not match request"); + } + return true; } - public bool WriteSingleRegister(int registerAddress, ushort value) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆鍗曚釜瀵勫瓨鍣�- throw new NotImplementedException(); + public bool WriteSingleRegister(int address, ushort value) { + byte[] request = new byte[12]; + request[0] = 0x00; // 浜嬪姟ID + request[1] = 0x01; + request[2] = 0x00; // 鍗忚ID + request[3] = 0x00; + request[4] = 0x00; // 闀垮害 + request[5] = 0x06; + request[6] = unitIdentifier; + request[7] = 0x06; // 鍔熻兘鐮�+ request[8] = (byte)(address >> 8); // 鍦板潃楂樺瓧鑺�+ request[9] = (byte)address; + request[10] = (byte)(value >> 8); // 鍊奸珮瀛楄妭 + request[11] = (byte)value; // 鍊间綆瀛楄妭 + + _networkStream.Write(request, 0, request.Length); + + // 妫�煡鍥炴樉鍝嶅簲锛堝悓WriteSingleCoil锛�+ byte[] response = new byte[12]; + _networkStream.Read(response, 0, 12); + if (!response.SequenceEqual(request)) + throw new Exception("Response mismatch"); + + return true; } public bool WriteMultipleCoils(int startingAddress, bool[] values) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆澶氫釜绾垮湀 - throw new NotImplementedException(); + int quantity = values.Length; + if (quantity < 1 || quantity > 1968) + throw new ArgumentException("Quantity must be between 1 and 1968"); + + // 璁$畻闇�鐨勫瓧鑺傛暟锛堟瘡涓瓧鑺傚瓨鍌�涓嚎鍦堢姸鎬侊級 + int byteCount = (quantity + 7) / 8; + byte[] coilBytes = new byte[byteCount]; + + // 灏哹ool鏁扮粍鍘嬬缉涓哄瓧鑺傛暟缁�+ for (int i = 0; i < quantity; i++) { + if (values[i]) { + int byteIndex = i / 8; + int bitIndex = i % 8; + coilBytes[byteIndex] |= (byte)(1 << bitIndex); + } + } + + // 鏋勫缓璇锋眰鎶ユ枃锛�3 + 绾垮湀瀛楄妭鏁帮級 + byte[] request = new byte[13 + coilBytes.Length]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�+ request[2] = 0x00; // 鍗忚ID楂樺瓧鑺�+ request[3] = 0x00; // 鍗忚ID浣庡瓧鑺�+ request[4] = (byte)((7 + coilBytes.Length) >> 8); // 闀垮害楂樺瓧鑺�+ request[5] = (byte)(7 + coilBytes.Length); // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; + request[7] = 0x0F; // 鍔熻兘鐮侊紙鍐欏涓嚎鍦堬級 + request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ request[12] = (byte)byteCount; // 瀛楄妭鏁�+ Buffer.BlockCopy(coilBytes, 0, request, 13, coilBytes.Length); + + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲锛堝浐瀹�2瀛楄妭锛�+ byte[] response = new byte[12]; + int bytesRead = _networkStream.Read(response, 0, 12); + if (bytesRead != 12) + throw new Exception("Invalid response length"); + + // 鏍¢獙鍥炴樉鐨勫湴鍧�拰鏁伴噺 + if (response[8] != request[8] || response[9] != request[9] || + response[10] != request[10] || response[11] != request[11]) + throw new Exception("Response address/quantity mismatch"); + + return true; } public bool WriteMultipleRegisters(int startingAddress, int[] values) { - // 瀹炵幇TCP鏂瑰紡鍐欏叆澶氫釜瀵勫瓨鍣�- throw new NotImplementedException(); + int quantity = values.Length; + if (quantity < 1 || quantity > 123) + throw new ArgumentException("Quantity must be between 1 and 123"); + + // 灏唘short鏁扮粍杞崲涓哄瓧鑺傛暟缁勶紙澶х搴忥級 + byte[] valueBytes = new byte[quantity * 2]; + for (int i = 0; i < quantity; i++) { + valueBytes[i * 2] = (byte)(values[i] >> 8); + valueBytes[i * 2 + 1] = (byte)values[i]; + } + + // 鏋勫缓璇锋眰鎶ユ枃锛�3 + 鍊煎瓧鑺傛暟锛�+ byte[] request = new byte[13 + valueBytes.Length]; + request[0] = 0x00; // 浜嬪姟ID楂樺瓧鑺�+ request[1] = 0x01; // 浜嬪姟ID浣庡瓧鑺�+ request[2] = 0x00; // 鍗忚ID楂樺瓧鑺�+ request[3] = 0x00; // 鍗忚ID浣庡瓧鑺�+ request[4] = (byte)((7 + valueBytes.Length) >> 8); // 闀垮害楂樺瓧鑺�+ request[5] = (byte)(7 + valueBytes.Length); // 闀垮害浣庡瓧鑺�+ request[6] = unitIdentifier; + request[7] = 0x10; // 鍔熻兘鐮侊紙鍐欏涓瘎瀛樺櫒锛�+ request[8] = (byte)(startingAddress >> 8); // 璧峰鍦板潃楂樺瓧鑺�+ request[9] = (byte)startingAddress; // 璧峰鍦板潃浣庡瓧鑺�+ request[10] = (byte)(quantity >> 8); // 鏁伴噺楂樺瓧鑺�+ request[11] = (byte)quantity; // 鏁伴噺浣庡瓧鑺�+ request[12] = (byte)(quantity * 2); // 瀛楄妭鏁�+ Buffer.BlockCopy(valueBytes, 0, request, 13, valueBytes.Length); + + // 鍙戦�璇锋眰 + _networkStream.Write(request, 0, request.Length); + + // 璇诲彇鍝嶅簲锛堝浐瀹�2瀛楄妭锛�+ byte[] response = new byte[12]; + int bytesRead = _networkStream.Read(response, 0, 12); + if (bytesRead != 12) + throw new Exception("Invalid response length"); + + // 鏍¢獙鍥炴樉鐨勫湴鍧�拰鏁伴噺 + if (response[8] != request[8] || response[9] != request[9] || + response[10] != request[10] || response[11] != request[11]) + throw new Exception("Response address/quantity mismatch"); + + return true; } public void Dispose() { _networkStream?.Dispose(); - //_tcpClient?.Dispose(); + _tcpClient?.Dispose(); } } } \ No newline at end of file -- Gitblit v1.9.1