FormParkSpaceStatus.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. using Google.Protobuf;
  2. using Message;
  3. using parkMonitor.LOG;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel;
  7. using System.Data;
  8. using System.Drawing;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using System.Windows.Forms;
  14. namespace parkspace_manager
  15. {
  16. public partial class FormParkSpaceStatus : Form
  17. {
  18. public static int s_spacesInRow = 18;
  19. public static int s_floors = 13;
  20. public static int s_rows = 1;
  21. public static bool s_isClosing;
  22. private static object s_map_update_lock;
  23. private static object s_parkspace_force_update_queue_lock;
  24. private static object s_parkspace_status_lock;
  25. /// <summary>
  26. /// 车位id与车位信息映射
  27. /// </summary>
  28. private Dictionary<int, Parkspace_info> m_idPssMap;
  29. /// <summary>
  30. /// 强制更新反馈消息队列,用于处理同时收到多个反馈消息的情况
  31. /// </summary>
  32. private Queue<Parkspace_force_update_response_msg> m_parkspace_force_update_response_queue;
  33. /// <summary>
  34. /// 当前所有车位状态,由界面更新线程主动更新
  35. /// </summary>
  36. Parkspace_allocation_data_msg m_parkspace_status;
  37. Thread m_update_display_thread;
  38. public FormParkSpaceStatus()
  39. {
  40. m_parkspace_status = new Parkspace_allocation_data_msg();
  41. s_map_update_lock = new object();
  42. s_parkspace_force_update_queue_lock = new object();
  43. s_parkspace_status_lock = new object();
  44. m_parkspace_force_update_response_queue = new Queue<Parkspace_force_update_response_msg>();
  45. m_idPssMap = new Dictionary<int, Parkspace_info>();
  46. s_isClosing = false;
  47. InitializeComponent();
  48. Communicator.Instance.Init();
  49. Communicator.Instance.Bind("tcp://192.168.2.154:12333");
  50. Communicator.Instance.Connect("tcp://192.168.2.127:30008");
  51. Communicator.Instance.Connect("tcp://192.168.2.127:30000");
  52. Communicator.Instance.SetParkspaceForceUpdateResponseDelegate(ParkspaceForceUpdateResponseCallback);
  53. // 库位显示
  54. m_update_display_thread = new Thread(new ThreadStart(UpdateParkingSpaceView));
  55. m_update_display_thread.Start();
  56. }
  57. public void Uninit()
  58. {
  59. s_isClosing = true;
  60. Communicator.Instance.Uninit();
  61. //if(m_update_display_thread!=null)
  62. //{
  63. // m_update_display_thread.Join();
  64. //}
  65. }
  66. /// <summary>
  67. /// 接收到强制更新车位反馈消息回调
  68. /// </summary>
  69. /// <param name="response"></param>
  70. void ParkspaceForceUpdateResponseCallback(Parkspace_force_update_response_msg response)
  71. {
  72. lock (s_parkspace_force_update_queue_lock)
  73. {
  74. if (m_parkspace_force_update_response_queue != null)
  75. {
  76. m_parkspace_force_update_response_queue.Enqueue(response);
  77. }
  78. }
  79. }
  80. /// <summary>
  81. /// 更新立体停车位显示
  82. /// </summary>
  83. private void UpdateParkingSpaceView()
  84. {
  85. while (!s_isClosing)
  86. {
  87. bool needUpdate = false;
  88. List<Parkspace_info> psList = null;
  89. Thread.Sleep(1000);
  90. bool get_status_result = Communicator.Instance.Get_parkspace_status(ref m_parkspace_status);
  91. lock (s_parkspace_status_lock)
  92. {
  93. if (get_status_result && (m_parkspace_status == null || m_parkspace_status.ParkspaceInfoEx == null))
  94. {
  95. get_status_result = false;
  96. }
  97. }
  98. if (!get_status_result)
  99. {
  100. lock (s_map_update_lock)
  101. {
  102. m_idPssMap.Clear();
  103. }
  104. continue;
  105. }
  106. else
  107. {
  108. lock (s_parkspace_status_lock)
  109. {
  110. psList = m_parkspace_status.ParkspaceInfoEx.ToList();
  111. }
  112. }
  113. if (psList == null || psList.Count <= 0)
  114. {
  115. Thread.Sleep(1000);
  116. continue;
  117. }
  118. //更新映射表
  119. try
  120. {
  121. lock (s_map_update_lock)
  122. {
  123. if (m_idPssMap.Count != psList.Count)
  124. {
  125. m_idPssMap.Clear();
  126. for (int i = 0; i < psList.Count; i++)
  127. {
  128. m_idPssMap.Add(psList[i].ParkingspaceIndexId, psList[i]);
  129. }
  130. }
  131. else
  132. {
  133. for (int i = 0; i < psList.Count; i++)
  134. {
  135. m_idPssMap[psList[i].ParkingspaceIndexId] = psList[i];
  136. }
  137. }
  138. }
  139. }
  140. catch (Exception e) { Console.WriteLine(e.StackTrace); /*Log.WriteLog(LogType.process, LogFile.WARNING, "实时更新所有库位异常");*/ }
  141. Action action = () =>
  142. {
  143. int blockSize = s_spacesInRow * s_floors * s_rows;
  144. int offset = (s_rows + 1 - ((blockSize / s_spacesInRow) % s_rows)) * s_spacesInRow;
  145. //创建控件
  146. if (ParkingSpaceMonitorPanel != null && ParkingSpaceMonitorPanel.Controls.Count == 0 || needUpdate)
  147. {
  148. TableLayoutPanel tlp = new TableLayoutPanel();
  149. tlp.Name = "tlp_ParkingSpace";
  150. tlp.ColumnCount = s_rows;
  151. tlp.RowCount = 1;
  152. tlp.Dock = DockStyle.Fill;
  153. tlp.AutoScroll = true;
  154. tlp.BackColor = SystemColors.GradientActiveCaption;
  155. for (int i = 0; i < s_rows; i++)
  156. {
  157. TableLayoutPanel temp = new TableLayoutPanel();
  158. temp.Name = "tlp_ParkingSpaceSection" + (i + 1).ToString();
  159. temp.RowCount = s_floors;
  160. temp.ColumnCount = s_spacesInRow;
  161. temp.Dock = DockStyle.Fill;
  162. temp.AutoSize = true;
  163. temp.BackColor = SystemColors.GradientActiveCaption;
  164. temp.Margin = new Padding(1, 2, 1, 2);
  165. for (int j = Math.Max(psList.Count, blockSize) - 1; j >= 0; j--)
  166. {
  167. Button btn = new Button();
  168. btn.Anchor = (AnchorStyles.Top | AnchorStyles.Left);
  169. btn.AutoSize = true;
  170. btn.Location = new Point(5, 5);
  171. btn.Margin = new Padding(1, 2, 1, 2);
  172. btn.Padding = new Padding(5);
  173. btn.Name = "lb_parkingSpace" + j;
  174. btn.TextAlign = ContentAlignment.MiddleCenter;
  175. btn.MouseClick += new MouseEventHandler(Btnvalue_Click);
  176. btn.MouseHover += new EventHandler(Btnvalue_Mouse_Hover);
  177. if (((j + offset) / s_spacesInRow) % s_rows == i)
  178. {
  179. if (j > psList.Count - 1)
  180. {
  181. btn.Text = "#####";
  182. temp.Controls.Add(btn);
  183. btn.BackColor = GetPSColor(Parkspace_status.EParkspaceError);
  184. }
  185. else
  186. {
  187. try
  188. {
  189. btn.Text = "车位" + psList[j].ParkingspaceIndexId;
  190. btn.BackColor = GetPSColor(psList[j].ParkingspaceStatus);
  191. temp.Controls.Add(btn);
  192. }
  193. catch { Log.WriteLog(LogType.process, LogFile.WARNING, "实时更新单一库位异常"); }
  194. }
  195. }
  196. }
  197. tlp.Controls.Add(temp);
  198. //tlpList.Add(temp);
  199. }
  200. ParkingSpaceMonitorPanel.Controls.Clear();
  201. ParkingSpaceMonitorPanel.Controls.Add(tlp);
  202. needUpdate = false;
  203. }
  204. //更新控件
  205. else
  206. {
  207. Control.ControlCollection psCC = ParkingSpaceMonitorPanel.Controls;
  208. foreach (Control segment in psCC)
  209. {
  210. Control.ControlCollection segmentCC = segment.Controls;
  211. //Console.WriteLine("seg::"+segmentCC.Count);
  212. foreach (Control spaces in segmentCC)
  213. {
  214. Control.ControlCollection spaceCC = spaces.Controls;
  215. //Console.WriteLine("spaces::"+spaceCC.Count);
  216. foreach (Control space in spaceCC)
  217. {
  218. if (space.GetType() == typeof(Button))
  219. {
  220. int index = -1;
  221. bool result = int.TryParse(space.Text.Substring(2), out index);
  222. lock (s_map_update_lock)
  223. {
  224. //Console.WriteLine("text is :" + space.Text+", index:"+index);
  225. if (m_idPssMap.ContainsKey(index))
  226. {
  227. //Console.WriteLine("index:" + index+", status:"+ idPssMap[index].spaceStatus);
  228. space.BackColor = GetPSColor(m_idPssMap[index].ParkingspaceStatus);
  229. }
  230. else if (result)
  231. {
  232. needUpdate = true;
  233. //Console.WriteLine("need update:"+index);
  234. break;
  235. }
  236. }
  237. }
  238. }
  239. }
  240. if (needUpdate)
  241. {
  242. break;
  243. }
  244. }
  245. }
  246. };
  247. if (this != null && this.IsHandleCreated)
  248. {
  249. this.Invoke(action);
  250. }
  251. }
  252. }
  253. /// <summary>
  254. /// 按钮点击事件
  255. /// </summary>
  256. /// <param name="sender"></param>
  257. /// <param name="e"></param>
  258. private void Btnvalue_Click(object sender, MouseEventArgs e)
  259. {
  260. Button btn = (Button)sender;
  261. //实例化窗口,选择待修改状态
  262. FormStatusSelect formStatusSelect = new FormStatusSelect(btn);
  263. formStatusSelect.Location = Control.MousePosition;
  264. formStatusSelect.StartPosition = FormStartPosition.Manual;
  265. formStatusSelect.SetCallback(ForceUpdateStatusCallback);
  266. formStatusSelect.ShowDialog();
  267. }
  268. private void Btnvalue_Mouse_Hover(object sender, EventArgs e)
  269. {
  270. Button btn = (Button)sender;
  271. // 创建the ToolTip
  272. ToolTip toolTip_parkspace_info = new ToolTip();
  273. // 设置显示样式
  274. toolTip_parkspace_info.AutoPopDelay = 20000;//提示信息的可见时间
  275. toolTip_parkspace_info.InitialDelay = 500;//事件触发多久后出现提示
  276. toolTip_parkspace_info.ReshowDelay = 1000;//指针从一个控件移向另一个控件时,经过多久才会显示下一个提示框
  277. toolTip_parkspace_info.ShowAlways = false;//是否显示提示框
  278. // 获取车位信息,处理后显示
  279. int parkspaceID = GetParkspaceIdFromButton(btn);
  280. Parkspace_info space_info = null;
  281. lock (s_parkspace_status_lock)
  282. {
  283. if (parkspaceID <= 0 || m_parkspace_status == null || m_parkspace_status.ParkspaceInfoEx == null)
  284. return;
  285. for (int i = 0; i < m_parkspace_status.ParkspaceInfoEx.Count; i++)
  286. {
  287. if (m_parkspace_status.ParkspaceInfoEx[i].ParkingspaceIndexId == parkspaceID)
  288. {
  289. space_info = m_parkspace_status.ParkspaceInfoEx[i];
  290. break;
  291. }
  292. }
  293. }
  294. if (space_info == null)
  295. return;
  296. // 设置伴随的对象
  297. toolTip_parkspace_info.SetToolTip(btn, space_info.ToString().Replace(",", "\n"));//设置提示按钮和提示内容
  298. }
  299. /// <summary>
  300. /// 定义用于发送修改请求,以及修改button状态的回调函数
  301. /// </summary>
  302. /// <param name="status"></param>
  303. private void ForceUpdateStatusCallback(Parkspace_status status, Button btn)
  304. {
  305. int parkspaceID = GetParkspaceIdFromButton(btn);
  306. lock(s_parkspace_status_lock)
  307. {
  308. if (parkspaceID <= 0 || m_parkspace_status == null || m_parkspace_status.ParkspaceInfoEx == null)
  309. return;
  310. }
  311. SendAndReceive(status, parkspaceID);
  312. }
  313. /// <summary>
  314. /// 发送后接收对应反馈消息
  315. /// </summary>
  316. private void SendAndReceive(Parkspace_status status, int parkspaceID)
  317. {
  318. // 遍历强制更新反馈队列,清除对应车位已存在的反馈消息,即将非对应车位的消息放回队列
  319. lock (s_parkspace_force_update_queue_lock)
  320. {
  321. for (int i = 0; i < m_parkspace_force_update_response_queue.Count; i++)
  322. {
  323. Parkspace_force_update_response_msg response = m_parkspace_force_update_response_queue.Dequeue();
  324. if (response.ManualParkspaceInfoEx != null && response.ManualParkspaceInfoEx.Count > 0 && response.ManualParkspaceInfoEx[0].ParkingspaceIndexId != parkspaceID)
  325. {
  326. m_parkspace_force_update_response_queue.Enqueue(response);
  327. }
  328. }
  329. }
  330. // 发送强制更新请求
  331. Parkspace_info space_info = null;
  332. lock (s_parkspace_status_lock)
  333. {
  334. //用于清除所有车位状态的特殊指令
  335. if (parkspaceID == 9999)
  336. {
  337. space_info = new Parkspace_info();
  338. if (m_parkspace_status.ParkspaceInfoEx.Count() > 0)
  339. {
  340. space_info = m_parkspace_status.ParkspaceInfoEx[0];
  341. }
  342. space_info.ParkingspaceIndexId = 9999;
  343. }
  344. else
  345. {
  346. for (int i = 0; i < m_parkspace_status.ParkspaceInfoEx.Count; i++)
  347. {
  348. if (m_parkspace_status.ParkspaceInfoEx[i].ParkingspaceIndexId == parkspaceID)
  349. {
  350. space_info = m_parkspace_status.ParkspaceInfoEx[i];
  351. break;
  352. }
  353. }
  354. }
  355. }
  356. DateTime startTime = DateTime.Now;
  357. string commandKey = startTime.ToString("yyyy-MM-dd_HH:mm:ss:ffff");
  358. try
  359. {
  360. space_info.ParkingspaceStatus = status;
  361. Parkspace_force_update_request_msg parkspace_force_update_request_msg = new Parkspace_force_update_request_msg();
  362. Base_info base_Info = new Base_info();
  363. base_Info.MsgType = Message_type.EParkspaceForceUpdateRequestMsg;
  364. base_Info.TimeoutMs = 2000;
  365. base_Info.Sender = Message.Communicator.EParkspace;
  366. base_Info.Receiver = Message.Communicator.EParkspace;
  367. parkspace_force_update_request_msg.BaseInfo = base_Info;
  368. parkspace_force_update_request_msg.CommandKey = commandKey;
  369. parkspace_force_update_request_msg.ManualParkspaceInfoEx.Add(space_info);
  370. Communicator.Instance.Send_msg(parkspace_force_update_request_msg.ToByteString());
  371. }
  372. catch (Exception ex) { Console.WriteLine(ex.StackTrace); }
  373. // 遍历强制更新反馈队列,寻找对应反馈消息
  374. bool get_result = false;
  375. while ((DateTime.Now - startTime).TotalMilliseconds < Communicator.Instance.m_timeout_milli)
  376. {
  377. lock (s_parkspace_force_update_queue_lock)
  378. {
  379. for (int i = 0; i < m_parkspace_force_update_response_queue.Count; i++)
  380. {
  381. Parkspace_force_update_response_msg response = m_parkspace_force_update_response_queue.Dequeue();
  382. if (response.ManualParkspaceInfoEx != null && response.ManualParkspaceInfoEx.Count > 0 && response.CommandKey == commandKey && response.ManualParkspaceInfoEx[0].ParkingspaceIndexId== parkspaceID)
  383. {
  384. get_result = true;
  385. if (response.ErrorManager != null)
  386. {
  387. if (response.ErrorManager.ErrorCode != 0)
  388. {
  389. //btn.BackColor = GetPSColor(status);
  390. Console.WriteLine("force update failed, code: " + response.ErrorManager.ErrorCode + ", description: " + response.ErrorManager.ErrorDescription);
  391. }
  392. }
  393. break;
  394. }
  395. else
  396. {
  397. m_parkspace_force_update_response_queue.Enqueue(response);
  398. }
  399. }
  400. }
  401. if (get_result)
  402. break;
  403. Thread.Sleep(50);
  404. }
  405. if (!get_result && space_info != null)
  406. {
  407. MessageBox.Show("force update get response timeout: " + space_info.ToString());
  408. }
  409. }
  410. /// <summary>
  411. /// 通过按钮信息截取车位id,失败返回-1
  412. /// </summary>
  413. /// <param name="btn"></param>
  414. /// <returns></returns>
  415. private int GetParkspaceIdFromButton(Button btn)
  416. {
  417. if (btn == null || btn.Text.Length < 3)
  418. return -1;
  419. int parkspaceID = -1;
  420. bool parse_result = int.TryParse(btn.Text.Substring(2), out parkspaceID);
  421. if (parse_result)
  422. {
  423. return parkspaceID;
  424. }
  425. else
  426. {
  427. return -1;
  428. }
  429. }
  430. /// <summary>
  431. /// 获取状态对应颜色
  432. /// </summary>
  433. /// <param name="status"></param>
  434. /// <returns></returns>
  435. private Color GetPSColor(Parkspace_status status)
  436. {
  437. switch (status)
  438. {
  439. case Parkspace_status.EParkspaceEmpty: return Color.White;
  440. case Parkspace_status.EParkspaceOccupied: return Color.Yellow;
  441. case Parkspace_status.EParkspaceReserved: return Color.SkyBlue;
  442. case Parkspace_status.EParkspaceLocked: return Color.LightGreen;
  443. case Parkspace_status.EParkspaceError: return Color.Red;
  444. default: return Color.Violet;
  445. }
  446. }
  447. private void FormParkSpaceStatus_FormClosing(object sender, FormClosingEventArgs e)
  448. {
  449. e.Cancel = true;
  450. this.Visible = false;
  451. }
  452. private void FormParkSpaceStatus_FormClosed(object sender, FormClosedEventArgs e)
  453. {
  454. try
  455. {
  456. if (m_update_display_thread != null)
  457. {
  458. m_update_display_thread.Abort();
  459. }
  460. }
  461. catch { Console.WriteLine("线程退出"); }
  462. //s_isClosing = true;
  463. ////if (m_update_display_thread != null)
  464. ////{
  465. //// m_update_display_thread.Join();
  466. ////}
  467. //Communicator.Instance.Uninit();
  468. }
  469. /// <summary>
  470. /// 一键清除所有号牌,车位全部设置空闲,调试用
  471. /// </summary>
  472. /// <param name="sender"></param>
  473. /// <param name="e"></param>
  474. private void btn_clear_Click(object sender, EventArgs e)
  475. {
  476. SendAndReceive(Parkspace_status.EParkspaceEmpty, 9999);
  477. }
  478. }
  479. }