/// <summary> /// The main worker method for the networking thread, TCP method /// </summary> /// <param name="sender">The BackgroundWorker object</param> /// <param name="e">The event args</param> public static void ManageConnections_tcp(object sender, DoWorkEventArgs e) { ConnectionLive = false; //Robot only NetworkPin.Write(ConnectionLive ? GpioPinValue.High : GpioPinValue.Low); while (true) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } //verify stop the timer HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); //setup and bind listener RobotRecieverIPEndPoint = new IPEndPoint(IPAddress.Parse(RobotIPV4Address), RobotRecieverPort); RobotReceiverTCPListener = new TcpListener(RobotRecieverIPEndPoint); RobotReceiverTCPListener.Server.SendTimeout = 5000;//value is miliseconds RobotReceiverTCPListener.Server.ReceiveTimeout = 5000; //set socket before binding! RobotReceiverTCPListener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); RobotReceiverTCPListener.Start();//now it's bound //wait for receiver client to get the ip address of the dashboard IPAddress address = null; bool recieverConnected = false; while (!recieverConnected) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } try { //try to accept the tcp connection and parse the ip address RobotRecieverTCPClient = RobotReceiverTCPListener.AcceptTcpClient(); address = IPAddress.Parse(TCPRecieve(RobotRecieverTCPClient)); recieverConnected = true; } catch (Exception) { //RobotController.RobotStatus = RobotStatus.Exception; //keep trying } } if (address.AddressFamily == AddressFamily.InterNetworkV6) { DashboardIPV6Address = address.ToString(); } else if (address.AddressFamily == AddressFamily.InterNetwork) { DashboardIPV4Address = address.ToString(); } //for now we'er just force using the IPV4 stuff //setup and bind sender to send ack RobotSenderIPEndPoint = new IPEndPoint(IPAddress.Parse(string.IsNullOrWhiteSpace(DashboardIPV6Address) ? DashboardIPV4Address : DashboardIPV6Address), RobotSenderPort); RobotSenderTCPClient = new TcpClient(); RobotSenderTCPClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); RobotSenderTCPClient.Client.SendTimeout = 5000;//value is miliseconds RobotSenderTCPClient.Client.ReceiveTimeout = 5000; bool senderConnected = false; while (!senderConnected) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } try { RobotSenderTCPClient.Connect(RobotSenderIPEndPoint); senderConnected = true; } catch (SocketException) { //keep trying } } RobotSenderTCPStream = RobotSenderTCPClient.GetStream(); //set new timeout settings for the robot receiver if (RobotRecieverTCPClient.Client.ReceiveTimeout != 5000) { RobotRecieverTCPClient.Client.ReceiveTimeout = 5000; } if (RobotRecieverTCPClient.Client.SendTimeout != 5000) { RobotRecieverTCPClient.Client.SendTimeout = 5000; } if (RobotRecieverTCPClient.GetStream().CanTimeout) { if (RobotRecieverTCPClient.GetStream().ReadTimeout != 5000) { RobotRecieverTCPClient.GetStream().ReadTimeout = 5000; } if (RobotRecieverTCPClient.GetStream().WriteTimeout != 5000) { RobotRecieverTCPClient.GetStream().WriteTimeout = 5000; } } //send ack to dashboard if (!TCPSend(RobotSenderTCPStream, "ack")) { continue; } //start to send heartbeats ConnectionLive = true; NetworkPin.Write(ConnectionLive ? GpioPinValue.High : GpioPinValue.Low); NumHeartbeatsSent = 0; HeartbeatTimer.Start(); DiagnosticTimer.Start(); if (RecoveredException != null) { LogNetwork("The network thread just recovered from an exception level event\n" + RecoveredException.ToString(), MessageType.Exception); RecoveredException = null; } //listen for dashboard events string result = null; while (ConnectionLive) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } result = TCPRecieve(RobotRecieverTCPClient); if (string.IsNullOrWhiteSpace(result)) { if (DEBUG_IGNORE_TIMEOUT && DEBUG_TCP_TEST) { Thread.Sleep(1000); continue; } //the dashboard has disocnnected! ConnectionLive = false; NetworkPin.Write(ConnectionLive ? GpioPinValue.High : GpioPinValue.Low); Disconnect(); break; } int messageTypeInt = -1; string messageTypeString = result.Split(',')[0]; if (int.TryParse(messageTypeString, out messageTypeInt)) { MessageType messageType = (MessageType)messageTypeInt; switch (messageType) { case MessageType.Heartbeat: //do nothing break; case MessageType.Control: string controlMessage = result.Substring(messageTypeString.Count() + 1); if (!controlMessage.Equals(ManualControlCommands)) { //assuming thread access is atomic... ManualControlCommands = controlMessage; if (ManualControlCommands.Equals("Start")) { RobotController.ControlStatus = ControlStatus.RequestManual; RobotController.ControllerThread.CancelAsync(); } else if (ManualControlCommands.Equals("Stop")) { RobotController.ControlStatus = ControlStatus.RelaseManual; RobotController.ControllerThread.CancelAsync(); } else if (ManualControlCommands.Split(',')[0].Equals("Shutdown")) { RobotController.Poweroff(TimeSpan.FromSeconds(int.Parse(ManualControlCommands.Split(',')[1]))); } else if (ManualControlCommands.Split(',')[0].Equals("Reboot")) { RobotController.Reboot(TimeSpan.FromSeconds(int.Parse(ManualControlCommands.Split(',')[1]))); } else if (ManualControlCommands.Split(',')[0].Equals("Cancel_Shutdown")) { RobotController.CancelShutdown(); } } break; } } } } }
/// <summary> /// The main worker method for the networking thread, UDP method /// </summary> /// <param name="sender">The BackgroundWorker object</param> /// <param name="e">The event args</param> public static void ManageConnections(object sender, DoWorkEventArgs e) { if (ConnectionLive) { ConnectionLive = false; } NetworkPin.Write(ConnectionLive ? GpioPinValue.High : GpioPinValue.Low); while (true) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } //verify stop the timer HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); //setup and bind listener RobotRecieverIPEndPoint = new IPEndPoint(IPAddress.Parse(RobotIPV4Address), RobotRecieverPort); RobotRecieverUDPClient = new UdpClient(); RobotRecieverUDPClient.Client.SendTimeout = 5000;//value is miliseconds RobotRecieverUDPClient.Client.ReceiveTimeout = 5000; RobotRecieverUDPClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); RobotRecieverUDPClient.Client.Bind(RobotRecieverIPEndPoint); //wait for receiver client to get the ip address of the dashboard bool receivedIP = false; string result = null; while (!receivedIP) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } try { result = Encoding.UTF8.GetString(RobotRecieverUDPClient.Receive(ref RobotRecieverIPEndPoint)); receivedIP = true; } catch (Exception) { } } //parse the ip address sent by the dashboard IPAddress address; try { address = IPAddress.Parse(result); } catch (Exception) { RobotController.SetRobotStatus(RobotStatus.Exception); e.Cancel = true; return; } if (address.AddressFamily == AddressFamily.InterNetworkV6) { DashboardIPV6Address = address.ToString(); } else if (address.AddressFamily == AddressFamily.InterNetwork) { DashboardIPV4Address = address.ToString(); } //setup and connect sender RobotSenderIPEndPoint = new IPEndPoint(IPAddress.Parse(string.IsNullOrWhiteSpace(DashboardIPV6Address) ? DashboardIPV4Address : DashboardIPV6Address), RobotSenderPort); RobotSenderUDPClient = new UdpClient(); RobotSenderUDPClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); RobotSenderUDPClient.Client.SendTimeout = 5000;//value is miliseconds RobotSenderUDPClient.Client.ReceiveTimeout = 5000; bool senderConnected = false; while (!senderConnected) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } try { RobotSenderUDPClient.Connect(RobotSenderIPEndPoint); senderConnected = true; } catch (Exception) { } } //send ack RobotSenderUDPClient.Send(Encoding.UTF8.GetBytes("ack"), Encoding.UTF8.GetByteCount("ack")); //start to send heartbeats NumHeartbeatsSent = 0; HeartbeatTimer.Start(); DiagnosticTimer.Start(); ConnectionLive = true; NetworkPin.Write(ConnectionLive ? GpioPinValue.High : GpioPinValue.Low); if (RecoveredException != null) { LogNetwork("The network thread just recovered from an exception level event\n" + RecoveredException.ToString(), MessageType.Exception); RecoveredException = null; } //listen for dashboard events while (ConnectionLive) { if (ConnectionManager.CancellationPending) { e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } try { result = Encoding.UTF8.GetString(RobotRecieverUDPClient.Receive(ref RobotRecieverIPEndPoint)); } catch (SocketException) { if (DEBUG_IGNORE_TIMEOUT && !DEBUG_TCP_TEST) { continue; } //the dashboard has disocnnected! ConnectionLive = false; NetworkPin.Write(ConnectionLive ? GpioPinValue.High : GpioPinValue.Low); e.Cancel = true; HeartbeatTimer.Stop(); DiagnosticTimer.Stop(); return; } int messageTypeInt = -1; string messageTypeString = result.Split(',')[0]; if (int.TryParse(messageTypeString, out messageTypeInt)) { MessageType messageType = (MessageType)messageTypeInt; switch (messageType) { case MessageType.Heartbeat: //do nothing break; case MessageType.Control: string controlMessage = result.Substring(messageTypeString.Count() + 1); if (!controlMessage.Equals(ManualControlCommands)) { //assuming thread access is atomic... ManualControlCommands = controlMessage; if (ManualControlCommands.Equals("Start")) { RobotController.ControlStatus = ControlStatus.RequestManual; RobotController.ControllerThread.CancelAsync(); } else if (ManualControlCommands.Equals("Stop")) { RobotController.ControlStatus = ControlStatus.RelaseManual; RobotController.ControllerThread.CancelAsync(); } else if (ManualControlCommands.Split(',')[0].Equals("Shutdown")) { RobotController.Poweroff(TimeSpan.FromSeconds(int.Parse(ManualControlCommands.Split(',')[1]))); } else if (ManualControlCommands.Split(',')[0].Equals("Reboot")) { RobotController.Reboot(TimeSpan.FromSeconds(int.Parse(ManualControlCommands.Split(',')[1]))); } else if (ManualControlCommands.Split(',')[0].Equals("Cancel_Shutdown")) { RobotController.CancelShutdown(); } } break; } } } } }