diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 247c1b8..3404796 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; +using System.IO.Ports; using ASCOM; using ASCOM.MeadeAutostar497.Controller; using ASCOM.Utilities; -using ASCOM.Utilities.Interfaces; using Moq; using NUnit.Framework; @@ -11,26 +11,25 @@ namespace MeadeAutostar497.UnitTests [TestFixture] public class TelescopeControllerUnitTests { - private Mock serialMock; + private Mock serialMock; private readonly List _availableComPorts = new List { "COM1", "COM2", "COM3" }; private TelescopeController _telescopeController; - private string transmittedString; - private string stringToRecieve; + private string _stringToRecieve = string.Empty; + private bool _isConnected = false; [SetUp] public void Setup() { - transmittedString = string.Empty; - stringToRecieve = string.Empty; + _stringToRecieve = string.Empty; + _isConnected = false; - serialMock = new Mock(); + serialMock = new Mock(); serialMock.SetupAllProperties(); - - serialMock.Setup(x => x.AvailableComPorts).Returns( () => _availableComPorts.ToArray()); - serialMock.Setup(X => X.Transmit(It.IsAny())).Callback(str => { transmittedString = str; }); - serialMock.Setup(X => X.Receive()).Returns(() => stringToRecieve); + serialMock.Setup(x => x.GetPortNames()).Returns( () => _availableComPorts.ToArray()); + serialMock.Setup(x => x.CommandTerminated(It.IsAny(), It.IsAny())).Returns(() => _stringToRecieve); + serialMock.Setup(x => x.IsOpen).Returns(() => _isConnected); _telescopeController = TelescopeController.Instance; _telescopeController.SerialPort = serialMock.Object; @@ -39,7 +38,6 @@ namespace MeadeAutostar497.UnitTests [TearDown] public void TearDown() { - _telescopeController.Connected = false; _telescopeController.Port = "COM1"; } @@ -59,7 +57,8 @@ namespace MeadeAutostar497.UnitTests [Test] public void ConnectedCanBeSetTrue() { - stringToRecieve = "test#"; + _stringToRecieve = "test#"; + _isConnected = true; _telescopeController.Connected = true; Assert.That(_telescopeController.Connected, Is.True); @@ -68,27 +67,30 @@ namespace MeadeAutostar497.UnitTests [Test] public void EnsureThatTheSerialCommunicationsAreSetCorrectly() { - Assert.That(serialMock.Object.Connected, Is.False); - - stringToRecieve = "test#"; + Assert.That(serialMock.Object.IsOpen, Is.False); + _stringToRecieve = "test#"; _telescopeController.Connected = true; + _isConnected = true; Assert.That(_telescopeController.Connected, Is.True); - Assert.That(serialMock.Object.DTREnable, Is.False); - Assert.That(serialMock.Object.RTSEnable, Is.False); - Assert.That(serialMock.Object.Speed, Is.EqualTo(SerialSpeed.ps9600)); + serialMock.Verify(x => x.Open(), Times.Once); + + Assert.That(serialMock.Object.DtrEnable, Is.False); + Assert.That(serialMock.Object.RtsEnable, Is.False); + Assert.That(serialMock.Object.BaudRate, Is.EqualTo(9600)); Assert.That(serialMock.Object.DataBits, Is.EqualTo(8)); - Assert.That(serialMock.Object.StopBits, Is.EqualTo(SerialStopBits.One)); - Assert.That(serialMock.Object.Parity, Is.EqualTo(SerialParity.None)); + Assert.That(serialMock.Object.StopBits, Is.EqualTo(StopBits.One)); + Assert.That(serialMock.Object.Parity, Is.EqualTo(Parity.None)); Assert.That(serialMock.Object.PortName, Is.EqualTo(_telescopeController.Port)); - Assert.That(serialMock.Object.Connected, Is.True); + Assert.That(serialMock.Object.IsOpen, Is.True); + } [Test] public void WhenOpensComPortToNonAutostarThrowException() { - Assert.That(serialMock.Object.Connected, Is.False); + Assert.That(serialMock.Object.IsOpen, Is.False); var exception = Assert.Throws(() => { _telescopeController.Connected = true; }); Assert.That(exception.Message, Is.EqualTo("Failed to communicate with telescope.")); @@ -99,11 +101,12 @@ namespace MeadeAutostar497.UnitTests [Test] public void CannotChangeSerialPortObjectWhenConnected() { - stringToRecieve = "test#"; + _stringToRecieve = "test#"; + _isConnected = true; _telescopeController.Connected = true; - Mock newSerialMock = new Mock(); + Mock newSerialMock = new Mock(); var exception = Assert.Throws( () => { _telescopeController.SerialPort = newSerialMock.Object; }); @@ -128,7 +131,8 @@ namespace MeadeAutostar497.UnitTests [Test] public void SettingPortToValidPortWhenConnectedFails() { - stringToRecieve = "test#"; + _stringToRecieve = "test#"; + _isConnected = true; _telescopeController.Connected = true; var exception = Assert.Throws( () => _telescopeController.Port = "COM2"); diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 264f601..a56d4d6 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -169,9 +169,9 @@ namespace ASCOM.MeadeAutostar497 { CheckConnected("CommandBlind"); // Call CommandString and return as soon as it finishes - this.CommandString(command, raw); + //this.CommandString(command, raw); // or - //throw new ASCOM.MethodNotImplementedException("CommandBlind"); + throw new ASCOM.MethodNotImplementedException("CommandBlind"); // DO NOT have both these sections! One or the other } @@ -187,8 +187,11 @@ namespace ASCOM.MeadeAutostar497 public string CommandString(string command, bool raw) { + // it's a good idea to put all the low level communication with the device here, + // then all communication calls this function + // you need something to ensure that only one command is in progress at a time CheckConnected("CommandString"); - return _telescopeController.CommandString(command, raw); + throw new ASCOM.MethodNotImplementedException("CommandString"); } public void Dispose() diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 6663772..f0bf070 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -1,15 +1,14 @@ using System; -using ASCOM.Utilities.Interfaces; +using System.IO.Ports; namespace ASCOM.MeadeAutostar497.Controller { public interface ITelescopeController { - ISerial SerialPort { get; set; } + ISerialProcessor SerialPort { get; set; } string Port { get; set; } bool Connected { get; set; } - string CommandString(string command, bool raw); bool Slewing { get; } DateTime utcDate { get; set; } } diff --git a/MeadeAutostar497/Controller/SerialProcessor.cs b/MeadeAutostar497/Controller/SerialProcessor.cs new file mode 100644 index 0000000..b49619f --- /dev/null +++ b/MeadeAutostar497/Controller/SerialProcessor.cs @@ -0,0 +1,138 @@ +using System; +using System.IO.Ports; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace ASCOM.MeadeAutostar497.Controller +{ + [ComVisible(false)] + public interface ISerialProcessor + { + bool IsOpen { get; } + bool DtrEnable { get; set; } + bool RtsEnable { get; set; } + int BaudRate { get; set; } + int DataBits { get; set; } + StopBits StopBits { get; set; } + Parity Parity { get; set; } + string PortName { get; set; } + string[] GetPortNames(); + void Open(); + void Close(); + + string CommandTerminated(string command, string terminator); + char CommandChar(string command); + string ReadTerminated(string terminator); + } + + [ComVisible(false)] + public class SerialProcessor : ISerialProcessor + { + private SerialPort _serialPort = new SerialPort(); + private Mutex serialMutex = new Mutex(); + + public bool IsOpen => _serialPort.IsOpen; + + public bool DtrEnable + { + get => _serialPort.DtrEnable; + set => _serialPort.DtrEnable = value; + } + + public bool RtsEnable + { + get => _serialPort.RtsEnable; + set => _serialPort.RtsEnable = value; + } + + public int BaudRate + { + get => _serialPort.BaudRate; + set => _serialPort.BaudRate = value; + } + + public int DataBits + { + get => _serialPort.DataBits; + set => _serialPort.DataBits = value; + } + + public StopBits StopBits + { + get => _serialPort.StopBits; + set => _serialPort.StopBits = value; + } + + public Parity Parity + { + get => _serialPort.Parity; + set => _serialPort.Parity = value; + } + + public string PortName + { + get => _serialPort.PortName; + set => _serialPort.PortName = value; + } + + public string[] GetPortNames() + { + return SerialPort.GetPortNames(); + } + + public void Open() + { + _serialPort.Open(); + } + + public void Close() + { + _serialPort.Close(); + } + + public string CommandTerminated(string command, string terminator) + { + serialMutex.WaitOne(); + try + { + _serialPort.Write(command); + string result = _serialPort.ReadTo("#"); + return result; + } + finally + { + serialMutex.ReleaseMutex(); + } + } + + public char CommandChar(string command) + { + serialMutex.WaitOne(); + try + { + _serialPort.Write(command); + var result = _serialPort.ReadChar(); + return Convert.ToChar(result); + } + finally + { + serialMutex.ReleaseMutex(); + } + } + + public string ReadTerminated(string terminator) + { + serialMutex.WaitOne(); + try + { + string result = _serialPort.ReadTo("#"); + return result; + } + finally + { + serialMutex.ReleaseMutex(); + } + } + } +} diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index fe6dc4c..2367d75 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -1,6 +1,7 @@ using System; using System.Configuration; using System.Data; +using System.IO.Ports; using System.Linq; using System.Threading; using ASCOM.Utilities; @@ -14,12 +15,10 @@ namespace ASCOM.MeadeAutostar497.Controller public static TelescopeController Instance => lazy.Value; - private Mutex serialMutex = new Mutex(); - - private ISerial _serialPort; - public ISerial SerialPort + private ISerialProcessor _serialPort; + public ISerialProcessor SerialPort { - get => _serialPort ?? (_serialPort = new Serial()); + get => _serialPort ?? (_serialPort = new SerialProcessor()); set { if (_serialPort == value) @@ -27,7 +26,7 @@ namespace ASCOM.MeadeAutostar497.Controller if (_serialPort != null) { - if (_serialPort.Connected) + if (_serialPort.IsOpen) throw new InvalidOperationException("Please disconnect before changing the serial engine."); } @@ -55,12 +54,12 @@ namespace ASCOM.MeadeAutostar497.Controller private bool ValidPort(string value) { - return SerialPort.AvailableComPorts.Contains(value); + return SerialPort.GetPortNames().Contains(value); } public bool Connected { - get => SerialPort.Connected; + get => SerialPort.IsOpen; set { if (value == Connected) @@ -71,60 +70,48 @@ namespace ASCOM.MeadeAutostar497.Controller //Connecting try { - SerialPort.DTREnable = false; - SerialPort.RTSEnable = false; - SerialPort.Speed = SerialSpeed.ps9600; + SerialPort.DtrEnable = false; + SerialPort.RtsEnable = false; + SerialPort.BaudRate = 9600; SerialPort.DataBits = 8; - SerialPort.StopBits = SerialStopBits.One; - SerialPort.Parity = SerialParity.None; + SerialPort.StopBits = StopBits.One; + SerialPort.Parity = Parity.None; SerialPort.PortName = Port; - SerialPort.Connected = true; + SerialPort.Open(); TestConnectionActive(); } catch (Exception) { - SerialPort.Connected = false; + if (SerialPort.IsOpen) + SerialPort.Close(); throw; } } else { //Disconnecting - SerialPort.Connected = false; + SerialPort.Close(); } } } private void TestConnectionActive() { - var firmwareVersionNumber = CommandString("GVN"); + var firmwareVersionNumber = SerialPort.CommandTerminated(":GVN#", "#"); if (string.IsNullOrEmpty(firmwareVersionNumber)) { throw new InvalidOperationException("Failed to communicate with telescope."); } } - public string CommandString(string command) - { - return CommandString($"#:{command}#", false); - } - - public string CommandString(string command, bool raw) - { - // it's a good idea to put all the low level communication with the device here, - // then all communication calls this function - // you need something to ensure that only one command is in progress at a time - return SerialCommand(command, true); - } - public bool Slewing { get { if (!Connected) return false; - var result = CommandString("D"); + var result = SerialPort.CommandTerminated("#:D#", "#"); return result != string.Empty; } } @@ -133,8 +120,8 @@ namespace ASCOM.MeadeAutostar497.Controller { get { - string telescopeDate = CommandString("GC"); - string telescopeTime = CommandString("GL"); + string telescopeDate = SerialPort.CommandTerminated("#:GC#", "#"); + string telescopeTime = SerialPort.CommandTerminated("#:GL#", "#"); int month = telescopeDate.Substring(0, 2).ToInteger(); int day = telescopeDate.Substring(3, 2).ToInteger(); @@ -156,40 +143,22 @@ namespace ASCOM.MeadeAutostar497.Controller set { //var result = SerialCommand(":SLHH:MM:SS#", true); - var timeResult = SerialCommand($"#:SL{value:hh:mm:ss}#", true); - if (timeResult != "1") + var timeResult = SerialPort.CommandChar($"#:SL{value:hh:mm:ss}#"); + if (timeResult != '1') { throw new InvalidOperationException("Failed to set local time"); } - var dateResult = SerialCommand($"#:SC{value:MM/dd/yy}#", true); - if (dateResult.Substring(0,1) != "1") + var dateResult = SerialPort.CommandChar($"#:SC{value:MM/dd/yy}#"); + if (dateResult != '1') { throw new InvalidOperationException("Failed to set local time"); } + + SerialPort.ReadTerminated("#"); + SerialPort.ReadTerminated("#"); } } - - private string SerialCommand(string command, bool expectsResult ) - { - serialMutex.WaitOne(); - try - { - SerialPort.Transmit(command); - if (expectsResult) - { - string result = SerialPort.ReceiveTerminated("#"); - - return result; - } - return string.Empty; - } - finally - { - SerialPort.ClearBuffers(); - serialMutex.ReleaseMutex(); - } - } } } diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/MeadeAutostar497/MeadeAutostar497.csproj index 940afa9..2640107 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/MeadeAutostar497/MeadeAutostar497.csproj @@ -90,6 +90,7 @@ +