瀏覽代碼

车位管理监控模块,可显示、修改车位状态,鼠标悬停显示详细信息

yct 4 年之前
父節點
當前提交
d074ba9476

+ 2 - 0
parkspace_manager/Form1.Designer.cs

@@ -42,6 +42,7 @@
             this.button1.Text = "开始";
             this.button1.UseVisualStyleBackColor = true;
             this.button1.Click += new System.EventHandler(this.button1_Click);
+            this.button1.MouseHover += new System.EventHandler(this.button1_MouseHover);
             // 
             // button2
             // 
@@ -73,6 +74,7 @@
             this.Controls.Add(this.button1);
             this.Name = "Form1";
             this.Text = "Form1";
+            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
             this.ResumeLayout(false);
 
         }

+ 33 - 8
parkspace_manager/Form1.cs

@@ -12,29 +12,54 @@ namespace parkspace_manager
 {
     public partial class Form1 : Form
     {
-        Communicator com;
+        //Communicator com;
+        FormParkSpaceStatus formParkSpaceStatus = null;
         public Form1()
         {
             InitializeComponent();
-            com = Communicator.Instance;
+            formParkSpaceStatus = new FormParkSpaceStatus();
+            //com = Communicator.Instance;
         }
 
         private void button1_Click(object sender, EventArgs e)
         {
-            com.Init();
-            com.Bind("tcp://192.168.2.144:20000");
-            com.Connect("tcp://192.168.2.125:20000");
+            //com.Init();
+            //com.Bind("tcp://192.168.2.144:20000");
+            //com.Connect("tcp://192.168.2.125:20000");
         }
 
         private void button2_Click(object sender, EventArgs e)
         {
-            com.Uninit();
+            //com.Uninit();
         }
 
         private void button3_Click(object sender, EventArgs e)
         {
-            FormParkSpaceStatus formParkSpaceStatus = new FormParkSpaceStatus();
-            formParkSpaceStatus.Show();
+            if (formParkSpaceStatus != null)
+            {
+                formParkSpaceStatus.Show();
+            }
+        }
+
+        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
+        {
+            formParkSpaceStatus.Uninit();
+        }
+
+        private void button1_MouseHover(object sender, EventArgs e)
+        {
+            Button btn = (Button)sender;
+            // 创建the ToolTip 
+            ToolTip toolTip1 = new ToolTip();
+
+            // 设置显示样式
+            toolTip1.AutoPopDelay = 5000;//提示信息的可见时间
+            toolTip1.InitialDelay = 500;//事件触发多久后出现提示
+            toolTip1.ReshowDelay = 500;//指针从一个控件移向另一个控件时,经过多久才会显示下一个提示框
+            toolTip1.ShowAlways = true;//是否显示提示框
+
+            //  设置伴随的对象.
+            toolTip1.SetToolTip(btn, "开始?");//设置提示按钮和提示内容
         }
     }
 }

+ 96 - 3
parkspace_manager/FormParkSpaceStatus.Designer.cs

@@ -29,24 +29,110 @@
         private void InitializeComponent()
         {
             this.ParkingSpaceMonitorPanel = new System.Windows.Forms.Panel();
+            this.parkspaceStatusSamplePanel = new System.Windows.Forms.Panel();
+            this.btn_unknown = new System.Windows.Forms.Button();
+            this.btn_error = new System.Windows.Forms.Button();
+            this.btn_locked = new System.Windows.Forms.Button();
+            this.btn_reserved = new System.Windows.Forms.Button();
+            this.btn_occupied = new System.Windows.Forms.Button();
+            this.btn_empty = new System.Windows.Forms.Button();
+            this.parkspaceStatusSamplePanel.SuspendLayout();
             this.SuspendLayout();
             // 
             // ParkingSpaceMonitorPanel
             // 
-            this.ParkingSpaceMonitorPanel.Location = new System.Drawing.Point(34, 12);
+            this.ParkingSpaceMonitorPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.ParkingSpaceMonitorPanel.Location = new System.Drawing.Point(0, 79);
             this.ParkingSpaceMonitorPanel.Name = "ParkingSpaceMonitorPanel";
-            this.ParkingSpaceMonitorPanel.Size = new System.Drawing.Size(1414, 782);
+            this.ParkingSpaceMonitorPanel.Size = new System.Drawing.Size(1574, 727);
             this.ParkingSpaceMonitorPanel.TabIndex = 0;
             // 
+            // parkspaceStatusSamplePanel
+            // 
+            this.parkspaceStatusSamplePanel.Controls.Add(this.btn_unknown);
+            this.parkspaceStatusSamplePanel.Controls.Add(this.btn_error);
+            this.parkspaceStatusSamplePanel.Controls.Add(this.btn_locked);
+            this.parkspaceStatusSamplePanel.Controls.Add(this.btn_reserved);
+            this.parkspaceStatusSamplePanel.Controls.Add(this.btn_occupied);
+            this.parkspaceStatusSamplePanel.Controls.Add(this.btn_empty);
+            this.parkspaceStatusSamplePanel.Dock = System.Windows.Forms.DockStyle.Top;
+            this.parkspaceStatusSamplePanel.Location = new System.Drawing.Point(0, 0);
+            this.parkspaceStatusSamplePanel.Name = "parkspaceStatusSamplePanel";
+            this.parkspaceStatusSamplePanel.Size = new System.Drawing.Size(1574, 73);
+            this.parkspaceStatusSamplePanel.TabIndex = 1;
+            // 
+            // btn_unknown
+            // 
+            this.btn_unknown.BackColor = System.Drawing.Color.Violet;
+            this.btn_unknown.Location = new System.Drawing.Point(864, 22);
+            this.btn_unknown.Name = "btn_unknown";
+            this.btn_unknown.Size = new System.Drawing.Size(133, 33);
+            this.btn_unknown.TabIndex = 5;
+            this.btn_unknown.Text = "未知";
+            this.btn_unknown.UseVisualStyleBackColor = false;
+            // 
+            // btn_error
+            // 
+            this.btn_error.BackColor = System.Drawing.Color.Red;
+            this.btn_error.Location = new System.Drawing.Point(700, 22);
+            this.btn_error.Name = "btn_error";
+            this.btn_error.Size = new System.Drawing.Size(133, 33);
+            this.btn_error.TabIndex = 4;
+            this.btn_error.Text = "故障";
+            this.btn_error.UseVisualStyleBackColor = false;
+            // 
+            // btn_locked
+            // 
+            this.btn_locked.BackColor = System.Drawing.Color.LightGreen;
+            this.btn_locked.Location = new System.Drawing.Point(528, 22);
+            this.btn_locked.Name = "btn_locked";
+            this.btn_locked.Size = new System.Drawing.Size(133, 33);
+            this.btn_locked.TabIndex = 3;
+            this.btn_locked.Text = "已锁定";
+            this.btn_locked.UseVisualStyleBackColor = false;
+            // 
+            // btn_reserved
+            // 
+            this.btn_reserved.BackColor = System.Drawing.Color.SkyBlue;
+            this.btn_reserved.Location = new System.Drawing.Point(356, 22);
+            this.btn_reserved.Name = "btn_reserved";
+            this.btn_reserved.Size = new System.Drawing.Size(133, 33);
+            this.btn_reserved.TabIndex = 2;
+            this.btn_reserved.Text = "已预约";
+            this.btn_reserved.UseVisualStyleBackColor = false;
+            // 
+            // btn_occupied
+            // 
+            this.btn_occupied.BackColor = System.Drawing.Color.Yellow;
+            this.btn_occupied.Location = new System.Drawing.Point(183, 22);
+            this.btn_occupied.Name = "btn_occupied";
+            this.btn_occupied.Size = new System.Drawing.Size(133, 33);
+            this.btn_occupied.TabIndex = 1;
+            this.btn_occupied.Text = "占用";
+            this.btn_occupied.UseVisualStyleBackColor = false;
+            // 
+            // btn_empty
+            // 
+            this.btn_empty.BackColor = System.Drawing.Color.White;
+            this.btn_empty.Location = new System.Drawing.Point(12, 22);
+            this.btn_empty.Name = "btn_empty";
+            this.btn_empty.Size = new System.Drawing.Size(133, 33);
+            this.btn_empty.TabIndex = 0;
+            this.btn_empty.Text = "空闲";
+            this.btn_empty.UseVisualStyleBackColor = false;
+            // 
             // FormParkSpaceStatus
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(1484, 806);
+            this.ClientSize = new System.Drawing.Size(1574, 806);
+            this.Controls.Add(this.parkspaceStatusSamplePanel);
             this.Controls.Add(this.ParkingSpaceMonitorPanel);
             this.Name = "FormParkSpaceStatus";
             this.Text = "FormParkSpaceStatus";
+            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormParkSpaceStatus_FormClosing);
             this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormParkSpaceStatus_FormClosed);
