ardupilot/Tools/ArdupilotMegaPlanner/NetSerialServer.cs

336 lines
12 KiB
C#
Raw Normal View History

2011-09-08 22:31:32 -03:00
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading;
using System.Net.NetworkInformation;
// SerialPort > CommsServer > NetSerial > Mavlink > Application
namespace SerialProxy
{
public class CommsServer
{
SerialPort comPort = new SerialPort();
public int runthreads = 0;
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public List<Socket> clients = new List<Socket>();
public int tcpport = 59001;
bool doDTR = false;
Thread t11;
Thread t12;
bool firstconnect = false;
public void toggleDTR(bool doit)
{
doDTR = doit;
}
public void toggleDTRnow()
{
comPort.DtrEnable = !doDTR;
System.Threading.Thread.Sleep(100);
comPort.DtrEnable = doDTR;
}
// from http://stackoverflow.com/questions/570098/in-c-how-to-check-if-a-tcp-port-is-available
public static bool CheckAvailableServerPort(int port)
{
bool isAvailable = true;
// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form. We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
try
{
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();
foreach (IPEndPoint endpoint in tcpConnInfoArray)
{
if (endpoint.Port == port)
{
isAvailable = false;
break;
}
}
}
catch { return true; } // this fails on unix... so we just accept
return isAvailable;
}
~CommsServer()
{
this.shutdown();
Console.WriteLine("CommsServer Destroyed!!!");
}
public CommsServer(int portno)
{
tcpport = portno;
}
public void Start(string comport,int baudrate)
{
Console.WriteLine("CommsServer Init");
if (!comPort.IsOpen)
{
Console.WriteLine("CommsServer set com setting");
comPort.BaudRate = baudrate;
comPort.DataBits = 8;
comPort.StopBits = StopBits.One;
comPort.Parity = Parity.None;
try
{
comPort.PortName = comport;
runthreads = 1;
Console.WriteLine("CommsServer threads");
t11 = new Thread(delegate() { try { mainloop(); } catch (Exception e) { Console.WriteLine("Serial Error " + e.ToString()); } }); // process serial data and send to clients
t11.Name = "CommsServer Serial";
t11.IsBackground = true;
t11.Start();
ArdupilotMega.MainV2.threads.Add(t11);
t12 = new Thread(delegate() { try { listernforclients(); } catch (Exception e) { Console.WriteLine("Socket Error " + e.ToString()); } }); // wait for tcp connections
t12.Name = "CommsServer Socket";
t12.IsBackground = true;
t12.Start();
ArdupilotMega.MainV2.threads.Add(t12);
Console.WriteLine("CommsServer set netserial.port");
NetSerial.port = this;
int timeout = 0;
while (comPort.IsOpen == false || listener.IsBound == false)
{
if (timeout > 200) { // timeout after 4 sec 200 * 20
this.shutdown();
throw new Exception("Timeout connecting port, Bad Settings or port in use");
}
System.Threading.Thread.Sleep(20); // allow threads to start
timeout++;
}
}
catch (Exception ex)
{
this.shutdown();
throw new Exception("CommServer Fail: " + ex.Message + "\n");
}
}
Console.WriteLine("CommsServer Started");
}
public void shutdown()
{
Console.WriteLine("CommsServer Shutdown");
runthreads = 0;
try
{
listener.Close();
}
catch { }
try
{
if (comPort != null && comPort.IsOpen)
comPort.Close();
comPort = null;
}
catch { }
try
{
List<Socket> clientscopy = new List<Socket>(clients);
foreach (Socket client in clientscopy)
{
try
{
client.Close();
}
catch (Exception)
{
}
}
clients.Clear();
}
catch { shutdown(); }
System.Threading.Thread.Sleep(500);
NetSerial.port = null;
}
void listernforclients()
{
Console.WriteLine("CommsServer listener");
IPEndPoint ipep = new IPEndPoint(IPAddress.Loopback, tcpport);
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
listener.Bind(ipep);
listener.Listen(10);
// Enter the listening loop.
while (runthreads == 1)
{
try
{
Console.WriteLine("CommsServer listern wait");
// Perform a blocking call to accept requests.
Socket client = listener.Accept();
Console.WriteLine("CommsServer listern accept");
comPort.DtrEnable = doDTR;
clients.Add(client);
System.Threading.Thread.Sleep(100);
firstconnect = true;
}
catch (Exception e) { Console.WriteLine("CommServer listener error : "+ e.Message); } // cant exit
}
listener.Close();
shutdown();
}
void mainloop()
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
List<Socket> clientscopy = new List<Socket>(clients);
byte[] data = new byte[1024 * 4];
try
{
comPort.ReadBufferSize = 100 * 1024;
comPort.Open();
}
catch (Exception e) { MessageBox.Show("CommsServer Error opening Com Port " + e.Message); this.shutdown(); return; }
Console.WriteLine("CommsServer comPort Opened");
while (runthreads == 1)
{
try
{
if (NetSerial.port == null) // make sure we always keep track of this
{
NetSerial.port = this;
}
if (comPort == null || !comPort.IsOpen)
{
Console.WriteLine("CommServer error : Closing");
runthreads = 0;
this.shutdown();
throw new Exception("CommServer : Comport Closed or null");
//return;
}
// do serial
while (comPort.BytesToRead > 0)
{
//Console.Write("BTR " + comPort.BytesToRead + "\r");
byte[] buffer = new byte[comPort.BytesToRead];
comPort.Read(buffer, 0, buffer.Length);
clientscopy = new List<Socket>(clients);
foreach (Socket client in clientscopy)
{
try
{
client.Send(buffer, 0, buffer.Length,SocketFlags.None);
}
catch
{
Console.WriteLine("CommsServer closing client ");
if (client != null)
client.Close();
clients.Remove(client);
}
}
System.Threading.Thread.Sleep(2); // this gives tme to hopefully be outside the main apm loop
}
// do tcp
if (clients.Count == 0 && firstconnect)
{
shutdown();
return;
}
// 57600 / 8 = 1000 / 7200 = 0.1388888888888889 ms per char
// 20ms per cycle = 144 bytes per cycle - avg 2500 bps
// System.Threading.Thread.Sleep(2);
clientscopy = new List<Socket>(clients);
foreach (Socket client in clientscopy)
{
//Console.WriteLine("NS BTR " + client.DataAvailable);
//byte[] temp = encoding.GetBytes(data);
if (client.Available != 0)
{
try
{
int size = client.Receive(data, 0, data.Length,SocketFlags.None);
//Console.WriteLine("TCP to Serial {0}", size);
comPort.Write(data, 0, size);
}
catch
{
Console.WriteLine("CommsServer closing client ");
if (client != null)
client.Close();
clients.Remove(client);
}
} // if
if (SocketConnected(client) == false)
{
Console.WriteLine("CommsServer closing client - Remote close");
if (client != null)
client.Close();
clients.Remove(client);
}
} // foreach
System.Threading.Thread.Sleep(1);
} // try
catch (Exception e) { Console.WriteLine("CommServer serial error : " + e.ToString()); } // cant exit
} // while
}
bool SocketConnected(Socket s)
{
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if (part1 & part2)
{//connection is closed
return false;
}
return true;
}
}
}