fcdfc80f033384b6fc72305c0037c320b2a30417.svn-base 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. //using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.IO.Ports;
  10. using Microsoft.Win32;
  11. namespace IControls_FireManager
  12. {
  13. public partial class EmergencyRepeater : Form
  14. {
  15. // 시리얼포트 3종
  16. public _Serial Receiver1_Serial = new _Serial();
  17. public _Serial Receiver2_Serial = new _Serial();
  18. public _Serial Emergency_Serial = new _Serial();
  19. // 큐처리 기간 ms
  20. public int TIME_QUEUE = 60;
  21. // 프로그램 자동실행
  22. public RegistryKey rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
  23. public bool init = false;
  24. public EmergencyRepeater()
  25. {
  26. InitializeComponent();
  27. // 공통 콤보박스 셋팅
  28. UI_Combobox_Initialize();
  29. // 파일을 읽고 콤보박스에 값이 있다면 셋팅하고 없다면, 무시한다.
  30. INI_Read();
  31. // 레지스트리 값 읽기
  32. Reg_Read();
  33. // 이벤트 핸들러 등록
  34. _Event.DebugView_SendMessage_Event += new _Event.DebugView_SendMessage_Handler(_Event_DebugView_SendMessage_Event);
  35. // 하지만 포트정보가 있다면 포트를 생성해본다, 성공이라면 시나리오대로 동작
  36. // 하지만 포트정보가 있다면 포트를 생성해본다, 성공이라면 시나리오대로 동작
  37. if (Port_Test() == true)
  38. {
  39. Start();
  40. this.button_Start.Text = "종료";
  41. }
  42. // 폼닫기 이벤트 핸들러 등록 (이벤트 핸들러 해제용)
  43. this.FormClosed += new FormClosedEventHandler(CreateForm_FormClosed);
  44. }
  45. public void CreateForm_FormClosed(object sender, FormClosedEventArgs e)
  46. {
  47. // 스레드 종료
  48. Application.ExitThread();
  49. // 프로세스 종료
  50. Application.Exit();
  51. // 프로세스가 남아있다면 최종 종료 (2개의 프로젝트가 공존하고 Application.ProductName 값이 2개다
  52. // 즉 IControls_Security 프로세스가 2개 공존 하므로 적용불가
  53. System.Diagnostics.Process[] mProcess = System.Diagnostics.Process.GetProcessesByName(Application.ProductName);
  54. foreach (System.Diagnostics.Process p in mProcess)
  55. p.Kill();
  56. // 최종 정리 (보완코드 : 크로스 스레드 문제 발생 여지가 있으므로 사용주의)
  57. Environment.Exit(0);
  58. }
  59. // 로그
  60. public delegate void DebugEditBox_SetTextCallback(TextBox textbox, string Data);
  61. public void Delegate_Set_Log(TextBox textbox, string Data)
  62. {
  63. if (textbox.InvokeRequired)
  64. {
  65. DebugEditBox_SetTextCallback d = new DebugEditBox_SetTextCallback(Delegate_Set_Log);
  66. textbox.Invoke(d, new object[] { textbox, Data });
  67. }
  68. else
  69. {
  70. textbox.AppendText(DateTime.Now.ToString("HH:mm:ss") + " " + Data + "\r\n");
  71. }
  72. }
  73. public void _Event_DebugView_SendMessage_Event(PortInfo PortName, string Data)
  74. {
  75. switch (PortName)
  76. {
  77. case PortInfo.Receiver1:
  78. if (this.textBox_Receiver1.Text.Length > 50000) this.textBox_Receiver1.Clear();
  79. Delegate_Set_Log(this.textBox_Receiver1, Data);
  80. break;
  81. case PortInfo.Receiver2:
  82. if (this.textBox_Receiver2.Text.Length > 50000) this.textBox_Receiver2.Clear();
  83. Delegate_Set_Log(this.textBox_Receiver2, Data);
  84. break;
  85. case PortInfo.Emergency:
  86. if (this.textBox_Emergency.Text.Length > 50000) this.textBox_Emergency.Clear();
  87. Delegate_Set_Log(this.textBox_Emergency, Data);
  88. break;
  89. }
  90. }
  91. //
  92. // UI 초기화
  93. //
  94. public void UI_Combobox_Initialize()
  95. {
  96. this.comboBox_Baudrate.Items.Add("2400");
  97. this.comboBox_Baudrate.Items.Add("4800");
  98. this.comboBox_Baudrate.Items.Add("9600");
  99. this.comboBox_Baudrate.Items.Add("19200");
  100. this.comboBox_Baudrate.Items.Add("38400");
  101. this.comboBox_Parity.Items.Add(Parity.None);
  102. this.comboBox_Parity.Items.Add(Parity.Even);
  103. this.comboBox_Parity.Items.Add(Parity.Odd);
  104. this.comboBox_Parity.Items.Add(Parity.Space);
  105. this.comboBox_Databit.Items.Add(8);
  106. this.comboBox_Databit.Items.Add(7);
  107. this.comboBox_Stopbit.Items.Add(StopBits.One);
  108. this.comboBox_Stopbit.Items.Add(StopBits.None);
  109. }
  110. //
  111. // 레지스트리값 읽기
  112. //
  113. public void Reg_Read()
  114. {
  115. init = true;
  116. if (rkApp.GetValue("IControls_EmergencyRepeater") == null)
  117. this.checkBox_Registry.Checked = false;
  118. else
  119. this.checkBox_Registry.Checked = true;
  120. init = false;
  121. }
  122. //
  123. // Ini 파일 가져오기
  124. //
  125. public void INI_Read()
  126. {
  127. // Common
  128. string BaudRate = _Ini.Read_Ini("COMMON", "BaudRate", 512, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  129. string Parity = _Ini.Read_Ini("COMMON", "Parity", 512, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  130. string DataBit = _Ini.Read_Ini("COMMON", "DataBit", 512, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  131. string StopBit = _Ini.Read_Ini("COMMON", "StopBit", 512, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  132. if (BaudRate != null && BaudRate.Length != 0) this.comboBox_Baudrate.Text = BaudRate;
  133. if (Parity != null && Parity.Length != 0) this.comboBox_Parity.Text = Parity;
  134. if (DataBit != null && DataBit.Length != 0) this.comboBox_Databit.Text = DataBit;
  135. if (StopBit != null && StopBit.Length != 0) this.comboBox_Stopbit.Text = StopBit;
  136. // Port
  137. string Receiver1 = _Ini.Read_Ini("Receiver1", "Port", 512, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  138. string Receiver2 = _Ini.Read_Ini("Receiver2", "Port", 512, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  139. string Emergency = _Ini.Read_Ini("Emergency", "Port", 512, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  140. if (Receiver1 != null && Receiver1.Length != 0) this.comboBox_Port_Receiver1.Text = Receiver1;
  141. if (Receiver2 != null && Receiver2.Length != 0) this.comboBox_Port_Receiver2.Text = Receiver2;
  142. if (Emergency != null && Emergency.Length != 0) this.comboBox_Port_Emergency.Text = Emergency;
  143. }
  144. //
  145. // Ini 파일 저장하기
  146. //
  147. private void button_Save_Click(object sender, EventArgs e)
  148. {
  149. try
  150. {
  151. // Common
  152. _Ini.Write_Ini("COMMON", "BaudRate", this.comboBox_Baudrate.Text, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  153. _Ini.Write_Ini("COMMON", "Parity", this.comboBox_Parity.Text, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  154. _Ini.Write_Ini("COMMON", "DataBit", this.comboBox_Databit.Text, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  155. _Ini.Write_Ini("COMMON", "StopBit", this.comboBox_Stopbit.Text, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  156. // Port
  157. _Ini.Write_Ini("Receiver1", "Port", this.comboBox_Port_Receiver1.Text, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  158. _Ini.Write_Ini("Receiver2", "Port", this.comboBox_Port_Receiver2.Text, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  159. _Ini.Write_Ini("Emergency", "Port", this.comboBox_Port_Emergency.Text, Environment.CurrentDirectory.ToString() + "\\" + "EmergencyRepeater.ini");
  160. MessageBox.Show("저장 성공");
  161. }
  162. catch
  163. {
  164. MessageBox.Show("저장 실패");
  165. }
  166. }
  167. //
  168. // 현재 포트 정보 가져오기
  169. //
  170. private void comboBox_Port_Receiver1_DropDown(object sender, EventArgs e)
  171. {
  172. comboBox_Port_Receiver1.Items.Clear();
  173. string[] ports = SerialPort.GetPortNames();
  174. foreach (string port in ports)
  175. comboBox_Port_Receiver1.Items.Add(port);
  176. }
  177. private void comboBox_Port_Receiver2_DropDown(object sender, EventArgs e)
  178. {
  179. comboBox_Port_Receiver2.Items.Clear();
  180. string[] ports = SerialPort.GetPortNames();
  181. foreach (string port in ports)
  182. comboBox_Port_Receiver2.Items.Add(port);
  183. }
  184. private void comboBox_Port_Emergency_DropDown(object sender, EventArgs e)
  185. {
  186. comboBox_Port_Emergency.Items.Clear();
  187. string[] ports = SerialPort.GetPortNames();
  188. foreach (string port in ports)
  189. comboBox_Port_Emergency.Items.Add(port);
  190. }
  191. //
  192. // 현재값 셋팅
  193. //
  194. private void button_Receiver1_Click(object sender, EventArgs e)
  195. {
  196. if(Port_Test_Receiver1()==true)
  197. _Event.DebugView_SendMessage_Write(PortInfo.Receiver1, "접속 성공");
  198. else
  199. _Event.DebugView_SendMessage_Write(PortInfo.Receiver1, "접속 실패");
  200. }
  201. private void button_Receiver2_Click(object sender, EventArgs e)
  202. {
  203. if (Port_Test_Receiver2() == true)
  204. _Event.DebugView_SendMessage_Write(PortInfo.Receiver2, "접속 성공");
  205. else
  206. _Event.DebugView_SendMessage_Write(PortInfo.Receiver2, "접속 실패");
  207. }
  208. private void button_Emergency_Click(object sender, EventArgs e)
  209. {
  210. if (Port_Test_Emergency() == true)
  211. _Event.DebugView_SendMessage_Write(PortInfo.Emergency, "접속 성공");
  212. else
  213. _Event.DebugView_SendMessage_Write(PortInfo.Emergency, "접속 실패");
  214. }
  215. //
  216. // 포트 접속가능한지 테스트
  217. //
  218. private bool Port_Test()
  219. {
  220. string result = null;
  221. //return true; // temp
  222. if (Port_Test_Receiver1() == false) result = result + "Receiver1 ";
  223. if (Port_Test_Receiver2() == false) result = result + "Receiver2 ";
  224. if (Port_Test_Emergency() == false) result = result + "Emergency ";
  225. if (result != null)
  226. {
  227. MessageBox.Show(result + " 포트 접속이 안됩니다");
  228. return false;
  229. }
  230. else
  231. {
  232. return true;
  233. }
  234. }
  235. private bool Port_Test_Receiver1()
  236. {
  237. if (this.comboBox_Port_Receiver1.Text == null || this.comboBox_Port_Receiver1.Text.Length == 0)
  238. return false;
  239. else
  240. {
  241. if (Serial_Test(Receiver1_Serial, this.comboBox_Port_Receiver1.Text, Int32.Parse(this.comboBox_Baudrate.Text), Get_Enum_Parity(this.comboBox_Parity.Text),
  242. Int32.Parse(this.comboBox_Databit.Text), Get_Enum_StopBits(this.comboBox_Stopbit.Text), PortInfo.Receiver1) == true)
  243. return true;
  244. else
  245. return false;
  246. }
  247. }
  248. private bool Port_Test_Receiver2()
  249. {
  250. if (this.comboBox_Port_Receiver2.Text == null || this.comboBox_Port_Receiver2.Text.Length == 0)
  251. return false;
  252. else
  253. {
  254. if (Serial_Test(Receiver2_Serial, this.comboBox_Port_Receiver2.Text, Int32.Parse(this.comboBox_Baudrate.Text), Get_Enum_Parity(this.comboBox_Parity.Text),
  255. Int32.Parse(this.comboBox_Databit.Text), Get_Enum_StopBits(this.comboBox_Stopbit.Text), PortInfo.Receiver2) == true)
  256. return true;
  257. else
  258. return false;
  259. }
  260. }
  261. private bool Port_Test_Emergency()
  262. {
  263. if (this.comboBox_Port_Emergency.Text == null || this.comboBox_Port_Emergency.Text.Length == 0)
  264. return false;
  265. else
  266. {
  267. if (Serial_Test(Emergency_Serial, this.comboBox_Port_Emergency.Text, Int32.Parse(this.comboBox_Baudrate.Text), Get_Enum_Parity(this.comboBox_Parity.Text),
  268. Int32.Parse(this.comboBox_Databit.Text), Get_Enum_StopBits(this.comboBox_Stopbit.Text), PortInfo.Emergency) == true)
  269. return true;
  270. else
  271. return false;
  272. }
  273. }
  274. private Parity Get_Enum_Parity(string Data)
  275. {
  276. if (Data == Parity.None.ToString()) return Parity.None;
  277. else if (Data == Parity.Even.ToString()) return Parity.Even;
  278. else if (Data == Parity.Odd.ToString()) return Parity.Odd;
  279. else if (Data == Parity.Space.ToString()) return Parity.Space;
  280. else return Parity.None;
  281. }
  282. private StopBits Get_Enum_StopBits(string Data)
  283. {
  284. if (Data == StopBits.One.ToString()) return StopBits.One;
  285. else if (Data == StopBits.None.ToString()) return StopBits.None;
  286. else return StopBits.One;
  287. }
  288. private bool Serial_Test(_Serial serial, string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, PortInfo info)
  289. {
  290. try
  291. {
  292. if (serial.Serial_Create(portName, baudRate, parity, dataBits, stopBits, info) == true)
  293. return true;
  294. else
  295. return false;
  296. }
  297. catch
  298. {
  299. //System.Windows.Forms.MessageBox.Show(portName + e.ToString());
  300. return false;
  301. }
  302. }
  303. // 시작버튼
  304. private void button_Start_Click(object sender, EventArgs e)
  305. {
  306. if (this.button_Start.Text == "시작")
  307. {
  308. // 하지만 포트정보가 있다면 포트를 생성해본다, 성공이라면 시나리오대로 동작
  309. if (Port_Test() == true)
  310. {
  311. Start();
  312. this.button_Start.Text = "종료";
  313. }
  314. }
  315. else
  316. {
  317. Receiver1_Serial.Serial_Dispose();
  318. Receiver2_Serial.Serial_Dispose();
  319. Emergency_Serial.Serial_Dispose();
  320. this.button_Start.Text = "시작";
  321. }
  322. }
  323. // 포트간 중계 시작
  324. private void Start()
  325. {
  326. DeleteTimer();
  327. _Timer_WindowBase.Create("Emergency_Rx_Queue_Security", TIME_QUEUE, Emergency_Rx_Queue_Security_Tick, true); // 수신큐 60 msec 마다 큐에 있는 값을 꺼냄
  328. _Timer_WindowBase.Create("Receiver_Tx_Queue_Security", TIME_QUEUE, Receiver_Tx_Queue_Security_Tick, true); // 발신큐 60 msec 마다 큐에 있는 값을 꺼냄
  329. _Timer_WindowBase.Create("Receiver_Rx_Queue_Security", TIME_QUEUE, Receiver_Rx_Queue_Security_Tick, true); // 수신큐 60 msec 마다 큐에 있는 값을 꺼냄
  330. _Timer_WindowBase.Create("Emergency_Tx_Queue_Security", 300, Emergency_Tx_Queue_Security_Tick, true); // 발신큐 60 msec 마다 큐에 있는 값을 꺼냄
  331. }
  332. private void DeleteTimer()
  333. {
  334. _Timer_WindowBase.Delete("Emergency_Rx_Queue_Security");
  335. _Timer_WindowBase.Delete("Receiver_Tx_Queue_Security");
  336. _Timer_WindowBase.Delete("Receiver_Rx_Queue_Security");
  337. _Timer_WindowBase.Delete("Emergency_Tx_Queue_Security");
  338. }
  339. // 비상방송 -> REPEATER
  340. private void Emergency_Rx_Queue_Security_Tick(object sender, EventArgs e)
  341. {
  342. try
  343. {
  344. // 큐가 비워져 있다면 실행안함
  345. if (Emergency_Serial.RxQueue.Count != 0)
  346. {
  347. lock (Emergency_Serial.CS_RxQueue)
  348. {
  349. // 큐에서 가져온다
  350. byte[] GetData =(byte[])Emergency_Serial.RxQueue.Peek();
  351. Receiver1_Serial.TxQueue_ADD(GetData);
  352. Receiver2_Serial.TxQueue_ADD(GetData);
  353. // 큐에서 제거
  354. if (Emergency_Serial.RxQueue.Count != 0)
  355. Emergency_Serial.RxQueue.Dequeue();
  356. }
  357. }
  358. }
  359. catch
  360. { Emergency_Serial.RxQueue.Clear(); }
  361. }
  362. // REPEATER -> 수신기
  363. private void Receiver_Tx_Queue_Security_Tick(object sender, EventArgs e)
  364. {
  365. try
  366. {
  367. // 큐가 비워져 있다면 실행안함
  368. if (Receiver1_Serial.TxQueue.Count != 0)
  369. {
  370. lock (Receiver1_Serial.CS_TxQueue)
  371. {
  372. // 큐에서 가져온다
  373. byte[] GetData = (byte[])Receiver1_Serial.TxQueue.Peek();
  374. Receiver1_Serial.Serial_Transmit(GetData);
  375. // 큐에서 제거
  376. if (Receiver1_Serial.TxQueue.Count != 0)
  377. Receiver1_Serial.TxQueue.Dequeue();
  378. }
  379. }
  380. // 큐가 비워져 있다면 실행안함
  381. if (Receiver2_Serial.TxQueue.Count != 0)
  382. {
  383. lock (Receiver2_Serial.CS_TxQueue)
  384. {
  385. // 큐에서 가져온다
  386. byte[] GetData = (byte[])Receiver2_Serial.TxQueue.Peek();
  387. Receiver2_Serial.Serial_Transmit(GetData);
  388. // 큐에서 제거
  389. if (Receiver2_Serial.TxQueue.Count != 0)
  390. Receiver2_Serial.TxQueue.Dequeue();
  391. }
  392. }
  393. }
  394. catch
  395. { Receiver1_Serial.TxQueue.Clear(); Receiver2_Serial.TxQueue.Clear(); }
  396. }
  397. // 수신기 -> REPEATER
  398. private void Receiver_Rx_Queue_Security_Tick(object sender, EventArgs e)
  399. {
  400. // 큐가 비워져 있다면 실행안함
  401. if (Receiver1_Serial.RxQueue.Count != 0)
  402. {
  403. lock (Receiver1_Serial.CS_RxQueue)
  404. {
  405. // 큐에서 가져온다
  406. byte[] GetData = (byte[])Receiver1_Serial.RxQueue.Peek();
  407. Emergency_Serial.TxQueue_ADD(GetData);
  408. // 큐에서 제거
  409. if (Receiver1_Serial.RxQueue.Count != 0)
  410. Receiver1_Serial.RxQueue.Dequeue();
  411. }
  412. }
  413. // 큐가 비워져 있다면 실행안함
  414. if (Receiver2_Serial.RxQueue.Count != 0)
  415. {
  416. lock (Receiver2_Serial.CS_RxQueue)
  417. {
  418. // 큐에서 가져온다
  419. byte[] GetData = (byte[])Receiver2_Serial.RxQueue.Peek();
  420. Emergency_Serial.TxQueue_ADD(GetData);
  421. // 큐에서 제거
  422. if (Receiver2_Serial.RxQueue.Count != 0)
  423. Receiver2_Serial.RxQueue.Dequeue();
  424. }
  425. }
  426. }
  427. // REPEATER -> 비상방송
  428. private void Emergency_Tx_Queue_Security_Tick(object sender, EventArgs e)
  429. {
  430. try
  431. {
  432. // 큐가 비워져 있다면 실행안함
  433. if (Emergency_Serial.TxQueue.Count != 0)
  434. {
  435. lock (Emergency_Serial.CS_TxQueue)
  436. {
  437. // 큐에서 가져온다
  438. byte[] GetData = (byte[])Emergency_Serial.TxQueue.Peek();
  439. Emergency_Serial.Serial_Transmit(GetData);
  440. // 큐에서 제거
  441. if (Emergency_Serial.TxQueue.Count != 0)
  442. Emergency_Serial.TxQueue.Dequeue();
  443. }
  444. }
  445. }
  446. catch
  447. { Emergency_Serial.TxQueue.Clear(); }
  448. }
  449. // 레지스트리값
  450. private void checkBox_Registry_CheckedChanged(object sender, EventArgs e)
  451. {
  452. if (init == true) return;
  453. try
  454. {
  455. if (this.checkBox_Registry.Checked == true)
  456. {
  457. rkApp.DeleteValue("IControls_EmergencyRepeater", false);
  458. rkApp.SetValue("IControls_EmergencyRepeater", Environment.CurrentDirectory.ToString() + "\\" + "IControls_EmergencyRepeater.lnk");
  459. MessageBox.Show("등록하였습니다!", "확인", MessageBoxButtons.OK);
  460. }
  461. else
  462. {
  463. rkApp.DeleteValue("IControls_EmergencyRepeater", false);
  464. MessageBox.Show("제거하였습니다!", "확인", MessageBoxButtons.OK);
  465. }
  466. }
  467. catch
  468. {
  469. }
  470. }
  471. private void button_Receiver1_Clear_Click(object sender, EventArgs e)
  472. {
  473. this.textBox_Receiver1.Clear();
  474. }
  475. private void button_Receiver2_Clear_Click(object sender, EventArgs e)
  476. {
  477. this.textBox_Receiver2.Clear();
  478. }
  479. private void button_Emergency_Clear_Click(object sender, EventArgs e)
  480. {
  481. this.textBox_Emergency.Clear();
  482. }
  483. }
  484. public enum PortInfo
  485. {
  486. Receiver1, Receiver2, Emergency
  487. }
  488. }