mirror of https://github.com/ArduPilot/ardupilot
336 lines
12 KiB
C#
336 lines
12 KiB
C#
|
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;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|