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