+            this.parkspaceStatusSamplePanel.ResumeLayout(false);
             this.ResumeLayout(false);
 
         }
@@ -54,5 +140,12 @@
         #endregion
 
         private System.Windows.Forms.Panel ParkingSpaceMonitorPanel;
+        private System.Windows.Forms.Panel parkspaceStatusSamplePanel;
+        private System.Windows.Forms.Button btn_empty;
+        private System.Windows.Forms.Button btn_occupied;
+        private System.Windows.Forms.Button btn_reserved;
+        private System.Windows.Forms.Button btn_locked;
+        private System.Windows.Forms.Button btn_error;
+        private System.Windows.Forms.Button btn_unknown;
     }
 }

+ 328 - 65
parkspace_manager/FormParkSpaceStatus.cs

@@ -1,4 +1,5 @@
-using Message;
+using Google.Protobuf;
+using Message;
 using parkMonitor.LOG;
 using System;
 using System.Collections.Generic;
@@ -15,26 +16,89 @@ namespace parkspace_manager
 {
     public partial class FormParkSpaceStatus : Form
     {
-        public static int spacesInRow = 15;
-        public static int floors = 11;
-        public static int rows = 1;
-        public bool isClosing;
-        private Dictionary<int, Parkspace_info> idPssMap;
+        public static int s_spacesInRow = 15;
+        public static int s_floors = 11;
+        public static int s_rows = 1;
+        public static bool s_isClosing;
+        private static object s_map_update_lock;
+        private static object s_parkspace_force_update_queue_lock;
+        private static object s_parkspace_status_lock;
+        /// <summary>
+        /// 车位id与车位信息映射
+        /// </summary>
+        private Dictionary<int, Parkspace_info> m_idPssMap;
+        /// <summary>
+        /// 提示信息管理器
+        /// </summary>
+        private ToolTip m_toolTip_parkspace_info;
+        ///// <summary>
+        ///// 按钮与对应提示信息映射
+        ///// </summary>
+        //private Dictionary<Button, ToolTip> m_btnToolTipMap;
+        /// <summary>
+        /// 强制更新反馈消息队列,用于处理同时收到多个反馈消息的情况
+        /// </summary>
+        private Queue<Parkspace_force_update_response_msg> m_parkspace_force_update_response_queue;
+        /// <summary>
+        /// 当前所有车位状态,由界面更新线程主动更新
+        /// </summary>
+        Parkspace_allocation_status_msg m_parkspace_status;
+        Thread m_update_display_thread;
+
         public FormParkSpaceStatus()
         {
-            isClosing = false;
+            m_parkspace_status = new Parkspace_allocation_status_msg();
+            s_map_update_lock = new object();
+            s_parkspace_force_update_queue_lock = new object();
+            s_parkspace_status_lock = new object();
+            m_parkspace_force_update_response_queue = new Queue<Parkspace_force_update_response_msg>();
+            m_idPssMap = new Dictionary<int, Parkspace_info>();
+
+            m_toolTip_parkspace_info = new ToolTip();
+            // 设置显示样式
+            m_toolTip_parkspace_info.AutoPopDelay = 20000;//提示信息的可见时间
+            m_toolTip_parkspace_info.InitialDelay = 500;//事件触发多久后出现提示
+            m_toolTip_parkspace_info.ReshowDelay = 500;//指针从一个控件移向另一个控件时,经过多久才会显示下一个提示框
+            m_toolTip_parkspace_info.ShowAlways = false;//是否显示提示框
+
+            //m_btnToolTipMap = new Dictionary<Button, ToolTip>();
+            s_isClosing = false;
 
             InitializeComponent();
 
             Communicator.Instance.Init();
             Communicator.Instance.Bind("tcp://192.168.2.144:20000");
             Communicator.Instance.Connect("tcp://192.168.2.125:20000");
+            Communicator.Instance.SetParkspaceForceUpdateResponseDelegate(ParkspaceForceUpdateResponseCallback);
 
             // 库位显示
-            Task.Factory.StartNew(() =>
+            m_update_display_thread = new Thread(new ThreadStart(UpdateParkingSpaceView));
+            m_update_display_thread.Start();
+        }
+
+        public void Uninit()
+        {
+            s_isClosing = true;
+            Communicator.Instance.Uninit();
+            //if(m_update_display_thread!=null)
+            //{
+            //    m_update_display_thread.Join();
+            //}
+        }
+
+        /// <summary>
+        /// 接收到强制更新车位反馈消息回调
+        /// </summary>
+        /// <param name="response"></param>
+        void ParkspaceForceUpdateResponseCallback(Parkspace_force_update_response_msg response)
+        {
+            lock (s_parkspace_force_update_queue_lock)
             {
-                UpdateParkingSpaceView();
-            });
+                if (m_parkspace_force_update_response_queue != null)
+                {
+                    m_parkspace_force_update_response_queue.Enqueue(response);
+                }
+            }
         }
 
         /// <summary>
@@ -42,76 +106,100 @@ namespace parkspace_manager
         /// </summary>
         private void UpdateParkingSpaceView()
         {
-            bool needUpdate = false;
-            Parkspace_allocation_status_msg parkspace_status = new Parkspace_allocation_status_msg();
-            while (!isClosing)
+            while (!s_isClosing)
             {
-                bool get_status_result = Communicator.Instance.Get_parkspace_status(ref parkspace_status);
-                if (!get_status_result || parkspace_status.ParkspaceInfo == null)
+                bool needUpdate = false;
+                List<Parkspace_info> psList = null;
+                Thread.Sleep(1000);
+                bool get_status_result = Communicator.Instance.Get_parkspace_status(ref m_parkspace_status);
+                lock (s_parkspace_status_lock)
+                {
+                    if (get_status_result && (m_parkspace_status == null || m_parkspace_status.ParkspaceInfo == null))
+                    {
+                        get_status_result = false;
+                    }
+                }
+                if (!get_status_result)
+                {
+                    lock (s_map_update_lock)
+                    {
+                        m_idPssMap.Clear();
+                    }
                     continue;
-                List<Parkspace_info> psList = parkspace_status.ParkspaceInfo.ToList();
+                }
+                else
+                {
+                    lock (s_parkspace_status_lock)
+                    {
+                        psList = m_parkspace_status.ParkspaceInfo.ToList();
+                    }
+                }
                 if (psList == null || psList.Count <= 0)
                 {
-                    Thread.Sleep(10000);
+                    Thread.Sleep(1000);
                     continue;
                 }
                 //更新映射表
                 try
                 {
-                    if (idPssMap.Count != psList.Count)
+                    lock (s_map_update_lock)
                     {
-                        idPssMap.Clear();
-                        for (int i = 0; i < psList.Count; i++)
+                        if (m_idPssMap.Count != psList.Count)
                         {
-                            idPssMap.Add(psList[i].ParkspaceId, psList[i]);
+                            m_idPssMap.Clear();
+                            for (int i = 0; i < psList.Count; i++)
+                            {
+                                m_idPssMap.Add(psList[i].ParkspaceId, psList[i]);
+                            }
                         }
-                    }
-                    else
-                    {
-                        for (int i = 0; i < psList.Count; i++)
+                        else
                         {
-                            idPssMap[psList[i].ParkspaceId] = psList[i];
+                            for (int i = 0; i < psList.Count; i++)
+                            {
+                                m_idPssMap[psList[i].ParkspaceId] = psList[i];
+                            }
                         }
                     }
                 }
-                catch { Log.WriteLog(LogType.process, LogFile.WARNING, "实时更新所有库位异常"); }
-
-                TableLayoutPanel tlp = new TableLayoutPanel();
-                tlp.Name = "tlp_ParkingSpace";
-                tlp.ColumnCount = rows;
-                tlp.RowCount = 1;
-                tlp.Dock = DockStyle.Fill;
-                tlp.AutoScroll = true;
-                tlp.BackColor = SystemColors.GradientActiveCaption;
-                this.Invoke(new Action(() =>
+                catch (Exception e) { Console.WriteLine(e.StackTrace); /*Log.WriteLog(LogType.process, LogFile.WARNING, "实时更新所有库位异常");*/ }
+                Action action = () =>
                 {
-                    //List<TableLayoutPanel> tlpList = new List<TableLayoutPanel>();
-                    int blockSize = spacesInRow * floors * rows;
-                    int offset = (rows + 1 - ((blockSize / spacesInRow) % rows)) * spacesInRow;
+                    int blockSize = s_spacesInRow * s_floors * s_rows;
+                    int offset = (s_rows + 1 - ((blockSize / s_spacesInRow) % s_rows)) * s_spacesInRow;
                     //创建控件
-                    if (ParkingSpaceMonitorPanel.Controls.Count == 0 || needUpdate)
+                    if (ParkingSpaceMonitorPanel != null && ParkingSpaceMonitorPanel.Controls.Count == 0 || needUpdate)
                     {
-                        for (int i = 0; i < rows; i++)
+                        TableLayoutPanel tlp = new TableLayoutPanel();
+                        tlp.Name = "tlp_ParkingSpace";
+                        tlp.ColumnCount = s_rows;
+                        tlp.RowCount = 1;
+                        tlp.Dock = DockStyle.Fill;
+                        tlp.AutoScroll = true;
+                        tlp.BackColor = SystemColors.GradientActiveCaption;
+
+                        for (int i = 0; i < s_rows; i++)
                         {
                             TableLayoutPanel temp = new TableLayoutPanel();
                             temp.Name = "tlp_ParkingSpaceSection" + (i + 1).ToString();
-                            temp.RowCount = floors;
-                            temp.ColumnCount = spacesInRow;
+                            temp.RowCount = s_floors;
+                            temp.ColumnCount = s_spacesInRow;
                             temp.Dock = DockStyle.Fill;
                             temp.AutoSize = true;
                             temp.BackColor = SystemColors.GradientActiveCaption;
-                            temp.Margin = new Padding(5, 2, 5, 2);
+                            temp.Margin = new Padding(1, 2, 1, 2);
                             for (int j = Math.Max(psList.Count, blockSize) - 1; j >= 0; j--)
                             {
                                 Button btn = new Button();
                                 btn.Anchor = (AnchorStyles.Top | AnchorStyles.Left);
                                 btn.AutoSize = true;
-                                btn.Location = new Point(10, 10);
-                                btn.Margin = new Padding(3, 10, 3, 10);
+                                btn.Location = new Point(5, 5);
+                                btn.Margin = new Padding(1, 2, 1, 2);
                                 btn.Padding = new Padding(5);
                                 btn.Name = "lb_parkingSpace" + j;
                                 btn.TextAlign = ContentAlignment.MiddleCenter;
-                                if (((j + offset) / spacesInRow) % rows == i)
+                                btn.MouseClick += new MouseEventHandler(Btnvalue_Click);
+                                btn.MouseHover += new EventHandler(Btnvalue_Mouse_Hover);
+                                if (((j + offset) / s_spacesInRow) % s_rows == i)
                                 {
                                     if (j > psList.Count - 1)
                                     {
@@ -152,21 +240,24 @@ namespace parkspace_manager
                                 //Console.WriteLine("spaces::"+spaceCC.Count);
                                 foreach (Control space in spaceCC)
                                 {
-                                    if (space.GetType() == typeof(Label))
+                                    if (space.GetType() == typeof(Button))
                                     {
                                         int index = -1;
                                         bool result = int.TryParse(space.Text.Substring(2), out index);
-                                        //Console.WriteLine("text is :" + space.Text+", index:"+index);
-                                        if (idPssMap.ContainsKey(index))
+                                        lock (s_map_update_lock)
                                         {
-                                            //Console.WriteLine("index:" + index+", status:"+ idPssMap[index].spaceStatus);
-                                            space.BackColor = GetPSColor(idPssMap[index].ParkspaceStatus);
-                                        }
-                                        else if (result)
-                                        {
-                                            needUpdate = true;
-                                            //Console.WriteLine("need update:"+index);
-                                            break;
+                                            //Console.WriteLine("text is :" + space.Text+", index:"+index);
+                                            if (m_idPssMap.ContainsKey(index))
+                                            {
+                                                //Console.WriteLine("index:" + index+", status:"+ idPssMap[index].spaceStatus);
+                                                space.BackColor = GetPSColor(m_idPssMap[index].ParkspaceStatus);
+                                            }
+                                            else if (result)
+                                            {
+                                                needUpdate = true;
+                                                //Console.WriteLine("need update:"+index);
+                                                break;
+                                            }
                                         }
                                     }
                                 }
@@ -177,8 +268,11 @@ namespace parkspace_manager
                             }
                         }
                     }
-                }));
-                Thread.Sleep(5000);
+                };
+                if (this != null && this.IsHandleCreated)
+                {
+                    this.Invoke(action);
+                }
             }
         }
 
@@ -187,11 +281,162 @@ namespace parkspace_manager
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
-        private void Btnvalue_Click(object sender, EventArgs e)
+        private void Btnvalue_Click(object sender, MouseEventArgs e)
         {
             Button btn = (Button)sender;
             //实例化窗口,选择待修改状态
-            
+            FormStatusSelect formStatusSelect = new FormStatusSelect(btn);
+            formStatusSelect.Location = Control.MousePosition;
+            formStatusSelect.StartPosition = FormStartPosition.Manual;
+            formStatusSelect.SetCallback(ForceUpdateStatusCallback);
+            formStatusSelect.ShowDialog();
+        }
+
+        private void Btnvalue_Mouse_Hover(object sender, EventArgs e)
+        {
+            Button btn = (Button)sender;
+            // 创建the ToolTip 
+            if (m_toolTip_parkspace_info == null)
+            {
+                m_toolTip_parkspace_info = new ToolTip();
+                // 设置显示样式
+                m_toolTip_parkspace_info.AutoPopDelay = 20000;//提示信息的可见时间
+                m_toolTip_parkspace_info.InitialDelay = 500;//事件触发多久后出现提示
+                m_toolTip_parkspace_info.ReshowDelay = 500;//指针从一个控件移向另一个控件时,经过多久才会显示下一个提示框
+                m_toolTip_parkspace_info.ShowAlways = false;//是否显示提示框
+            }
+
+            // 获取车位信息,处理后显示
+            int parkspaceID = GetParkspaceIdFromButton(btn);
+            Parkspace_info space_info = null;
+            lock (s_parkspace_status_lock)
+            {
+                if (parkspaceID <= 0 || m_parkspace_status == null || m_parkspace_status.ParkspaceInfo == null)
+                    return;
+                for (int i = 0; i < m_parkspace_status.ParkspaceInfo.Count; i++)
+                {
+                    if (m_parkspace_status.ParkspaceInfo[i].ParkspaceId == parkspaceID)
+                    {
+                        space_info = m_parkspace_status.ParkspaceInfo[i];
+                        break;
+                    }
+                }
+            }
+            if (space_info == null)
+                return;
+            //  设置伴随的对象
+            m_toolTip_parkspace_info.SetToolTip(btn, space_info.ToString().Replace(",", "\n"));//设置提示按钮和提示内容
+        }
+
+        /// <summary>
+        /// 定义用于发送修改请求,以及修改button状态的回调函数
+        /// </summary>
+        /// <param name="status"></param>
+        private void ForceUpdateStatusCallback(Parkspace_status status, Button btn)
+        {
+            int parkspaceID = GetParkspaceIdFromButton(btn);
+            lock(s_parkspace_status_lock)
+            {
+                if (parkspaceID <= 0 || m_parkspace_status == null || m_parkspace_status.ParkspaceInfo == null)
+                    return;
+            }
+
+            // 遍历强制更新反馈队列,清除对应车位已存在的反馈消息,即将非对应车位的消息放回队列
+            lock (s_parkspace_force_update_queue_lock)
+            {
+                for (int i = 0; i < m_parkspace_force_update_response_queue.Count; i++)
+                {
+                    Parkspace_force_update_response_msg response = m_parkspace_force_update_response_queue.Dequeue();
+                    if (response.UpdateSpaceInfo != null && response.UpdateSpaceInfo.ParkspaceId != parkspaceID)
+                    {
+                        m_parkspace_force_update_response_queue.Enqueue(response);
+                    }
+                }
+            }
+            // 发送强制更新请求
+            Parkspace_info space_info = null;
+            lock (s_parkspace_status_lock)
+            {
+                for (int i = 0; i < m_parkspace_status.ParkspaceInfo.Count; i++)
+                {
+                    if (m_parkspace_status.ParkspaceInfo[i].ParkspaceId == parkspaceID)
+                    {
+                        space_info = m_parkspace_status.ParkspaceInfo[i];
+                        break;
+                    }
+                }
+            }
+            DateTime startTime = DateTime.Now;
+            string commandKey = startTime.ToString("yyyy-MM-dd_HH:mm:ss:ffff");
+            try
+            {
+                space_info.ParkspaceStatus = status;
+                Parkspace_force_update_request_msg parkspace_force_update_request_msg = new Parkspace_force_update_request_msg();
+                Base_info base_Info = new Base_info();
+                base_Info.MsgType = Message_type.EParkspaceForceUpdateRequestMsg;
+                base_Info.TimeoutMs = 2000;
+                base_Info.Sender = Message.Communicator.EParkspace;
+                base_Info.Receiver = Message.Communicator.EParkspace;
+                parkspace_force_update_request_msg.BaseInfo = base_Info;
+                parkspace_force_update_request_msg.CommandKey = commandKey;
+                parkspace_force_update_request_msg.UpdateSpaceInfo = space_info;
+                Communicator.Instance.Send_msg(parkspace_force_update_request_msg.ToByteString());
+            }
+            catch (Exception ex) { Console.WriteLine(ex.StackTrace); }
+
+            // 遍历强制更新反馈队列,寻找对应反馈消息
+            bool get_result = false;
+            while ((DateTime.Now - startTime).TotalMilliseconds < Communicator.Instance.m_timeout_milli)
+            {
+                lock (s_parkspace_force_update_queue_lock)
+                {
+                    for (int i = 0; i < m_parkspace_force_update_response_queue.Count; i++)
+                    {
+                        Parkspace_force_update_response_msg response = m_parkspace_force_update_response_queue.Dequeue();
+                        if (response.UpdateSpaceInfo != null && response.CommandKey == commandKey && response.UpdateSpaceInfo.ParkspaceId == parkspaceID)
+                        {
+                            get_result = true;
+                            if (response.ErrorManager != null)
+                            {
+                                if (response.ErrorManager.ErrorCode != 0)
+                                {
+                                    //btn.BackColor = GetPSColor(status);
+                                    Console.WriteLine("force update failed, code: " + response.ErrorManager.ErrorCode + ", description: " + response.ErrorManager.ErrorDescription);
+                                }
+                            }
+                            break;
+                        }
+                        else
+                        {
+                            m_parkspace_force_update_response_queue.Enqueue(response);
+                        }
+                    }
+                }
+                if (get_result)
+                    break;
+                Thread.Sleep(50);
+            }
+        }
+
+        /// <summary>
+        /// 通过按钮信息截取车位id,失败返回-1
+        /// </summary>
+        /// <param name="btn"></param>
+        /// <returns></returns>
+        private int GetParkspaceIdFromButton(Button btn)
+        {
+            if (btn == null || btn.Text.Length < 3)
+                return -1;
+            int parkspaceID = -1;
+            bool parse_result = int.TryParse(btn.Text.Substring(2), out parkspaceID);
+            if (parse_result)
+            {
+                return parkspaceID;
+            }
+            else
+            {
+                return -1;
+            }
         }
 
         /// <summary>
@@ -206,16 +451,34 @@ namespace parkspace_manager
                 case Parkspace_status.EParkspaceEmpty: return Color.White;
                 case Parkspace_status.EParkspaceOccupied: return Color.Yellow;
                 case Parkspace_status.EParkspaceReserved: return Color.SkyBlue;
-                case Parkspace_status.EParkspaceLocked: return Color.Blue;
+                case Parkspace_status.EParkspaceLocked: return Color.LightGreen;
                 case Parkspace_status.EParkspaceError: return Color.Red;
                 default: return Color.Violet;
             }
         }
 
