From 369835d314f147995b7d5d4670c168f6c578cf74 Mon Sep 17 00:00:00 2001 From: John Lewin Date: Fri, 29 Dec 2017 14:54:43 -0800 Subject: [PATCH] Move SerialPortCommunication to MatterControl.Printing project --- .../Communication/FoundStringCallBacks.cs | 128 +++ .../FrostedSerial/CSharpSerialPortWrapper.cs | 167 ++++ .../FrostedSerial/FrostedSerialPort.cs | 925 ++++++++++++++++++ .../FrostedSerial/FrostedSerialPortFactory.cs | 223 +++++ .../FrostedSerial/FrostedSerialStream.cs | 531 ++++++++++ .../FrostedSerial/IFrostedSerialPort.cs | 189 ++++ .../FrostedSerial/IFrostedSerialStream.cs | 33 + .../Communication/SerialPortFixer.cs | 218 +++++ .../Communication/TermiosH.cs | 158 +++ .../MatterControl.Printing.csproj | 14 +- MatterControl.csproj | 4 - PrinterEmulator/PrinterEmulator.csproj | 6 +- Submodules/agg-sharp | 2 +- .../MatterControl.AutomationTests.csproj | 8 +- .../MatterControl.Tests.csproj | 4 - 15 files changed, 2592 insertions(+), 18 deletions(-) create mode 100644 MatterControl.Printing/Communication/FoundStringCallBacks.cs create mode 100644 MatterControl.Printing/Communication/FrostedSerial/CSharpSerialPortWrapper.cs create mode 100644 MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPort.cs create mode 100644 MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPortFactory.cs create mode 100644 MatterControl.Printing/Communication/FrostedSerial/FrostedSerialStream.cs create mode 100644 MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialPort.cs create mode 100644 MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialStream.cs create mode 100644 MatterControl.Printing/Communication/SerialPortFixer.cs create mode 100644 MatterControl.Printing/Communication/TermiosH.cs diff --git a/MatterControl.Printing/Communication/FoundStringCallBacks.cs b/MatterControl.Printing/Communication/FoundStringCallBacks.cs new file mode 100644 index 000000000..1bb37a28d --- /dev/null +++ b/MatterControl.Printing/Communication/FoundStringCallBacks.cs @@ -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 > dictionaryOfCallbacks = new Dictionary>(); + + public void AddCallbackToKey(string key, EventHandler value) + { + if (dictionaryOfCallbacks.ContainsKey(key)) + { + dictionaryOfCallbacks[key] += value; + } + else + { + dictionaryOfCallbacks.Add(key, value); + } + } + + public void RemoveCallbackFromKey(string key, EventHandler 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); + } + } + } + } +} \ No newline at end of file diff --git a/MatterControl.Printing/Communication/FrostedSerial/CSharpSerialPortWrapper.cs b/MatterControl.Printing/Communication/FrostedSerial/CSharpSerialPortWrapper.cs new file mode 100644 index 000000000..532e05531 --- /dev/null +++ b/MatterControl.Printing/Communication/FrostedSerial/CSharpSerialPortWrapper.cs @@ -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 + } \ No newline at end of file diff --git a/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPort.cs b/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPort.cs new file mode 100644 index 000000000..e9190a98a --- /dev/null +++ b/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPort.cs @@ -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 FilterPortsForMac(List allPorts) + { + IEnumerable 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 serial_ports = new List(); + + // 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 seen = new List(); + + 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); } + } + } +} diff --git a/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPortFactory.cs b/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPortFactory.cs new file mode 100644 index 000000000..6381219f1 --- /dev/null +++ b/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialPortFactory.cs @@ -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 availableFactories = new Dictionary(); + + 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(); + + 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; + } + } + } +} diff --git a/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialStream.cs b/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialStream.cs new file mode 100644 index 000000000..a32b294d7 --- /dev/null +++ b/MatterControl.Printing/Communication/FrostedSerial/FrostedSerialStream.cs @@ -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."); + } + } + } +} \ No newline at end of file diff --git a/MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialPort.cs b/MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialPort.cs new file mode 100644 index 000000000..620fd8e7b --- /dev/null +++ b/MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialPort.cs @@ -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; + } +} \ No newline at end of file diff --git a/MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialStream.cs b/MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialStream.cs new file mode 100644 index 000000000..7531974f9 --- /dev/null +++ b/MatterControl.Printing/Communication/FrostedSerial/IFrostedSerialStream.cs @@ -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; } + } +} \ No newline at end of file diff --git a/MatterControl.Printing/Communication/SerialPortFixer.cs b/MatterControl.Printing/Communication/SerialPortFixer.cs new file mode 100644 index 000000000..cb3068bb4 --- /dev/null +++ b/MatterControl.Printing/Communication/SerialPortFixer.cs @@ -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 + } +} \ No newline at end of file diff --git a/MatterControl.Printing/Communication/TermiosH.cs b/MatterControl.Printing/Communication/TermiosH.cs new file mode 100644 index 000000000..22294f32a --- /dev/null +++ b/MatterControl.Printing/Communication/TermiosH.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/MatterControl.Printing/MatterControl.Printing.csproj b/MatterControl.Printing/MatterControl.Printing.csproj index 7f80fc6a3..d3df7e527 100644 --- a/MatterControl.Printing/MatterControl.Printing.csproj +++ b/MatterControl.Printing/MatterControl.Printing.csproj @@ -17,16 +17,17 @@ full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG;USE_STANDARD_SERIAL prompt 4 AnyCPU + true pdbonly true bin\Release\ - TRACE + TRACE;USE_STANDARD_SERIAL prompt 4 AnyCPU @@ -45,6 +46,15 @@ + + + + + + + + + diff --git a/MatterControl.csproj b/MatterControl.csproj index 88357eb99..6157e16d1 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -583,10 +583,6 @@ {D3E41B4E-BFBB-44CA-94C8-95C00F754FDD} VectorMath - - {D3ABF72C-64C2-4E51-A119-E077210FA990} - SerialPortCommunication - {C46CA728-DD2F-4DD1-971A-AAA89D9DFF95} MatterSlice diff --git a/PrinterEmulator/PrinterEmulator.csproj b/PrinterEmulator/PrinterEmulator.csproj index 7696d1624..feb9a1566 100644 --- a/PrinterEmulator/PrinterEmulator.csproj +++ b/PrinterEmulator/PrinterEmulator.csproj @@ -79,9 +79,9 @@ - - {D3ABF72C-64C2-4E51-A119-E077210FA990} - SerialPortCommunication + + {97d5ade3-c1b4-4b46-8a3e-718a4f7f079f} + MatterControl.Printing diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 95e733a96..dbe5a9eb4 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 95e733a96dd969922769292967959a339964c92b +Subproject commit dbe5a9eb4460cc7950927a51304ef2678e1b872b diff --git a/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj b/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj index 999e2eaef..9fce5cc2b 100644 --- a/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj +++ b/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj @@ -86,6 +86,10 @@ {0b8d6f56-bd7f-4426-b858-d9292b084656} MatterControl + + {97d5ade3-c1b4-4b46-8a3e-718a4f7f079f} + MatterControl.Printing + {bb58ca42-991b-41b7-bde7-dcd2911df8b9} PrinterEmulator @@ -118,10 +122,6 @@ {545B6912-77FF-4B34-BA76-6C3D6A32BE6A} RenderOpenGl - - {D3ABF72C-64C2-4E51-A119-E077210FA990} - SerialPortCommunication - {195cbe56-e654-437b-ab05-3be1b9452497} Agg.Tests diff --git a/Tests/MatterControl.Tests/MatterControl.Tests.csproj b/Tests/MatterControl.Tests/MatterControl.Tests.csproj index d8f55a5a5..d5f860f1f 100644 --- a/Tests/MatterControl.Tests/MatterControl.Tests.csproj +++ b/Tests/MatterControl.Tests/MatterControl.Tests.csproj @@ -131,10 +131,6 @@ {545b6912-77ff-4b34-ba76-6c3d6a32be6a} RenderOpenGl - - {D3ABF72C-64C2-4E51-A119-E077210FA990} - SerialPortCommunication - {195CBE56-E654-437B-AB05-3BE1B9452497} Agg.Tests