using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
namespace CommandMessenger.Transport.Serial
{
///
/// Utility methods for serial communication handling.
///
public static class SerialUtils
{
private static readonly bool IsMonoRuntime = (Type.GetType("Mono.Runtime") != null);
///
/// Commonly used baud rates.
///
public static int[] CommonBaudRates
{
get
{
return new []
{
115200, // Arduino Uno, Mega, with AT8u2 USB
57600, // Arduino Duemilanove, FTDI Serial
9600 // Often used as default, but slow!
};
}
}
/// Queries if a given port exists.
/// true if it succeeds, false if it fails.
public static bool PortExists(string serialPortName)
{
if (IsMonoRuntime)
{
return File.Exists(serialPortName);
}
else
{
return SerialPort.GetPortNames().Contains(serialPortName);
}
}
///
/// Retrieve available serial ports.
///
/// Array of serial port names.
public static string[] GetPortNames()
{
/**
* Under Mono SerialPort.GetPortNames() returns /dev/ttyS* devices,
* but Arduino is detected as ttyACM* or ttyUSB*
* */
if (IsMonoRuntime)
{
var searchPattern = new Regex("ttyACM.+|ttyUSB.+");
return Directory.GetFiles("/dev").Where(f => searchPattern.IsMatch(f)).ToArray();
}
else
{
return SerialPort.GetPortNames();
}
}
///
/// Retrieves the possible baud rates for the provided serial port. Windows ONLY.
///
/// List of supported baud rates.
public static int[] GetSupportedBaudRates(string serialPortName)
{
try
{
var serialPort = new SerialPort(serialPortName);
serialPort.Open();
if (serialPort.IsOpen)
{
var fieldInfo = serialPort.BaseStream.GetType()
.GetField("commProp", BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo != null)
{
object p = fieldInfo.GetValue(serialPort.BaseStream);
var fieldInfoValue = p.GetType()
.GetField("dwSettableBaud",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (fieldInfoValue != null)
{
var dwSettableBaud = (Int32)fieldInfoValue.GetValue(p);
serialPort.Close();
return BaudRateMaskToActualRates(dwSettableBaud).ToArray();
}
}
}
}
catch
{
// Ignore.
}
// Can't determine possible baud rates, will use all possible values
return BaudRateMaskToActualRates(int.MaxValue).ToArray();
}
///
/// Get the range of possible baud rates for serial port.
///
/// dwSettableBaud parameter from the COMMPROP Structure
/// List of bad rates
private static List BaudRateMaskToActualRates(int possibleBaudRates)
{
#pragma warning disable 219
// ReSharper disable InconsistentNaming
//const int BAUD_075 = 0x00000001;
//const int BAUD_110 = 0x00000002;
//const int BAUD_150 = 0x00000008;
const int BAUD_300 = 0x00000010;
const int BAUD_600 = 0x00000020;
const int BAUD_1200 = 0x00000040;
const int BAUD_1800 = 0x00000080;
const int BAUD_2400 = 0x00000100;
const int BAUD_4800 = 0x00000200;
const int BAUD_7200 = 0x00000400;
const int BAUD_9600 = 0x00000800;
const int BAUD_14400 = 0x00001000;
const int BAUD_19200 = 0x00002000;
const int BAUD_38400 = 0x00004000;
const int BAUD_56K = 0x00008000;
const int BAUD_57600 = 0x00040000;
const int BAUD_115200 = 0x00020000;
const int BAUD_128K = 0x00010000;
#pragma warning restore 219
var baudRateCollection = new List();
// We start with the most common baudrates:
if ((possibleBaudRates & BAUD_115200) > 0)
baudRateCollection.Add(115200); // Maxspeed Arduino Uno, Mega, with AT8u2 USB
if ((possibleBaudRates & BAUD_9600) > 0)
baudRateCollection.Add(9600); // Often default speed
if ((possibleBaudRates & BAUD_57600) > 0)
baudRateCollection.Add(57600); // Maxspeed Arduino Duemilanove, FTDI Serial
// After that going from fastest to slowest baudrates:
if ((possibleBaudRates & BAUD_128K) > 0)
baudRateCollection.Add(128000);
if ((possibleBaudRates & BAUD_56K) > 0)
baudRateCollection.Add(56000);
if ((possibleBaudRates & BAUD_38400) > 0)
baudRateCollection.Add(38400);
if ((possibleBaudRates & BAUD_19200) > 0)
baudRateCollection.Add(19200);
if ((possibleBaudRates & BAUD_14400) > 0)
baudRateCollection.Add(14400);
if ((possibleBaudRates & BAUD_7200) > 0)
baudRateCollection.Add(7200);
if ((possibleBaudRates & BAUD_4800) > 0)
baudRateCollection.Add(4800);
if ((possibleBaudRates & BAUD_2400) > 0)
baudRateCollection.Add(2400);
if ((possibleBaudRates & BAUD_1800) > 0)
baudRateCollection.Add(1800);
if ((possibleBaudRates & BAUD_1200) > 0)
baudRateCollection.Add(1200);
if ((possibleBaudRates & BAUD_600) > 0)
baudRateCollection.Add(600);
if ((possibleBaudRates & BAUD_300) > 0)
baudRateCollection.Add(300);
// Skip old and slow rates.
/*if ((possibleBaudRates & BAUD_150) > 0)
baudRateCollection.Add(150);
if ((possibleBaudRates & BAUD_110) > 0)
baudRateCollection.Add(110);
if ((possibleBaudRates & BAUD_075) > 0)
baudRateCollection.Add(75);*/
return baudRateCollection;
}
}
}