forked from ArduPilot/MissionPlanner
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNetSerialServer.cs
335 lines (284 loc) · 11.5 KB
/
NetSerialServer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
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;
}
}
}