using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HslCommunication.ModBus;
using HslCommunication;
using HslCommunication.BasicFramework;
using System.Net;
using System.Threading;
using System.Collections;
using System.Timers;
using HslCommunication.Controls;
using parkMonitor.entity;
using parkMonitor.model;
using System.Diagnostics;
using System.Configuration;
using parkMonitor.server.uiLogServer;

namespace parkMonitor.server
{
    /*
     * PLC通信类
     * 
     * 初始化：
     * PLCLinker plc = new PLCLinker();
     * plc.Start();
     * 
     * 读PLC：
     * PLCMessage ps = plc.getMessage();
     * 
     * 写PLC
     * PLCNode pn = new PLCNode("addr","value");
     * plc.setMessage(pn);
     * plc.setMessage(ps);
     * 
     * 结束
     * plc.Stop();
     * 
     * */
    public class PLCLinker : IEquipments
    {
        private Boolean isConnection = false;
        private bool isRecorded = false, exceptionBreak = false, isClosing = false;
        private static string json = "";//读到的数据
        private string json2 = "";//写入的数据
        private PLCMessage plcMsg = new PLCMessage();
        System.Timers.Timer timer;
        //parameteres for plc read function
        private int startAddr = 0;
        private int addrLength = 110;
        /// <summary> plc重连标记位 </summary>
        private int linkCount = 0;
        //plc 基本配置
        private const short PLC_TIME_SCALE = 100;
        private const short LASER_TIME_SCALE = 5000;
        private string ipString;
        private int port;
        private byte station;
        //addresses for machine arm controlling
        private int fetching_startRobot_address;
        private int parking_startRobot_address;
        //addresses for laser data to be written to plc
        private int parkingSpaceID_address;
        //addresses for space info to be written to plc
        private int parkingLaserCenterX_address;
        //parameters(addresses) for Laser monitoring
        private int laser_start_address;
        private int fetch_completed_address;
        private int fetch_completed_acknowledge_address;
        private int fetch_to_address;
        private int frontWheelbase_address;
        private int rearWheelbase_address;
        private int park_completed_address;
        private int park_completed_acknowledge_address;
        private int LASER_RESCAN_COUNT;
        private int LASER_HEARTBEAT_PERIOD;
        private int PLC_refresh_interval;
        /// <summary>
        /// 激光管理list
        /// </summary>
        private List<LaserProcessUnit> laserMgmtList = new List<LaserProcessUnit>();
        private RobotProcessUnit rpu1;
        private List<string> decompressIndex;

        private int cx, cy, aa;

        public PLCLinker()
        {
            try
            {
                LASER_RESCAN_COUNT = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_rescan_count"));
                LASER_HEARTBEAT_PERIOD = Int32.Parse(ConfigurationManager.AppSettings.Get("laser_countdown"));
                PLC_refresh_interval = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_refresh_interval"));

                parking_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parking_startRobot_address"));
                parkingLaserCenterX_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingLaserCenterX_address"));
                parkingSpaceID_address = Int32.Parse(ConfigurationManager.AppSettings.Get("parkingSpaceID_address"));
                park_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_address"));
                park_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_completed_acknowledge_address"));

                fetching_startRobot_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetching_startRobot_address"));
                fetch_to_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_to_address"));
                fetch_completed_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_address"));
                fetch_completed_acknowledge_address = Int32.Parse(ConfigurationManager.AppSettings.Get("fetch_completed_acknowledge_address"));
                frontWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("frontWheelbase_address"));
                rearWheelbase_address = Int32.Parse(ConfigurationManager.AppSettings.Get("rearWheelbase_address"));

                laser_start_address = Int32.Parse(ConfigurationManager.AppSettings.Get("park_command_address"));

                rpu1 = new RobotProcessUnit(1, parking_startRobot_address, parkingLaserCenterX_address, parkingSpaceID_address, park_completed_address, park_completed_acknowledge_address, fetching_startRobot_address, fetch_to_address, fetch_completed_address, fetch_completed_acknowledge_address, frontWheelbase_address, rearWheelbase_address);

                //激光管理
                for (int i = 1; i < 20; i++)
                {
                    try
                    {
                        string laser = ConfigurationManager.AppSettings.Get("laser" + i + "_status_address");
                        int laser_status_address = Int32.Parse(laser);
                        LaserProcessUnit lpu = new LaserProcessUnit(i, laser_start_address, laser_status_address, LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD);
                        laserMgmtList.Add(lpu);
                        plcMsg.laserMsgList.Add(lpu.laserMsg);
                    }
                    catch (Exception) { }
                }

                //定义plc被压缩的地址段
                decompressIndex = new List<string>();
                //25-27
                for (int i = 0; i < 3; i++)
                {
                    decompressIndex.Add((25 + i).ToString());
                }
                //48-53
                for (int i = 0; i < 6; i++)
                {
                    decompressIndex.Add((48 + i).ToString());
                }
                //70-76
                for (int i = 0; i < 7; i++)
                {
                    decompressIndex.Add((70 + i).ToString());
                }

                //临时
                cx = Int32.Parse(ConfigurationManager.AppSettings.Get("cx"));
                cy = Int32.Parse(ConfigurationManager.AppSettings.Get("cy"));
                aa = Int32.Parse(ConfigurationManager.AppSettings.Get("aa"));
            }
            catch (Exception)
            {
                Console.WriteLine("PLC相关配置文件异常");
            }
        }

