You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
335 lines
12 KiB
335 lines
12 KiB
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; |
|
} |
|
|
|
} |
|
}
|
|
|