+        private void FormParkSpaceStatus_FormClosing(object sender, FormClosingEventArgs e)
+        {
+            e.Cancel = true;
+            this.Visible = false;
+        }
+
         private void FormParkSpaceStatus_FormClosed(object sender, FormClosedEventArgs e)
         {
-            isClosing = true;
-            Communicator.Instance.Uninit();
+            try
+            {
+                if (m_update_display_thread != null)
+                {
+                    m_update_display_thread.Abort();
+                }
+            }
+            catch { Console.WriteLine("线程退出"); }
+            //s_isClosing = true;
+            ////if (m_update_display_thread != null)
+            ////{
+            ////    m_update_display_thread.Join();
+            ////}
+            //Communicator.Instance.Uninit();
         }
     }
 }

+ 93 - 0
parkspace_manager/FormStatusSelect.Designer.cs

@@ -0,0 +1,93 @@
+namespace parkspace_manager
+{
+    partial class FormStatusSelect
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.btn_confirm = new System.Windows.Forms.Button();
+            this.btn_cancel = new System.Windows.Forms.Button();
+            this.listBox_status = new System.Windows.Forms.ListBox();
+            this.SuspendLayout();
+            // 
+            // btn_confirm
+            // 
+            this.btn_confirm.Location = new System.Drawing.Point(13, 126);
+            this.btn_confirm.Name = "btn_confirm";
+            this.btn_confirm.Size = new System.Drawing.Size(88, 37);
+            this.btn_confirm.TabIndex = 0;
+            this.btn_confirm.Text = "确定";
+            this.btn_confirm.UseVisualStyleBackColor = true;
+            this.btn_confirm.Click += new System.EventHandler(this.btn_confirm_Click);
+            // 
+            // btn_cancel
+            // 
+            this.btn_cancel.Location = new System.Drawing.Point(122, 125);
+            this.btn_cancel.Name = "btn_cancel";
+            this.btn_cancel.Size = new System.Drawing.Size(88, 37);
+            this.btn_cancel.TabIndex = 1;
+            this.btn_cancel.Text = "取消";
+            this.btn_cancel.UseVisualStyleBackColor = true;
+            this.btn_cancel.Click += new System.EventHandler(this.btn_cancel_Click);
+            // 
+            // listBox_status
+            // 
+            this.listBox_status.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
+            this.listBox_status.FormattingEnabled = true;
+            this.listBox_status.ItemHeight = 20;
+            this.listBox_status.Items.AddRange(new object[] {
+            "空闲",
+            "占用",
+            "已预约",
+            "锁定",
+            "故障"});
+            this.listBox_status.Location = new System.Drawing.Point(25, 12);
+            this.listBox_status.Name = "listBox_status";
+            this.listBox_status.Size = new System.Drawing.Size(169, 104);
+            this.listBox_status.TabIndex = 2;
+            // 
+            // FormStatusSelect
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(228, 181);
+            this.Controls.Add(this.listBox_status);
+            this.Controls.Add(this.btn_cancel);
+            this.Controls.Add(this.btn_confirm);
+            this.Name = "FormStatusSelect";
+            this.ShowInTaskbar = false;
+            this.Text = "FormStatusSelect";
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btn_confirm;
+        private System.Windows.Forms.Button btn_cancel;
+        private System.Windows.Forms.ListBox listBox_status;
+    }
+}