        //**************************************** PLC读写相关方法 **************************************
        private ModBusTcpClient busTcpClient
        {
            get;
            set;
        }

        private void WriteMessage(string message)
        {
            isRecorded = true;
            //json2 = "[{\"Adress\":\"1\",\"Value\":\"0043\"},{\"Adress\":\"2\",\"Value\":\"0043\"}]";
            json2 = message;
        }

        ///<summary>采集数据显示转json</summary>
        private static void DisplayString_ToJson(string str)
        {
            List<PLCNode> return_Value = new List<PLCNode>();
            if (!string.IsNullOrEmpty(str))
            {
                ArrayList array = GetSeparateSubString(str, 4);
                int Read_Address = 0;//0地址
                return_Value.Clear();
                foreach (string arr in array)
                {
                    PLCNode rv = new PLCNode();
                    //Console.WriteLine("地址:" + Read_Address + ": " + arr);
                    rv.Address = Read_Address.ToString();
                    rv.Value = Int32.Parse(arr, System.Globalization.NumberStyles.HexNumber).ToString();//plc数据16进制？
                    return_Value.Add(rv);
                    Read_Address++;
                }
            }
            json = JsonHelper.SerializeObject(return_Value);//序列化     
            //List<PLCValue> prv = JsonHelper.DeserializeJsonToList<PLCValue>(json);

            //Console.WriteLine(json);
        }

        ///<summary>截取</summary>
        private static ArrayList GetSeparateSubString(string txtString, int charNumber)
        {
            ArrayList arrList = new ArrayList();
            string tempStr = txtString;
            for (int i = 0; i < tempStr.Length; i += charNumber)
            {
                if ((tempStr.Length - i) > charNumber)
                {
                    arrList.Add(tempStr.Substring(i, charNumber));
                }
                else
                {
                    arrList.Add(tempStr.Substring(i));
                }
            }
            return arrList;
        }

        private void InitTimer()
        {
            try
            {
                timer = new System.Timers.Timer(PLC_refresh_interval);
            }
            catch (Exception)
            {
                timer = new System.Timers.Timer(PLC_TIME_SCALE);
            }

            timer.AutoReset = true;
            timer.Enabled = true;
            timer.Elapsed += new ElapsedEventHandler(TimerUp);
        }

