Move SerialPortCommunication to MatterControl.Printing project

This commit is contained in:
John Lewin 2017-12-29 14:54:43 -08:00
parent 3e012ca610
commit 369835d314
15 changed files with 2592 additions and 18 deletions

View file

@ -0,0 +1,128 @@
/*
Copyright (c) 2014, Lars Brubaker
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
namespace MatterHackers.SerialPortCommunication
{
public class FoundStringEventArgs : EventArgs
{
public bool CallbackWasCalled { get; set; }
private bool sendToDelegateFunctions = true;
private string lineToCheck;
public FoundStringEventArgs(string lineReceived)
{
this.lineToCheck = lineReceived.Trim();
}
public string LineToCheck { get { return lineToCheck; } }
public bool SendToDelegateFunctions
{
get
{
return sendToDelegateFunctions;
}
set
{
sendToDelegateFunctions = value;
}
}
}
public class FoundStringCallbacks
{
public Dictionary<string, EventHandler<FoundStringEventArgs> > dictionaryOfCallbacks = new Dictionary<string, EventHandler<FoundStringEventArgs>>();
public void AddCallbackToKey(string key, EventHandler<FoundStringEventArgs> value)
{
if (dictionaryOfCallbacks.ContainsKey(key))
{
dictionaryOfCallbacks[key] += value;
}
else
{
dictionaryOfCallbacks.Add(key, value);
}
}
public void RemoveCallbackFromKey(string key, EventHandler<FoundStringEventArgs> value)
{
if (dictionaryOfCallbacks.ContainsKey(key))
{
if (dictionaryOfCallbacks[key] == null)
{
throw new Exception();
}
dictionaryOfCallbacks[key] -= value;
if (dictionaryOfCallbacks[key] == null)
{
dictionaryOfCallbacks.Remove(key);
}
}
else
{
throw new Exception();
}
}
}
public class FoundStringStartsWithCallbacks : FoundStringCallbacks
{
public void CheckForKeys(FoundStringEventArgs e)
{
foreach (var pair in this.dictionaryOfCallbacks)
{
if (e.LineToCheck.StartsWith(pair.Key))
{
e.CallbackWasCalled = true;
pair.Value(this, e);
}
}
}
}
public class FoundStringContainsCallbacks : FoundStringCallbacks
{
public void CheckForKeys(FoundStringEventArgs e)
{
foreach (var pair in this.dictionaryOfCallbacks)
{
if (e.LineToCheck.Contains(pair.Key))
{
e.CallbackWasCalled = true;
pair.Value(this, e);
}
}
}
}
}

View file

@ -0,0 +1,167 @@
/*
Copyright (c) 2014, Kevin Pope
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.IO;
using System.Text;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
#if USE_STANDARD_SERIAL
public class CSharpSerialPortWrapper : IFrostedSerialPort
{
private System.IO.Ports.SerialPort port;
internal CSharpSerialPortWrapper(string serialPortName)
{
if (FrostedSerialPortFactory.GetAppropriateFactory("RepRap").IsWindows)
{
try
{
SerialPortFixer.Execute(serialPortName);
}
catch (Exception)
{
}
}
port = new System.IO.Ports.SerialPort(serialPortName);
}
public int ReadTimeout
{
get { return port.ReadTimeout; }
set { port.ReadTimeout = value; }
}
public string ReadExisting()
{
return port.ReadExisting();
}
public int BytesToRead
{
get
{
return port.BytesToRead;
}
}
public void Dispose()
{
port.Dispose();
}
public bool IsOpen
{
get { return port.IsOpen; }
}
public void Open()
{
port.Open();
}
public void Close()
{
try
{
port.Close();
}
catch (Exception)
{
}
}
public int WriteTimeout
{
get
{
return port.WriteTimeout;
}
set
{
port.WriteTimeout = value;
}
}
public int BaudRate
{
get
{
return port.BaudRate;
}
set
{
port.BaudRate = value;
}
}
public bool RtsEnable
{
get
{
return port.RtsEnable;
}
set
{
port.RtsEnable = value;
}
}
public bool DtrEnable
{
get
{
return port.DtrEnable;
}
set
{
port.DtrEnable = value;
}
}
public void Write(string str)
{
port.Write(str);
}
public void Write(byte[] buffer, int offset, int count)
{
port.Write(buffer, offset, count);
}
public int Read(byte[] buffer, int offset, int count)
{
return port.Read(buffer, offset, count);
}
}
#endif
}

View file

@ -0,0 +1,925 @@
/*
Copyright (c) 2014, Kevin Pope
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using MatterHackers.Agg.Platform;
using Microsoft.Win32;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
[MonitoringDescription("")]
[System.ComponentModel.DesignerCategory("")]
public class FrostedSerialPort : Component, IFrostedSerialPort
{
public const int InfiniteTimeout = -1;
private const int DefaultReadBufferSize = 4096;
private const int DefaultWriteBufferSize = 2048;
private const int DefaultBaudRate = 9600;
private const int DefaultDataBits = 8;
private const Parity DefaultParity = Parity.None;
private const StopBits DefaultStopBits = StopBits.One;
private bool is_open;
private int baud_rate;
private Parity parity;
private StopBits stop_bits;
private Handshake handshake;
private int data_bits;
private bool break_state = false;
private bool dtr_enable = false;
private bool rts_enable = false;
private IFrostedSerialStream stream;
private Encoding encoding = Encoding.ASCII;
private string new_line = Environment.NewLine;
private string port_name;
private int read_timeout = InfiniteTimeout;
private int write_timeout = InfiniteTimeout;
private int readBufferSize = DefaultReadBufferSize;
private int writeBufferSize = DefaultWriteBufferSize;
private object error_received = new object();
private object data_received = new object();
private object pin_changed = new object();
public FrostedSerialPort() :
this(FrostedSerialPort.GetDefaultPortName(), DefaultBaudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
{
}
public FrostedSerialPort(IContainer container)
: this()
{
// TODO: What to do here?
}
public FrostedSerialPort(string portName) :
this(portName, DefaultBaudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
{
}
public FrostedSerialPort(string portName, int baudRate) :
this(portName, baudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
{
}
public FrostedSerialPort(string portName, int baudRate, Parity parity) :
this(portName, baudRate, parity, DefaultDataBits, DefaultStopBits)
{
}
public FrostedSerialPort(string portName, int baudRate, Parity parity, int dataBits) :
this(portName, baudRate, parity, dataBits, DefaultStopBits)
{
}
public FrostedSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
{
port_name = portName;
baud_rate = baudRate;
data_bits = dataBits;
stop_bits = stopBits;
this.parity = parity;
}
// On non-Android platforms simply return true as port access validation isn't applicable
public static bool EnsureDeviceAccess()
{
return true;
}
private static Regex linuxDefaultUIFilter = new Regex("/dev/ttyS*\\d+", RegexOptions.CultureInvariant | RegexOptions.Compiled);
private static IEnumerable<string> FilterPortsForMac(List<string> allPorts)
{
IEnumerable<string> filteredPorts;
if (AggContext.OperatingSystem == OSType.X11)
{
// A default and naive filter that works well on Ubuntu 14
filteredPorts = allPorts.Where(portName => portName != "/dev/tty" && !linuxDefaultUIFilter.Match(portName).Success);
}
else
{
// looks_like_mac -- serialPort.StartsWith("/dev/tty."); looks_like_pc -- serialPort.StartsWith("COM")
filteredPorts = allPorts.Where(portName => portName.StartsWith("/dev/tty.")
|| portName.StartsWith("COM")
|| portName == "Emulator");
}
return filteredPorts.Any() ? filteredPorts : allPorts;
}
public static bool MockPortsForTest = false;
public static string[] GetPortNames(bool filter = true)
{
var p = Environment.OSVersion.Platform;
List<string> serial_ports = new List<string>();
// Are we on Unix?
if (MockPortsForTest)
{
serial_ports.Add("COM-TestA");
serial_ports.Add("COM-TestB");
serial_ports.Add("COM-TestC");
serial_ports.Add("COM-Test0");
serial_ports.Add("COM-Test1");
}
else if (p == PlatformID.Unix || p == PlatformID.MacOSX)
{
string[] ttys = Directory.GetFiles("/dev/", "tty*");
// If filtering was not requested, return the raw listing of /dev/tty* - (subsequent filtering happens in client code)
if (!filter)
{
return ttys;
}
// Probe for Linux-styled devices: /dev/ttyS* or /dev/ttyUSB*
foreach (string dev in ttys)
{
if (dev != "/dev/tty" && dev.StartsWith("/dev/tty") && !dev.StartsWith("/dev/ttyC"))
{
serial_ports.Add(dev);
}
}
}
else
{
#if USE_STANDARD_SERIAL
using (RegistryKey subkey = Registry.LocalMachine.OpenSubKey("HARDWARE\\DEVICEMAP\\SERIALCOMM"))
{
if (subkey != null)
{
string[] names = subkey.GetValueNames();
foreach (string value in names)
{
string port = subkey.GetValue(value, "").ToString();
if (port != "")
serial_ports.Add(port);
}
}
}
#endif
}
#if DEBUG
serial_ports.Add("Emulator");
#endif
return FilterPortsForMac(serial_ports).ToArray();
}
public static string GetDefaultPortName()
{
string[] ports = FrostedSerialPort.GetPortNames();
if (ports.Length > 0)
{
return ports[0];
}
else
{
int p = (int)Environment.OSVersion.Platform;
if (p == 4 || p == 128 || p == 6)
return "ttyS0"; // Default for Unix
else
return "COM1"; // Default for Windows
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public Stream BaseStream
{
get
{
CheckOpen();
return (Stream)stream;
}
}
[DefaultValueAttribute(DefaultBaudRate)]
[Browsable(true)]
[MonitoringDescription("")]
public int BaudRate
{
get
{
return baud_rate;
}
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException("value");
if (is_open)
stream.SetAttributes(value, parity, data_bits, stop_bits, handshake);
baud_rate = value;
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public bool BreakState
{
get
{
return break_state;
}
set
{
CheckOpen();
if (value == break_state)
return; // Do nothing.
stream.SetBreakState(value);
break_state = value;
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public int BytesToRead
{
get
{
CheckOpen();
return stream.BytesToRead;
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public int BytesToWrite
{
get
{
CheckOpen();
return stream.BytesToWrite;
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public bool CDHolding
{
get
{
CheckOpen();
return (stream.GetSignals() & SerialSignal.Cd) != 0;
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public bool CtsHolding
{
get
{
CheckOpen();
return (stream.GetSignals() & SerialSignal.Cts) != 0;
}
}
[DefaultValueAttribute(DefaultDataBits)]
[Browsable(true)]
[MonitoringDescription("")]
public int DataBits
{
get
{
return data_bits;
}
set
{
if (value < 5 || value > 8)
throw new ArgumentOutOfRangeException("value");
if (is_open)
stream.SetAttributes(baud_rate, parity, value, stop_bits, handshake);
data_bits = value;
}
}
//[MonoTODO("Not implemented")]
[Browsable(true)]
[MonitoringDescription("")]
[DefaultValue(false)]
public bool DiscardNull
{
get
{
throw new NotImplementedException();
}
set
{
// LAMESPEC: Msdn states that an InvalidOperationException exception
// is fired if the port is not open, which is *not* happening.
throw new NotImplementedException();
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
public bool DsrHolding
{
get
{
CheckOpen();
return (stream.GetSignals() & SerialSignal.Dsr) != 0;
}
}
[DefaultValueAttribute(false)]
[Browsable(true)]
[MonitoringDescription("")]
public bool DtrEnable
{
get
{
return dtr_enable;
}
set
{
if (value == dtr_enable)
return;
if (is_open)
stream.SetSignal(SerialSignal.Dtr, value);
dtr_enable = value;
}
}
[Browsable(false)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
[MonitoringDescription("")]
public Encoding Encoding
{
get
{
return encoding;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
encoding = value;
}
}
[DefaultValueAttribute(Handshake.None)]
[Browsable(true)]
[MonitoringDescription("")]
public Handshake Handshake
{
get
{
return handshake;
}
set
{
if (value < Handshake.None || value > Handshake.RequestToSendXOnXOff)
throw new ArgumentOutOfRangeException("value");
if (is_open)
stream.SetAttributes(baud_rate, parity, data_bits, stop_bits, value);
handshake = value;
}
}
[Browsable(false)]
public bool IsOpen
{
get
{
return is_open;
}
}
[DefaultValueAttribute("\n")]
[Browsable(false)]
[MonitoringDescription("")]
public string NewLine
{
get
{
return new_line;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length == 0)
throw new ArgumentException("NewLine cannot be null or empty.", "value");
new_line = value;
}
}
[DefaultValueAttribute(DefaultParity)]
[Browsable(true)]
[MonitoringDescription("")]
public Parity Parity
{
get
{
return parity;
}
set
{
if (value < Parity.None || value > Parity.Space)
throw new ArgumentOutOfRangeException("value");
if (is_open)
stream.SetAttributes(baud_rate, value, data_bits, stop_bits, handshake);
parity = value;
}
}
//[MonoTODO("Not implemented")]
[Browsable(true)]
[MonitoringDescription("")]
[DefaultValue(63)]
public byte ParityReplace
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
[Browsable(true)]
[MonitoringDescription("")]
[DefaultValue("COM1")] // silly Windows-ism. We should ignore it.
public string PortName
{
get
{
return port_name;
}
set
{
if (is_open)
throw new InvalidOperationException("Port name cannot be set while port is open.");
if (value == null)
throw new ArgumentNullException("value");
if (value.Length == 0 || value.StartsWith("\\\\"))
throw new ArgumentException("value");
port_name = value;
}
}
[DefaultValueAttribute(DefaultReadBufferSize)]
[Browsable(true)]
[MonitoringDescription("")]
public int ReadBufferSize
{
get
{
return readBufferSize;
}
set
{
if (is_open)
throw new InvalidOperationException();
if (value <= 0)
throw new ArgumentOutOfRangeException("value");
if (value <= DefaultReadBufferSize)
return;
readBufferSize = value;
}
}
[DefaultValueAttribute(InfiniteTimeout)]
[Browsable(true)]
[MonitoringDescription("")]
public int ReadTimeout
{
get
{
return read_timeout;
}
set
{
if (value < 0 && value != InfiniteTimeout)
throw new ArgumentOutOfRangeException("value");
if (is_open)
stream.ReadTimeout = value;
read_timeout = value;
}
}
//[MonoTODO("Not implemented")]
[DefaultValueAttribute(1)]
[Browsable(true)]
[MonitoringDescription("")]
public int ReceivedBytesThreshold
{
get
{
throw new NotImplementedException();
}
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException("value");
throw new NotImplementedException();
}
}
[DefaultValueAttribute(false)]
[Browsable(true)]
[MonitoringDescription("")]
public bool RtsEnable
{
get
{
return rts_enable;
}
set
{
if (value == rts_enable)
return;
if (is_open)
stream.SetSignal(SerialSignal.Rts, value);
rts_enable = value;
}
}
[DefaultValueAttribute(DefaultStopBits)]
[Browsable(true)]
[MonitoringDescription("")]
public StopBits StopBits
{
get
{
return stop_bits;
}
set
{
if (value < StopBits.One || value > StopBits.OnePointFive)
throw new ArgumentOutOfRangeException("value");
if (is_open)
stream.SetAttributes(baud_rate, parity, data_bits, value, handshake);
stop_bits = value;
}
}
[DefaultValueAttribute(DefaultWriteBufferSize)]
[Browsable(true)]
[MonitoringDescription("")]
public int WriteBufferSize
{
get
{
return writeBufferSize;
}
set
{
if (is_open)
throw new InvalidOperationException();
if (value <= 0)
throw new ArgumentOutOfRangeException("value");
if (value <= DefaultWriteBufferSize)
return;
writeBufferSize = value;
}
}
[DefaultValueAttribute(InfiniteTimeout)]
[Browsable(true)]
[MonitoringDescription("")]
public int WriteTimeout
{
get
{
return write_timeout;
}
set
{
if (value < 0 && value != InfiniteTimeout)
throw new ArgumentOutOfRangeException("value");
if (is_open)
stream.WriteTimeout = value;
write_timeout = value;
}
}
// methods
public void Close()
{
Dispose(true);
}
protected override void Dispose(bool disposing)
{
if (!is_open)
return;
is_open = false;
// Do not close the base stream when the finalizer is run; the managed code can still hold a reference to it.
if (disposing)
stream.Close();
stream = null;
}
public void DiscardInBuffer()
{
CheckOpen();
stream.DiscardInBuffer();
}
public void DiscardOutBuffer()
{
CheckOpen();
stream.DiscardOutBuffer();
}
public void Open()
{
if (is_open)
throw new InvalidOperationException("Port is already open");
stream = new FrostedSerialPortStream(port_name, baud_rate, data_bits, parity, stop_bits, dtr_enable,
rts_enable, handshake, read_timeout, write_timeout, readBufferSize, writeBufferSize);
is_open = true;
}
public int Read(byte[] buffer, int offset, int count)
{
CheckOpen();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException("offset or count less than zero.");
if (buffer.Length - offset < count)
throw new ArgumentException("offset+count",
"The size of the buffer is less than offset + count.");
return stream.Read(buffer, offset, count);
}
public int Read(char[] buffer, int offset, int count)
{
CheckOpen();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException("offset or count less than zero.");
if (buffer.Length - offset < count)
throw new ArgumentException("offset+count",
"The size of the buffer is less than offset + count.");
int c, i;
for (i = 0; i < count && (c = ReadChar()) != -1; i++)
buffer[offset + i] = (char)c;
return i;
}
internal int read_byte()
{
byte[] buff = new byte[1];
if (stream.Read(buff, 0, 1) > 0)
return buff[0];
return -1;
}
public int ReadByte()
{
CheckOpen();
return read_byte();
}
public int ReadChar()
{
CheckOpen();
byte[] buffer = new byte[16];
int i = 0;
do
{
int b = read_byte();
if (b == -1)
return -1;
buffer[i++] = (byte)b;
char[] c = encoding.GetChars(buffer, 0, 1);
if (c.Length > 0)
return (int)c[0];
} while (i < buffer.Length);
return -1;
}
public string ReadExisting()
{
CheckOpen();
int count = BytesToRead;
byte[] bytes = new byte[count];
int n = stream.Read(bytes, 0, count);
return new String(encoding.GetChars(bytes, 0, n));
}
public string ReadLine()
{
return ReadTo(new_line);
}
public string ReadTo(string value)
{
CheckOpen();
if (value == null)
throw new ArgumentNullException("value");
if (value.Length == 0)
throw new ArgumentException("value");
// Turn into byte array, so we can compare
byte[] byte_value = encoding.GetBytes(value);
int current = 0;
List<byte> seen = new List<byte>();
while (true)
{
int n = read_byte();
if (n == -1)
break;
seen.Add((byte)n);
if (n == byte_value[current])
{
current++;
if (current == byte_value.Length)
return encoding.GetString(seen.ToArray(), 0, seen.Count - byte_value.Length);
}
else
{
current = (byte_value[0] == n) ? 1 : 0;
}
}
return encoding.GetString(seen.ToArray());
}
public void Write(string str)
{
CheckOpen();
if (str == null)
throw new ArgumentNullException("str");
byte[] buffer = encoding.GetBytes(str);
Write(buffer, 0, buffer.Length);
}
public void Write(byte[] buffer, int offset, int count)
{
CheckOpen();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException();
if (buffer.Length - offset < count)
throw new ArgumentException("offset+count",
"The size of the buffer is less than offset + count.");
stream.Write(buffer, offset, count);
}
public void Write(char[] buffer, int offset, int count)
{
CheckOpen();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException();
if (buffer.Length - offset < count)
throw new ArgumentException("offset+count",
"The size of the buffer is less than offset + count.");
byte[] bytes = encoding.GetBytes(buffer, offset, count);
stream.Write(bytes, 0, bytes.Length);
}
public void WriteLine(string str)
{
Write(str + new_line);
}
private void CheckOpen()
{
if (!is_open)
throw new InvalidOperationException("Specified port is not open.");
}
internal void OnErrorReceived(SerialErrorReceivedEventArgs args)
{
SerialErrorReceivedEventHandler handler =
(SerialErrorReceivedEventHandler)Events[error_received];
if (handler != null)
handler(this, args);
}
internal void OnDataReceived(SerialDataReceivedEventArgs args)
{
SerialDataReceivedEventHandler handler =
(SerialDataReceivedEventHandler)Events[data_received];
if (handler != null)
handler(this, args);
}
internal void OnDataReceived(SerialPinChangedEventArgs args)
{
SerialPinChangedEventHandler handler =
(SerialPinChangedEventHandler)Events[pin_changed];
if (handler != null)
handler(this, args);
}
// events
[MonitoringDescription("")]
public event SerialErrorReceivedEventHandler ErrorReceived
{
add { Events.AddHandler(error_received, value); }
remove { Events.RemoveHandler(error_received, value); }
}
[MonitoringDescription("")]
public event SerialPinChangedEventHandler PinChanged
{
add { Events.AddHandler(pin_changed, value); }
remove { Events.RemoveHandler(pin_changed, value); }
}
[MonitoringDescription("")]
public event SerialDataReceivedEventHandler DataReceived
{
add { Events.AddHandler(data_received, value); }
remove { Events.RemoveHandler(data_received, value); }
}
}
}

View file

@ -0,0 +1,223 @@
/*
Copyright (c) 2014, Kevin Pope
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using Microsoft.Win32.SafeHandles;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
public class FrostedSerialPortFactory
{
[DllImport("SetSerial", SetLastError = true)]
private static extern int set_baud(string portName, int baud_rate);
static Dictionary<string, FrostedSerialPortFactory> availableFactories = new Dictionary<string,FrostedSerialPortFactory>();
public static FrostedSerialPortFactory GetAppropriateFactory(string driverType)
{
lock(availableFactories)
{
try
{
if (availableFactories.Count == 0)
{
// always add a serial port this is a raw port
availableFactories.Add("Raw", new FrostedSerialPortFactory());
// add in any plugins that we find with other factories.
var portFactories = PluginFinder.CreateInstancesOf<FrostedSerialPortFactory>();
foreach (FrostedSerialPortFactory plugin in portFactories)
{
availableFactories.Add(plugin.GetDriverType(), plugin);
}
// If we did not find a RepRap driver add the default.
if (!availableFactories.ContainsKey("RepRap"))
{
availableFactories.Add("RepRap", new FrostedSerialPortFactory());
}
}
if (!string.IsNullOrEmpty(driverType)
&& availableFactories.ContainsKey(driverType))
{
return availableFactories[driverType];
}
return availableFactories["RepRap"];
}
catch
{
return new FrostedSerialPortFactory();
}
}
}
virtual protected string GetDriverType()
{
return "RepRap";
}
[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);
//Windows-only function
public virtual bool SerialPortAlreadyOpen(string portName)
{
if (AggContext.OperatingSystem == OSType.Windows)
{
const int dwFlagsAndAttributes = 0x40000000;
const int GENERIC_READ = unchecked((int)0x80000000);
const int GENERIC_WRITE = 0x40000000;
//Borrowed from Microsoft's Serial Port Open Method :)
using (SafeFileHandle hFile = CreateFile(@"\\.\" + portName, GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, 3, dwFlagsAndAttributes, IntPtr.Zero))
{
hFile.Close();
return hFile.IsInvalid;
}
}
else
{
return false;
}
}
protected FrostedSerialPortFactory()
{
}
public bool IsWindows
{
get
{
PlatformID id = Environment.OSVersion.Platform;
return id == PlatformID.Win32Windows || id == PlatformID.Win32NT; // WinCE not supported
}
}
public virtual IFrostedSerialPort Create(string serialPortName)
{
#if __ANDROID__
//Create an instance of a FrostedSerialPort
IFrostedSerialPort newPort = null;
newPort = new FrostedSerialPort(serialPortName);
return newPort;
#else
IFrostedSerialPort newPort = null;
// if we can find a mac helper class (to get us 250k)
string appBundle = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
if (File.Exists(Path.Combine(appBundle, "libFrostedSerialHelper.dylib")))
{
// use it
newPort = new FrostedSerialPort(serialPortName);
}
else // use the c# native serial port
{
#if USE_STANDARD_SERIAL
newPort = new CSharpSerialPortWrapper(serialPortName);
#endif
}
return newPort;
#endif // ANDROID
}
public virtual IFrostedSerialPort CreateAndOpen(string serialPortName, int baudRate, bool DtrEnableOnConnect)
{
#if __ANDROID__
//Create an instance of a FrostedSerialPort and open it
IFrostedSerialPort newPort = Create(serialPortName);
newPort.BaudRate = baudRate;
if (DtrEnableOnConnect)
{
newPort.DtrEnable = true;
}
// Set the read/write timeouts
newPort.ReadTimeout = 500;
newPort.WriteTimeout = 500;
newPort.Open();
return newPort;
#else
IFrostedSerialPort newPort = Create(serialPortName);
bool isLinux = !(newPort is FrostedSerialPort) && !IsWindows;
bool customBaudAssignment = isLinux && baudRate > 115200;
// Only set serial port .BaudRate when not using Linux workaround
if (!customBaudAssignment)
{
newPort.BaudRate = baudRate;
}
if (DtrEnableOnConnect)
{
newPort.DtrEnable = true;
}
// Set the read/write timeouts
newPort.ReadTimeout = 500;
newPort.WriteTimeout = 500;
newPort.Open();
if (customBaudAssignment)
{
// Once mono has enforced its ANSI baud rate policy(in SerialPort.Open), reset the baud rate to the user specified
// value by calling set_baud in libSetSerial.so
set_baud(serialPortName, baudRate);
}
return newPort;
#endif // ANDROID
}
public virtual bool SerialPortIsAvailable(string serialPortName)
{
try
{
return FrostedSerialPort.GetPortNames().Any(portName => string.Compare(portName, serialPortName, true) == 0);
}
catch
{
return false;
}
}
}
}

View file

@ -0,0 +1,531 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct tDeviceInfo
{
public uint c_iflag;
public uint c_oflag;
public uint c_cflag;
public uint c_lflag;
public fixed byte c_cc[20];
public uint c_ispeed;
public uint c_ospeed;
}
internal class FrostedSerialPortStream : Stream, IFrostedSerialStream, IDisposable
{
private int fd;
private int read_timeout;
private int write_timeout;
private bool disposed;
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int open_serial(string portName);
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int set_attributes(int fd, int baudRate, Parity parity, int dataBits, StopBits stopBits, Handshake handshake);
public FrostedSerialPortStream(string portName, int baudRate, int dataBits, Parity parity, StopBits stopBits,
bool dtrEnable, bool rtsEnable, Handshake handshake, int readTimeout, int writeTimeout,
int readBufferSize, int writeBufferSize)
{
fd = open_serial(portName);
if (fd == -1)
{
ThrowIOException();
}
TryBaudRate(baudRate);
int canSetAttributes = set_attributes(fd, baudRate, parity, dataBits, stopBits, handshake);
if (canSetAttributes != 0)
{
throw new IOException(canSetAttributes.ToString()); // Probably Win32Exc for compatibility
}
read_timeout = readTimeout;
write_timeout = writeTimeout;
SetSignal(SerialSignal.Dtr, dtrEnable);
if (handshake != Handshake.RequestToSend &&
handshake != Handshake.RequestToSendXOnXOff)
{
SetSignal(SerialSignal.Rts, rtsEnable);
}
}
private int SetupBaudRate(int baudRate)
{
throw new NotImplementedException();
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int tcgetattr(int fd, tDeviceInfo newtio);
private int TCGetAttribute(int fd, tDeviceInfo newtio)
{
int result = tcgetattr(fd, newtio);
return result;
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int tcsetattr(int fd, uint optional_actions, tDeviceInfo newtio);
private int TCSetAttribute(int fd, uint optional_actions, tDeviceInfo newtio)
{
return tcsetattr(fd, optional_actions, newtio);
}
private int CFSetISpeed(tDeviceInfo newtio, int baudRate)
{
newtio.c_ispeed = (uint)baudRate;
return (int)newtio.c_ispeed;
}
private int CFSetOSpeed(tDeviceInfo newtio, int baudRate)
{
newtio.c_ospeed = (uint)baudRate;
return (int)newtio.c_ospeed;
}
private bool SetFrostedAttributes(int fd, int baudRate, Parity parity, int dataBits, StopBits stopBits, Handshake handshake)
{
tDeviceInfo newtio = new tDeviceInfo();
if (TCGetAttribute(fd, newtio) == -1)
{
return false;
}
newtio.c_cflag |= (uint)(e_c_oflag.CLOCAL | e_c_oflag.CREAD);
// there is no defenition for e_c_lflag.ECHOL that I can find. It was in the list of or'ed flags below
unchecked
{
newtio.c_lflag &= (uint)-(int)(e_c_lflag.ICANON | e_c_lflag.ECHO | e_c_lflag.ECHOE | e_c_lflag.ECHOK | e_c_lflag.ECHONL | e_c_lflag.ISIG | e_c_lflag.IEXTEN);
}
newtio.c_oflag &= (uint)(e_c_oflag.OPOST);
newtio.c_iflag = (uint)e_c_iflag.IGNBRK;
baudRate = SetupBaudRate(baudRate);
unchecked
{
newtio.c_cflag &= (uint)-(uint)e_c_oflag.CSIZE;
}
switch (dataBits)
{
case 5:
newtio.c_cflag |= (uint)e_c_oflag.CS5;
break;
case 6:
newtio.c_cflag |= (uint)e_c_oflag.CS6;
break;
case 7:
newtio.c_cflag |= (uint)e_c_oflag.CS6;
break;
case 8:
default:
newtio.c_cflag |= (uint)e_c_oflag.CS8;
break;
}
switch (stopBits)
{
case StopBits.None:
break;
case StopBits.One:
unchecked
{
newtio.c_cflag &= (uint)-(uint)e_c_oflag.CSTOPB;
}
break;
case StopBits.Two:
newtio.c_cflag |= (uint)e_c_oflag.CSTOPB;
break;
case StopBits.OnePointFive:
break;
}
unchecked
{
newtio.c_iflag &= (uint)-(uint)(e_c_iflag.INPCK | e_c_iflag.ISTRIP);
}
switch (parity)
{
case Parity.None: /* None */
newtio.c_cflag &= ~(uint)(e_c_oflag.PARENB | e_c_oflag.PARODD);
break;
case Parity.Odd: /* Odd */
newtio.c_cflag |= (uint)(e_c_oflag.PARENB | e_c_oflag.PARODD);
break;
case Parity.Even: /* Even */
newtio.c_cflag &= ~(uint)(e_c_oflag.PARODD);
newtio.c_cflag |= (uint)(e_c_oflag.PARENB);
break;
case Parity.Mark: /* Mark */
/* XXX unhandled */
break;
case Parity.Space: /* Space */
/* XXX unhandled */
break;
}
newtio.c_iflag &= ~(uint)(e_c_iflag.IXOFF | e_c_iflag.IXON);
#if CRTSCTS
newtio.c_cflag &= ~CRTSCTS;
#endif //* def CRTSCTS */
switch (handshake)
{
case Handshake.None: /* None */
/* do nothing */
break;
case Handshake.RequestToSend: /* RequestToSend (RTS) */
#if CRTSCTS
newtio.c_cflag |= CRTSCTS;
#endif //* def CRTSCTS */
break;
case Handshake.RequestToSendXOnXOff: /* RequestToSendXOnXOff (RTS + XON/XOFF) */
#if CRTSCTS
newtio.c_cflag |= CRTSCTS;
#endif //* def CRTSCTS */
/* fall through */
case Handshake.XOnXOff: /* XOnXOff */
newtio.c_iflag |= (uint)(e_c_iflag.IXOFF | e_c_iflag.IXON);
break;
}
if (CFSetOSpeed(newtio, baudRate) < 0 || CFSetISpeed(newtio, baudRate) < 0 ||
TCSetAttribute(fd, (uint)e_tcsetaatr.TCSANOW, newtio) < 0)
{
return false;
}
else
{
return true;
}
//return set_attributes(fd, baudRate, parity, dataBits, sb, hs);
}
public override bool CanRead
{
get
{
return true;
}
}
public override bool CanSeek
{
get
{
return false;
}
}
public override bool CanWrite
{
get
{
return true;
}
}
public override bool CanTimeout
{
get
{
return true;
}
}
public override int ReadTimeout
{
get
{
return read_timeout;
}
set
{
if (value < 0 && value != FrostedSerialPort.InfiniteTimeout)
throw new ArgumentOutOfRangeException("value");
read_timeout = value;
}
}
public override int WriteTimeout
{
get
{
return write_timeout;
}
set
{
if (value < 0 && value != FrostedSerialPort.InfiniteTimeout)
throw new ArgumentOutOfRangeException("value");
write_timeout = value;
}
}
public override long Length
{
get
{
throw new NotSupportedException();
}
}
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
public override void Flush()
{
// If used, this _could_ flush the serial port
// buffer (not the SerialPort class buffer)
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int read_serial(int fd, byte[] buffer, int offset, int count);
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern bool poll_serial(int fd, out int error, int timeout);
public override int Read([In, Out] byte[] buffer, int offset, int count)
{
CheckDisposed();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException("offset or count less than zero.");
if (buffer.Length - offset < count)
throw new ArgumentException("offset+count",
"The size of the buffer is less than offset + count.");
int error;
bool poll_result = poll_serial(fd, out error, read_timeout);
if (error == -1)
ThrowIOException();
if (!poll_result)
{
// see bug 79735 http://bugzilla.ximian.com/show_bug.cgi?id=79735
// should the next line read: return -1;
throw new TimeoutException();
}
int result = read_serial(fd, buffer, offset, count);
if (result == -1)
ThrowIOException();
return result;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int write_serial(int fd, byte[] buffer, int offset, int count, int timeout);
public override void Write(byte[] buffer, int offset, int count)
{
CheckDisposed();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException();
if (buffer.Length - offset < count)
throw new ArgumentException("offset+count",
"The size of the buffer is less than offset + count.");
// FIXME: this reports every write error as timeout
if (write_serial(fd, buffer, offset, count, write_timeout) < 0)
throw new TimeoutException("The operation has timed-out");
}
protected override void Dispose(bool disposing)
{
if (disposed)
return;
disposed = true;
if (close_serial(fd) != 0)
{
//Don't do anything
}
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int close_serial(int fd);
public override void Close()
{
((IDisposable)this).Dispose();
}
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~FrostedSerialPortStream()
{
Dispose(false);
}
private void CheckDisposed()
{
if (disposed)
throw new ObjectDisposedException(GetType().FullName);
}
public void SetAttributes(int baud_rate, Parity parity, int data_bits, StopBits sb, Handshake hs)
{
if (!SetFrostedAttributes(fd, baud_rate, parity, data_bits, sb, hs))
ThrowIOException();
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int get_bytes_in_buffer(int fd, int input);
public int BytesToRead
{
get
{
int result = get_bytes_in_buffer(fd, 1);
if (result == -1)
ThrowIOException();
return result;
}
}
public int BytesToWrite
{
get
{
int result = get_bytes_in_buffer(fd, 0);
if (result == -1)
ThrowIOException();
return result;
}
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int discard_buffer(int fd, bool inputBuffer);
public void DiscardInBuffer()
{
if (discard_buffer(fd, true) != 0)
ThrowIOException();
}
public void DiscardOutBuffer()
{
if (discard_buffer(fd, false) != 0)
ThrowIOException();
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern SerialSignal get_signals(int fd, out int error);
public SerialSignal GetSignals()
{
int error;
SerialSignal signals = get_signals(fd, out error);
if (error == -1)
ThrowIOException();
return signals;
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int set_signal(int fd, SerialSignal signal, bool value);
public void SetSignal(SerialSignal signal, bool value)
{
if (signal < SerialSignal.Cd || signal > SerialSignal.Rts ||
signal == SerialSignal.Cd ||
signal == SerialSignal.Cts ||
signal == SerialSignal.Dsr)
throw new Exception("Invalid internal value");
if (set_signal(fd, signal, value) == -1)
ThrowIOException();
}
[DllImport("FrostedSerialHelper", SetLastError = true)]
private static extern int breakprop(int fd);
public void SetBreakState(bool value)
{
if (value)
if (breakprop(fd) == -1)
ThrowIOException();
}
[DllImport("libc")]
private static extern IntPtr strerror(int errnum);
private static void ThrowIOException()
{
int errnum = Marshal.GetLastWin32Error();
string error_message = Marshal.PtrToStringAnsi(strerror(errnum));
throw new IOException(error_message);
}
[DllImport("FrostedSerialHelper")]
private static extern bool is_baud_rate_legal(int baud_rate);
private void TryBaudRate(int baudRate)
{
if (!is_baud_rate_legal(baudRate))
{
// this kind of exception to be compatible with MSDN API
throw new ArgumentOutOfRangeException("baudRate",
"Given baud rate is not supported on this platform.");
}
}
}
}

View file

@ -0,0 +1,189 @@
/*
Copyright (c) 2014, Kevin Pope
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
public delegate void SerialDataReceivedEventHandler(object sender, SerialDataReceivedEventArgs e);
public delegate void SerialPinChangedEventHandler(object sender, SerialPinChangedEventArgs e);
public delegate void SerialErrorReceivedEventHandler(object sender, SerialErrorReceivedEventArgs e);
public interface IFrostedSerialPort
{
bool RtsEnable { get; set; }
bool DtrEnable { get; set; }
int BaudRate { get; set; }
int BytesToRead { get; }
void Write(string str);
void Write(byte[] buffer, int offset, int count);
int WriteTimeout { get; set; }
int ReadTimeout { get; set; }
string ReadExisting();
int Read(byte[] buffer, int offset, int count);
bool IsOpen { get; }
void Open();
void Close();
void Dispose();
}
internal enum SerialSignal
{
None = 0,
Cd = 1, // Carrier detect
Cts = 2, // Clear to send
Dsr = 4, // Data set ready
Dtr = 8, // Data terminal ready
Rts = 16 // Request to send
}
public enum Handshake
{
None,
XOnXOff,
RequestToSend,
RequestToSendXOnXOff
}
public enum StopBits
{
None,
One,
Two,
OnePointFive
}
public enum Parity
{
None,
Odd,
Even,
Mark,
Space
}
public enum SerialError
{
RXOver = 1,
Overrun = 2,
RXParity = 4,
Frame = 8,
TXFull = 256
}
public enum SerialData
{
Chars = 1,
Eof
}
public enum SerialPinChange
{
CtsChanged = 8,
DsrChanged = 16,
CDChanged = 32,
Break = 64,
Ring = 256
}
public class SerialDataReceivedEventArgs : EventArgs
{
internal SerialDataReceivedEventArgs(SerialData eventType)
{
this.eventType = eventType;
}
// properties
public SerialData EventType
{
get
{
return eventType;
}
}
private SerialData eventType;
}
public class SerialPinChangedEventArgs : EventArgs
{
internal SerialPinChangedEventArgs(SerialPinChange eventType)
{
this.eventType = eventType;
}
// properties
public SerialPinChange EventType
{
get
{
return eventType;
}
}
private SerialPinChange eventType;
}
public class SerialErrorReceivedEventArgs : EventArgs
{
internal SerialErrorReceivedEventArgs(SerialError eventType)
{
this.eventType = eventType;
}
// properties
public SerialError EventType
{
get
{
return eventType;
}
}
private SerialError eventType;
}
}

View file

@ -0,0 +1,33 @@
using System;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
internal interface IFrostedSerialStream : IDisposable
{
int Read(byte[] buffer, int offset, int count);
void Write(byte[] buffer, int offset, int count);
void SetAttributes(int baud_rate, Parity parity, int data_bits, StopBits sb, Handshake hs);
void DiscardInBuffer();
void DiscardOutBuffer();
SerialSignal GetSignals();
void SetSignal(SerialSignal signal, bool value);
void SetBreakState(bool value);
void Close();
int BytesToRead { get; }
int BytesToWrite { get; }
int ReadTimeout { get; set; }
int WriteTimeout { get; set; }
}
}

View file

@ -0,0 +1,218 @@
// Copyright 2010-2014 Zach Saw
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
public 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.Close();
m_Handle = null;
}
}
#endregion IDisposable Members
#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 = CreateFile(@"\\.\" + portName, dwAccess, 0, IntPtr.Zero, 3, dwFlagsAndAttributes, IntPtr.Zero);
if (hFile.IsInvalid)
{
WinIoError();
}
try
{
int fileType = GetFileType(hFile);
if ((fileType != 2) && (fileType != 0))
{
throw new ArgumentException("Invalid Serial Port", "portName");
}
m_Handle = hFile;
InitializeDcb();
}
catch
{
hFile.Close();
m_Handle = null;
throw;
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private 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)]
private static extern bool GetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetCommState(SafeFileHandle hFile, ref Dcb lpDcb);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool ClearCommError(SafeFileHandle hFile, ref int lpErrors, ref Comstat lpStat);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
IntPtr securityAttrs, int dwCreationDisposition,
int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
private 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 (
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 (!ClearCommError(m_Handle, ref commErrors, ref comStat))
{
WinIoError();
}
if (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 (!ClearCommError(m_Handle, ref commErrors, ref comStat))
{
WinIoError();
}
if (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 Nested type: COMSTAT
#region Nested type: DCB
[StructLayout(LayoutKind.Sequential)]
private 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 Nested type: DCB
#endregion Implementation
}
}

View file

@ -0,0 +1,158 @@
using System;
namespace MatterHackers.SerialPortCommunication.FrostedSerial
{
public enum e_cc_c
{
/* Indices into c_cc array. Default values in parentheses. POSIX Table 7-5. */
VEOF = 0, /* cc_c[VEOF] = EOF char (^D) */
VEOL = 1, /* cc_c[VEOL] = EOL char (undef) */
VERASE = 2, /* cc_c[VERASE] = ERASE char (^H) */
VINTR = 3, /* cc_c[VINTR] = INTR char (DEL) */
VKILL = 4, /* cc_c[VKILL] = KILL char (^U) */
VMIN = 5, /* cc_c[VMIN] = MIN value for timer */
VQUIT = 6, /* cc_c[VQUIT] = QUIT char (^\) */
VTIME = 7, /* cc_c[VTIME] = TIME value for timer */
VSUSP = 8, /* cc_c[VSUSP] = SUSP (^Z, ignored) */
VSTART = 9, /* cc_c[VSTART] = START char (^S) */
VSTOP = 10, /* cc_c[VSTOP] = STOP char (^Q) */
//_POSIX_VDISABLE =(cc_t)0xFF, /* You can't even generate this /*
/* character with 'normal' keyboards.
* But some language specific keyboards
* can generate 0xFF. It seems that all
* 256 are used, so cc_t should be a
* short...
*/
SIZE = 20, /* size of cc_c array, some extra space * for extensions. */
};
/* Values for termios c_iflag bit map. POSIX Table 7-2. */
[Flags]
public enum e_c_iflag
{
BRKINT = 0x0001, /* signal interrupt on break */
ICRNL = 0x0002, /* map CR to NL on input */
IGNBRK = 0x0004, /* ignore break */
IGNCR = 0x0008, /* ignore CR */
IGNPAR = 0x0010, /* ignore characters with parity errors */
INLCR = 0x0020, /* map NL to CR on input */
INPCK = 0x0040, /* enable input parity check */
ISTRIP = 0x0080, /* mask off 8th bit */
IXOFF = 0x0100, /* enable start/stop input control */
IXON = 0x0200, /* enable start/stop output control */
PARMRK = 0x0400, /* mark parity errors in the input queue */
};
/* Values for termios c_oflag bit map. POSIX Sec. 7.1.2.3. */
[Flags]
public enum e_c_oflag
{
OPOST = 0x0001, /* perform output processing */
/* Values for termios c_cflag bit map. POSIX Table 7-3. */
CLOCAL = 0x0001, /* ignore modem status lines */
CREAD = 0x0002, /* enable receiver */
CSIZE = 0x000C, /* number of bits per character */
CS5 = 0x0000, /* if CSIZE is CS5, characters are 5 bits */
CS6 = 0x0004, /* if CSIZE is CS6, characters are 6 bits */
CS7 = 0x0008, /* if CSIZE is CS7, characters are 7 bits */
CS8 = 0x000C, /* if CSIZE is CS8, characters are 8 bits */
CSTOPB = 0x0010, /* send 2 stop bits if set, else 1 */
HUPCL = 0x0020, /* hang up on last close */
PARENB = 0x0040, /* enable parity on output */
PARODD = 0x0080, /* use odd parity if set, else even */
};
/* Values for termios c_lflag bit map. POSIX Table 7-4. */
[Flags]
public enum e_c_lflag
{
ECHO = 0x0001, /* enable echoing of input characters */
ECHOE = 0x0002, /* echo ERASE as backspace */
ECHOK = 0x0004, /* echo KILL */
ECHONL = 0x0008, /* echo NL */
ICANON = 0x0010, /* canonical input (erase and kill enabled) */
IEXTEN = 0x0020, /* enable extended functions */
ISIG = 0x0040, /* enable signals */
NOFLSH = 0x0080, /* disable flush after interrupt or quit */
TOSTOP = 0x0100, /* send SIGTTOU (job control, not implemented*/
};
/* Values for the baud rate settings. POSIX Table 7-6. */
[Flags]
public enum e_baud_rate
{
B0 = 0x0000, /* hang up the line */
B50 = 0x1000, /* 50 baud */
B75 = 0x2000, /* 75 baud */
B110 = 0x3000, /* 110 baud */
B134 = 0x4000, /* 134.5 baud */
B150 = 0x5000, /* 150 baud */
B200 = 0x6000, /* 200 baud */
B300 = 0x7000, /* 300 baud */
B600 = 0x8000, /* 600 baud */
B1200 = 0x9000, /* 1200 baud */
B1800 = 0xA000, /* 1800 baud */
B2400 = 0xB000, /* 2400 baud */
B4800 = 0xC000, /* 4800 baud */
B9600 = 0xD000, /* 9600 baud */
B19200 = 0xE000, /* 19200 baud */
B38400 = 0xF000, /* 38400 baud */
};
/* Optional actions for tcsetattr(). POSIX Sec. 7.2.1.2. */
[Flags]
public enum e_tcsetaatr
{
TCSANOW = 1, /* changes take effect immediately */
TCSADRAIN = 2, /* changes take effect after output is done */
TCSAFLUSH = 3, /* wait for output to finish and flush input */
};
/* Queue_selector values for tcflush(). POSIX Sec. 7.2.2.2. */
[Flags]
public enum e_tcflush
{
TCIFLUSH = 1, /* flush accumulated input data */
TCOFLUSH = 2, /* flush accumulated output data */
TCIOFLUSH = 3, /* flush accumulated input and output data */
};
/* Action values for tcflow(). POSIX Sec. 7.2.2.2. */
[Flags]
public enum e_tcflow
{
TCOOFF = 1, /* suspend output */
TCOON = 2, /* restart suspended output */
TCIOFF = 3, /* transmit a STOP character on the line */
TCION = 4, /* transmit a START character on the line */
};
internal static class testCLass
{
private static void TestFunc()
{
uint c_cflag = 0;
uint c_lflag = 0;
uint c_oflag = 0;
//uint c_iflag = 0;
c_cflag |= (uint)(e_c_oflag.CLOCAL | e_c_oflag.CREAD);
//c_lflag &= (uint)-(e_c_lflag.ICANON | e_c_lflag.ECHO | e_c_lflag.ECHOE | e_c_lflag.ECHOK | e_c_lflag.ECHOL | e_c_lflag.ECHONL | e_c_lflag.ISIG | e_c_lflag.IEXTEN);
// not supported in docs I can find ECHOL
unchecked
{
c_lflag &= (uint)-(uint)(e_c_lflag.ICANON | e_c_lflag.ECHO | e_c_lflag.ECHOE | e_c_lflag.ECHOK | e_c_lflag.ECHONL | e_c_lflag.ISIG | e_c_lflag.IEXTEN);
}
c_oflag &= (uint)(e_c_oflag.OPOST);
//c_iflag = (uint)e_c_iflag.IGNBRK;
}
}
}

View file

@ -17,16 +17,17 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG;USE_STANDARD_SERIAL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;USE_STANDARD_SERIAL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
@ -45,6 +46,15 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Communication\FoundStringCallBacks.cs" />
<Compile Include="Communication\FrostedSerial\CSharpSerialPortWrapper.cs" />
<Compile Include="Communication\FrostedSerial\FrostedSerialPort.cs" />
<Compile Include="Communication\FrostedSerial\FrostedSerialPortFactory.cs" />
<Compile Include="Communication\FrostedSerial\FrostedSerialStream.cs" />
<Compile Include="Communication\FrostedSerial\IFrostedSerialPort.cs" />
<Compile Include="Communication\FrostedSerial\IFrostedSerialStream.cs" />
<Compile Include="Communication\SerialPortFixer.cs" />
<Compile Include="Communication\TermiosH.cs" />
<Compile Include="GCode\GCodeFile.cs" />
<Compile Include="GCode\GCodeMemoryFile.cs" />
<Compile Include="GCode\GCodeFileStreamed.cs" />

View file

@ -583,10 +583,6 @@
<Project>{D3E41B4E-BFBB-44CA-94C8-95C00F754FDD}</Project>
<Name>VectorMath</Name>
</ProjectReference>
<ProjectReference Include="Submodules\agg-sharp\SerialPortCommunication\SerialPortCommunication.csproj">
<Project>{D3ABF72C-64C2-4E51-A119-E077210FA990}</Project>
<Name>SerialPortCommunication</Name>
</ProjectReference>
<ProjectReference Include="Submodules\MatterSlice\MatterSlice.csproj">
<Project>{C46CA728-DD2F-4DD1-971A-AAA89D9DFF95}</Project>
<Name>MatterSlice</Name>

View file

@ -79,9 +79,9 @@
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Submodules\agg-sharp\SerialPortCommunication\SerialPortCommunication.csproj">
<Project>{D3ABF72C-64C2-4E51-A119-E077210FA990}</Project>
<Name>SerialPortCommunication</Name>
<ProjectReference Include="..\MatterControl.Printing\MatterControl.Printing.csproj">
<Project>{97d5ade3-c1b4-4b46-8a3e-718a4f7f079f}</Project>
<Name>MatterControl.Printing</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

@ -1 +1 @@
Subproject commit 95e733a96dd969922769292967959a339964c92b
Subproject commit dbe5a9eb4460cc7950927a51304ef2678e1b872b

View file

@ -86,6 +86,10 @@
<Project>{0b8d6f56-bd7f-4426-b858-d9292b084656}</Project>
<Name>MatterControl</Name>
</ProjectReference>
<ProjectReference Include="..\..\MatterControl.Printing\MatterControl.Printing.csproj">
<Project>{97d5ade3-c1b4-4b46-8a3e-718a4f7f079f}</Project>
<Name>MatterControl.Printing</Name>
</ProjectReference>
<ProjectReference Include="..\..\PrinterEmulator\PrinterEmulator.csproj">
<Project>{bb58ca42-991b-41b7-bde7-dcd2911df8b9}</Project>
<Name>PrinterEmulator</Name>
@ -118,10 +122,6 @@
<Project>{545B6912-77FF-4B34-BA76-6C3D6A32BE6A}</Project>
<Name>RenderOpenGl</Name>
</ProjectReference>
<ProjectReference Include="..\..\Submodules\agg-sharp\SerialPortCommunication\SerialPortCommunication.csproj">
<Project>{D3ABF72C-64C2-4E51-A119-E077210FA990}</Project>
<Name>SerialPortCommunication</Name>
</ProjectReference>
<ProjectReference Include="..\..\Submodules\agg-sharp\Tests\Agg.Tests\Agg.Tests.csproj">
<Project>{195cbe56-e654-437b-ab05-3be1b9452497}</Project>
<Name>Agg.Tests</Name>

View file

@ -131,10 +131,6 @@
<Project>{545b6912-77ff-4b34-ba76-6c3d6a32be6a}</Project>
<Name>RenderOpenGl</Name>
</ProjectReference>
<ProjectReference Include="..\..\Submodules\agg-sharp\SerialPortCommunication\SerialPortCommunication.csproj">
<Project>{D3ABF72C-64C2-4E51-A119-E077210FA990}</Project>
<Name>SerialPortCommunication</Name>
</ProjectReference>
<ProjectReference Include="..\..\Submodules\agg-sharp\Tests\Agg.Tests\Agg.Tests.csproj">
<Project>{195CBE56-E654-437B-AB05-3BE1B9452497}</Project>
<Name>Agg.Tests</Name>