+ 105 - 0
parkspace_manager/FormStatusSelect.cs

@@ -0,0 +1,105 @@
+using Message;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace parkspace_manager
+{
+    public partial class FormStatusSelect : Form
+    {
+        /// <summary>
+        /// 状态修改回调格式声明
+        /// </summary>
+        /// <param name="status"></param>
+        public delegate void StatusCallback(Parkspace_status status, Button btn);
+        /// <summary>
+        /// 修改状态回调
+        /// </summary>
+        public StatusCallback m_set_status_callback = null;
+        /// <summary>
+        /// 已选择的状态
+        /// </summary>
+        public Parkspace_status m_selected_status { get; set; }
+        /// <summary>
+        /// 待修改按钮
+        /// </summary>
+        public Button m_linked_btn;
+        /// <summary>
+        /// 构造
+        /// </summary>
+        public FormStatusSelect(Button btn)
+        {
+            InitializeComponent();
+            m_selected_status = Parkspace_status.EParkspaceError;
+            m_linked_btn = btn;
+        }
+
+        /// <summary>
+        /// 设置回调
+        /// </summary>
+        public void SetCallback(StatusCallback callback)
+        {
+            m_set_status_callback = callback;
+        }
+
+        /// <summary>
+        /// 确认状态修改
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void btn_confirm_Click(object sender, EventArgs e)
+        {
+            Task.Factory.StartNew(() => {
+                this.Invoke(new Action(()=> {
+                    Index2status(listBox_status.SelectedIndex);
+                    m_set_status_callback?.Invoke(m_selected_status, m_linked_btn);
+                    Close();
+                }));
+            });
+            btn_confirm.Enabled = false;
+            btn_cancel.Enabled = false;
+        }
+
+        /// <summary>
+        /// 选项index转状态枚举
+        /// </summary>
+        /// <param name="index"></param>
+        private void Index2status(int index)
+        {
+            switch(index)
+            {
+                case 0:
+                    m_selected_status = Parkspace_status.EParkspaceEmpty;
+                    break;
+                case 1:
+                    m_selected_status = Parkspace_status.EParkspaceOccupied;
+                    break;
+                case 2:
+                    m_selected_status = Parkspace_status.EParkspaceReserved;
+                    break;
+                case 3:
+                    m_selected_status = Parkspace_status.EParkspaceLocked;
+                    break;
+                case 4:
+                    m_selected_status = Parkspace_status.EParkspaceError;
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// 取消状态修改
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void btn_cancel_Click(object sender, EventArgs e)
+        {
+            Close();
+        }
+    }
+}

+ 120 - 0
parkspace_manager/FormStatusSelect.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 146 - 69
parkspace_manager/communication/Communicator.cs

@@ -13,16 +13,35 @@ namespace parkspace_manager
 {
     class Communicator
     {
+        // 各类消息委托,收到对应消息即调用对应委托/回调
+        public delegate void parkspaceStatusDelegate(Parkspace_allocation_status_msg parkspace_status);
+        public delegate void parkspaceForceUpdateResponseDelegate(Parkspace_force_update_response_msg response);
+        // 对应委托/回调句柄
+        private parkspaceStatusDelegate m_parkspaceStatusCallback;
+        private parkspaceForceUpdateResponseDelegate m_parkspaceForceUpdateResponseCallback;
+        // 对应委托/回调句柄设置函数
+        public void SetParkspaceStatusDelegate(parkspaceStatusDelegate callback)
+        {
+            m_parkspaceStatusCallback = callback;
+        }
+        public void SetParkspaceForceUpdateResponseDelegate(parkspaceForceUpdateResponseDelegate callback)
+        {
+            m_parkspaceForceUpdateResponseCallback = callback;
+        }
+
+        /// <summary>
+        /// 消息超时时间
+        /// </summary>
+        public int m_timeout_milli = 2000;
+        /// <summary>
+        /// 单例锁对象
+        /// </summary>
         private readonly static object lockObj = new object();
         /// <summary>
         /// 单例
         /// </summary>
         private static Communicator instance = null;
         /// <summary>
-        /// 消息超时时间
-        /// </summary>
-        private static int timeout_milli = 2000;
-        /// <summary>
         /// 接收解析锁
         /// </summary>
         private object m_receive_lock;
@@ -43,10 +62,6 @@ namespace parkspace_manager
         /// </summary>
         private DateTime m_last_parkspace_status_time;
         /// <summary>
-        /// 车位状态超时
-        /// </summary>
-        private bool mb_parkspace_status_timeout;
-        /// <summary>
         /// 发送队列
         /// </summary>
         private Queue<ByteString> m_send_queue;
@@ -71,13 +86,17 @@ namespace parkspace_manager
         /// </summary>
         private BusSocket m_socket;
         /// <summary>
+        /// nnxx生成id队列
+        /// </summary>
+        private Queue<NanomsgEndpoint> nanomsgEndpoints_queue;
+        /// <summary>
         /// 实例退出标记
         /// </summary>
-        private bool mb_exit;
+        public bool mb_exit;
         /// <summary>
         /// 初始化标记
         /// </summary>
-        private bool mb_initialized;
+        public bool mb_initialized;
 
         /// <summary>
         /// 构造函数
@@ -88,13 +107,13 @@ namespace parkspace_manager
         {
             mb_exit = false;
             mb_initialized = false;
-            mb_parkspace_status_timeout = false;
             m_receive_lock = new object();
             m_send_lock = new object();
             m_parkspace_status_access_lock = new object();
             m_receive_queue = new Queue<ByteString>();
             m_send_queue = new Queue<ByteString>();
             m_parkspace_current_status = new Parkspace_allocation_status_msg();
+            nanomsgEndpoints_queue = new Queue<NanomsgEndpoint>();
         }
 
         /// <summary>
@@ -142,15 +161,29 @@ namespace parkspace_manager
         /// <returns></returns>
         public bool Init()
         {
-            mb_initialized = true; 
-            m_socket = new BusSocket();
-            m_thread_receive = new Thread(new ParameterizedThreadStart(Receive_thread_function));
-            m_thread_send = new Thread(new ParameterizedThreadStart(Send_thread_function));
-            m_thread_decode_receive = new Thread(new ParameterizedThreadStart(Decode_thread_function));
-            m_thread_receive.Start(this);
-            m_thread_send.Start(this);
-            m_thread_decode_receive.Start(this);
-            return true;
+            try
+            {
+                if (!mb_initialized)
+                {
+                    mb_exit = false;
+                    mb_initialized = true;
+                    m_socket = new BusSocket();
+                    m_thread_receive = new Thread(new ParameterizedThreadStart(Receive_thread_function));
+                    m_thread_send = new Thread(new ParameterizedThreadStart(Send_thread_function));
+                    m_thread_decode_receive = new Thread(new ParameterizedThreadStart(Decode_thread_function));
+                    m_thread_receive.Start(this);
+                    m_thread_send.Start(this);
+                    m_thread_decode_receive.Start(this);
+                    // 设置车位状态回调
+                    SetParkspaceStatusDelegate(ParkspaceStatusUpdate);
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            catch (Exception ex) { Console.WriteLine(ex.StackTrace); return false; }
         }
 
         /// <summary>
@@ -160,12 +193,22 @@ namespace parkspace_manager
         public bool Uninit()
         {
             mb_exit = true;
-            if(m_thread_receive!=null)
+            if (m_thread_receive != null)
                 m_thread_receive.Join();
-            if(m_thread_send!=null)
+            if (m_thread_send != null)
                 m_thread_send.Join();
             if (m_thread_decode_receive != null)
                 m_thread_decode_receive.Join();
+            if(m_socket!=null)
+            {
+                while(nanomsgEndpoints_queue.Count>0)
+                {
+                    NanomsgEndpoint nnep = nanomsgEndpoints_queue.Dequeue();
+                    m_socket.Shutdown(nnep);
+                }
+                m_socket.Dispose();
+            }
+            mb_initialized = false;
             return true;
         }
 
@@ -195,6 +238,20 @@ namespace parkspace_manager
             return true;
         }
 
+        /// <summary>
+        /// 车位更新回调内部定义
+        /// </summary>
+        /// <param name="parkspace_status"></param>
+        private void ParkspaceStatusUpdate(Parkspace_allocation_status_msg parkspace_status)
+        {
+            lock (m_parkspace_status_access_lock)
+            {
+                m_parkspace_current_status = parkspace_status;
+                //comm.m_parkspace_current_status.MergeFrom(parkspace_status);
+                m_last_parkspace_status_time = DateTime.Now;
+            }
+        }
+
         /// <summary>
         /// 获取当前车位状态
         /// </summary>
@@ -202,9 +259,10 @@ namespace parkspace_manager
         {
             lock (m_parkspace_status_access_lock)
             {
+                msg = new Parkspace_allocation_status_msg();
                 msg.MergeFrom(m_parkspace_current_status);
             }
-            if((DateTime.Now-m_last_parkspace_status_time).Milliseconds > timeout_milli)
+            if ((DateTime.Now - m_last_parkspace_status_time).Milliseconds > m_timeout_milli)
             {
                 return false;
             }
@@ -218,9 +276,13 @@ namespace parkspace_manager
         /// 发送手动更新车位消息
         /// </summary>
         /// <returns></returns>
-        public bool Send_msg()
+        public bool Send_msg(ByteString bs)
         {
-
+            lock(m_send_lock)
+            {
+                m_send_queue.Enqueue(bs);
+            }
+            return true;
         }
 
         /// <summary>
@@ -232,21 +294,26 @@ namespace parkspace_manager
             if (handle == null)
                 return;
             Communicator comm = (Communicator)handle;
-            while(!comm.mb_exit)
+            while (!comm.mb_exit)
             {
-                if (!comm.mb_initialized || comm.m_socket==null)
-                    continue;
-                byte[] data = comm.m_socket.ReceiveImmediate();
-                if(data!=null && data.Length>0)
+                try
                 {
-                    lock (comm.m_receive_lock)
+                    if (!comm.mb_initialized || comm.m_socket == null)
+                        continue;
+                    byte[] data = comm.m_socket.ReceiveImmediate();
+                    if (data != null && data.Length > 0 && comm.m_receive_queue != null)
                     {
-                        //ByteString tmp = ByteString.CopyFrom(data);
-                        //Base_msg base_msg = Base_msg.Parser.ParseFrom(tmp);
-                        //Console.WriteLine(base_msg.ToString());
-                        comm.m_receive_queue.Enqueue(ByteString.CopyFrom(data));
+                        lock (comm.m_receive_lock)
+                        {
+                            //ByteString tmp = ByteString.CopyFrom(data);
+                            //Base_msg base_msg = Base_msg.Parser.ParseFrom(tmp);
+                            //Console.WriteLine(base_msg.ToString());
+                            //Console.WriteLine("msg received");
+                            comm.m_receive_queue.Enqueue(ByteString.CopyFrom(data));
+                        }
                     }
                 }
+                catch (Exception ex) { Console.WriteLine(ex.StackTrace); }
                 Thread.Sleep(50);
             }
             Console.WriteLine("receive thread exit");
@@ -263,14 +330,22 @@ namespace parkspace_manager
             Communicator comm = (Communicator)handle;
             while (!comm.mb_exit)
             {
-                if (!comm.mb_initialized || comm.m_socket == null)
-                    continue;
-                lock(comm.m_send_lock)
+                try
                 {
-
+                    if (!comm.mb_initialized || comm.m_socket == null)
+                        continue;
+                    lock (comm.m_send_lock)
+                    {
+                        while (comm.m_send_queue.Count > 0)
+                        {
+                            ByteString bs = comm.m_send_queue.Dequeue();
+                            comm.m_socket.Send(bs.ToByteArray());
+                        }
+                    }
+                    //Console.WriteLine("msg sent");
                 }
-
-                Thread.Sleep(500);
+                catch (Exception ex) { Console.WriteLine(ex.StackTrace); }
+                Thread.Sleep(50);
             }
             Console.WriteLine("send thread exit");
         }
@@ -286,32 +361,25 @@ namespace parkspace_manager
             Communicator comm = (Communicator)handle;
             while (!comm.mb_exit)
             {
-                DateTime current_time = DateTime.Now;
-
-                if (!comm.mb_initialized)
-                    continue;
-                Parkspace_allocation_status_msg parkspace_status = null;
-                lock (comm.m_receive_lock)
+                try
                 {
-                    if (comm.m_receive_queue.Count > 0)
+                    DateTime current_time = DateTime.Now;
+
+                    if (!comm.mb_initialized)
+                        continue;
+                    ByteString msg_str = null;
+                    lock (comm.m_receive_lock)
                     {
-                        ByteString msg_str = comm.m_receive_queue.Dequeue();
-                        parkspace_status = comm.Decode_msg(msg_str);
-                        if (parkspace_status != null)
+                        if (comm.m_receive_queue.Count > 0)
                         {
-                            comm.m_last_parkspace_status_time = DateTime.Now;
-                            Console.WriteLine(parkspace_status.ToString());
+                            msg_str = comm.m_receive_queue.Dequeue();
                         }
                     }
+                    // 解析
+                    comm.Decode_msg(msg_str);
+                    //Console.WriteLine("msg parsed");
                 }
-                if(parkspace_status != null)
-                {
-                    lock (comm.m_parkspace_status_access_lock)
-                    {
-                        comm.m_parkspace_current_status = parkspace_status;
-                        //comm.m_parkspace_current_status.MergeFrom(parkspace_status);
-                    }
-                }
+                catch (Exception ex) { Console.WriteLine(ex.StackTrace); }
                 Thread.Sleep(50);
             }
             Console.WriteLine("decode thread exit");
@@ -320,17 +388,26 @@ namespace parkspace_manager
         /// <summary>
         /// 解析string到protobuf消息
         /// </summary>
-        private Parkspace_allocation_status_msg Decode_msg(ByteString msg)
+        private void Decode_msg(ByteString msg)
         {
+            if (msg == null)
+                return;
             Base_msg base_msg = Base_msg.Parser.ParseFrom(msg);
-            if(base_msg.BaseInfo.MsgType == Message_type.EParkspaceAllocationStatusMsg)
-            {
-                Parkspace_allocation_status_msg parsed_msg = Parkspace_allocation_status_msg.Parser.ParseFrom(msg);
-                return parsed_msg;
-            }
-            else
+            switch(base_msg.BaseInfo.MsgType)
             {
-                return null;
+                case Message_type.EParkspaceAllocationStatusMsg:
+                    Parkspace_allocation_status_msg parkspace_status_msg = Parkspace_allocation_status_msg.Parser.ParseFrom(msg);
+                    m_parkspaceStatusCallback?.Invoke(parkspace_status_msg);
+                    break;
+                case Message_type.EParkspaceForceUpdateResponseMsg:
+                    Console.WriteLine("update response");
+                    Parkspace_force_update_response_msg parkspace_force_update_msg = Parkspace_force_update_response_msg.Parser.ParseFrom(msg);
+                    Console.WriteLine(parkspace_force_update_msg.ToString());
+                    m_parkspaceForceUpdateResponseCallback?.Invoke(parkspace_force_update_msg);
+                    break;
+                default:
+                    Console.WriteLine("unrecognized message received");
+                    break;
             }
         }
 

+ 9 - 0
parkspace_manager/parkspace_manager.csproj

@@ -84,6 +84,12 @@
     <Compile Include="FormParkSpaceStatus.Designer.cs">
       <DependentUpon>FormParkSpaceStatus.cs</DependentUpon>
     </Compile>
+    <Compile Include="FormStatusSelect.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="FormStatusSelect.Designer.cs">
+      <DependentUpon>FormStatusSelect.cs</DependentUpon>
+    </Compile>
     <Compile Include="LOG\Credence.cs" />
     <Compile Include="LOG\log.cs" />
     <Compile Include="LOG\LogManager.cs" />
@@ -99,6 +105,9 @@
     <EmbeddedResource Include="FormParkSpaceStatus.resx">
       <DependentUpon>FormParkSpaceStatus.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="FormStatusSelect.resx">
+      <DependentUpon>FormStatusSelect.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="Properties\Resources.resx">
       <Generator>ResXFileCodeGenerator</Generator>
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>