111
cjs
2025-06-13 6226621ae47b6dd28e4517ca79bf66b6fa57d95e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
 
using Hanhe.iWCS.Business;
using Hanhe.iWCS.Common;
using Hanhe.iWCS.Interface;
using Hanhe.iWCS.MData;
using Hanhe.iWCS.Model;
using Hanhe.iWCS.Model.AMS;
using Microsoft.Owin.Hosting;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static Hanhe.iWCS.TaizhouGEMTwoProtocol.EnentListen;
using static Hanhe.iWCS.TaizhouGEMTwoProtocol.MESHelper;
using static Hanhe.iWCS.TaizhouGEMTwoProtocol.PLCControl;
using static Hanhe.iWCS.TaizhouGEMTwoProtocol.ProcessHelper;
 
namespace Hanhe.iWCS.TaizhouGEMTwoProtocol
{
    /// <summary>
    /// 设备协议解析类
    /// </summary>
    public class ProtocolAnalysis : IProtocolAnalysis
    {
        private EquipmentCommandEQBLL CommandEQBLL = new EquipmentCommandEQBLL();
        private ICallTaskProcessing iCallTask = new ICallTaskProcessing();
        private Logger AMSLoggerAPI = new Logger();
 
        public void StringRequestInfo(string protocolMsg, string address, int port) {
        }
 
        public void StringRequestInfo(string protocolMsg, string address, int port, string sessionID) {
            //16进制接收
            protocolMsg = protocolMsg.Trim();//3f 00 11 20 30 40 50 60 70 80 90 A0 24 24
            if (protocolMsg != "") {
            }
            #region 握手反馈指令
            //UpdateHandshakeFeedbackCode(protocolMsg);
            PLCControl.Analysis(protocolMsg);
 
            #endregion
        }
        
        public void UpdateHandshakeFeedbackCode(string commandText) {
            var query = Query.And(Query.EQ("CommandText", commandText + "$$"), Query.EQ("Status", Constants.COMMANDEQ_STATUS_SENDED));
            EquipmentCommandEQ eq = MongoDBSingleton.Instance.FindOne<EquipmentCommandEQ>(query, typeof(EquipmentCommandEQ).Name);
            if (eq != null) {
                UpdateBuilder updateBuider = Update.Set("isHandshake", 1).Set("FeedbackCode", commandText);
                MongoDBSingleton.Instance.Update<EquipmentCommandEQ>(query, updateBuider, UpdateFlags.None);
            }
        }
 
        private static bool api = false;
        public ProtocolAnalysis() {
            if (!api) {
                Startup();
                api = true;
            }
        }
        public static void Startup() {
            Console.WriteLine("Startup ApiController");
            Task.Run(() => {
                var url = "http://+:8801";
                using (WebApp.Start<Startup>(url)) {
                    Console.WriteLine("Running on {0}", url);
                    Console.ReadLine();
                }
            });
        }
 