        ///<summary>实时采集</summary>
        private void TimerUp(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                if (isConnection)
                {
                    //从哪个地址开始,读取长度
                    PLC_Read((ushort)startAddr, (ushort)addrLength);
                    //LaserMonitor();
                }
                else
                {
                    if (linkCount-- >= 0)
                    {
                        Task.Factory.StartNew(() =>
                        {
                            while (true)
                            {
                                Console.WriteLine("尝试重连plc");
                                UILogServer.ins.log("尝试重连plc");
                                LinkStart();
                                Thread.Sleep(10000);
                                if (isConnection)
                                {
                                    linkCount = 0;
                                    break;
                                }
                            }
                        });
                        linkCount = -1;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        ///<summary>读取</summary>
        private void PLC_Read(ushort address, ushort length)
        {
            try
            {
                OperateResult<byte[]> read = busTcpClient.ReadRegister(address, length);
                if (read.IsSuccess)
                {
                    string returned_value = SoftBasic.ByteToHexString(read.Content);
                    DisplayString_ToJson(returned_value);
                }
                else
                {
                    if (!exceptionBreak)
                    {
                        AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                        Console.WriteLine("读取失败");
                        isConnection = false;
                        exceptionBreak = true;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        ///<summary>写入</summary>
        private void WriteJson(string json)
        {
            try
            {
                if (!string.IsNullOrEmpty(json))
                {
                    List<PLCNode> PLC_Value = JsonHelper.DeserializeJsonToList<PLCNode>(json);
                    foreach (var item in PLC_Value)
                    {
                        //WriteResultRender(busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value)), item.Address);
                        busTcpClient.WriteRegister(ushort.Parse(item.Address), ushort.Parse(item.Value));
                        Thread.Sleep(20);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        ///<summary>写入判断</summary>
        private static void WriteResultRender(OperateResult result, string address)
        {
            if (result.IsSuccess)
            {
                Console.WriteLine("写入成功");
            }
            else
            {
                Console.WriteLine("写入失败");
            }
        }

        ///<summary>地址-值写入plc</summary>
        private void SendtoPLC(string addr, string value)
        {
            PLCNode wrv = new PLCNode();
            wrv.Address = addr;
            wrv.Value = value;
            json2 = "[" + JsonHelper.SerializeObject(wrv) + "]";
            WriteMessage(json2);
            if (isConnection && isRecorded)
            {
                WriteJson(json2);
                isRecorded = false;
            }
        }

        /// <summary>启动与plc的连接</summary>
        private void LinkStart()
        {
            if (busTcpClient != null)
            {
                busTcpClient.ConnectClose();
            }
            busTcpClient = new ModBusTcpClient(ipString, port, station);
            try
            {
                OperateResult connect = busTcpClient.ConnectServer();
                if (connect.IsSuccess)
                {
                    AsyncCmdServer.ins.send(AsyncCmdType.PLCOnline);
                    Console.WriteLine("连接成功");
                    UILogServer.ins.log("PLC连接成功");
                    isConnection = true;
                    linkCount = 0;
                }
                else
                {
                    AsyncCmdServer.ins.send(AsyncCmdType.PLCOffline);
                    Console.WriteLine("连接失败，重试");
                    UILogServer.ins.error("PLC连接失败，重试");
                    isConnection = false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            InitTimer();//启动计时器
        }

        /// <summary>将plc地址块完全解压</summary>
        private List<PLCNode> ListDecompression(List<PLCNode> plcList, List<string> decompressIndex)
        {
            List<string> temp = new List<string>();
            List<PLCNode> decomPlcList = new List<PLCNode>();
            if (plcList != null && addrLength > 100)
            {
                try
                {
                    for (int i = 0; i < plcList.Count; i++)
                    {
                        if (!decompressIndex.Contains(plcList[i].Address))
                        {
                            temp.Add(plcList[i].Value);
                        }
                        //定位三个被压缩区域
                        else
                        {
                            //默认LSB优先
                            int value = Int32.Parse(plcList[i].Value);
                            int count = 16;
                            while (count-- > 0)
                            {
                                temp.Add((value & 0x01).ToString());
                                value = value >> 1;
                            }
                        }
                    }
                }
                catch (Exception) { }
            }
            for (int i = 0; i < temp.Count; i++)
            {
                decomPlcList.Add(new PLCNode(i.ToString(), temp[i]));
            }
            return decomPlcList;
        }
        //************************************ 雷达相关方法 **************************************
        /*
         * 激光监听PARK_STATUS, 0等待，1启动，其余异常
         * PARK_STATUS 控制：
         * 核心线程调用SetMessage将其置1，plc线程检测到PARK_COMPLETED则复位到0，(核心将plc“PARK_COMPLETED”复位)，其余异常情况由监控或核心线程置2或其他值
         * 
         * 读到LASER_STATUS（扫摆激光状态），监控线程显示该状态，一旦为状态5，处理完成后置0
         * 
         * */
        private void LaserMonitor()
        {
            try
            {
                if (plcMsg.originalPlcList != null)
                {
                    foreach (LaserProcessUnit lds in laserMgmtList)
                    {
                        foreach (PLCNode p in plcMsg.originalPlcList)
                        {
                            int addr = Int32.Parse(p.Address);
                            int value = Int32.Parse(p.Value);
                            lds.LaserStatusChecking(addr, value);
                        }
                        lds.LaserRecord(plcMsg.originalPlcList);
                    }
                }
                else
                {
                    AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                    return;
                }
                Thread.Sleep(200);
            }
            catch (Exception)
            {
                AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                return;
            }
        }
        private void WaitForLaserReady(LaserProcessUnit lpuTemp)
        {
            bool jumpOut = false;
            while (!jumpOut)
            {
                Thread.Sleep(1000);
                if (plcMsg != null && plcMsg.originalPlcList.Count > lpuTemp.laser_status_address)
                {
                    foreach (PLCNode node in plcMsg.originalPlcList)
                    {
                        //判断激光空闲状态
                        if (node.Address.Equals(lpuTemp.laser_status_address.ToString()) && (node.Value.Equals("254") || node.Value.Equals("255")) && !lpuTemp.occupied)
                        {
                            lpuTemp.occupied = true;
                            jumpOut = true;
                            break;
                        }
                    }
                }
            }
        }
        //***************公有方法****************
        public AbstractMessage GetMessage()
        {
            try
            {
                plcMsg.originalPlcList = JsonHelper.DeserializeJsonToList<PLCNode>(json);
                if (decompressIndex != null && decompressIndex.Count != 0)
                {
                    plcMsg.extendedPlcList = ListDecompression(plcMsg.originalPlcList, decompressIndex);
                }
                return (PLCMessage)plcMsg.Clone();
            }
            catch (Exception)
            {
                AsyncCmdServer.ins.send(AsyncCmdType.PLCReadException);
                return new PLCMessage();
            }
        }

        public void SetMessage(AbstractMessage message)
        {
            if (message.GetType().Equals(typeof(PLCMessage)))
            {
                PLCMessage ps = (PLCMessage)message;
                for (int i = 0; i < ps.originalPlcList.Count; i++)
                {
                    SendtoPLC(ps.originalPlcList[i].Address, ps.originalPlcList[i].Value);
                }
            }
            else if (message.GetType().Equals(typeof(PLCNode)))
            {
                PLCNode pv = (PLCNode)message;
                SendtoPLC(pv.Address, pv.Value);
            }
            else if (message.GetType().Equals(typeof(ControlMessage)))
            {
                ControlMessage pm = (ControlMessage)message;
                if (pm != null && pm.status != 0)
                {
                    switch (pm.status)
                    {
                        //停车startLaser--park_command_address
                        case 1:
                            //start laser scanning for parking
                            LaserProcessUnit lpuTemp = null;
                            Task.Factory.StartNew(() =>
                            {
                                string laser_start_addr = "";
                                foreach (LaserProcessUnit lpu in laserMgmtList)
                                {
                                    if (pm.laserID == lpu.id)
                                    {
                                        lpuTemp = lpu;
                                        laser_start_addr = lpu.laser_start_address.ToString();
                                        break;
                                    }
                                }
                                if (laser_start_addr == "")
                                    return;
                                lock (lpuTemp)
                                {
                                    WaitForLaserReady(lpuTemp);
                                    SendtoPLC(laser_start_addr, "0");

                                    foreach (LaserMessage lm in plcMsg.laserMsgList)
                                    {
                                        if (lm.id == lpuTemp.id)
                                        {
                                            lm.status = 6;
                                            break;
                                        }
                                    }
                                    Thread.Sleep(300);
                                    SendtoPLC(laser_start_addr, "1");
                                    Thread.Sleep(100);
                                    SendtoPLC("1", "1");//停车指令置1
                                }
                            });
                            //Console.WriteLine("扫摆激光启动");
                            break;
                        //停车激光的6个数据,停车机械手,车位信息4个
                        case 2:
                            if (pm.RobotID == 1)
                            {

                                //停车启动机械手
                                SendtoPLC(rpu1.parking_startRobot_address.ToString(), "1");
                                //自动或手动输入激光雷达数据
                                if (cx == 0 && cy == 0 && aa == 0)
                                {
                                    SendtoPLC(rpu1.parking_laserCenterX_address.ToString(), pm.centerX);
                                    SendtoPLC((rpu1.parking_laserCenterX_address + 1).ToString(), pm.centerY);
                                    SendtoPLC((rpu1.parking_laserCenterX_address + 2).ToString(), pm.angleA);
                                }
                                else
                                {
                                    SendtoPLC(rpu1.parking_laserCenterX_address.ToString(), cx.ToString());
                                    SendtoPLC((rpu1.parking_laserCenterX_address + 1).ToString(), cy.ToString());
                                    SendtoPLC((rpu1.parking_laserCenterX_address + 2).ToString(), aa.ToString());
                                }
                                //车位信息
                                SendtoPLC(rpu1.parkingSpaceID_address.ToString(), pm.parkingSpaceID);
                                SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), pm.parkingSpaceX);
                                SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), pm.parkingSpaceY);
                                SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), pm.parkingSpaceZ);
                            }
                            break;
                        //停车完成归零--park_completed_address
                        case 3:
                            if (pm.RobotID == 1)
                            {
                                //SendtoPLC(rpu1.park_completed_address.ToString(), "0");//停车完成复位
                                SendtoPLC(rpu1.park_completed_acknowledge_address.ToString(), "0");
                                SendtoPLC("1", "0");//停车指令置0
                                //Console.WriteLine("停车完成");
                            }
                            break;
                        //取车机械手,车位信息4个
                        case 4:
                            if (pm.RobotID == 1 && pm.fetchPosition != 0)
                            {
                                //前后轮轮距
                                SendtoPLC(rpu1.frontWheelbase.ToString(), pm.frontWheelbase.ToString());
                                SendtoPLC(rpu1.rearWheelbase.ToString(), pm.rearWheelbase.ToString());
                                //取至区域
                                //SendtoPLC(rpu1.fetch_to_address.ToString(), pm.fetchPosition.ToString());
                                SendtoPLC(rpu1.fetch_to_address.ToString(), pm.parkingSpaceX);
                                //车位信息
                                SendtoPLC(rpu1.parkingSpaceID_address.ToString(), pm.parkingSpaceID);
                                SendtoPLC((rpu1.parkingSpaceID_address + 1).ToString(), pm.parkingSpaceX);
                                SendtoPLC((rpu1.parkingSpaceID_address + 2).ToString(), pm.parkingSpaceY);
                                SendtoPLC((rpu1.parkingSpaceID_address + 3).ToString(), pm.parkingSpaceZ);
                                //Console.WriteLine("取车中，开始抓车");
                                SendtoPLC(rpu1.fetching_startRobot_address.ToString(), "1");
                            }
                            break;
                        case 5:
                            if (pm.RobotID == 1)
                            {
                                //取车完成复位
                                SendtoPLC(rpu1.fetch_completed_acknowledge_address.ToString(), "0");
                                SendtoPLC(rpu1.fetch_to_address.ToString(), "0");
                            }
                            break;
                        default: Console.WriteLine("输入plc数据异常"); break;
                    }
                }
            }
            else
            {
                AsyncCmdServer.ins.send(AsyncCmdType.PLCWriteException);
                Debug.WriteLine("输入字符串有误");
            }
        }

        /// <summary>
        /// 开启激光线程与模拟plc自动重置子线程
        /// </summary>
        public void Start()
        {
            Task.Factory.StartNew(() =>
            {
                while (!isClosing)
                {
                    LaserMonitor();
                }
            });

            //Task.Factory.StartNew(() =>
            //{
            //    while (!isClosing)
            //    {
            //        //模拟plc自动重置
            //        foreach (PLCNode p in listForLaser)
            //        {
            //            int addr = Int32.Parse(p.Address);
            //            int value = Int32.Parse(p.Value);
            //            if (addr == parking_startRobot_address && value == 1)
            //            {
            //                Thread.Sleep(8000);
            //                SendtoPLC(addr.ToString(), "0");
            //                Thread.Sleep(1000);
            //                SendtoPLC(park_completed_addr.ToString(), "1");
            //            }
            //            if (addr == fetching_startRobot_address && value == 1)
            //            {
            //                Thread.Sleep(8000);
            //                SendtoPLC(addr.ToString(), "0");
            //                Thread.Sleep(1000);
            //                SendtoPLC(fetch_completed_address.ToString(), "1");
            //            }
            //        }
            //    }
            //});

            exceptionBreak = false; linkCount = 0;
            foreach (LaserMessage lm in plcMsg.laserMsgList)
            {
                lm.status = 6;
            }
            try
            {
                ipString = ConfigurationManager.AppSettings.Get("PLC_ip_address");
                port = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_port"));
                station = (byte)Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_station"));
                startAddr = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_start_address"));
                addrLength = Int32.Parse(ConfigurationManager.AppSettings.Get("PLC_address_length"));
            }
            catch (Exception) { UILogServer.ins.error("PLC配置文件异常"); }
            LinkStart();
        }

        public void Stop()
        {
            exceptionBreak = false; isClosing = true;
            busTcpClient.ConnectClose();//stop释放资源
            //throw new NotImplementedException();
        }
    }

    /// <summary>
    /// 激光数据记录与处理类
    /// </summary>
    class LaserProcessUnit
    {
        public int laser_start_address { get; set; }
        public int laser_status_address { get; set; }
        public int id { get; set; }
        public bool occupied { get; set; }
        private int LASER_RESCAN_COUNT, LASER_HEARTBEAT_PERIOD, laser_rescan_countdown, laser_heartbeat_countdown;
        private bool laser_record, laser_heartbeat_test, enable_status_check = true, disconnected = false;
        private HashSet<int> laser_heartbeat = new HashSet<int>();
        private IEquipments plc = null;
        public LaserMessage laserMsg = new LaserMessage();

        public LaserProcessUnit(int id, int park_command_address, int laser_status_address, int laser_rescan_count, int laser_heartbeat_period)
        {
            try
            {
                laserMsg.id = id;
                this.id = id;
                laserMsg.status = 6;
                occupied = false;
                this.laser_start_address = park_command_address;
                this.laser_status_address = laser_status_address;
                LASER_RESCAN_COUNT = laser_rescan_count;
                LASER_HEARTBEAT_PERIOD = laser_heartbeat_period;
                laser_rescan_countdown = LASER_RESCAN_COUNT;
                laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
                plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
            }
            catch (Exception)
            {
                UILogServer.ins.error("激光设备配置文件错误");
            }
        }

        ///<summary>激光状态监测</summary>
        public void LaserStatusChecking(int addr, int value)
        {
            if (enable_status_check)
            {
                int status_addr = laser_status_address;
                if (addr == status_addr)
                {
                    if (!disconnected)
                    {
                        laserMsg.status = value;
                        //UILogServer.ins.log(value.ToString());
                    }
                    //after status 0, start to check laser heartbeat
                    if (value == 0)
                    {
                        laserMsg.abort_rescan = false;//就绪状态设置允许重测
                        laser_heartbeat_test = true;
                    }

                    //after status 3 or 4, start to check laser heartbeat
                    if (value == 3 && !laserMsg.recorded)
                    {
                        if (plc == null)
                        {
                            plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
                        }
                        if (plc != null)
                        {
                            //停车指令置0
                            PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
                            plc.SetMessage(pn);
                            Thread.Sleep(2000);
                            laser_record = true;
                            laser_rescan_countdown = LASER_RESCAN_COUNT;
                            laser_heartbeat_test = true;
                        }
                    }

                    else if (value == 4)
                    {
                        laser_record = false;
                        //启动重测指令
                        if (laser_rescan_countdown > 0)
                        {
                            enable_status_check = false;
                            Task t = Task.Factory.StartNew(() =>
                            {
                                Thread.Sleep(500);
                                if (plc == null)
                                {
                                    plc = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
                                }
                                if (plc != null)
                                {
                                    lock (laserMsg)
                                    {
                                        laser_rescan_countdown--;
                                        //停车指令置0
                                        PLCNode pn = new PLCNode(laser_start_address.ToString(), "0");
                                        plc.SetMessage(pn);
                                        //未终止重测，车未开走，停车指令归零后置1
                                        if (!laserMsg.abort_rescan)
                                        {
                                            UILogServer.ins.error("激光" + laserMsg.id + "计算异常，重新测量");
                                            //重测检测心跳
                                            Task rescan_wait_heartbeat = Task.Factory.StartNew(() =>
                                            {
                                                while (laserMsg.status != 254 && laserMsg.status != 255)
                                                {
                                                    Thread.Sleep(1000);
                                                }
                                            });
                                            rescan_wait_heartbeat.Wait();
                                            pn = new PLCNode(laser_start_address.ToString(), "1");
                                            plc.SetMessage(pn);
                                            laserMsg.status = value;
                                        }
                                        else
                                        {
                                            laserMsg.status = 6;
                                        }
                                    }
                                    Thread.Sleep(500);
                                }
                                enable_status_check = true;
                            });
                        }
                        else if (laser_rescan_countdown == 0)
                        {
                            //激光1异常
                            laser_rescan_countdown = -1;
                            laser_heartbeat_test = true;
                            UILogServer.ins.error("激光" + laserMsg.id + "计算异常超过重测次数，请检查");
                        }
                    }

                    //status 5, system error
                    if (value == 5)
                    {
                        lock (laserMsg)
                        {
                            laser_heartbeat_test = false;
                            //AsyncCmdServer.ins.send(AsyncCmdType.LaserSystemException);
                            Console.WriteLine("激光" + laserMsg.id + "系统状态异常");
                            //UILogServer.ins.error("激光系统异常");
                        }
                    }

                    //find the heartbeat of laser
                    if (laser_heartbeat_test && laser_heartbeat_countdown-- > 0 && value != 3 && value != 4)
                    {
                        if (value == 254 || value == 255)
                            laser_heartbeat.Add(value);
                        if (laser_heartbeat.Contains(254) && laser_heartbeat.Contains(255))
                        {
                            disconnected = false;
                            laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
                            laser_heartbeat_test = false;
                            Console.WriteLine("激光" + laserMsg.id + "已检测到心跳");
                            laser_heartbeat.Clear();
                        }
                        //fail to check laser heartbeat
                        if (laser_heartbeat_countdown <= 0)
                        {
                            laser_heartbeat_countdown = LASER_HEARTBEAT_PERIOD;
                            lock (laserMsg)
                            {
                                disconnected = true;
                                laserMsg.status = -1;
                            }
                            Console.WriteLine("激光" + laserMsg.id + "心跳检测失败");
                        }
                    }
                }
            }
            else { return; }
        }

        /// <summary>激光数据记录</summary>
        public void LaserRecord(List<PLCNode> plist)
        {
            lock (laserMsg)
            {
                //激光未掉线，记录数据写入plc
                if (laserMsg.status != -1)
                {
                    if (laser_record)
                    {
                        laser_record = false;
                        foreach (PLCNode p in plist)
                        {
                            int addr = Int32.Parse(p.Address);
                            int value = Int32.Parse(p.Value);
                            if (addr == laser_status_address + 1)
                                laserMsg.data.centerX = value;
                            else if (addr == laser_status_address + 2)
                                laserMsg.data.centerY = value;
                            else if (addr == laser_status_address + 3)
                                laserMsg.data.angleA = value;
                            else if (addr == laser_status_address + 4)
                                laserMsg.data.length = value;
                            else if (addr == laser_status_address + 5)
                                laserMsg.data.width = value;
                            else if (addr == laser_status_address + 6)
                                laserMsg.data.height = value;
                        }
                        laserMsg.recorded = true;
                        occupied = false;
                        //Console.WriteLine("激光测量数据已记录");
                    }
                }
                else
                {
                    //laser.status = -1;
                    Console.WriteLine("与编号为：" + laserMsg.id + "的激光连接中断");
                }
            }
        }
    }

    /// <summary>
    /// 机械手逻辑处理类
    /// </summary>
    class RobotProcessUnit
    {
        public int id { get; set; }
        public int parking_startRobot_address { get; set; }
        public int parking_laserCenterX_address { get; set; }
        public int parkingSpaceID_address { get; set; }
        public int park_completed_address { get; set; }
        public int park_completed_acknowledge_address { get; set; }
        public int fetching_startRobot_address { get; set; }
        public int fetch_completed_address { get; set; }
        public int fetch_completed_acknowledge_address { get; set; }
        public int fetch_to_address { get; set; }
        public int frontWheelbase { get; set; }
        public int rearWheelbase { get; set; }

        public RobotProcessUnit(int id, int parking_startRobot_address, int parking_laserCenterX_address, int parkingSpaceID_address, int park_completed_address, int park_completed_acknowledge_address, int fetching_startRobot_address, int fetch_to_address, int fetch_completed_address, int fetch_completed_acknowledge_address, int frontWheelbase, int rearWheelbase)
        {
            this.id = id;
            this.parking_startRobot_address = parking_startRobot_address;
            this.parking_laserCenterX_address = parking_laserCenterX_address;
            this.parkingSpaceID_address = parkingSpaceID_address;
            this.park_completed_address = park_completed_address;
            this.park_completed_acknowledge_address = park_completed_acknowledge_address;
            this.fetching_startRobot_address = fetching_startRobot_address;
            this.fetch_completed_address = fetch_completed_address;
            this.fetch_completed_acknowledge_address = fetch_completed_acknowledge_address;
            this.fetch_to_address = fetch_to_address;
            this.frontWheelbase = frontWheelbase;
            this.rearWheelbase = rearWheelbase;
        }
    }
}
