添加的文件
This commit is contained in:
parent
3362a1b47c
commit
d4a9dc5bf3
512
Plane.FormationCreator/Util/CommsSerialPort.cs
Normal file
512
Plane.FormationCreator/Util/CommsSerialPort.cs
Normal file
@ -0,0 +1,512 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO.Ports;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System.Threading;
|
||||
|
||||
namespace Plane.Util
|
||||
{
|
||||
|
||||
public class SerialPort : System.IO.Ports.SerialPort, ICommsSerial
|
||||
{
|
||||
static object locker = new object();
|
||||
|
||||
public new bool DtrEnable { get { return base.DtrEnable; } set { if (base.DtrEnable == value) return; if (ispx4(base.PortName)) return; base.DtrEnable = value; } }
|
||||
public new bool RtsEnable { get { return base.RtsEnable; } set { if (base.RtsEnable == value) return; if (ispx4(base.PortName)) return; base.RtsEnable = value; } }
|
||||
/*
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
Type mytype = typeof(System.IO.Ports.SerialPort);
|
||||
FieldInfo field = mytype.GetField("internalSerialStream", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
Stream stream = (Stream)field.GetValue(this);
|
||||
|
||||
if (stream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
catch (Exception ex) { Console.WriteLine("1 " + ex.ToString()); }
|
||||
stream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { Console.WriteLine("2 " + ex.ToString()); }
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
catch (Exception ex) { Console.WriteLine("3 " + ex.ToString()); }
|
||||
}
|
||||
*/
|
||||
public new void Open()
|
||||
{
|
||||
// 500ms write timeout - win32 api default
|
||||
this.WriteTimeout = 500;
|
||||
|
||||
if (base.IsOpen)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// this causes element not found with bluetooth devices.
|
||||
if (BaudRate > 115200)
|
||||
{
|
||||
Console.WriteLine("Doing SerialPortFixer");
|
||||
SerialPortFixer.Execute(this.PortName);
|
||||
Console.WriteLine("Done SerialPortFixer");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
|
||||
|
||||
if (PortName.StartsWith("/"))
|
||||
if (!File.Exists(PortName))
|
||||
throw new Exception("No such device");
|
||||
|
||||
try
|
||||
{
|
||||
base.Open();
|
||||
}
|
||||
catch {
|
||||
try { Close(); }
|
||||
catch { }
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public new void Close()
|
||||
{
|
||||
base.Close();
|
||||
}
|
||||
|
||||
public void toggleDTR()
|
||||
{
|
||||
if (ispx4(this.PortName))
|
||||
{
|
||||
Console.WriteLine("PX4 - no DTR");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool open = this.IsOpen;
|
||||
Console.WriteLine("toggleDTR " + this.IsOpen);
|
||||
try
|
||||
{
|
||||
if (!open)
|
||||
this.Open();
|
||||
}
|
||||
catch { }
|
||||
|
||||
|
||||
base.DtrEnable = false;
|
||||
base.RtsEnable = false;
|
||||
|
||||
System.Threading.Thread.Sleep(50);
|
||||
|
||||
base.DtrEnable = true;
|
||||
base.RtsEnable = true;
|
||||
|
||||
System.Threading.Thread.Sleep(50);
|
||||
|
||||
try
|
||||
{
|
||||
if (!open)
|
||||
this.Close();
|
||||
}
|
||||
catch { }
|
||||
Console.WriteLine("toggleDTR done " + this.IsOpen);
|
||||
}
|
||||
|
||||
public new static string[] GetPortNames()
|
||||
{
|
||||
// prevent hammering
|
||||
lock (locker)
|
||||
{
|
||||
List<string> allPorts = new List<string>();
|
||||
|
||||
if (Directory.Exists("/dev/"))
|
||||
{
|
||||
// cleanup now
|
||||
GC.Collect();
|
||||
// mono is failing in here on linux "too many open files"
|
||||
try
|
||||
{
|
||||
if (Directory.Exists("/dev/serial/by-id/"))
|
||||
allPorts.AddRange(Directory.GetFiles("/dev/serial/by-id/", "*"));
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
allPorts.AddRange(Directory.GetFiles("/dev/", "ttyACM*"));
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
allPorts.AddRange(Directory.GetFiles("/dev/", "ttyUSB*"));
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
allPorts.AddRange(Directory.GetFiles("/dev/", "rfcomm*"));
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
allPorts.AddRange(Directory.GetFiles("/dev/", "*usb*"));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
string[] ports = null;
|
||||
|
||||
try
|
||||
{
|
||||
ports = System.IO.Ports.SerialPort.GetPortNames()
|
||||
.Select(p => p.TrimEnd())
|
||||
.Select(FixBlueToothPortNameBug)
|
||||
.ToArray();
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (ports != null)
|
||||
allPorts.AddRange(ports);
|
||||
|
||||
return allPorts.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<string, string> comportnamecache = new Dictionary<string, string>();
|
||||
|
||||
public static string GetNiceName(string port)
|
||||
{
|
||||
// make sure we are exclusive
|
||||
lock (locker)
|
||||
{
|
||||
|
||||
portnamenice = "";
|
||||
|
||||
if (comportnamecache.ContainsKey(port))
|
||||
{
|
||||
return comportnamecache[port];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CallWithTimeout(new Action<string>(GetName), 1000, port);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
comportnamecache[port] = portnamenice;
|
||||
|
||||
return (string)portnamenice.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
static string portnamenice = "";
|
||||
|
||||
static void GetName(string port)
|
||||
{
|
||||
try
|
||||
{
|
||||
/*
|
||||
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_SerialPort"); // Win32_USBControllerDevice
|
||||
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
|
||||
{
|
||||
foreach (ManagementObject obj2 in searcher.Get())
|
||||
{
|
||||
//DeviceID
|
||||
if (obj2.Properties["DeviceID"].Value.ToString().ToUpper() == port.ToUpper())
|
||||
{
|
||||
portnamenice = obj2.Properties["Name"].Value.ToString();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch { }
|
||||
|
||||
portnamenice = "";
|
||||
}
|
||||
|
||||
static void CallWithTimeout(Action<string> action, int timeoutMilliseconds, string data)
|
||||
{
|
||||
Thread threadToKill = null;
|
||||
Action wrappedAction = () =>
|
||||
{
|
||||
threadToKill = Thread.CurrentThread;
|
||||
action(data);
|
||||
};
|
||||
|
||||
IAsyncResult result = wrappedAction.BeginInvoke(null, null);
|
||||
if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
|
||||
{
|
||||
wrappedAction.EndInvoke(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
threadToKill.Abort();
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ispx4(string port)
|
||||
{
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// .NET bug: sometimes bluetooth ports are enumerated with bogus characters
|
||||
// eg 'COM10' becomes 'COM10c' - one workaround is to remove the non numeric
|
||||
// char. Annoyingly, sometimes a numeric char is added, which means this
|
||||
// does not work in all cases.
|
||||
// See http://connect.microsoft.com/VisualStudio/feedback/details/236183/system-io-ports-serialport-getportnames-error-with-bluetooth
|
||||
private static string FixBlueToothPortNameBug(string portName)
|
||||
{
|
||||
if (!portName.StartsWith("COM"))
|
||||
return portName;
|
||||
var newPortName = "COM"; // Start over with "COM"
|
||||
foreach (var portChar in portName.Substring(3).ToCharArray()) // Remove "COM", put the rest in a character array
|
||||
{
|
||||
if (char.IsDigit(portChar))
|
||||
newPortName += portChar.ToString(); // Good character, append to portName
|
||||
// else
|
||||
//log.WarnFormat("Bad (Non Numeric) character in port name '{0}' - removing", portName);
|
||||
}
|
||||
|
||||
return newPortName;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SerialPortFixer : IDisposable
|
||||
{
|
||||
|
||||
|
||||
public static void Execute(string portName)
|
||||
{
|
||||
using (new SerialPortFixer(portName))
|
||||
{
|
||||
}
|
||||
}
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_Handle != null)
|
||||
{
|
||||
m_Handle.Dispose();
|
||||
m_Handle = null;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation
|
||||
|
||||
private const int DcbFlagAbortOnError = 14;
|
||||
private const int CommStateRetries = 10;
|
||||
private SafeFileHandle m_Handle;
|
||||
|
||||
private SerialPortFixer(string portName)
|
||||
{
|
||||
const int dwFlagsAndAttributes = 0x40000000;
|
||||
const int dwAccess = unchecked((int)0xC0000000); if ((portName == null) || !portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new ArgumentException("Invalid Serial Port", "portName");
|
||||
}
|
||||
SafeFileHandle hFile = NativeMethods.CreateFile(@"\\.\" + portName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes,
|
||||
IntPtr.Zero);
|
||||
if (hFile.IsInvalid)
|
||||
{
|
||||
WinIoError();
|
||||
}
|
||||
try
|
||||
{
|
||||
int fileType = NativeMethods.GetFileType(hFile);
|
||||
if ((fileType != 2) && (fileType != 0))
|
||||
{
|
||||
throw new ArgumentException("Invalid Serial Port", "portName");
|
||||
}
|
||||
m_Handle = hFile;
|
||||
InitializeDcb();
|
||||
}
|
||||
catch
|
||||
{
|
||||
hFile.Dispose();
|
||||
m_Handle = null;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NativeMethods
|
||||
{
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern int FormatMessage(int dwFlags, HandleRef lpSource, int dwMessageId, int dwLanguageId,
|
||||
StringBuilder lpBuffer, int nSize, IntPtr arguments);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern bool GetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern bool SetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
|
||||
IntPtr securityAttrs, int dwCreationDisposition,
|
||||
int dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern int GetFileType(SafeFileHandle hFile);
|
||||
|
||||
}
|
||||
|
||||
private void InitializeDcb()
|
||||
{
|
||||
Dcb dcb = new Dcb();
|
||||
GetCommStateNative(ref dcb);
|
||||
|
||||
dcb.Flags &= ~(1u << DcbFlagAbortOnError);
|
||||
|
||||
SetCommStateNative(ref dcb);
|
||||
}
|
||||
|
||||
private static string GetMessage(int errorCode)
|
||||
{
|
||||
StringBuilder lpBuffer = new StringBuilder(0x200);
|
||||
if (
|
||||
NativeMethods.FormatMessage(0x3200, new HandleRef(null, IntPtr.Zero), errorCode, 0, lpBuffer, lpBuffer.Capacity,
|
||||
IntPtr.Zero) != 0)
|
||||
{
|
||||
return lpBuffer.ToString();
|
||||
}
|
||||
return "Unknown Error";
|
||||
}
|
||||
|
||||
private static int MakeHrFromErrorCode(int errorCode)
|
||||
{
|
||||
return (int)(0x80070000 | (uint)errorCode);
|
||||
}
|
||||
|
||||
private static void WinIoError()
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
throw new IOException(GetMessage(errorCode), MakeHrFromErrorCode(errorCode));
|
||||
}
|
||||
|
||||
private void GetCommStateNative(ref Dcb lpDcb)
|
||||
{
|
||||
int commErrors = 0;
|
||||
Comstat comStat = new Comstat();
|
||||
|
||||
for (int i = 0; i < CommStateRetries; i++)
|
||||
{
|
||||
if (!NativeMethods.ClearCommError(m_Handle, ref commErrors, ref comStat))
|
||||
{
|
||||
WinIoError();
|
||||
}
|
||||
if (NativeMethods.GetCommState(m_Handle, ref lpDcb))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (i == CommStateRetries - 1)
|
||||
{
|
||||
WinIoError();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void SetCommStateNative(ref Dcb lpDcb)
|
||||
{
|
||||
int commErrors = 0;
|
||||
Comstat comStat = new Comstat(); for (int i = 0; i < CommStateRetries; i++)
|
||||
{
|
||||
if (!NativeMethods.ClearCommError(m_Handle, ref commErrors, ref comStat))
|
||||
{
|
||||
WinIoError();
|
||||
}
|
||||
if (NativeMethods.SetCommState(m_Handle, ref lpDcb))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (i == CommStateRetries - 1)
|
||||
{
|
||||
WinIoError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Nested type: COMSTAT
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct Comstat
|
||||
{
|
||||
public readonly uint Flags;
|
||||
public readonly uint cbInQue;
|
||||
public readonly uint cbOutQue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: DCB
|
||||
|
||||
/*
|
||||
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx
|
||||
DWORD fBinary :1;
|
||||
DWORD fParity :1;
|
||||
DWORD fOutxCtsFlow :1;
|
||||
DWORD fOutxDsrFlow :1;
|
||||
DWORD fDtrControl :2;
|
||||
DWORD fDsrSensitivity :1;
|
||||
DWORD fTXContinueOnXoff :1;
|
||||
DWORD fOutX :1;
|
||||
DWORD fInX :1;
|
||||
DWORD fErrorChar :1;
|
||||
DWORD fNull :1;
|
||||
DWORD fRtsControl :2;
|
||||
DWORD fAbortOnError :1;
|
||||
DWORD fDummy2 :17;
|
||||
*/
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Dcb
|
||||
{
|
||||
public readonly uint DCBlength;
|
||||
public readonly uint BaudRate;
|
||||
public uint Flags;
|
||||
public readonly ushort wReserved;
|
||||
public readonly ushort XonLim;
|
||||
public readonly ushort XoffLim;
|
||||
public readonly byte ByteSize;
|
||||
public readonly byte Parity;
|
||||
public readonly byte StopBits;
|
||||
public readonly byte XonChar;
|
||||
public readonly byte XoffChar;
|
||||
public readonly byte ErrorChar;
|
||||
public readonly byte EofChar;
|
||||
public readonly byte EvtChar;
|
||||
public readonly ushort wReserved1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
86
Plane.FormationCreator/Util/PasswordBoxHelper.cs
Normal file
86
Plane.FormationCreator/Util/PasswordBoxHelper.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
|
||||
namespace Plane.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// 为PasswordBox控件的Password增加绑定功能
|
||||
/// </summary>
|
||||
public static class PasswordBoxHelper
|
||||
{
|
||||
public static readonly DependencyProperty PasswordProperty =
|
||||
DependencyProperty.RegisterAttached("Password",
|
||||
typeof(string), typeof(PasswordBoxHelper),
|
||||
new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));
|
||||
public static readonly DependencyProperty AttachProperty =
|
||||
DependencyProperty.RegisterAttached("Attach",
|
||||
typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, Attach));
|
||||
private static readonly DependencyProperty IsUpdatingProperty =
|
||||
DependencyProperty.RegisterAttached("IsUpdating", typeof(bool),
|
||||
typeof(PasswordBoxHelper));
|
||||
|
||||
|
||||
public static void SetAttach(DependencyObject dp, bool value)
|
||||
{
|
||||
dp.SetValue(AttachProperty, value);
|
||||
}
|
||||
public static bool GetAttach(DependencyObject dp)
|
||||
{
|
||||
return (bool)dp.GetValue(AttachProperty);
|
||||
}
|
||||
public static string GetPassword(DependencyObject dp)
|
||||
{
|
||||
return (string)dp.GetValue(PasswordProperty);
|
||||
}
|
||||
public static void SetPassword(DependencyObject dp, string value)
|
||||
{
|
||||
dp.SetValue(PasswordProperty, value);
|
||||
}
|
||||
private static bool GetIsUpdating(DependencyObject dp)
|
||||
{
|
||||
return (bool)dp.GetValue(IsUpdatingProperty);
|
||||
}
|
||||
private static void SetIsUpdating(DependencyObject dp, bool value)
|
||||
{
|
||||
dp.SetValue(IsUpdatingProperty, value);
|
||||
}
|
||||
private static void OnPasswordPropertyChanged(DependencyObject sender,
|
||||
DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
PasswordBox passwordBox = sender as PasswordBox;
|
||||
passwordBox.PasswordChanged -= PasswordChanged;
|
||||
if (!(bool)GetIsUpdating(passwordBox))
|
||||
{
|
||||
passwordBox.Password = (string)e.NewValue;
|
||||
}
|
||||
passwordBox.PasswordChanged += PasswordChanged;
|
||||
}
|
||||
private static void Attach(DependencyObject sender,
|
||||
DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
PasswordBox passwordBox = sender as PasswordBox;
|
||||
if (passwordBox == null)
|
||||
return;
|
||||
if ((bool)e.OldValue)
|
||||
{
|
||||
passwordBox.PasswordChanged -= PasswordChanged;
|
||||
}
|
||||
if ((bool)e.NewValue)
|
||||
{
|
||||
passwordBox.PasswordChanged += PasswordChanged;
|
||||
}
|
||||
}
|
||||
private static void PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PasswordBox passwordBox = sender as PasswordBox;
|
||||
SetIsUpdating(passwordBox, true);
|
||||
SetPassword(passwordBox, passwordBox.Password);
|
||||
SetIsUpdating(passwordBox, false);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user