        public int workflowToDeviceDriver(TN_I_TASK_DTL_ACTION action) {
            int iResult = 0;
            CMMLog.Info($"任务处理:Action Code:{action.CN_N_ACTION_CODE},TaskNo:{action.CN_S_TASK_NO}");
 
            switch (action.CN_N_ACTION_CODE)
            {
                case 1012: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "起点申请进入"); break;
                case 1312: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "电梯安全对接"); break;
                case 1112: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "滚筒车起点到位"); break;
                case 1212: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "滚筒车取货完成通知PLC"); break;
                case 1013: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "终点申请进入"); break;
                case 1113: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "滚筒车终点到位"); break;
                case 1213: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "滚筒车卸货完成通知PLC"); break;
                case 1313: AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "拍照扫码"); break;
            }
 
            if (action.CN_N_ACTION_CODE == 1027) {
                var mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null ) {
                    if (ProcessHelper.Intercept(mst)) iResult = 1027;//拦截更改 WCS 任务类型(将 WMS 任务类型更改为 WCS 任务类型,因为 WCS 需要根据任务类型进行对应任务流程处理)
                    else
                    {
                        CMMLog.Info($"推送任务:任务号{mst.CN_S_TASK_NO},任务类型:{mst.CN_S_BUSS_TYPE}");
                        bool IsSendTask = true;
                        // 3楼缓存架入叠托 任务 取货完成才允许推送下一条 
                        if (mst.CN_S_BUSS_TYPE == "3楼缓存架入叠托")
                        {
                            var taskInfoList = MongoDBSingleton.Instance.Find<TN_I_TASK_MST>(Query.And(Query.NotIn("CN_S_STATUS", new List<MongoDB.Bson.BsonValue>() { "未执行", "待推送" }), Query.EQ("CN_S_END_BIT", mst.CN_S_END_BIT)), "TN_I_TASK_MST");
                            if (taskInfoList.Count > 0)
                            {
                                // 遍历查询执行中的这些任务是否都已经取货完成,如果都取货完成,则可以推送此任务
                                for (int i = 0; i < taskInfoList.Count; i++)
                                {
                                    //2024-12-18 变更 叠包任务推送现下发的任务先推,WCS需要新加一个毫秒级推送判断 
                                    if (taskInfoList[i].CN_T_CREATE < mst.CN_T_CREATE)
                                    {
                                        IsSendTask = false;
                                        break;
                                    }
 
                                    if (!ProcessHelper.CheckStartFreeTwo(taskInfoList[i].CN_S_START_BIT))
                                    {
                                        IsSendTask = false;
                                        Console.WriteLine($"3楼缓存架入叠托 任务拦截:该任务 :{taskInfoList[i].CN_S_TASK_NO} 未取货完成,不允许推送当前任务:{mst.CN_S_TASK_NO}");
                                        break;
                                    }
                                }
                            }
                        }
                        mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                        if (IsSendTask) ProcessHelper.SendTask(mst);
                    }
                }
                iResult = 1027;
            }
 
            #region 取消
            if (action.CN_N_ACTION_CODE == 7) {
                TN_I_TASK_MST mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                string agvNo = action.CN_S_DEVICE_CODE;
                if (mst != null) {
                    //请求前
                    if (action.CN_N_ORDER == 0)
                    {
                        WorkFlowAction.TrackLog(action.CN_S_TASK_NO, 0, 7, "收到ams取消请求");
                    }
 
                    if (action.CN_N_ORDER == 1 || action.CN_N_ORDER == 0) {
                        ProcessHelper.TaskCancel(mst);
                        iCallTask.CancelTask(mst.CN_S_TASK_NO, "1");
                        AMSHelper.SetStatus(action.CN_S_TASK_NO, 1, "7", "0", true);
                        if (mst.CN_S_BUSS_TYPE != "电梯取货" && mst.CN_S_BUSS_TYPE != "电梯卸货" && mst.CN_S_BUSS_TYPE != "3楼包装取料") 
                            WMSHelper.ExecuteState(mst.CN_S_SOURCE_NO, action.CN_N_ACTION_CODE);
                        iCallTask.DeleteTask(mst.CN_S_TASK_NO);
                    }
                    if (mst.CN_S_BUSS_TYPE == "电梯取货" || mst.CN_S_BUSS_TYPE == "电梯卸货" || mst.CN_S_BUSS_TYPE == "满托转运" || mst.CN_S_BUSS_TYPE == "空托出库")
                    {
                        ProcessHelper.ForceCancel(mst, action);
                        MongoDBSingleton.Instance.Remove<TimeCuoInfoCom>(Query.EQ("timeStamp", mst.CN_S_BATCH_NO), "TimeCuoInfoCom", RemoveFlags.None);
                    }
                    if (mst.CN_S_BUSS_TYPE == "3楼包装补空") PLCControl.PickUpBlankComplete(mst.CN_S_END_BIT);
                }
            }
 
            #endregion
 
            #region 强制完成
            if (action.CN_N_ACTION_CODE == 1022) {
                TN_I_TASK_MST mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null) {
                    ProcessHelper.ForceComplete(mst, action);
                    if (mst.CN_S_BUSS_TYPE == "3楼缓存架入叠托")
                    {
                        var plc = Settings.GetPlcInfo().Where(a => a.deviceType == "3").FirstOrDefault();
                        if (plc != null)
                        {
                            var machine = MongoDBSingleton.Instance.FindOne<WMSInfo>(Query.EQ("trayCode", mst.CN_S_BATCH_NO), "WMSInfo");
                            if (machine != null)
                            {
                                #region   写多个MODBUS数据
                                if (Settings.cacheStackWrite == "0")
                                {
                                    int[] num = DiePan(machine);
 
                                    CMMLog.Info($"send num:" + JsonConvert.SerializeObject(num));
                                    var wirteall01 = OITcpHelper.RegisterWriteOutPutMulti(new OITcpHelper.RegisterWriteOutPutModelMulti
                                    {
                                        addr = plc.writeAddr + 10,
                                        host = plc.ip,
                                        port = plc.port,
                                        data = num
                                    });
                                }
                                else WriteCacheStackingData(plc, mst, machine);
                                #endregion
                                MongoDBSingleton.Instance.Remove<WMSInfo>(Query.EQ("trayCode", mst.CN_S_BATCH_NO), "WMSInfo", RemoveFlags.Single);
                            }
                        }
                    }
                    MongoDBSingleton.Instance.Remove<Mongo_AGV_TASK_STATE>(Query.EQ("TaskNo", mst.CN_S_TASK_NO), RemoveFlags.Single);
                    WorkFlowAction.TrackLog(mst.CN_S_TASK_NO, 1, 1022, "收到ams强制完成请求");
                    AMSHelper.SetStatus(action.CN_S_TASK_NO, 1, "1022", "0", true);
                    iCallTask.CancelTask(mst.CN_S_TASK_NO, "1");
                    if (mst.CN_S_BUSS_TYPE != "电梯取货" && mst.CN_S_BUSS_TYPE != "电梯卸货" && mst.CN_S_BUSS_TYPE != "3楼包装取料") 
                        WMSHelper.ExecuteState(mst.CN_S_SOURCE_NO, action.CN_N_ACTION_CODE);
                    //if (mst.CN_S_BUSS_TYPE == "电梯取货" && mst.CN_S_BUSS_TYPE == "电梯卸货") 
                    //    MongoDBSingleton.Instance.ReomveAll<TimeCuoInfoCom>();
                    if (mst.CN_S_BUSS_TYPE == "包装线补空") PLCControl.PickUpBlankCompleteTetracobalt(mst.CN_S_END_BIT);
                    if (mst.CN_S_BUSS_TYPE == "3楼包装补空") PLCControl.PickUpBlankComplete(mst.CN_S_END_BIT);
 
                    if (ERPService.SendERPTaskType.Contains(mst.CN_S_BUSS_TYPE) && ERPService.ERPSwitch01 == "1") ERPService.SendERPTaskInfo(mst);
 
                    iCallTask.DeleteTask(mst.CN_S_TASK_NO);
                }
            }
            #endregion
 
            if (action.CN_N_ACTION_CODE == 13) {
                var task = iCallTask.FindTask(action.CN_S_TASK_NO);
                AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), "", "AGV调整任务优先级成功" + action.Ext1);
            }
 
            #region 任务状态委托(1-开始;3-开始取货;4-取货完成;5-开始卸货;6-卸货完成;2-完成)
            if (action.CN_N_ACTION_CODE == 1 || action.CN_N_ACTION_CODE == 3 || action.CN_N_ACTION_CODE == 2 || action.CN_N_ACTION_CODE == 4 || action.CN_N_ACTION_CODE == 5 || action.CN_N_ACTION_CODE == 6) {
                WorkFlowAction.TrackLog(action.CN_S_TASK_NO, 1, action.CN_N_ACTION_CODE, "");
                TN_I_TASK_MST mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null) {
                    if (!string.IsNullOrEmpty(action.CN_S_DEVICE_CODE))
                    {
                        // 因调用AMSAPI无法在开始取货时更新车号,因此此处直接连接AMS数据库进行更新
                        MoboxHelper.UpdateEndBit(mst.CN_S_TASK_NO, action.CN_S_DEVICE_CODE);
                        if (action.CN_N_ACTION_CODE != 1) MoboxHelper.UpdateTaskState(mst.CN_S_TASK_NO, action.CN_N_ACTION_CODE);
                    }
                    if (action.CN_N_ACTION_CODE == 1)
                    {
                        AMSHelper.SetStatus(action.CN_S_TASK_NO, 1, "1", action.CN_S_DEVICE_CODE, true);
                        if (mst.CN_S_BUSS_TYPE != "电梯取货" && mst.CN_S_BUSS_TYPE != "电梯卸货" && mst.CN_S_BUSS_TYPE != "3楼包装取料") 
                            WMSHelper.ExecuteState(mst.CN_S_SOURCE_NO, action.CN_N_ACTION_CODE);
                    }
                    if (action.CN_N_ACTION_CODE == 4)
                    {
                        AMSHelper.SetStatus(action.CN_S_TASK_NO, 1, "4", action.CN_S_DEVICE_CODE, true);
                        if (mst.CN_S_BUSS_TYPE == "3楼包装补空") PLCControl.PickUpBlankComplete(mst.CN_S_END_BIT);
                        if (mst.CN_S_BUSS_TYPE.Contains("3楼包装取料")) PLCControl.CheckUpReqUnload(mst.CN_S_END_BIT, mst.CN_S_TASK_NO);
                        if (mst.CN_S_BUSS_TYPE == "3楼缓存架入叠托") WMSHelper.ExecuteState(mst.CN_S_SOURCE_NO, action.CN_N_ACTION_CODE);
                        if (mst.CN_S_BUSS_TYPE == "3楼缓存架入叠托") PLCControl.writeStackingMouth6(mst.CN_S_END_BIT, mst.CN_S_TASK_NO);
                        if (mst.CN_S_BUSS_TYPE == "包装线补空") PLCControl.PickUpBlankCompleteTetracobalt(mst.CN_S_END_BIT, mst.CN_S_START_BIT);
 
                        //四钴车间根据起点改变货位托盘类型绑定关系
                        var trayInfo = MongoDBSingleton.Instance.FindOne<trayTypeTable>(Query.EQ("locCode", mst.CN_S_START_BIT), "trayTypeTable");
                        if(trayInfo != null)
                        {
                            MongoDBSingleton.Instance.Update<trayTypeTable>(Query.EQ("locCode", mst.CN_S_START_BIT), Update.Set("locCode", mst.CN_S_END_BIT), UpdateFlags.None);
                        }
                    }
                    if (action.CN_N_ACTION_CODE == 6)
                    {
                        AMSHelper.SetStatus(action.CN_S_TASK_NO, 1, "6", action.CN_S_DEVICE_CODE, true);
                        if (mst.CN_S_BUSS_TYPE == "3楼包装补空")
                        {
                            //将数据记录到中间表
                            var agvloc = Settings.GetDDSiteList().Where(a => a.ddLoc == mst.CN_S_END_BIT).First();
                            if (agvloc != null)
                            {
                                var quantity = agvloc.quantity;
                                CMMLog.Info($"3楼包装补空,终点{mst.CN_S_END_BIT}站点个数:{quantity}");
                                var emptyInfo = MongoDBSingleton.Instance.FindOne<BZEmptyPoint>(Query.EQ("Bit", mst.CN_S_END_BIT), "BZEmptyPoint");
                                if (emptyInfo != null)
                                {
                                    MongoDBSingleton.Instance.Update<BZEmptyPoint>(Query.EQ("Bit", mst.CN_S_END_BIT), Update.Set("Quantity", quantity), UpdateFlags.None);
                                }
                                else
                                {
                                    MongoDBSingleton.Instance.Insert(new BZEmptyPoint { Bit = mst.CN_S_END_BIT, Quantity = quantity });
                                }
                            }
                        }
                        if (mst.CN_S_BUSS_TYPE == "四钴成品出库" || mst.CN_S_BUSS_TYPE == "四钴辅材出库")
                        {
                            //3楼成品出库收到6之后,终点货位数量减1,(注:6信号会发多次)
                            var slptInfo = MongoDBSingleton.Instance.FindOne<SLPTLoc>(Query.And(Query.EQ("locCode", mst.CN_S_END_BIT), Query.EQ("count", 0)), "SLPTLoc");
                            if (slptInfo != null)
                            {
                                MongoDBSingleton.Instance.Update<SLPTLoc>(Query.EQ("locCode", mst.CN_S_END_BIT), Update.Set("taskNum", slptInfo.taskNum - 1).Set("count", slptInfo.count + 1), UpdateFlags.None);
                            }
 
                            //四钴成品出库卸货完成,删除货位托盘类型绑定表数据
                            MongoDBSingleton.Instance.Remove<trayTypeTable>(Query.EQ("locCode", mst.CN_S_END_BIT), "trayTypeTable", RemoveFlags.None);
                        }
                    }
                    if (action.CN_N_ACTION_CODE == 2) {
                        AMSHelper.SetStatus(action.CN_S_TASK_NO, 1, "2", action.CN_S_DEVICE_CODE, true);
                        CMMLog.Info($"完成任务处理:收到2信号之后特殊任务类型处理:任务号:{mst.CN_S_TASK_NO},任务类型:{mst.CN_S_BUSS_TYPE}");
                        if (mst.CN_S_BUSS_TYPE == "电梯取货")
                        {
                            var ele = MongoDBSingleton.Instance.FindOne<ElevatorTask>(Query.EQ("taskNo", mst.CN_S_SOURCE_NO), "ElevatorTask");
                            if (ele != null)
                            {
                                AMSHelper.SetStatus(ele.wmsTaskNo, 1, "2", action.CN_S_DEVICE_CODE, true);
                                WMSHelper.ExecuteState(ele.wmsSourceNo, action.CN_N_ACTION_CODE);
                                MongoDBSingleton.Instance.Remove<ElevatorTask>(Query.EQ("taskNo", mst.CN_S_SOURCE_NO), RemoveFlags.Single);
                            }
                        }
                        if (mst.CN_S_BUSS_TYPE != "电梯取货" && mst.CN_S_BUSS_TYPE != "电梯卸货" && mst.CN_S_BUSS_TYPE != "3楼包装取料") 
                            WMSHelper.ExecuteState(mst.CN_S_SOURCE_NO, action.CN_N_ACTION_CODE);
                        //if (mst.CN_S_BUSS_TYPE == "3楼包装补空") PLCControl.PickUpBlankComplete(mst.CN_S_END_BIT);
                        if (mst.CN_S_BUSS_TYPE == "四钴成品出库" || mst.CN_S_BUSS_TYPE == "四钴辅材出库")
                        {
                            //3楼成品出库收到2信号之后 将中间表count数量清除
                            var slptInfo = MongoDBSingleton.Instance.FindOne<SLPTLoc>(Query.EQ("locCode", mst.CN_S_END_BIT), "SLPTLoc");
                            if (slptInfo != null)
                            {
                                MongoDBSingleton.Instance.Update<SLPTLoc>(Query.EQ("locCode", mst.CN_S_END_BIT), Update.Set("count", 0), UpdateFlags.None);
                            }
                        }
 
                        if (ERPService.SendERPTaskType.Contains(mst.CN_S_BUSS_TYPE) && ERPService.ERPSwitch01 == "1") ERPService.SendERPTaskInfo(mst);
 
                        iCallTask.DeleteTask(mst.CN_S_TASK_NO);
                    }
                }
            }
            #endregion
 
            #region 小车状态写入通道 (1-开始;2-完成 4-取货完成 6-卸货完成)
            if (action.CN_N_ACTION_CODE == 1 || action.CN_N_ACTION_CODE == 2 || action.CN_N_ACTION_CODE == 4 || action.CN_N_ACTION_CODE == 6)
            {
                WorkFlowAction.TrackLog(action.CN_S_TASK_NO, 1, action.CN_N_ACTION_CODE, "");
                TN_I_TASK_MST mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                CMMLog.Info($"小车状态写入通道处理开始");
                if (mst != null)
                {
                    CMMLog.Info($"车号:{mst.CN_S_ForkliftNo}");
                    var stateInfo = Settings.GetAGVStateList().Where(a => a.AgvNo == mst.CN_S_ForkliftNo && a.enable == 1).FirstOrDefault();
                    if (stateInfo != null)
                    {
                        if (action.CN_N_ACTION_CODE == 1)
                        {
                            //开始,往通道写入1
                            var writeRes = OITcpHelper.RegisterWriteOutPut(new OITcpHelper.RegisterWriteOutPutModel
                            {
                                host = stateInfo.ip,
                                port = stateInfo.port,
                                addr = stateInfo.writeAddr + 5,
                                data = 1
                            });
                            CMMLog.Info($"在通道{stateInfo.writeAddr + 5}中写入1,ip:{stateInfo.ip},端口:{stateInfo.port}");
                        }
                        if (action.CN_N_ACTION_CODE == 2)
                        {
                            //完成,往通道写入0
                            var writeRes = OITcpHelper.RegisterWriteOutPut(new OITcpHelper.RegisterWriteOutPutModel
                            {
                                host = stateInfo.ip,
                                port = stateInfo.port,
                                addr = stateInfo.writeAddr + 5,
                                data = 0
                            });
                            CMMLog.Info($"在通道{stateInfo.writeAddr + 5}中写入0,ip:{stateInfo.ip},端口:{stateInfo.port}");
                        }
                        if (action.CN_N_ACTION_CODE == 4)
                        {
                            //取货完成,往通道写入1
                            var writeRes = OITcpHelper.RegisterWriteOutPut(new OITcpHelper.RegisterWriteOutPutModel
                            {
                                host = stateInfo.ip,
                                port = stateInfo.port,
                                addr = stateInfo.writeAddr + 6,
                                data = 1
                            });
                            CMMLog.Info($"在通道{stateInfo.writeAddr + 6}中写入1,ip:{stateInfo.ip},端口:{stateInfo.port}");
                        }
                        if (action.CN_N_ACTION_CODE == 6)
                        {
                            //卸货完成,往通道写入0
                            var writeRes = OITcpHelper.RegisterWriteOutPut(new OITcpHelper.RegisterWriteOutPutModel
                            {
                                host = stateInfo.ip,
                                port = stateInfo.port,
                                addr = stateInfo.writeAddr + 6,
                                data = 0
                            });
                            CMMLog.Info($"在通道{stateInfo.writeAddr + 6}中写入1,ip:{stateInfo.ip},端口:{stateInfo.port}");
                        }
                    }
                    else CMMLog.Info($"小车{mst.CN_S_ForkliftNo}信号未配置");
                }
 
            }
            #endregion
 
            #region   3楼设备任务
 
            //起点安全对接      1012:安全请求进入     4:安全请求退出
            if (action.CN_N_ACTION_CODE == 1012 || action.CN_N_ACTION_CODE == 4 || action.CN_N_ACTION_CODE == 1312)
            {
                CMMLog.Info($"起点安全对接:收到信号:{action.CN_N_ACTION_CODE},任务号:{action.CN_S_TASK_NO},开始根据任务号查询主表中对应数据!");
                var mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null)
                {
                    CMMLog.Info($"起点安全对接:收到任务号:{mst.CN_S_TASK_NO},任务类型:{mst.CN_S_BUSS_TYPE},任务信号:{action.CN_N_ACTION_CODE}");
                    //3楼拆盘补空:拆盘机补空托盘            3楼包装补空:包装机补空托
                    if (mst.CN_S_BUSS_TYPE.Contains("3楼包装取料") || mst.CN_S_BUSS_TYPE == "3楼复称入缓存架" || mst.CN_S_BUSS_TYPE == "3楼复称入缓存架NG" || mst.CN_S_BUSS_TYPE == "3楼缓存架入叠托" || mst.CN_S_BUSS_TYPE == "3楼叠盘下线" || mst.CN_S_BUSS_TYPE == "3楼打包下线" || mst.CN_S_BUSS_TYPE == "四钴辅材入库")
                    {
                        CMMLog.Info($"起点安全对接:即将进入任务流程:{mst.CN_S_BUSS_TYPE},状态号为:{action.CN_N_ACTION_CODE}");
                        ProcessHelper.StartPickUpDoorSafe(mst, action.CN_N_ACTION_CODE);
                    }
                    else if (mst.CN_S_BUSS_TYPE == "电梯卸货" || mst.CN_S_BUSS_TYPE == "电梯取货" || mst.CN_S_BUSS_TYPE == "满托转运") 
                    {
                        if(mst.CN_S_BUSS_TYPE == "电梯取货" && action.CN_N_ACTION_CODE != 1012)
                        {
                            ProcessHelper.OperateDoor(mst, action.CN_N_ACTION_CODE == 1312 ? 1012 : 4);
                        }
                    }
                }
            }
 
            //滚筒车起点到位信号、取货完成信号    1112        1212     3、4          只对滚筒车对接
            if (action.CN_N_ACTION_CODE == 1112 || action.CN_N_ACTION_CODE == 1212)
            {
                var mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null)
                {
                    if (mst.CN_S_BUSS_TYPE.Contains("3楼包装取料"))
                    {
                        ProcessHelper.PickupAndUnload(mst, action.CN_N_ACTION_CODE);
                    }
                }
            }
 
            if (action.CN_N_ACTION_CODE == 8)
            {
                var mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null)
                {
                    var plc = Settings.GetPlcInfo().Where(a => a.location == mst.CN_S_START_BIT).FirstOrDefault();
 
                    if (mst.CN_S_BUSS_TYPE == "3楼缓存架入叠托")
                    {
                        CMMLog.Debug($"3楼缓存架入叠托NG:TaskNo:{action.CN_S_TASK_NO},叠包NG写入值4。");
                        PLCControl.CacheStackingMouth8(plc);
                    }
                }
            }
 
            //终点安全对接      1013:安全请求进入     6:安全请求退出
            if (action.CN_N_ACTION_CODE == 1013 || action.CN_N_ACTION_CODE == 6 || action.CN_N_ACTION_CODE == 1312)
            {
                CMMLog.Info($"终点安全对接:收到信号:{action.CN_N_ACTION_CODE},任务号:{action.CN_S_TASK_NO},开始根据任务号查询主表中对应数据!");
                TN_I_TASK_MST mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null)
                {
                    CMMLog.Info($"终点安全对接:收到任务号:{mst.CN_S_TASK_NO},任务类型:{mst.CN_S_BUSS_TYPE},任务信号:{action.CN_N_ACTION_CODE}");
                    //3楼拆盘补空:拆盘机补空托盘            3楼包装补空:包装机补空托
                    if (mst.CN_S_BUSS_TYPE.Contains("3楼包装取料") || mst.CN_S_BUSS_TYPE == "3楼复称入缓存架" || mst.CN_S_BUSS_TYPE == "3楼缓存架入叠托" || mst.CN_S_BUSS_TYPE == "3楼拆盘补空" || mst.CN_S_BUSS_TYPE == "电梯取货" || mst.CN_S_BUSS_TYPE == "包装线补空" || mst.CN_S_BUSS_TYPE == "四钴成品出库" || mst.CN_S_BUSS_TYPE == "四钴辅材出库")
                    {
                        ProcessHelper.EndPickUpDoorSafe(mst, action.CN_N_ACTION_CODE);
                    }
                    if (mst.CN_S_BUSS_TYPE == "电梯取货" || mst.CN_S_BUSS_TYPE == "电梯卸货" || mst.CN_S_BUSS_TYPE == "满托转运")
                    {
                        //二段电梯任务终点交互
                        if (mst.CN_S_BUSS_TYPE == "电梯取货" && action.CN_N_ACTION_CODE != 1312)
                        {
                            //电梯取货任务 终点不需要进行安全交互
                        }
                        else if (mst.CN_S_BUSS_TYPE == "电梯卸货")
                        {
                            //小车到达等待点之后发送信号,判断哪部电梯可以使用,然后创建电梯生成任务
                            //异常情况需要打印:1.两部电梯都不可以使用,2.两部电梯都可以使用,默认使用第一台电梯设备
                            CMMLog.Info($"终点安全对接:电梯卸货:收到信号{action.CN_N_ACTION_CODE}");
                            if (action.CN_N_ACTION_CODE == 1312 || action.CN_N_ACTION_CODE == 6)
                            {
                                var taskBit = MongoDBSingleton.Instance.FindOne<ElevatorTask>(Query.EQ("taskNo", mst.CN_S_SOURCE_NO), "ElevatorTask");
                                CMMLog.Info($"终点安全对接:电梯卸货:taskno:{mst.CN_S_TASK_NO},occupy:{taskBit.occupy}");
                                if (taskBit.occupy == "")
                                {
                                    string eleBit = PLCControl.ElevatorTaskBit(taskBit.startFloor);
                                    CMMLog.Info("终点安全对接:电梯卸货:获取电梯点位elebit" + eleBit);
                                    if (eleBit == "0")
                                    {
                                        CMMLog.Info("终点安全对接:电梯卸货:当前无电梯可以使用!");
                                        Console.WriteLine("终点安全对接:电梯卸货:当前无电梯可以使用!");
                                    }
                                    else
                                    {
                                        //改终点为开启的电梯
                                        //TSHelper.GoToAGV(mst.CN_S_TASK_NO, 1, StockInstance.Instance.GetAGVCodeForBitCode(eleBit));
                                    
                                        //TSHelper.GoToAGV(mst.CN_S_TASK_NO, 2, StockInstance.Instance.GetAGVCodeForBitCode(eleBit));
                                        //AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "修改终点");
                                        var taskInfo = MongoDBSingleton.Instance.FindOne<ElevatorTask>(Query.EQ("taskNo", mst.CN_S_SOURCE_NO), "ElevatorTask");
                                        //赋值 二段电梯点位
                                        MongoDBSingleton.Instance.Update<TN_I_TASK_MST>(Query.EQ("_id", mst._id), Update.Set("Ext3",eleBit), UpdateFlags.None);
                                        string endBit02 = PLCControl.ElevatorTaskBit02(eleBit);
                                        MongoDBSingleton.Instance.Update<ElevatorTask>(Query.EQ("taskNo", taskInfo.taskNo), Update.Set("taskNo", taskInfo.wmsTaskNo + "_1").Set("endBit02", endBit02).Set("occupy", eleBit).Set("endBit",eleBit), UpdateFlags.None);
                                        CMMLog.Info("终点安全对接:电梯卸货:elebit:" + eleBit);
                                        //写入当前楼层--呼叫电梯
                                        PLCControl.ElevatorTaskFloor(taskInfo.startFloor, eleBit);
                                    }
                                }
                                else
                                {
                                    CMMLog.Info("终点安全对接:电梯卸货:电梯occupy占用字段不为空,进入电梯开门关门服务!");
                                    ProcessHelper.OperateDoor(mst, action.CN_N_ACTION_CODE);
                                }
                            }
                        }
                    }
                }
            }
 
            //滚筒车终点到位信号、卸货完成信号     1113        1213        5、6      只对滚筒车对接
            if (action.CN_N_ACTION_CODE == 1113 || action.CN_N_ACTION_CODE == 1213)
            {
                var mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                if (mst != null)
                {
                    //3楼拆盘补空:拆盘机补空托盘            3楼包装补空:包装机补空托
                    if (mst.CN_S_BUSS_TYPE.Contains("3楼包装取料")) ProcessHelper.DiscRemoverEmptySupport(mst, action.CN_N_ACTION_CODE);
                }
            }
 
            //缓存架入叠托,小车扫码
            if(action.CN_N_ACTION_CODE == 1313)
            {
                TN_I_TASK_MST mst = iCallTask.FindTask(action.CN_S_TASK_NO);
                var plc = Settings.GetPlcInfo().Where(a => a.location == mst.CN_S_END_BIT).FirstOrDefault();
                if(plc != null)
                {
                    PLCControl.CacheStackingMouth1313(plc.deviceType, mst.CN_S_TASK_NO);
                    //AMSHelper.TaskTrackLogMessage(action.CN_S_TASK_NO, action.CN_N_ORDER.ToString(), action.CN_N_ACTION_CODE.ToString(), "小车扫码");
                }
            }
 
 
            #region 电动门A门交管信号(1023-开门 1025-关门)  B门交管信号(1013-开门 6--关门)
            if (action.CN_N_ACTION_CODE == 1023)
            {
                CMMLog.Info($"收到信号{action.CN_N_ACTION_CODE},门号:{action.Ext2}");
                //电动门开门
                var doorInfo = Settings.GetPlcInfo().Where(a => a.Extend == action.Ext2 && a.enable == 1).FirstOrDefault();
                if (doorInfo != null)
                {
                    //电动门开门步骤:
                    //1、在通道【40101】中写入1,发送开门信号
                    //2、读取通道【40001】中的值,如果为1,表示开门到位,通知小车进去
                    var writeRes = OITcpHelper.RegisterWriteOutPut(new OITcpHelper.RegisterWriteOutPutModel
                    {
                        host = doorInfo.ip,
                        port = doorInfo.port,
                        addr = doorInfo.writeAddr,
                        data = 1
                    });
                    CMMLog.Info($"发送开门信号,在通道{doorInfo.writeAddr}中写入1,ip:{doorInfo.ip},端口:{doorInfo.port}");
 
                    var result = OITcpHelper.RegisterReadOutPut(new OITcpHelper.RegisterReadOutPutModel
                    {
                        dataNum = 1,
                        addr = doorInfo.readAddr,
                        host = doorInfo.ip,
                        port = doorInfo.port
                    });
 
                    if (result != null && result.errCode == 0)
                    {
                        CMMLog.Info($"电动门开门流程:读取电动门通道号为:{doorInfo.readAddr}里面的值为{result.result[0]}");
                        //Console.WriteLine($"电动门开门流程:读取电动门通道号为:{doorInfo.readAddr}里面的值为{result.result[0]},{doorInfo.readAddr + 1}里面的值为{result.result[1]}");
                        if (result.result[0] == 2)
                        {
                            //推送小车进去
                            CMMLog.Info($"电动门已经打开,门号:{action.Ext2}");
 
                            writeRes = OITcpHelper.RegisterWriteOutPut(new OITcpHelper.RegisterWriteOutPutModel
                            {
                                host = doorInfo.ip,
                                port = doorInfo.port,
                                addr = doorInfo.writeAddr,
                                data = 2
                            });
                            CMMLog.Info($"在通道{doorInfo.writeAddr}中写入2,ip:{doorInfo.ip},端口:{doorInfo.port}");
 
                            TSHelper.Traffic(action.Ext2);
                        }
                    }
                    else CMMLog.Info($"电动门开门流程:未读取到包装机通道{doorInfo.readAddr}里面的数据!!!result:{JsonConvert.SerializeObject(result)}");
                }
                else CMMLog.Info($"门号为【{action.Ext2}】的门未在配置文件配置或者未启用");
            }
            else if (action.CN_N_ACTION_CODE == 1025)
            {
                //电动门关门
                var doorInfo = Settings.GetPlcInfo().Where(a => a.Extend == action.Ext2 && a.enable == 1).FirstOrDefault();
                if (doorInfo != null)
                {
                    //电动门关门步骤
                    //1、小车通过电动门后,在通道【40101】中写入2
                    var writeRes = OITcpHelper.RegisterWriteOutPut(new OITcpHelper.RegisterWriteOutPutModel
                    {
                        host = doorInfo.ip,
                        port = doorInfo.port,
                        addr = doorInfo.writeAddr,
                        data = 3
                    });
                    CMMLog.Info($"电动门关门流程,在通道{doorInfo.writeAddr}中写入2,ip:{doorInfo.ip},端口:{doorInfo.port}");
                }
                else CMMLog.Info($"门号为【{action.Ext2}】的门未在配置文件配置或者未启用");
            }
            #endregion
 
            #endregion
 
            return iResult;
        }
 
        #region AGV车体状态信息
        public void HangChaAGVEvent(HangChaAGV _hangChaAGV) {
        }
        public void HangChaAGVEvent(List<HangChaAGV> agvs) {
 
        }
 
        #endregion
 
        /// <summary>
        /// 周转托盘位
        /// </summary>
        public class BZEmptyPoint
        {
            public ObjectId _id { get; set; }
            /// <summary>
            /// 空托缓存点
            /// </summary>
            public string Bit { get; set; }
            /// <summary>
            /// 托盘数量
            /// </summary>
            public int Quantity { get; set; }
        }
 
    }
}