From 21e7bcd530bc46d623e12cb9dea2a6314d188e5e Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 10 Mar 2021 19:25:27 +0000 Subject: [PATCH 01/23] Added support for the GW Command. Removed the implementation of Tracking Set as this does not do anything in the code. Set Can Set Tracking to false. Get tracking always returns true is the GW command is not supported. --- .../TelescopeUnitTests.cs | 23 +-- Meade.net.Telescope/Alignment.cs | 10 ++ Meade.net.Telescope/AlignmentStatus.cs | 11 ++ .../Meade.net.Telescope.csproj | 2 + Meade.net.Telescope/Telescope.cs | 131 ++++++++++++------ 5 files changed, 123 insertions(+), 54 deletions(-) create mode 100644 Meade.net.Telescope/Alignment.cs create mode 100644 Meade.net.Telescope/AlignmentStatus.cs diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 16b330d..be47538 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -621,15 +621,18 @@ namespace Meade.net.Telescope.UnitTests } - [TestCase("A", AlignmentModes.algAltAz)] - [TestCase("P", AlignmentModes.algPolar)] - [TestCase("G", AlignmentModes.algGermanPolar)] - public void AlignmentMode_Get_WhenScopeInAltAz_ReturnsAltAz(string telescopeMode, AlignmentModes alignmentMode) + [TestCase("A", AlignmentModes.algAltAz, TelescopeList.Autostar497, TelescopeList.Autostar497_31Ee)] + [TestCase("P", AlignmentModes.algPolar, TelescopeList.Autostar497, TelescopeList.Autostar497_31Ee)] + [TestCase("A", AlignmentModes.algAltAz, TelescopeList.Autostar497, TelescopeList.Autostar497_43Eg)] + [TestCase("P", AlignmentModes.algPolar, TelescopeList.Autostar497, TelescopeList.Autostar497_43Eg)] + [TestCase("G", AlignmentModes.algGermanPolar, TelescopeList.Autostar497, TelescopeList.Autostar497_43Eg)] + public void AlignmentMode_Get_WhenScopeInAltAz_ReturnsAltAz(string telescopeMode, AlignmentModes alignmentMode, string productName, string firmware) { const char ack = (char)6; _sharedResourcesWrapperMock.Setup(x => x.SendChar(ack.ToString())).Returns(telescopeMode); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GW#")).Returns($"{telescopeMode}N0"); - ConnectTelescope(); + ConnectTelescope(productName, firmware); var actualResult = _telescope.AlignmentMode; @@ -897,11 +900,11 @@ namespace Meade.net.Telescope.UnitTests } [Test] - public void CanSetTracking_Get_ReturnsTrue() + public void CanSetTracking_Get_ReturnsFalse() { var result = _telescope.CanSetTracking; - Assert.That(result, Is.True); + Assert.That(result, Is.False); } [Test] @@ -2121,11 +2124,9 @@ namespace Meade.net.Telescope.UnitTests [TestCase(true)] [TestCase(false)] - public void Tracking_SetAndGet_WhenValueSet_ThenCanGetNewValue(bool tracking) + public void Tracking_Set_ThenThrowsNotImplementedException(bool tracking) { - _telescope.Tracking = tracking; - - Assert.That(_telescope.Tracking, Is.EqualTo( tracking)); + Assert.Throws( () => { _telescope.Tracking = tracking; } ); } [Test] diff --git a/Meade.net.Telescope/Alignment.cs b/Meade.net.Telescope/Alignment.cs new file mode 100644 index 0000000..7450c67 --- /dev/null +++ b/Meade.net.Telescope/Alignment.cs @@ -0,0 +1,10 @@ +namespace ASCOM.Meade.net +{ + public enum Alignment + { + NeedsAlignment, + OneStarAligned, + TwoStarAligned, + ThreeStarAligned + } +} \ No newline at end of file diff --git a/Meade.net.Telescope/AlignmentStatus.cs b/Meade.net.Telescope/AlignmentStatus.cs new file mode 100644 index 0000000..a602f5a --- /dev/null +++ b/Meade.net.Telescope/AlignmentStatus.cs @@ -0,0 +1,11 @@ +using ASCOM.DeviceInterface; + +namespace ASCOM.Meade.net +{ + public class AlignmentStatus + { + public AlignmentModes AlignmentMode { get; set; } + public bool Tracking { get; set; } + public Alignment Status { get; set; } + } +} \ No newline at end of file diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index cfae8a4..9b8c187 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -118,6 +118,8 @@ + + diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index ada8098..1008e89 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -510,7 +510,7 @@ namespace ASCOM.Meade.net private bool FirmwareIsGreaterThan(string minVersion) { var currentVersion = SharedResourcesWrapper.FirmwareVersion; - var comparison = String.Compare(currentVersion, minVersion, StringComparison.Ordinal); + var comparison = string.Compare(currentVersion, minVersion, StringComparison.Ordinal); return comparison >= 0; } @@ -830,47 +830,41 @@ namespace ASCOM.Meade.net CheckConnected("AlignmentMode Get"); - const char ack = (char) 6; - - var alignmentString = SharedResourcesWrapper.SendChar(ack.ToString()); - //ACK <0x06> Query of alignment mounting mode. - //Returns: - //A If scope in AltAz Mode - //D If scope is currently in the Downloader[Autostar II & Autostar] - //L If scope in Land Mode - //P If scope in Polar Mode - - //todo implement GW Command - Supported in Autostar 43Eg and above - //if FirmwareIsGreaterThan(TelescopeList.Autostar497_43EG) - //{ - //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); - //:GW# Get Scope Alignment Status - //Returns: # - // where: - //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial - //tracking: T - tracking, N - not tracking - //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. - //} - - AlignmentModes alignmentMode; - switch (alignmentString) + if (FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg)) { - case "A": - alignmentMode = AlignmentModes.algAltAz; - break; - case "P": - alignmentMode = AlignmentModes.algPolar; - break; - case "G": - alignmentMode = AlignmentModes.algGermanPolar; - break; - default: - throw new InvalidValueException( - $"unknown alignment returned from telescope: {alignmentString}"); + var alignmentStatus = GetScopeAlignmentStatus(); + return alignmentStatus.AlignmentMode; } + else + { + const char ack = (char)6; + //ACK <0x06> Query of alignment mounting mode. + //Returns: + //A If scope in AltAz Mode + //D If scope is currently in the Downloader[Autostar II & Autostar] + //L If scope in Land Mode + //P If scope in Polar Mode + var alignmentString = SharedResourcesWrapper.SendChar(ack.ToString()); + AlignmentModes alignmentMode; + switch (alignmentString) + { + case "A": + alignmentMode = AlignmentModes.algAltAz; + break; + case "P": + alignmentMode = AlignmentModes.algPolar; + break; + //case "G": + // alignmentMode = AlignmentModes.algGermanPolar; + // break; + default: + throw new InvalidValueException( + $"unknown alignment returned from telescope: {alignmentString}"); + } - LogMessage("AlignmentMode Get", $"alignmode = {alignmentMode}"); - return alignmentMode; + LogMessage("AlignmentMode Get", $"alignmode = {alignmentMode}"); + return alignmentMode; + } } set { @@ -901,6 +895,50 @@ namespace ASCOM.Meade.net //Returns: nothing } } + + private AlignmentStatus GetScopeAlignmentStatus() + { + var alignmentString = SharedResourcesWrapper.SendString(":GW#"); + //:GW# Get Scope Alignment Status + //Returns: # + // where: + //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial + //tracking: T - tracking, N - not tracking + //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. + + var alignmentStatus = new AlignmentStatus(); + switch (alignmentString[0]) + { + case 'A': + alignmentStatus.AlignmentMode = AlignmentModes.algAltAz; + break; + case 'P': + alignmentStatus.AlignmentMode = AlignmentModes.algPolar; + break; + case 'G': + alignmentStatus.AlignmentMode = AlignmentModes.algGermanPolar; + break; + } + alignmentStatus.Tracking = alignmentString[0] == 'T'; + switch (alignmentString[1]) + { + case '0': + alignmentStatus.Status = Alignment.NeedsAlignment; + break; + case '1': + alignmentStatus.Status = Alignment.OneStarAligned; + break; + case '2': + alignmentStatus.Status = Alignment.TwoStarAligned; + break; + case '3': + alignmentStatus.Status = Alignment.ThreeStarAligned; + break; + } + + + return alignmentStatus; + } public double Altitude { @@ -1111,8 +1149,8 @@ namespace ASCOM.Meade.net { get { - LogMessage("CanSetTracking", "Get - " + true); - return true; + LogMessage("CanSetTracking", "Get - " + false); + return false; } } @@ -2236,12 +2274,19 @@ namespace ASCOM.Meade.net get { LogMessage("Tracking", $"Get - {_tracking}"); + if (FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg)) + { + var alignmentStatus = GetScopeAlignmentStatus(); + _tracking = alignmentStatus.Tracking; + } + return _tracking; } set { - LogMessage("Tracking Set", $"{value}"); - _tracking = value; + throw new ASCOM.NotImplementedException("Tracking Set"); + //LogMessage("Tracking Set", $"{value}"); + //_tracking = value; } } From a2abbbb3d086a15372aa98fabe6f40997a1ffcd6 Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Wed, 21 Apr 2021 17:24:40 +0100 Subject: [PATCH 02/23] Working on a possible side of pier implementation --- Meade.net.Telescope/Telescope.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 1008e89..02bf7d0 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1660,7 +1660,16 @@ namespace ASCOM.Meade.net get { LogMessage("SideOfPier Get", "Not implemented"); - throw new PropertyNotImplementedException("SideOfPier", false); + if (!FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg)) + throw new PropertyNotImplementedException("SideOfPier", false); + else + { + var alignmentStatus = GetScopeAlignmentStatus(); + if (alignmentStatus.AlignmentMode != AlignmentModes.algPolar) + throw new PropertyNotImplementedException("SideOfPier", false); + + //return + } } // ReSharper disable once ValueParameterNotUsed set From fe3c1069542466182a01012753cae01edeca5445 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Mon, 7 Jun 2021 17:58:20 +1000 Subject: [PATCH 03/23] Add unit test around meridian flip detection --- .../TelescopeUnitTests.cs | 135 +++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index e86fd2c..c931d76 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -2,6 +2,7 @@ using System.Globalization; using System.Reflection; using ASCOM; +using ASCOM.Astrometry; using ASCOM.Astrometry.AstroUtils; using ASCOM.Astrometry.NOVAS; using ASCOM.DeviceInterface; @@ -1229,10 +1230,11 @@ namespace Meade.net.Telescope.UnitTests public void DestinationSideOfPier_WhenHASiderealTimeDiffIsNotNull_ThenSideOfPierIsCalculated(double ra, double dec, double siderealTime, PierSide expectedDSOP) { // given - // SideralTime uses ConditionRA to normalize to 0..24h, so we use it to mock the property + // SideralTime uses ConditionRA to normalize to [0..24h), so we use it to mock the property _astroUtilsMock.Setup(x => x.ConditionRA(It.IsAny())).Returns(siderealTime); var ha = siderealTime - ra; + // normalized hour angle range is [-12h..12h] var normalisedHA = ha > 12 ? ha - 24 : ha < -12 ? ha + 24 : ha; _astroUtilsMock.Setup(x => x.ConditionHA(It.Is(v => v == ha))).Returns(normalisedHA); @@ -1242,7 +1244,7 @@ namespace Meade.net.Telescope.UnitTests var actualDSOP = _telescope.DestinationSideOfPier(ra, dec); // then - Assert.That(siderealTime, Is.InRange(0, 24 + double.Epsilon)); + Assert.That(siderealTime, Is.InRange(0, 24)); Assert.That(normalisedHA, Is.InRange(-12, 12 + double.Epsilon)); Assert.That(actualDSOP, Is.EqualTo(expectedDSOP)); @@ -1845,6 +1847,135 @@ namespace Meade.net.Telescope.UnitTests Assert.That(excpetion.AccessorSet, Is.True); } + delegate void NovasSiderealTimeDelegate(double jdHigh, double jdLow, double jdDelta, GstType gstType, Method method, Accuracy accuracy, ref double sideralTime); + + /// + /// Test cases obtained via .NET telescope simulator + /// + [TestCase(9.4337648353882, -76.7178112042103, "2021-06-07T05:23:41.7610000Z", 8.13556526999591, 145.166333333333, 2d, PierSide.pierWest, PierSide.pierEast)] + [TestCase(10.1581570159006, 11.8639491368916, "2021-06-07T10:59:19.7000000Z", 9.72726050605156, 145.166333333333, 1d, PierSide.pierWest, PierSide.pierEast)] + [TestCase(9.66583199112222, 81.2310578173083, "2021-06-07T11:19:24.5540000Z", 7.73744116673785, 110.285166666667, 2d, PierSide.pierWest, PierSide.pierEast)] + [TestCase(8.32978972808615, -29.816491813155, "2021-06-07T11:29:33.7040000Z", 7.90712206850482, 110.285166666667, 1d, PierSide.pierWest, PierSide.pierEast)] + [TestCase(1.76405553984887, 60.7756226366989, "2021-06-07T11:34:07.5270000Z", 0.214893775091689, -6.24266666666667, 2d, PierSide.pierWest, PierSide.pierEast)] + [TestCase(0.523375885742411, -33.1288722052936, "2021-06-07T11:38:25.1670000Z", 0.286661722506396, -6.24266666666667, 0.5d, PierSide.pierWest, PierSide.pierEast)] + public void SideOfPier_WhenTrackingThroughMeridianAfterSubsequentGoto_ThenAMeridianFlipIsPerformed( + double ra, + double dec, + string jnowTimeStr, /* JNOW of object before transit */ + double jnowSiderealTime, + double siteLongitude, + double trackingTimeHours, + PierSide pierSideBeforeTransit, + PierSide pierSideAfterRetargeting + ) + { + // given + var jnowTime = DateTimeOffset.ParseExact(jnowTimeStr, "o", CultureInfo.InvariantCulture).UtcDateTime; + var trackingTimeDiff = TimeSpan.FromHours(trackingTimeHours); + var timeAfterTracking = jnowTime + trackingTimeDiff; + var raAsHMS = ra + "HMS"; + var decAsDMS = dec + "DMS"; + var currentTime = jnowTime; + + _clockMock.Setup(x => x.UtcNow).Returns(() => currentTime); + + _sharedResourcesWrapperMock.Setup(x => x.SendChar("MS", false)).Returns("0"); + + // setup for RA + _utilMock.Setup(x => x.HoursToHMS(ra, ":", ":", ":", 2)).Returns(raAsHMS); + _utilMock.Setup(x => x.HMSToHours(raAsHMS)).Returns(ra); + + // setup for DEC + _utilMock.Setup(x => x.DMSToDegrees(decAsDMS)).Returns(dec); + _utilMock.Setup(x => x.DegreesToDMS(dec, "*", ":", ":", 2)).Returns(decAsDMS); + + // setup for SiteLongitude + var siteLongitudeResult = siteLongitude + "Gg"; + _sharedResourcesWrapperMock.Setup(x => x.SendString("Gg", false)).Returns(siteLongitudeResult); + // remember to invert longitude + _utilMock.Setup(x => x.DMSToDegrees(siteLongitudeResult)).Returns(-siteLongitude); + + // setup for SideralTime + var siteLongitudeAdj = siteLongitude / 360.0 * 24.0; + var jnowSiderealTimeWithoutLongAdj = jnowSiderealTime - siteLongitudeAdj; + var afterTrackingSiderealTimeWithoutLongAdj = jnowSiderealTimeWithoutLongAdj + trackingTimeHours; + + _utilMock.Setup(x => x.DateUTCToJulian(It.IsAny())).Returns(pDateTime => pDateTime.Ticks); + + _novasMock + .Setup(x => x.SiderealTime( + It.IsAny(), + 0d, + 0d, + GstType.GreenwichApparentSiderealTime, + Method.EquinoxBased, + Accuracy.Reduced, + ref It.Ref.IsAny)) + .Callback(new NovasSiderealTimeDelegate(NovasSiderealTime)) + .Returns(0); + + _astroUtilsMock.Setup(x => x.ConditionRA(It.IsAny())).Returns(pRA => pRA < 0 ? pRA + 24 : pRA >= 24 ? pRA - 24 : pRA); + + void NovasSiderealTime(double pJDHigh, double pJDLow, double pJDDelta, GstType pGSTType, Method pMethod, Accuracy pAccuracy, ref double pSideralTime) + { + if (pJDHigh == jnowTime.Ticks) + { + pSideralTime = jnowSiderealTimeWithoutLongAdj; + } + else if (pJDHigh == timeAfterTracking.Ticks) + { + pSideralTime = afterTrackingSiderealTimeWithoutLongAdj; + } + else + { + Assert.Fail($"No sideral time defined for {pJDHigh}"); + } + } + + // Setup DestinationSideOfPier + _astroUtilsMock.Setup(x => x.ConditionHA(It.IsAny())).Returns(pHA => pHA < -12 ? pHA + 12 : pHA > 12 ? pHA - 12 : pHA); + + ConnectTelescope(); + + // when + _telescope.SlewToCoordinatesAsync(ra, dec); + var actualSideOfPierAfterSlew = _telescope.SideOfPier; + // simulate tracking time + currentTime += trackingTimeDiff; + var actualSideOfPierAfterTracking = _telescope.SideOfPier; + _telescope.SlewToTargetAsync(); + var actualSideOfPierAfterRetargeting = _telescope.SideOfPier; + + // then + Assert.That(_telescope.TargetRightAscension, Is.EqualTo(ra)); + Assert.That(_telescope.TargetDeclination, Is.EqualTo(dec)); + Assert.That(actualSideOfPierAfterSlew, Is.EqualTo(pierSideBeforeTransit)); + Assert.That(actualSideOfPierAfterTracking, Is.EqualTo(pierSideBeforeTransit)); + Assert.That(actualSideOfPierAfterRetargeting, Is.EqualTo(pierSideAfterRetargeting)); + + _clockMock.Verify(x => x.UtcNow, Times.AtLeast(2)); + + foreach (var time in new[] { jnowTime, timeAfterTracking }) + { + _utilMock.Verify(x => x.DateUTCToJulian(time)); + + _novasMock + .Verify(x => x.SiderealTime( + time.Ticks, + 0d, + 0d, + GstType.GreenwichApparentSiderealTime, + Method.EquinoxBased, + Accuracy.Reduced, + ref It.Ref.IsAny), + Times.Once); + } + + _sharedResourcesWrapperMock.Verify(x => x.SendString("Gg", false), Times.Exactly(3)); + _sharedResourcesWrapperMock.Verify(x => x.SendChar("MS", false), Times.Exactly(2)); + _sharedResourcesWrapperMock.Verify(x => x.SendString("D", false), Times.Exactly(3)); + } + [Test] public void SiteElevation_Get_WhenNotConnectedThrowsException() { From 1684bd60bd49c9317e722b2fcaf5e3b5bcd55f2e Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sat, 12 Jun 2021 15:47:34 +1000 Subject: [PATCH 04/23] Move SideOfPier, TargetRA/DEC properties to SharedResourcesWrapper This change allows several instances of the driver to be in sync w.r.t. TargetRightAscension, TargetDeclination and SideOfPier --- .../TelescopeUnitTests.cs | 11 +- Meade.net.Telescope/Telescope.cs | 135 +++++++++--------- Meade.net/SharedResources.cs | 31 ++-- Meade.net/Wrapper/SharedResourcesWrapper.cs | 25 +++- 4 files changed, 122 insertions(+), 80 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index c931d76..274f6ea 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -100,10 +100,15 @@ namespace Meade.net.Telescope.UnitTests SameDevice = 1 }; - _sharedResourcesWrapperMock.Setup(x => x.Connect("Serial", It.IsAny(), It.IsAny())).Returns( () => _connectionInfo ); + _sharedResourcesWrapperMock.Setup(x => x.Connect("Serial", It.IsAny(), It.IsAny())).Returns( () => _connectionInfo); _sharedResourcesWrapperMock.Setup(x => x.ReadProfile()).Returns(_profileProperties); + _sharedResourcesWrapperMock + .SetupProperty(x => x.SideOfPier) + .SetupProperty(x => x.TargetRightAscension) + .SetupProperty(x => x.TargetDeclination); + _astroMathsMock = new Mock(); _clockMock = new Mock(); @@ -1230,6 +1235,10 @@ namespace Meade.net.Telescope.UnitTests public void DestinationSideOfPier_WhenHASiderealTimeDiffIsNotNull_ThenSideOfPierIsCalculated(double ra, double dec, double siderealTime, PierSide expectedDSOP) { // given + + // deterministic start + _sharedResourcesWrapperMock.Object.SideOfPier = PierSide.pierUnknown; + // SideralTime uses ConditionRA to normalize to [0..24h), so we use it to mock the property _astroUtilsMock.Setup(x => x.ConditionRA(It.IsAny())).Returns(siderealTime); diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index c4f65dc..cfdee7b 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -418,8 +418,6 @@ namespace ASCOM.Meade.net $"Connected to port {ComPort}. Product: {SharedResourcesWrapper.ProductName} Version:{SharedResourcesWrapper.FirmwareVersion}"); _userNewerPulseGuiding = IsNewPulseGuidingSupported(); - _targetDeclination = InvalidParameter; - _targetRightAscension = InvalidParameter; _tracking = true; LogMessage("Connected Set", $"New Pulse Guiding Supported: {_userNewerPulseGuiding}"); @@ -443,6 +441,11 @@ namespace ASCOM.Meade.net SetTelescopePrecision("Connect"); + // target RA, DEC and SideOfPier are set to default values + SharedResourcesWrapper.SideOfPier = PierSide.pierUnknown; + SharedResourcesWrapper.TargetDeclination = InvalidParameter; + SharedResourcesWrapper.TargetRightAscension = InvalidParameter; + LogMessage("Connected Set", $"SendDateTime: {SendDateTime}"); if (SendDateTime) { @@ -720,7 +723,7 @@ namespace ASCOM.Meade.net var result = SharedResourcesWrapper.SendString("GZ"); LogMessage("SetLongFormat", $"Get - Azimuth {result}"); //:GZ# Get telescope azimuth - //Returns: DDD*MM.T or DDD*MM’SS# + //Returns: DDD*MM.T or DDD*MM'SS# //The current telescope Azimuth depending on the selected precision. IsLongFormat = result.Length > 6; @@ -754,8 +757,8 @@ namespace ASCOM.Meade.net var result = SharedResourcesWrapper.SendChar("P"); //:P# Toggles High Precsion Pointing. When High precision pointing is enabled scope will first allow the operator to center a nearby bright star before moving to the actual target. //Returns: - //“HIGH PRECISION” Current setting after this command. - //“LOW PRECISION” Current setting after this command. + //"HIGH PRECISION" Current setting after this command. + //"LOW PRECISION" Current setting after this command. int throwAwayCharacters = "LOW PRECISION".Length - 1; @@ -816,33 +819,33 @@ namespace ASCOM.Meade.net case 1: command = $"SM{sitename}"; //:SM# - //Set site 1’s name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. + //Set site 1's name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. // Returns: - //0 – Invalid + //0 - Invalid //1 - Valid break; case 2: command = $"SN{sitename}"; //:SN# - //Set site 2’s name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. + //Set site 2's name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. // Returns: - //0 – Invalid + //0 - Invalid //1 - Valid break; case 3: command = $"SO{sitename}"; //:SO# - //Set site 3’s name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. + //Set site 3's name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. // Returns: - //0 – Invalid + //0 - Invalid //1 - Valid break; case 4: command = $"SP{sitename}"; //:SP# - //Set site 4’s name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. + //Set site 4's name to be.LX200s only accept 3 character strings. Other scopes accept up to 15 characters. // Returns: - //0 – Invalid + //0 - Invalid //1 - Valid break; default: @@ -867,22 +870,22 @@ namespace ASCOM.Meade.net return SharedResourcesWrapper.SendString("GM"); //:GM# Get Site 1 Name //Returns: # - //A ‘#’ terminated string with the name of the requested site. + //A '#' terminated string with the name of the requested site. case 2: return SharedResourcesWrapper.SendString("GN"); //:GN# Get Site 2 Name //Returns: # - //A ‘#’ terminated string with the name of the requested site. + //A '#' terminated string with the name of the requested site. case 3: return SharedResourcesWrapper.SendString("GO"); //:GO# Get Site 3 Name //Returns: # - //A ‘#’ terminated string with the name of the requested site. + //A '#' terminated string with the name of the requested site. case 4: return SharedResourcesWrapper.SendString("GP"); //:GP# Get Site 4 Name //Returns: # - //A ‘#’ terminated string with the name of the requested site. + //A '#' terminated string with the name of the requested site. default: throw new ArgumentOutOfRangeException(nameof(site), site, Resources.Telescope_GetSiteName_Site_out_of_range); @@ -1040,7 +1043,7 @@ namespace ASCOM.Meade.net //firmware bug in 44Eg, :GA# is returning the dec, not the altitude! var result = SharedResourcesWrapper.SendString("GA"); //:GA# Get Telescope Altitude - //Returns: sDD* MM# or sDD*MM’SS# + //Returns: sDD* MM# or sDD*MM'SS# //The current scope altitude. The returned format depending on the current precision setting. var alt = _utilities.DMSToDegrees(result); @@ -1147,7 +1150,7 @@ namespace ASCOM.Meade.net var result = SharedResourcesWrapper.SendString("GZ"); //:GZ# Get telescope azimuth - //Returns: DDD*MM#T or DDD*MM’SS# + //Returns: DDD*MM#T or DDD*MM'SS# //The current telescope Azimuth depending on the selected precision. double az = _utilities.DMSToDegrees(result); @@ -1347,7 +1350,7 @@ namespace ASCOM.Meade.net var result = SharedResourcesWrapper.SendString("GD"); //:GD# Get Telescope Declination. - //Returns: sDD*MM# or sDD*MM’SS# + //Returns: sDD*MM# or sDD*MM'SS# //Depending upon the current precision setting for the telescope. double declination = _utilities.DMSToDegrees(result); @@ -1449,7 +1452,7 @@ namespace ASCOM.Meade.net if (!value.InRange(0, 15.0417)) { - throw new InvalidValueException(propertyName, value.ToString(CultureInfo.CurrentCulture), $"{0.ToString(CultureInfo.CurrentCulture)} to {15.0417.ToString(CultureInfo.CurrentCulture)}”/sec"); + throw new InvalidValueException(propertyName, value.ToString(CultureInfo.CurrentCulture), $"{0.ToString(CultureInfo.CurrentCulture)} to {15.0417.ToString(CultureInfo.CurrentCulture)}\"/sec"); } LogMessage($"{propertyName} Set", $"Setting new guiderate {value.ToString(CultureInfo.CurrentCulture)} arc seconds/second ({value.ToString(CultureInfo.CurrentCulture)} degrees/second)"); @@ -1457,7 +1460,7 @@ namespace ASCOM.Meade.net //:RgSS.S# //Set guide rate to +/ -SS.S to arc seconds per second.This rate is added to or subtracted from the current tracking //Rates when the CCD guider or handbox guider buttons are pressed when the guide rate is selected.Rate shall not exceed - //sidereal speed(approx 15.0417”/sec)[Autostar II only] + //sidereal speed(approx 15.0417"/sec)[Autostar II only] //Returns: Nothing //info from RickB says that 15.04107 is a better value for @@ -1583,7 +1586,7 @@ namespace ASCOM.Meade.net //Returns: Nothing _movingPrimary = true; // in principle we could calculate the current side of pier, but unknown is the safer option. - _pierSide = PierSide.pierUnknown; + SharedResourcesWrapper.SideOfPier = PierSide.pierUnknown; break; case ComparisonResult.Lower: SharedResourcesWrapper.SendBlind("Mw"); @@ -1591,7 +1594,7 @@ namespace ASCOM.Meade.net //Returns: Nothing _movingPrimary = true; // in principle we could calculate the current side of pier, but unknown is the safer option. - _pierSide = PierSide.pierUnknown; + SharedResourcesWrapper.SideOfPier = PierSide.pierUnknown; break; } break; @@ -1672,7 +1675,7 @@ namespace ASCOM.Meade.net //Setting park to true before sending the park command as the Autostar and Audiostar stop serial communications once the park command has been issued. SharedResourcesWrapper.SetParked(true, parkedPosition); SharedResourcesWrapper.SendBlind("hP"); - //:hP# Autostar, Autostar II and LX 16”Slew to Park Position + //:hP# Autostar, Autostar II and LX 16" Slew to Park Position //Returns: Nothing } @@ -1728,8 +1731,8 @@ namespace ASCOM.Meade.net //:MgwDDDD# //Guide telescope in the commanded direction(nsew) for the number of milliseconds indicated by the unsigned number //passed in the command.These commands support serial port driven guiding. - //Returns – Nothing - //LX200 – Not Supported + //Returns - Nothing + //LX200 - Not Supported _utilities.WaitForMilliseconds(duration); } else @@ -1851,11 +1854,6 @@ namespace ASCOM.Meade.net throw new MethodNotImplementedException("SetPark"); } - /// - /// Start with . - /// As we do not know the physical declination axis position, we have to keep track manually. - /// - private PierSide _pierSide = PierSide.pierUnknown; public PierSide SideOfPier { get @@ -1864,7 +1862,7 @@ namespace ASCOM.Meade.net { // while mount is slewing return unknown, this is required since // DoSlewAsync updates _pierSide before slew is finished - var pierSide = Slewing ? PierSide.pierUnknown : _pierSide; + var pierSide = Slewing ? PierSide.pierUnknown : SharedResourcesWrapper.SideOfPier; LogMessage("SideOfPier", "Get - " + pierSide); return pierSide; @@ -1996,7 +1994,7 @@ namespace ASCOM.Meade.net //:StsDD*MM# //Sets the current site latitude to sDD* MM# //Returns: - //0 – Invalid + //0 - Invalid //1 - Valid if (result != "1") throw new InvalidOperationException("Failed to set site latitude."); @@ -2063,9 +2061,9 @@ namespace ASCOM.Meade.net var result = SharedResourcesWrapper.SendChar(commandstring); //:SgDDD*MM# - //Set current site’s longitude to DDD*MM an ASCII position string + //Set current site's longitude to DDD*MM an ASCII position string //Returns: - //0 – Invalid + //0 - Invalid //1 - Valid if (result != "1") throw new InvalidOperationException("Failed to set site longitude."); @@ -2172,7 +2170,7 @@ namespace ASCOM.Meade.net { // Update side of pier to destination side of pier // Assumption: Mount will do meridian flip if required - _pierSide = DestinationSideOfPier(TargetRightAscension, TargetDeclination); + SharedResourcesWrapper.SideOfPier = DestinationSideOfPier(TargetRightAscension, TargetDeclination); } SetSlewingMinEndTime(); @@ -2201,11 +2199,11 @@ namespace ASCOM.Meade.net break; case false: var maResponse = SharedResourcesWrapper.SendChar("MA"); - //:MA# Autostar, LX 16”, Autostar II – Slew to target Alt and Az + //:MA# Autostar, LX 16", Autostar II - Slew to target Alt and Az //Returns: //0 - No fault - //1 – Fault - // LX200 – Not supported + //1 - Fault + //LX200 - Not supported if (maResponse == "1") { @@ -2345,8 +2343,8 @@ namespace ASCOM.Meade.net } //:D# Requests a string of bars indicating the distance to the current target location. //Returns: - //LX200's – a string of bar characters indicating the distance. - //Autostars and Autostar II – a string containing one bar until a slew is complete, then a null string is returned. + //LX200's - a string of bar characters indicating the distance. + //Autostars and Autostar II - a string containing one bar until a slew is complete, then a null string is returned. bool isSlewing = false; try @@ -2433,41 +2431,42 @@ namespace ASCOM.Meade.net // At least the classic LX200 low precision might not slew to the exact target position // This Requires to retrieve the aimed target ra de from the telescope + double targetRA = SharedResourcesWrapper.TargetRightAscension ?? InvalidParameter; double ra = RightAscension; - if (Math.Abs(_targetRightAscension - InvalidParameter) > 0.1 && - _utilities.HoursToHMS(ra, ":", ":", ":", _digitsRa) != _utilities.HoursToHMS(_targetRightAscension, ":", ":", ":", _digitsRa)) + if (Math.Abs(targetRA - InvalidParameter) > 0.1 && + _utilities.HoursToHMS(ra, ":", ":", ":", _digitsRa) != _utilities.HoursToHMS(targetRA, ":", ":", ":", _digitsRa)) { - LogMessage("SyncToTarget", $"differ RA real {ra} targeted {_targetRightAscension}"); - _targetRightAscension = ra; + LogMessage("SyncToTarget", $"differ RA real {ra} targeted {targetRA}"); + SharedResourcesWrapper.TargetRightAscension = ra; } + double targetDEC = SharedResourcesWrapper.TargetDeclination ?? InvalidParameter; double de = Declination; - if (Math.Abs(_targetDeclination - InvalidParameter) > 0.1 && - _utilities.DegreesToDMS(de, "*", ":", ":", _digitsDe) != _utilities.DegreesToDMS(_targetDeclination, "*", ":", ":", _digitsDe)) + if (Math.Abs(targetDEC - InvalidParameter) > 0.1 && + _utilities.DegreesToDMS(de, "*", ":", ":", _digitsDe) != _utilities.DegreesToDMS(targetDEC, "*", ":", ":", _digitsDe)) { - LogMessage("SyncToTarget", $"differ DE real {de} targeted {_targetDeclination}"); - _targetDeclination = de; + LogMessage("SyncToTarget", $"differ DE real {de} targeted {targetDEC}"); + SharedResourcesWrapper.TargetDeclination = de; } } - private double _targetDeclination = InvalidParameter; public double TargetDeclination { get { - if (_targetDeclination.Equals(InvalidParameter)) + var targetDeclination = SharedResourcesWrapper.TargetDeclination ?? InvalidParameter; + if (targetDeclination.Equals(InvalidParameter)) throw new InvalidOperationException("Target not set"); //var result = SerialPort.CommandTerminated(":Gd#", "#"); ////:Gd# Get Currently Selected Object/Target Declination - ////Returns: sDD* MM# or sDD*MM’SS# + ////Returns: sDD* MM# or sDD*MM'SS# ////Depending upon the current precision setting for the telescope. //double targetDec = DmsToDouble(result); //return targetDec; - - LogMessage("TargetDeclination Get", $"{_targetDeclination}"); - return _targetDeclination; + LogMessage("TargetDeclination Get", $"{targetDeclination}"); + return targetDeclination; } set { @@ -2496,23 +2495,23 @@ namespace ASCOM.Meade.net //Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting //Returns: //1 - Dec Accepted - //0 – Dec invalid + //0 - Dec invalid if (result == "0") { throw new InvalidOperationException("Target declination invalid"); } - _targetDeclination = _utilities.DMSToDegrees(dms); + SharedResourcesWrapper.TargetDeclination = _utilities.DMSToDegrees(dms); } } - private double _targetRightAscension = InvalidParameter; public double TargetRightAscension { get { - if (_targetRightAscension.Equals(InvalidParameter)) + var targetRightAscension = SharedResourcesWrapper.TargetRightAscension ?? InvalidParameter; + if (targetRightAscension.Equals(InvalidParameter)) throw new InvalidOperationException("Target not set"); //var result = SerialPort.CommandTerminated(":Gr#", "#"); @@ -2523,8 +2522,8 @@ namespace ASCOM.Meade.net //double targetRa = HmsToDouble(result); //return targetRa; - LogMessage("TargetRightAscension Get", $"{_targetRightAscension}"); - return _targetRightAscension; + LogMessage("TargetRightAscension Get", $"{targetRightAscension}"); + return targetRightAscension; } set { @@ -2549,13 +2548,13 @@ namespace ASCOM.Meade.net //:SrHH:MM:SS# //Set target object RA to HH:MM.T or HH: MM: SS depending on the current precision setting. // Returns: - //0 – Invalid + //0 - Invalid //1 - Valid if (response == "0") throw new InvalidOperationException("Failed to set TargetRightAscension."); - _targetRightAscension = _utilities.HMSToHours(hms); + SharedResourcesWrapper.TargetRightAscension = _utilities.HMSToHours(hms); } } @@ -2735,7 +2734,7 @@ namespace ASCOM.Meade.net //:SLHH:MM:SS# //Set the local Time //Returns: - //0 – Invalid + //0 - Invalid //1 - Valid if (timeResult != "1") { @@ -2747,8 +2746,8 @@ namespace ASCOM.Meade.net //:SCMM/DD/YY# //Change Handbox Date to MM/DD/YY //Returns: - //D = ‘0’ if the date is invalid.The string is the null string. - //D = ‘1’ for valid dates and the string is “Updating Planetary Data# #” + //D = '0' if the date is invalid. The string is the null string. + //D = '1' for valid dates and the string is "Updating Planetary Data# #" //Note: For Autostar II this is the UTC data! if (dateResult != "1") { @@ -2796,7 +2795,7 @@ namespace ASCOM.Meade.net //Bypass handbox entry of daylight savings, date and time.Use the values supplied in this command.This feature is //intended to allow use of the Autostar II from permanent installations where GPS reception is not possible, such as within //metal domes. This command must be issued while the telescope is waiting at the initial daylight savings prompt. - //Returns: 1 – if command was accepted. + //Returns: 1 - if command was accepted. return result == "1"; } diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 47730ef..bcf1134 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -4,7 +4,7 @@ // ================ // // This class is a container for all shared resources that may be needed -// by the drivers served by the Local Server. +// by the drivers served by the Local Server. // // NOTES: // @@ -20,6 +20,7 @@ using System.Globalization; using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Windows.Forms; +using ASCOM.DeviceInterface; using ASCOM.Meade.net.Wrapper; using ASCOM.Utilities; using ASCOM.Utilities.Interfaces; @@ -49,7 +50,7 @@ namespace ASCOM.Meade.net #region single serial port connector // - // this region shows a way that a single serial port could be connected to by multiple + // this region shows a way that a single serial port could be connected to by multiple // drivers. // // Connected is used to handle the connections to the port. @@ -73,7 +74,7 @@ namespace ASCOM.Meade.net public static IProfileFactory ProfileFactory { - get => _profileFactory ?? ( _profileFactory = new ProfileFactory()); + get => _profileFactory ?? (_profileFactory = new ProfileFactory()); set => _profileFactory = value; } @@ -122,7 +123,7 @@ namespace ASCOM.Meade.net public static bool SendBool(string command, bool raw = false) { - + var result = SendChar(command, raw); return result == "1"; @@ -273,7 +274,7 @@ namespace ASCOM.Meade.net profileProperties.Speed = Convert.ToInt32(driverProfile.GetValue(DriverId, SpeedName, string.Empty, SpeedDefault)); profileProperties.Parity = driverProfile.GetValue(DriverId, ParityName, string.Empty, ParityDefault); profileProperties.SendDateTime = Convert.ToBoolean(driverProfile.GetValue(DriverId, SendDateTimeName, string.Empty, SendDateTimeDefault)); - + profileProperties.ParkedBehaviour = EnumExtensionMethods.GetValueFromDescription(driverProfile.GetValue(DriverId, ParkedBehaviourName, string.Empty, ParkedBehaviourDefault)); profileProperties.ParkedAlt = double.Parse(driverProfile.GetValue(DriverId, ParkedAltName, string.Empty, ParkedAltDefault), NumberFormatInfo.InvariantInfo); profileProperties.ParkedAz = double.Parse(driverProfile.GetValue(DriverId, ParkedAzimuthName, string.Empty, ParkedAzimuthDefault), NumberFormatInfo.InvariantInfo); @@ -311,7 +312,7 @@ namespace ASCOM.Meade.net } #endregion - + #region Multi Driver handling public static string ProductName { get; private set; } = string.Empty; @@ -334,7 +335,7 @@ namespace ASCOM.Meade.net private static readonly Dictionary ConnectedDevices = new Dictionary(); private static readonly Dictionary ConnectedDeviceIds = new Dictionary(); - private static IProfileFactory _profileFactory ; + private static IProfileFactory _profileFactory; /// @@ -350,7 +351,7 @@ namespace ASCOM.Meade.net { if (!ConnectedDevices.ContainsKey(deviceId)) ConnectedDevices.Add(deviceId, new DeviceHardware()); - + if (!ConnectedDeviceIds.ContainsKey(driverId)) ConnectedDeviceIds.Add(driverId, new DeviceHardware()); @@ -363,7 +364,7 @@ namespace ASCOM.Meade.net SharedSerial.DTREnable = profileProperties.RtsDtrEnabled; SharedSerial.RTSEnable = profileProperties.RtsDtrEnabled; SharedSerial.DataBits = profileProperties.DataBits; - SharedSerial.StopBits = (SerialStopBits)Enum.Parse(typeof(SerialStopBits), profileProperties.StopBits ); + SharedSerial.StopBits = (SerialStopBits)Enum.Parse(typeof(SerialStopBits), profileProperties.StopBits); SharedSerial.Parity = (SerialParity)Enum.Parse(typeof(SerialParity), profileProperties.Parity); SharedSerial.Speed = (SerialSpeed)profileProperties.Speed; SharedSerial.Handshake = (SerialHandshake)Enum.Parse(typeof(SerialHandshake), profileProperties.Handshake); @@ -493,7 +494,7 @@ namespace ASCOM.Meade.net Count = 0; } } - + public static void SetParked(bool atPark, ParkedPosition parkedPosition) { IsParked = atPark; @@ -503,5 +504,15 @@ namespace ASCOM.Meade.net public static bool IsParked { get; private set; } public static ParkedPosition ParkedPosition { get; private set; } + + /// + /// Start with . + /// As we do not know the physical declination axis position, we have to keep track manually. + /// + public static PierSide SideOfPier { get; set; } = PierSide.pierUnknown; + + public static double? TargetRightAscension { get; set; } + + public static double? TargetDeclination { get; set; } } } \ No newline at end of file diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index d7b078c..83fe829 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -1,4 +1,5 @@ using System; +using ASCOM.DeviceInterface; using ASCOM.Utilities.Interfaces; namespace ASCOM.Meade.net.Wrapper @@ -31,6 +32,10 @@ namespace ASCOM.Meade.net.Wrapper void SetParked(bool atPark, ParkedPosition parkedPosition); bool IsParked { get; } ParkedPosition ParkedPosition { get; } + + PierSide SideOfPier { get; set; } + double? TargetRightAscension { get; set; } + double? TargetDeclination { get; set; } } public class SharedResourcesWrapper : ISharedResourcesWrapper @@ -74,7 +79,7 @@ namespace ASCOM.Meade.net.Wrapper return SharedResources.SendBool(command, raw); } - public string SendChar(string message,bool raw = false) + public string SendChar(string message, bool raw = false) { return SharedResources.SendChar(message, raw); } @@ -112,5 +117,23 @@ namespace ASCOM.Meade.net.Wrapper public bool IsParked => SharedResources.IsParked; public ParkedPosition ParkedPosition => SharedResources.ParkedPosition; + + public PierSide SideOfPier + { + get => SharedResources.SideOfPier; + set => SharedResources.SideOfPier = value; + } + + public double? TargetRightAscension + { + get => SharedResources.TargetRightAscension; + set => SharedResources.TargetRightAscension = value; + } + + public double? TargetDeclination + { + get => SharedResources.TargetDeclination; + set => SharedResources.TargetDeclination = value; + } } } From bdbd206a54f11d8e4b9a73ec1343bf77f3ebff2f Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sat, 12 Jun 2021 16:05:56 +1000 Subject: [PATCH 05/23] Avoid possible data race condition when calculating DSOP --- Meade.net.Telescope/Telescope.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index cfdee7b..80a1cf1 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1394,7 +1394,7 @@ namespace ASCOM.Meade.net var destinationSOP = hourAngle > 0 ? PierSide.pierEast : - (hourAngle < 0 ? PierSide.pierWest : SideOfPier); + (hourAngle < 0 ? PierSide.pierWest : SharedResourcesWrapper.SideOfPier); // avoid pierUnknown while Slewing LogMessage("DestinationSideOfPier", $"Destination SOP of RA {rightAscension.ToString(CultureInfo.InvariantCulture)} is {destinationSOP}"); From 6c769f36490dbbe1b2b7b37fbb517f1dc3e33eed Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sat, 12 Jun 2021 20:09:51 +1000 Subject: [PATCH 06/23] Add SlewSettleTime and IsLongFormat to SharedResources interface Also ensure that digit precision is set during initialisation --- .../TelescopeUnitTests.cs | 67 ++++++++++++++++++- Meade.net.Telescope/Telescope.cs | 37 +++++----- Meade.net/MeadeTelescopeBase.cs | 4 +- Meade.net/SharedResources.cs | 10 ++- Meade.net/Wrapper/SharedResourcesWrapper.cs | 16 +++++ 5 files changed, 110 insertions(+), 24 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 274f6ea..9a3adf3 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -107,7 +107,9 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock .SetupProperty(x => x.SideOfPier) .SetupProperty(x => x.TargetRightAscension) - .SetupProperty(x => x.TargetDeclination); + .SetupProperty(x => x.TargetDeclination) + .SetupProperty(x => x.SlewSettleTime) + .SetupProperty(x => x.IsLongFormat); _astroMathsMock = new Mock(); @@ -1018,6 +1020,29 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar("P", false), Times.Never); } + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void SlewSettleTime_WhenSecondConnectionMade_ThenSlewSettleTimeIsPreserved(short slewSettleTime) + { + ConnectTelescope(); + + _telescope.SlewSettleTime = slewSettleTime; + + Assert.That(_connectionInfo.SameDevice, Is.EqualTo(1)); + + var secondTelescopeInstance = + new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, + _sharedResourcesWrapperMock.Object, _astroMathsMock.Object, _clockMock.Object, _novasMock.Object); + + Assert.That(secondTelescopeInstance.Connected, Is.False); + + _connectionInfo.SameDevice = 2; + secondTelescopeInstance.Connected = true; + + Assert.That(secondTelescopeInstance.SlewSettleTime, Is.EqualTo(slewSettleTime)); + } + [Test] public void CanSetPark_Get_ReturnsFalse() { @@ -2369,6 +2394,46 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.EqualTo(declination)); } + [TestCase(-90d)] + [TestCase(-45d)] + [TestCase(0d)] + [TestCase(45d)] + [TestCase(90d)] + public void TargetDeclination_Set_WhenSecondConnectionMade_ThenSlewSettleTimeIsPreserved(double targetDeclination) + { + var targetDeclinationDMS = targetDeclination + "DMS"; + var sign = targetDeclination >= 0 ? "+" : string.Empty; + var command = $"Sd{sign}{targetDeclinationDMS}"; + + _utilMock.Setup(x => x.DegreesToDMS(targetDeclination, "*", ":", ":", 2)).Returns(targetDeclinationDMS); + _utilMock.Setup(x => x.DMSToDegrees(targetDeclinationDMS)).Returns(targetDeclination); + _sharedResourcesWrapperMock.Setup(x => x.SendChar(command, false)).Returns("1"); + + ConnectTelescope(); + Assert.That(_connectionInfo.SameDevice, Is.EqualTo(1)); + Assert.That(_sharedResourcesWrapperMock.Object.IsLongFormat, Is.True); + + _telescope.TargetDeclination = targetDeclination; + + Assert.That(_telescope.TargetDeclination, Is.EqualTo(targetDeclination)); + + var secondTelescopeInstance = + new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, + _sharedResourcesWrapperMock.Object, _astroMathsMock.Object, _clockMock.Object, _novasMock.Object); + + Assert.That(secondTelescopeInstance.Connected, Is.False); + + _connectionInfo.SameDevice = 2; + secondTelescopeInstance.Connected = true; + + Assert.That(_sharedResourcesWrapperMock.Object.IsLongFormat, Is.True); + Assert.That(secondTelescopeInstance.TargetDeclination, Is.EqualTo(targetDeclination)); + + _utilMock.Verify(x => x.DegreesToDMS(targetDeclination, "*", ":", ":", 2), Times.Once); + _utilMock.Verify(x => x.DMSToDegrees(targetDeclinationDMS), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendChar(command, false), Times.Once); + } + [Test] public void TargetRightAscension_Set_WhenNotConnected_ThenThrowsException() { diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 80a1cf1..03e9b1b 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -78,8 +78,6 @@ namespace ASCOM.Meade.net /// private int _digitsDe = 2; - private short _settleTime; - /// /// Initializes a new instance of the class. /// Must be public for COM registration. @@ -487,6 +485,13 @@ namespace ASCOM.Meade.net CheckParked(); } + if (!SharedResourcesWrapper.IsLongFormat) + { + // use low precision digits + _digitsRa = 1; + _digitsDe = 0; + } + var raAndDec = GetTelescopeRaAndDec(); LogMessage("Connected Set", $"Connected OK. Current RA = {_utilitiesExtra.HoursToHMS(raAndDec.RightAscension)} Dec = {_utilitiesExtra.DegreesToDMS(raAndDec.Declination)}"); @@ -634,8 +639,6 @@ namespace ASCOM.Meade.net return comparison >= 0; } - private bool IsLongFormat { get; set; } - /// /// classic LX200 needs initial set of target coordinates, if it is slewing and the target RA DE coordinates are 0 and differ from the current coordinates /// @@ -708,13 +711,11 @@ namespace ASCOM.Meade.net public void SetLongFormat(bool setLongFormat) { - IsLongFormat = false; - if (!IsLongFormatSupported()) { LogMessage("SetLongFormat", "Long coordinate format not supported for this mount"); - _digitsRa = 1; - _digitsDe = 0; + + SharedResourcesWrapper.Lock(() => SharedResourcesWrapper.IsLongFormat = false); return; } @@ -726,9 +727,9 @@ namespace ASCOM.Meade.net //Returns: DDD*MM.T or DDD*MM'SS# //The current telescope Azimuth depending on the selected precision. - IsLongFormat = result.Length > 6; + SharedResourcesWrapper.IsLongFormat = result.Length > 6; - if (IsLongFormat != setLongFormat) + if (SharedResourcesWrapper.IsLongFormat != setLongFormat) { _utilities.WaitForMilliseconds(500); SharedResourcesWrapper.SendBlind("U"); @@ -737,9 +738,9 @@ namespace ASCOM.Meade.net //High - Dec / Az / El displays and messages HH:MM: SS sDD*MM:SS // Returns Nothing result = SharedResourcesWrapper.SendString("GZ"); - IsLongFormat = result.Length > 6; + SharedResourcesWrapper.IsLongFormat = result.Length > 6; LogMessage("SetLongFormat", $"Get - Azimuth {result}"); - if (IsLongFormat == setLongFormat) + if (SharedResourcesWrapper.IsLongFormat == setLongFormat) LogMessage("SetLongFormat", $"Long coordinate format: {setLongFormat} "); } else @@ -2077,14 +2078,14 @@ namespace ASCOM.Meade.net get { CheckConnected("SlewSettleTime Get"); - LogMessage("SlewSettleTime Get", $"{_settleTime} Seconds"); - return _settleTime; + LogMessage("SlewSettleTime Get", $"{SharedResourcesWrapper.SlewSettleTime} Seconds"); + return SharedResourcesWrapper.SlewSettleTime; } set { CheckConnected("SlewSettleTime Set"); - LogMessage("SlewSettleTime Set", $"Setting from {_settleTime} to {value}"); - _settleTime = value; + LogMessage("SlewSettleTime Set", $"Setting from {SharedResourcesWrapper.SlewSettleTime} to {value}"); + SharedResourcesWrapper.SlewSettleTime = value; } } @@ -2481,7 +2482,7 @@ namespace ASCOM.Meade.net if (value < -90) throw new InvalidValueException("Declination cannot be less than -90."); - var dms = IsLongFormat ? + var dms = SharedResourcesWrapper.IsLongFormat ? _utilities.DegreesToDMS(value, "*", ":", ":", _digitsDe) : _utilities.DegreesToDM(value, "*", "", _digitsDe); @@ -2537,7 +2538,7 @@ namespace ASCOM.Meade.net if (value >= 24) throw new InvalidValueException("Right ascension value cannot be greater than 23:59:59"); - var hms = IsLongFormat ? + var hms = SharedResourcesWrapper.IsLongFormat ? _utilities.HoursToHMS(value, ":", ":", ":", _digitsRa) : _utilities.HoursToHM(value, ":", "", _digitsRa).Replace(',','.'); diff --git a/Meade.net/MeadeTelescopeBase.cs b/Meade.net/MeadeTelescopeBase.cs index 0e36a17..5e4c942 100644 --- a/Meade.net/MeadeTelescopeBase.cs +++ b/Meade.net/MeadeTelescopeBase.cs @@ -33,7 +33,7 @@ namespace ASCOM.Meade.net protected ParkedBehaviour ParkedBehaviour; protected HorizonCoordinates ParkedAltAz; - protected readonly ISharedResourcesWrapper SharedResourcesWrapper; + protected readonly ISharedResourcesWrapper SharedResourcesWrapper; public MeadeTelescopeBase() { @@ -81,7 +81,7 @@ namespace ASCOM.Meade.net Altitude = profileProperties.ParkedAlt, Azimuth = profileProperties.ParkedAz }; - + LogMessage("ReadProfile", $"Trace logger enabled: {Tl.Enabled}"); LogMessage("ReadProfile", $"Com Port: {ComPort}"); LogMessage("ReadProfile", $"Backlash Steps: {BacklashCompensation}"); diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index bcf1134..8165e7b 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -509,10 +509,14 @@ namespace ASCOM.Meade.net /// Start with . /// As we do not know the physical declination axis position, we have to keep track manually. /// - public static PierSide SideOfPier { get; set; } = PierSide.pierUnknown; + public static PierSide SideOfPier { get; internal set; } = PierSide.pierUnknown; - public static double? TargetRightAscension { get; set; } + public static double? TargetRightAscension { get; internal set; } - public static double? TargetDeclination { get; set; } + public static double? TargetDeclination { get; internal set; } + + public static short SlewSettleTime { get; internal set; } + + public static bool IsLongFormat { get; internal set; } } } \ No newline at end of file diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index 83fe829..d123a71 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -36,6 +36,10 @@ namespace ASCOM.Meade.net.Wrapper PierSide SideOfPier { get; set; } double? TargetRightAscension { get; set; } double? TargetDeclination { get; set; } + + short SlewSettleTime { get; set; } + + bool IsLongFormat { get; set; } } public class SharedResourcesWrapper : ISharedResourcesWrapper @@ -135,5 +139,17 @@ namespace ASCOM.Meade.net.Wrapper get => SharedResources.TargetDeclination; set => SharedResources.TargetDeclination = value; } + + public short SlewSettleTime + { + get => SharedResources.SlewSettleTime; + set => SharedResources.SlewSettleTime = value; + } + + public bool IsLongFormat + { + get => SharedResources.IsLongFormat; + set => SharedResources.IsLongFormat = value; + } } } From 036a9d711648279ef43b0bf354c1bb9783c719d3 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sun, 13 Jun 2021 09:45:07 +1000 Subject: [PATCH 07/23] Add multi-connection test for TargetRightAscension --- .../TelescopeUnitTests.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 9a3adf3..4467bf8 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -2516,6 +2516,44 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.EqualTo(rightAscension)); } + [TestCase(0d)] + [TestCase(6d)] + [TestCase(12d)] + [TestCase(23.599d)] + public void TargetRightAscension_Set_WhenSecondConnectionMade_ThenSlewSettleTimeIsPreserved(double targetRightAscension) + { + var targetRightAscensionHMS = targetRightAscension + "HMS"; + var command = $"Sr{targetRightAscensionHMS}"; + + _utilMock.Setup(x => x.HoursToHMS(targetRightAscension, ":", ":", ":", 2)).Returns(targetRightAscensionHMS); + _utilMock.Setup(x => x.HMSToHours(targetRightAscensionHMS)).Returns(targetRightAscension); + _sharedResourcesWrapperMock.Setup(x => x.SendChar(command, false)).Returns("1"); + + ConnectTelescope(); + Assert.That(_connectionInfo.SameDevice, Is.EqualTo(1)); + Assert.That(_sharedResourcesWrapperMock.Object.IsLongFormat, Is.True); + + _telescope.TargetRightAscension = targetRightAscension; + + Assert.That(_telescope.TargetRightAscension, Is.EqualTo(targetRightAscension)); + + var secondTelescopeInstance = + new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, + _sharedResourcesWrapperMock.Object, _astroMathsMock.Object, _clockMock.Object, _novasMock.Object); + + Assert.That(secondTelescopeInstance.Connected, Is.False); + + _connectionInfo.SameDevice = 2; + secondTelescopeInstance.Connected = true; + + Assert.That(_sharedResourcesWrapperMock.Object.IsLongFormat, Is.True); + Assert.That(secondTelescopeInstance.TargetRightAscension, Is.EqualTo(targetRightAscension)); + + _utilMock.Verify(x => x.HoursToHMS(targetRightAscension, ":", ":", ":", 2), Times.Once); + _utilMock.Verify(x => x.HMSToHours(targetRightAscensionHMS), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendChar(command, false), Times.Once); + } + [Test] public void Tracking_Get_WhenDefault_ThenIsTrue() { From 0b75b8d2cd46950955ea0044456cadab069622a2 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sun, 13 Jun 2021 09:49:09 +1000 Subject: [PATCH 08/23] Remove now unneeded Setup for DestinationSideOfPier DestinationSideOfPier will not call Slewing anymore, since it reads the property from SharedResourcesWrapper directly. --- Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 4467bf8..fd414ae 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -3085,9 +3085,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTarget_WhenSlewing_ThenWaitsForTheSlewToComplete() { - // avoid calling SideOfPier because it will call Slewing - _astroUtilsMock.Setup(x => x.ConditionHA(It.IsAny())).Returns(+1); - _sharedResourcesWrapperMock.Setup(x => x.SendChar("MS", false)).Returns("0"); var slewCounter = 0; @@ -3169,9 +3166,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToCoordinates_WhenCalled_ThenSetsTargetAndSlews() { - // avoid calling SideOfPier because it will call Slewing - _astroUtilsMock.Setup(x => x.ConditionHA(It.IsAny())).Returns(+1); - _testProperties.rightAscension = 1; var declination = 2; @@ -3295,9 +3289,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAz_WhenCalled_ThenSetsTargetAndSlews() { - // avoid calling SideOfPier because it will call Slewing - _astroUtilsMock.Setup(x => x.ConditionHA(It.IsAny())).Returns(+1); - _testProperties.rightAscension = 10.0; _testProperties.declination = 20; var azimuth = 30; From b23da15022f8a91ce8ecfd5cc85bef79bce889c9 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sun, 13 Jun 2021 16:30:35 +1000 Subject: [PATCH 09/23] Make Focuser.cs ASCII compatible --- Meade.net.focuser/Focuser.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 93e0ca0..8d3ac6c 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -43,7 +43,7 @@ namespace ASCOM.Meade.net /// Private variable to hold an ASCOM Utilities object /// private readonly IUtil _utilities; - + /// /// Initializes a new instance of the class. /// Must be public for COM registration. @@ -304,7 +304,7 @@ namespace ASCOM.Meade.net var backlashCompensationSteps = direction ? Math.Abs(BacklashCompensation) : 0; var steps = Math.Abs(position) + backlashCompensationSteps; - + MoveFocuser(direction, steps); @@ -343,11 +343,11 @@ namespace ASCOM.Meade.net //:FS# Set Focus speed to slowest setting //Returns: Nothing - //:F# Autostar, Autostar II – set focuser speed to where is an ASCII digit 1..4 + //:F# Autostar, Autostar II - set focuser speed to where is an ASCII digit 1..4 //Returns: Nothing - //All others – Not Supported + //All others - Not Supported _utilities.WaitForMilliseconds(100); - + PerformFocuserMove(directionOut); _utilities.WaitForMilliseconds(steps); @@ -418,7 +418,7 @@ namespace ASCOM.Meade.net #region ASCOM Registration // Register or unregister driver for ASCOM. This is harmless if already - // registered or unregistered. + // registered or unregistered. // /// /// Register or unregister the driver with the ASCOM Platform. @@ -488,7 +488,7 @@ namespace ASCOM.Meade.net } #endregion - + /// /// Use this function to throw an exception if we aren't connected to the hardware /// From 2e3572375f5ec8918c814c1dc1589826a513dd8b Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sun, 13 Jun 2021 17:23:15 +1000 Subject: [PATCH 10/23] Test that SideralTime is preserved across connections --- .../TelescopeUnitTests.cs | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index fd414ae..255bc01 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1881,6 +1881,43 @@ namespace Meade.net.Telescope.UnitTests Assert.That(excpetion.AccessorSet, Is.True); } + [TestCase(0, 34, PierSide.pierEast)] + [TestCase(12, 34, PierSide.pierEast)] + [TestCase(23.4, 34, PierSide.pierWest)] + public void SideOfPier_WhenSecondConnectionMade_ThenValueIsPreserved(double ra, double dec, PierSide expectedPierSide) + { + _sharedResourcesWrapperMock.Setup(x => x.SendChar("MS", false)).Returns("0"); + _utilMock.Setup(x => x.HMSToHours(null)).Returns(ra); + _utilMock.Setup(x => x.DMSToDegrees(null)).Returns(dec); + _astroUtilsMock.Setup(x => x.ConditionHA(It.IsAny())).Returns(pHA => pHA < -12 ? pHA + 12 : pHA > 12 ? pHA - 12 : pHA); + _astroUtilsMock.Setup(x => x.ConditionRA(It.IsAny())).Returns(pRA => pRA < 0 ? pRA + 24 : pRA >= 24 ? pRA - 24 : pRA); + + ConnectTelescope(); + Assert.That(_connectionInfo.SameDevice, Is.EqualTo(1)); + + _telescope.SlewToCoordinates(ra, dec); + var sideOfPierAfterSlew = _telescope.SideOfPier; + + Assert.That(sideOfPierAfterSlew, Is.EqualTo(expectedPierSide)); + + var secondTelescopeInstance = + new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, + _sharedResourcesWrapperMock.Object, _astroMathsMock.Object, _clockMock.Object, _novasMock.Object); + + Assert.That(secondTelescopeInstance.Connected, Is.False); + + _connectionInfo.SameDevice = 2; + secondTelescopeInstance.Connected = true; + + Assert.That(secondTelescopeInstance.SideOfPier, Is.EqualTo(sideOfPierAfterSlew)); + + _sharedResourcesWrapperMock.Verify(x => x.SendChar("MS", false), Times.Once); + _utilMock.Verify(x => x.HMSToHours(null), Times.Once); + _utilMock.Verify(x => x.DMSToDegrees(null), Times.AtLeast(2)); + _astroUtilsMock.Verify(x => x.ConditionHA(It.IsAny()), Times.Once); + _astroUtilsMock.Verify(x => x.ConditionRA(It.IsAny()), Times.Once); + } + delegate void NovasSiderealTimeDelegate(double jdHigh, double jdLow, double jdDelta, GstType gstType, Method method, Accuracy accuracy, ref double sideralTime); /// @@ -2399,7 +2436,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(0d)] [TestCase(45d)] [TestCase(90d)] - public void TargetDeclination_Set_WhenSecondConnectionMade_ThenSlewSettleTimeIsPreserved(double targetDeclination) + public void TargetDeclination_Set_WhenSecondConnectionMade_ThenValueIsPreserved(double targetDeclination) { var targetDeclinationDMS = targetDeclination + "DMS"; var sign = targetDeclination >= 0 ? "+" : string.Empty; @@ -2520,7 +2557,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(6d)] [TestCase(12d)] [TestCase(23.599d)] - public void TargetRightAscension_Set_WhenSecondConnectionMade_ThenSlewSettleTimeIsPreserved(double targetRightAscension) + public void TargetRightAscension_Set_WhenSecondConnectionMade_ThenValueIsPreserved(double targetRightAscension) { var targetRightAscensionHMS = targetRightAscension + "HMS"; var command = $"Sr{targetRightAscensionHMS}"; From af750549fe7ed65eb69f93e43ac09db2ed96deaf Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sun, 13 Jun 2021 17:36:42 +1000 Subject: [PATCH 11/23] Test that low-precision digit values are preserved across connections --- .../TelescopeUnitTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 255bc01..978e51a 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1020,6 +1020,40 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar("P", false), Times.Never); } + [Test] + public void IsLongFormat_WhenHighPrecisionNotSupportedAndSecondConnectionMade_ThenDigitPrecisionValuesArePreserved() + { + var ra = 12d; + var dec = 34d; + + _utilMock.Setup(x => x.HoursToHM(ra, ":", "", 1)).Returns(ra + "HM"); + _utilMock.Setup(x => x.DegreesToDM(dec, "*", "", 0)).Returns(dec + "DM"); + + ConnectTelescope(TelescopeList.LX200CLASSIC); + + _telescope.TargetRightAscension = ra; + _telescope.TargetDeclination = dec; + + Assert.That(_connectionInfo.SameDevice, Is.EqualTo(1)); + + var secondTelescopeInstance = + new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, + _sharedResourcesWrapperMock.Object, _astroMathsMock.Object, _clockMock.Object, _novasMock.Object); + + Assert.That(secondTelescopeInstance.Connected, Is.False); + + _connectionInfo.SameDevice = 2; + secondTelescopeInstance.Connected = true; + + secondTelescopeInstance.TargetRightAscension = ra; + secondTelescopeInstance.TargetDeclination = dec; + + _utilMock.Verify(x => x.HoursToHM(ra, ":", "", 1), Times.Exactly(2)); + _utilMock.Verify(x => x.DegreesToDM(dec, "*", "", 0), Times.Exactly(2)); + _utilMock.Verify(x => x.HoursToHMS(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), 2), Times.Never); + _utilMock.Verify(x => x.DegreesToDMS(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), 2), Times.Never); + } + [TestCase(0)] [TestCase(1)] [TestCase(2)] From 6fc476b031e867c3c31d5137c1bea838d55f4692 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Tue, 22 Jun 2021 17:21:21 +1000 Subject: [PATCH 12/23] Make further properties multi-client and thread-safe Move MovingPrimary, MovingSecondary, EarliestNonSlewingTime to SharedResources, make all new properties thread-safe (atomic) operations. --- .../TelescopeUnitTests.cs | 42 +++++++++-- Meade.net.Telescope/Telescope.cs | 35 ++++----- .../Meade.net.UnitTests.csproj | 6 ++ .../SharedResourcesUnitTests.cs | 12 +-- Meade.net.UnitTests/ThreadSafeBoolTests.cs | 39 ++++++++++ .../ThreadSafeDateTimeTests.cs | 64 ++++++++++++++++ Meade.net.UnitTests/ThreadSafeEnumTests.cs | 51 +++++++++++++ .../ThreadSafeNullableDoubleTests.cs | 45 ++++++++++++ Meade.net.UnitTests/packages.config | 2 + Meade.net/Meade.net.csproj | 4 + Meade.net/SharedResources.cs | 73 +++++++++++++++++-- Meade.net/ThreadSafeBool.cs | 17 +++++ Meade.net/ThreadSafeDateTime.cs | 20 +++++ Meade.net/ThreadSafeEnum.cs | 21 ++++++ Meade.net/ThreadSafeNullableDouble.cs | 24 ++++++ Meade.net/Wrapper/SharedResourcesWrapper.cs | 24 ++++++ 16 files changed, 435 insertions(+), 44 deletions(-) create mode 100644 Meade.net.UnitTests/ThreadSafeBoolTests.cs create mode 100644 Meade.net.UnitTests/ThreadSafeDateTimeTests.cs create mode 100644 Meade.net.UnitTests/ThreadSafeEnumTests.cs create mode 100644 Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs create mode 100644 Meade.net/ThreadSafeBool.cs create mode 100644 Meade.net/ThreadSafeDateTime.cs create mode 100644 Meade.net/ThreadSafeEnum.cs create mode 100644 Meade.net/ThreadSafeNullableDouble.cs diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 978e51a..e5dddec 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1004,20 +1004,28 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar("P", false), Times.AtLeastOnce); } - [TestCase("High", false, true)] - [TestCase("High", true, true)] - [TestCase("Low", false, false)] - [TestCase("Low", true, false)] - public void Precision_Set_WhenSecondConnectionMade_ThenTelescopePrecisionNotChanged(string desiredPresision, bool telescopePrecision, bool finalPrecision) + [TestCase("High")] + [TestCase("Low")] + public void Precision_Set_WhenSecondConnectionMade_ThenTelescopePrecisionNotChanged(string desiredPresision) { + var isLongFormat = desiredPresision == "High" + || (desiredPresision == "Low" + ? false + : throw new ArgumentOutOfRangeException(nameof(desiredPresision), desiredPresision, "Should be High or Low")); + _sharedResourcesWrapperMock.SetupProperty(x => x.IsLongFormat, isLongFormat); + _sharedResourcesWrapperMock.Setup(x => x.SendString("GR", false)).Returns(() => _testProperties.telescopeRaResult); + _utilMock.Setup(x => x.HMSToHours(_testProperties.telescopeRaResult)).Returns(() => _testProperties.rightAscension); + _profileProperties.Precision = desiredPresision; _connectionInfo.SameDevice = 2; //_connectionInfo.Connections = 2; + _telescope.Connected = true; _sharedResourcesWrapperMock.Verify(x => x.SendChar("P", false), Times.Never); + _sharedResourcesWrapperMock.Verify(x => x.IsLongFormat, Times.Once); } [Test] @@ -1687,6 +1695,9 @@ namespace Meade.net.Telescope.UnitTests [TestCase(GuideDirections.guideSouth, TelescopeAxes.axisSecondary)] public void PulseGuide_WhenMovingAxisAndPulseGuideAttempted_ThenThrowsExpectedException(GuideDirections direction, TelescopeAxes axes) { + _sharedResourcesWrapperMock.SetupProperty(x => x.MovingPrimary); + _sharedResourcesWrapperMock.SetupProperty(x => x.MovingSecondary); + _sharedResourcesWrapperMock.SetupProperty(x => x.EarliestNonSlewingTime, DateTime.MinValue); _sharedResourcesWrapperMock.Setup(x => x.SendString("D", false)).Returns(""); var duration = 0; @@ -1697,6 +1708,8 @@ namespace Meade.net.Telescope.UnitTests var exception = Assert.Throws(() => _telescope.PulseGuide(direction, duration)); Assert.That(exception.Message, Is.EqualTo("Unable to PulseGuide while moving same axis.")); + Assert.That(_sharedResourcesWrapperMock.Object.MovingPrimary, Is.EqualTo(axes == TelescopeAxes.axisPrimary)); + Assert.That(_sharedResourcesWrapperMock.Object.MovingSecondary, Is.EqualTo(axes == TelescopeAxes.axisSecondary)); } [TestCase(GuideDirections.guideEast)] @@ -2909,6 +2922,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(15, 10, "2021-10-03T20:36:00", "2021-10-03T20:36:25", false)] public void Slewing_WhenTelescopeIsSlewing_ThenReturnsExpectedValueForSettleTime(short settleTime, short profileSettleTime, string startSlewing, string endSlewing, bool isSlewing) { + _sharedResourcesWrapperMock.SetupProperty(x => x.EarliestNonSlewingTime, DateTime.MinValue); _profileProperties.SettleTime = profileSettleTime; var timescalled = 0; @@ -2979,6 +2993,10 @@ namespace Meade.net.Telescope.UnitTests [TestCase(-1, TelescopeAxes.axisSecondary)] public void Slewing_WhenTelescopeIsMoving_ThenDoesNotSendCommandAndReturnsTrue(int rate, TelescopeAxes axis) { + _sharedResourcesWrapperMock.SetupProperty(x => x.MovingPrimary); + _sharedResourcesWrapperMock.SetupProperty(x => x.MovingSecondary); + _sharedResourcesWrapperMock.SetupProperty(x => x.EarliestNonSlewingTime, DateTime.MinValue); + ConnectTelescope(); _telescope.MoveAxis(axis, rate); @@ -2986,6 +3004,9 @@ namespace Meade.net.Telescope.UnitTests var result = _telescope.Slewing; Assert.That(result, Is.True); + Assert.That(_sharedResourcesWrapperMock.Object.MovingPrimary, Is.EqualTo(axis == TelescopeAxes.axisPrimary)); + Assert.That(_sharedResourcesWrapperMock.Object.MovingSecondary, Is.EqualTo(axis == TelescopeAxes.axisSecondary)); + _sharedResourcesWrapperMock.Verify(x => x.SendString("D", false), Times.Never); } @@ -3005,6 +3026,11 @@ namespace Meade.net.Telescope.UnitTests [TestCase(-1, TelescopeAxes.axisSecondary, 10, 20, true, true)] public void Slewing_WhenTelescopeStops_ThenWaitsForSettleTime(int rate, TelescopeAxes axis, short profileSettleTime, short driverSettleTime, bool expectedResultInWaitingPeriod, bool afterProfileSettleTimeUp) { + _sharedResourcesWrapperMock.SetupProperty(x => x.MovingPrimary); + _sharedResourcesWrapperMock.SetupProperty(x => x.MovingSecondary); + _sharedResourcesWrapperMock.SetupProperty(x => x.SlewSettleTime); + _sharedResourcesWrapperMock.SetupProperty(x => x.EarliestNonSlewingTime, DateTime.MinValue); + _profileProperties.SettleTime = profileSettleTime; DateTime currentTime = MakeTime("2021-01-23T22:02:10"); @@ -3022,17 +3048,17 @@ namespace Meade.net.Telescope.UnitTests _telescope.MoveAxis(axis, 0); - currentTime = currentTime + TimeSpan.FromSeconds(profileSettleTime / 2); + currentTime += TimeSpan.FromSeconds(profileSettleTime / 2); result = _telescope.Slewing; Assert.That(result, Is.EqualTo(expectedResultInWaitingPeriod)); - currentTime = currentTime + TimeSpan.FromSeconds(profileSettleTime / 2); + currentTime += TimeSpan.FromSeconds(profileSettleTime / 2); result = _telescope.Slewing; Assert.That(result, Is.EqualTo(afterProfileSettleTimeUp)); - currentTime = currentTime + TimeSpan.FromSeconds(driverSettleTime); + currentTime += TimeSpan.FromSeconds(driverSettleTime); result = _telescope.Slewing; Assert.That(result, Is.False); diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 03e9b1b..2980a5c 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -938,8 +938,8 @@ namespace ASCOM.Meade.net //:Q# Halt all current slewing //Returns:Nothing - _movingPrimary = false; - _movingSecondary = false; + SharedResourcesWrapper.MovingPrimary = false; + SharedResourcesWrapper.MovingSecondary = false; SetSlewingMinEndTime(); } @@ -1522,9 +1522,6 @@ namespace ASCOM.Meade.net } } - private bool _movingPrimary; - private bool _movingSecondary; - public void MoveAxis(TelescopeAxes axis, double rate) { LogMessage("MoveAxis", $"Axis={axis} rate={rate}"); @@ -1573,7 +1570,7 @@ namespace ASCOM.Meade.net SetSlewingMinEndTime(); } - _movingPrimary = false; + SharedResourcesWrapper.MovingPrimary = false; SharedResourcesWrapper.SendBlind("Qe"); //:Qe# Halt eastward Slews //Returns: Nothing @@ -1585,17 +1582,13 @@ namespace ASCOM.Meade.net SharedResourcesWrapper.SendBlind("Me"); //:Me# Move Telescope East at current slew rate //Returns: Nothing - _movingPrimary = true; - // in principle we could calculate the current side of pier, but unknown is the safer option. - SharedResourcesWrapper.SideOfPier = PierSide.pierUnknown; + SharedResourcesWrapper.MovingPrimary = true; break; case ComparisonResult.Lower: SharedResourcesWrapper.SendBlind("Mw"); //:Mw# Move Telescope West at current slew rate //Returns: Nothing - _movingPrimary = true; - // in principle we could calculate the current side of pier, but unknown is the safer option. - SharedResourcesWrapper.SideOfPier = PierSide.pierUnknown; + SharedResourcesWrapper.MovingPrimary = true; break; } break; @@ -1607,7 +1600,7 @@ namespace ASCOM.Meade.net { SetSlewingMinEndTime(); } - _movingSecondary = false; + SharedResourcesWrapper.MovingSecondary = false; SharedResourcesWrapper.SendBlind("Qn"); //:Qn# Halt northward Slews //Returns: Nothing @@ -1619,13 +1612,13 @@ namespace ASCOM.Meade.net SharedResourcesWrapper.SendBlind("Mn"); //:Mn# Move Telescope North at current slew rate //Returns: Nothing - _movingSecondary = true; + SharedResourcesWrapper.MovingSecondary = true; break; case ComparisonResult.Lower: SharedResourcesWrapper.SendBlind("Ms"); //:Ms# Move Telescope South at current slew rate //Returns: Nothing - _movingSecondary = true; + SharedResourcesWrapper.MovingSecondary = true; break; } break; @@ -1695,11 +1688,11 @@ namespace ASCOM.Meade.net _isGuiding = true; try { - if (_movingPrimary && + if (SharedResourcesWrapper.MovingPrimary && (direction == GuideDirections.guideEast || direction == GuideDirections.guideWest)) throw new InvalidOperationException("Unable to PulseGuide while moving same axis."); - if (_movingSecondary && + if (SharedResourcesWrapper.MovingSecondary && (direction == GuideDirections.guideNorth || direction == GuideDirections.guideSouth)) throw new InvalidOperationException("Unable to PulseGuide while moving same axis."); @@ -2279,11 +2272,9 @@ namespace ASCOM.Meade.net if (_isGuiding) return false; - return _movingPrimary || _movingSecondary; + return SharedResourcesWrapper.MovingPrimary || SharedResourcesWrapper.MovingSecondary; } - private DateTime _earliestNonSlewingTime = DateTime.MinValue; - public bool Slewing { get @@ -2292,7 +2283,7 @@ namespace ASCOM.Meade.net if (isSlewing) SetSlewingMinEndTime(); - else if (_clock.UtcNow < _earliestNonSlewingTime) + else if (_clock.UtcNow < SharedResourcesWrapper.EarliestNonSlewingTime) isSlewing = true; LogMessage("Slewing", $"Result = {isSlewing}"); @@ -2302,7 +2293,7 @@ namespace ASCOM.Meade.net private void SetSlewingMinEndTime() { - _earliestNonSlewingTime = _clock.UtcNow + GetTotalSlewingSettleTime(); + SharedResourcesWrapper.EarliestNonSlewingTime = _clock.UtcNow + GetTotalSlewingSettleTime(); } private TimeSpan GetTotalSlewingSettleTime() diff --git a/Meade.net.UnitTests/Meade.net.UnitTests.csproj b/Meade.net.UnitTests/Meade.net.UnitTests.csproj index 636c411..803c477 100644 --- a/Meade.net.UnitTests/Meade.net.UnitTests.csproj +++ b/Meade.net.UnitTests/Meade.net.UnitTests.csproj @@ -1,5 +1,6 @@  + @@ -98,6 +99,10 @@ + + + + @@ -116,5 +121,6 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + \ No newline at end of file diff --git a/Meade.net.UnitTests/SharedResourcesUnitTests.cs b/Meade.net.UnitTests/SharedResourcesUnitTests.cs index 0465c34..e936814 100644 --- a/Meade.net.UnitTests/SharedResourcesUnitTests.cs +++ b/Meade.net.UnitTests/SharedResourcesUnitTests.cs @@ -29,7 +29,7 @@ namespace Meade.net.UnitTests [Test] public void CheckThatSerialPortIsSetToUseMock() { - Assert.That(SharedResources.SharedSerial,Is.EqualTo(_serialMock.Object)); + Assert.That(SharedResources.SharedSerial, Is.EqualTo(_serialMock.Object)); } [TestCase(true, "Test")] @@ -160,7 +160,7 @@ namespace Meade.net.UnitTests string GuideRateProfileNameDefault = "10.077939"; //67% of sidereal rate string PrecisionDefault = "Unchanged"; string GuidingStyleDefault = "Auto"; - + string BacklashCompensationDefault = "3000"; string ReverseFocuserDiectionDefault = "true"; @@ -239,15 +239,15 @@ namespace Meade.net.UnitTests SharedResources.ProfileFactory = profileFactoryMock.Object; var profileProperties = SharedResources.ReadProfile(); - + Assert.That(profeWrapper.DeviceType, Is.EqualTo("Telescope")); Assert.That(profileProperties.TraceLogger, Is.EqualTo(bool.Parse(TraceStateDefault))); Assert.That(profileProperties.ComPort, Is.EqualTo(ComPortDefault)); - + Assert.That(profileProperties.GuideRateArcSecondsPerSecond, - Is.EqualTo(double.Parse(GuideRateProfileNameDefault))); + Is.EqualTo(double.Parse(GuideRateProfileNameDefault))); Assert.That(profileProperties.Precision, Is.EqualTo(PrecisionDefault)); Assert.That(profileProperties.GuidingStyle, Is.EqualTo(GuidingStyleDefault)); @@ -423,7 +423,7 @@ namespace Meade.net.UnitTests string serialPortReturn = string.Empty; - _serialMock.Setup(x => x.Transmit("#:GVP#")).Callback(() => { + _serialMock.Setup(x => x.Transmit("#:GVP#")).Callback(() => { serialPortReturn = string.Empty; throw new Exception("Testerror"); }); diff --git a/Meade.net.UnitTests/ThreadSafeBoolTests.cs b/Meade.net.UnitTests/ThreadSafeBoolTests.cs new file mode 100644 index 0000000..a757fd8 --- /dev/null +++ b/Meade.net.UnitTests/ThreadSafeBoolTests.cs @@ -0,0 +1,39 @@ +using ASCOM.Meade.net; +using NUnit.Framework; + +namespace Meade.net.UnitTests +{ + public class ThreadSafeBoolTests + { + [TestCase(false)] + [TestCase(true)] + public void WhenConvertedValueIsSame(bool value) + { + // given + ThreadSafeBool sut = value; + + // when + bool actual = sut; + + // then + Assert.That(actual, Is.EqualTo(value)); + } + + [TestCase(false, false)] + [TestCase(false, true)] + [TestCase(true, false)] + [TestCase(true, true)] + public void WhenSetValueIsChanged(bool value, bool setValue) + { + // given + ThreadSafeBool sut = value; + + // when + sut.Set(setValue); + bool afterset = sut; + + // then + Assert.That(afterset, Is.EqualTo(setValue)); + } + } +} diff --git a/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs b/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs new file mode 100644 index 0000000..5fd619c --- /dev/null +++ b/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs @@ -0,0 +1,64 @@ +using ASCOM.Meade.net; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Meade.net.UnitTests +{ + public class ThreadSafeDateTimeTests + { + [TestCaseSource(nameof(DateTimeSource))] + public void WhenConvertedValueIsSame(DateTime value) + { + // given + ThreadSafeDateTime sut = value; + + // when + DateTime actual = sut; + + // then + Assert.That(actual, Is.EqualTo(value)); + } + + [TestCaseSource(nameof(DateTimeSetSource))] + public void WhenSetValueIsChanged(DateTime value, DateTime setValue) + { + // given + ThreadSafeDateTime sut = value; + + // when + sut.Set(setValue); + DateTime afterset = sut; + + // then + Assert.That(afterset, Is.EqualTo(setValue)); + } + + static readonly DateTime Example1 = DateTimeOffset.Parse("2012-05-09T02:10:31.296761Z", CultureInfo.InvariantCulture).UtcDateTime; + static readonly DateTime Example2 = DateTimeOffset.Parse("2051-03-09T23:15:11.556081Z", CultureInfo.InvariantCulture).UtcDateTime; + + static IEnumerable DateTimeSource => new[] + { + DateTime.MinValue, + Example1, + Example2 + }; + + static IEnumerable DateTimeSetSource => new[] + { + new TestCaseData(DateTime.MinValue, Example1), + new TestCaseData(DateTime.MinValue, Example2), + new TestCaseData(DateTime.MinValue, DateTime.MinValue), + new TestCaseData(Example1, Example1), + new TestCaseData(Example1, Example2), + new TestCaseData(Example1, DateTime.MinValue), + new TestCaseData(Example2, Example1), + new TestCaseData(Example2, Example2), + new TestCaseData(Example2, DateTime.MinValue) + }; + } +} diff --git a/Meade.net.UnitTests/ThreadSafeEnumTests.cs b/Meade.net.UnitTests/ThreadSafeEnumTests.cs new file mode 100644 index 0000000..5157cd7 --- /dev/null +++ b/Meade.net.UnitTests/ThreadSafeEnumTests.cs @@ -0,0 +1,51 @@ +using ASCOM.DeviceInterface; +using ASCOM.Meade.net; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Meade.net.UnitTests +{ + public class ThreadSafeEnumTests + { + [TestCase(PierSide.pierUnknown)] + [TestCase(PierSide.pierEast)] + [TestCase(PierSide.pierWest)] + public void WhenConvertedValueIsSame(PierSide value) + { + // given + ThreadSafeEnum sut = value; + + // when + PierSide actual = sut; + + // then + Assert.That(actual, Is.EqualTo(value)); + } + + [TestCase(PierSide.pierUnknown, PierSide.pierUnknown)] + [TestCase(PierSide.pierUnknown, PierSide.pierUnknown)] + [TestCase(PierSide.pierUnknown, PierSide.pierUnknown)] + [TestCase(PierSide.pierEast, PierSide.pierUnknown)] + [TestCase(PierSide.pierEast, PierSide.pierWest)] + [TestCase(PierSide.pierEast, PierSide.pierEast)] + [TestCase(PierSide.pierWest, PierSide.pierUnknown)] + [TestCase(PierSide.pierWest, PierSide.pierWest)] + [TestCase(PierSide.pierWest, PierSide.pierEast)] + public void WhenSetValueIsChanged(PierSide value, PierSide setValue) + { + // given + ThreadSafeEnum sut = value; + + // when + sut.Set(setValue); + PierSide afterset = sut; + + // then + Assert.That(afterset, Is.EqualTo(setValue)); + } + } +} diff --git a/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs b/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs new file mode 100644 index 0000000..3537f4e --- /dev/null +++ b/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs @@ -0,0 +1,45 @@ +using ASCOM.Meade.net; +using NUnit.Framework; + +namespace Meade.net.UnitTests +{ + public class ThreadSafeNullableDoubleTests + { + [TestCase(0.1d)] + [TestCase(-12.34d)] + [TestCase(0d)] + [TestCase(null)] + public void WhenConvertedValueIsSame(double? value) + { + // given + ThreadSafeNullableDouble sut = value; + + // when + double? actual = sut; + + // then + Assert.That(actual, Is.EqualTo(value)); + } + + [TestCase(0.1d, 0.2d)] + [TestCase(-12.34d, 5d)] + [TestCase(0d, 1d)] + [TestCase(null, 2d)] + [TestCase(0.1d, null)] + [TestCase(-12.34d, null)] + [TestCase(0d, null)] + [TestCase(null, null)] + public void WhenSetValueIsChanged(double? value, double? setValue) + { + // given + ThreadSafeNullableDouble sut = value; + + // when + sut.Set(setValue); + double? afterset = sut; + + // then + Assert.That(afterset, Is.EqualTo(setValue)); + } + } +} diff --git a/Meade.net.UnitTests/packages.config b/Meade.net.UnitTests/packages.config index 507c431..55f7ddc 100644 --- a/Meade.net.UnitTests/packages.config +++ b/Meade.net.UnitTests/packages.config @@ -5,6 +5,8 @@ + + \ No newline at end of file diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index 4711710..1a6b06e 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -146,6 +146,10 @@ + + + + diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 8165e7b..b27a0e6 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -19,6 +19,7 @@ using System.Collections.Generic; using System.Globalization; using System.Runtime.InteropServices; using System.Security.AccessControl; +using System.Threading; using System.Windows.Forms; using ASCOM.DeviceInterface; using ASCOM.Meade.net.Wrapper; @@ -245,7 +246,7 @@ namespace ASCOM.Meade.net private const string HandShakeDefault = "None"; private const string ParityDefault = "None"; private const string SendDateTimeDefault = "false"; - private static string ParkedBehaviourDefault = "No Coordinates"; + private const string ParkedBehaviourDefault = "No Coordinates"; private const string ParkedAltDefault = "0"; private const string ParkedAzimuthDefault = "180"; @@ -501,22 +502,78 @@ namespace ASCOM.Meade.net ParkedPosition = parkedPosition; } - public static bool IsParked { get; private set; } + private static readonly ThreadSafeBool _isParked = false; + public static bool IsParked + { + get => _isParked; + private set => _isParked.Set(value); + } - public static ParkedPosition ParkedPosition { get; private set; } + private static ParkedPosition _parkedPosition; + public static ParkedPosition ParkedPosition + { + get => _parkedPosition; + private set => Interlocked.Exchange(ref _parkedPosition, value); + } + private static readonly ThreadSafeEnum _sideOfPier = PierSide.pierUnknown; /// /// Start with . /// As we do not know the physical declination axis position, we have to keep track manually. /// - public static PierSide SideOfPier { get; internal set; } = PierSide.pierUnknown; + public static PierSide SideOfPier + { + get => _sideOfPier; + internal set => _sideOfPier.Set(value); + } - public static double? TargetRightAscension { get; internal set; } + private static readonly ThreadSafeNullableDouble _targetRightAscension = null as double?; + public static double? TargetRightAscension + { + get => _targetRightAscension; + internal set => _targetRightAscension.Set(value); + } - public static double? TargetDeclination { get; internal set; } + private static readonly ThreadSafeNullableDouble _targetDeclination = null as double?; + public static double? TargetDeclination + { + get => _targetDeclination; + internal set => _targetDeclination.Set(value); + } - public static short SlewSettleTime { get; internal set; } + private static int _slewSettleTime; + public static short SlewSettleTime + { + get => Convert.ToInt16(_slewSettleTime); + internal set => Interlocked.Exchange(ref _slewSettleTime, value); + } - public static bool IsLongFormat { get; internal set; } + private static readonly ThreadSafeBool _isLongFormat = false; + public static bool IsLongFormat + { + get => _isLongFormat; + internal set => _isLongFormat.Set(value); + } + + private static readonly ThreadSafeBool _movingPrimary = false; + public static bool MovingPrimary + { + get => _movingPrimary; + internal set => _movingPrimary.Set(value); + } + + private static readonly ThreadSafeBool _movingSecondary = false; + public static bool MovingSecondary + { + get => _movingSecondary; + internal set => _movingSecondary.Set(value); + } + + private static readonly ThreadSafeDateTime _earliestNonSlewingTime = DateTime.MinValue; + public static DateTime EarliestNonSlewingTime + { + get => _earliestNonSlewingTime; + internal set => _earliestNonSlewingTime.Set(value); + } } } \ No newline at end of file diff --git a/Meade.net/ThreadSafeBool.cs b/Meade.net/ThreadSafeBool.cs new file mode 100644 index 0000000..b60d275 --- /dev/null +++ b/Meade.net/ThreadSafeBool.cs @@ -0,0 +1,17 @@ +using System.Threading; + +namespace ASCOM.Meade.net +{ + public class ThreadSafeBool + { + private object _value; + + public ThreadSafeBool(in bool value) => _value = value; + + public void Set(in bool value) => Interlocked.Exchange(ref _value, value); + + public static implicit operator ThreadSafeBool(in bool value) => new ThreadSafeBool(value); + + public static implicit operator bool(ThreadSafeBool @this) => (bool)@this._value; + } +} \ No newline at end of file diff --git a/Meade.net/ThreadSafeDateTime.cs b/Meade.net/ThreadSafeDateTime.cs new file mode 100644 index 0000000..c336ef2 --- /dev/null +++ b/Meade.net/ThreadSafeDateTime.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading; + +namespace ASCOM.Meade.net +{ + public class ThreadSafeDateTime + { + private long _value; + + public ThreadSafeDateTime(in DateTime value) => _value = DateTimeToLong(value); + + public void Set(in DateTime value) => Interlocked.Exchange(ref _value, DateTimeToLong(value)); + + private static long DateTimeToLong(in DateTime value) => value.ToUniversalTime().Ticks; + + public static implicit operator ThreadSafeDateTime(in DateTime value) => new ThreadSafeDateTime(value); + + public static implicit operator DateTime(ThreadSafeDateTime @this) => new DateTime(Interlocked.Read(ref @this._value), DateTimeKind.Utc); + } +} \ No newline at end of file diff --git a/Meade.net/ThreadSafeEnum.cs b/Meade.net/ThreadSafeEnum.cs new file mode 100644 index 0000000..f942dfc --- /dev/null +++ b/Meade.net/ThreadSafeEnum.cs @@ -0,0 +1,21 @@ +using System; +using System.Threading; + +namespace ASCOM.Meade.net +{ + public class ThreadSafeEnum + where T: struct, Enum + { + private long _value; + + public ThreadSafeEnum(T value) => _value = EnumToLong(value); + + public void Set(T value) => Interlocked.Exchange(ref _value, EnumToLong(value)); + + private static long EnumToLong(T value) => Convert.ToInt64(value); + + public static implicit operator ThreadSafeEnum(T value) => new ThreadSafeEnum(value); + + public static implicit operator T(ThreadSafeEnum @this) => (T) Enum.ToObject(typeof(T), Interlocked.Read(ref @this._value)); + } +} \ No newline at end of file diff --git a/Meade.net/ThreadSafeNullableDouble.cs b/Meade.net/ThreadSafeNullableDouble.cs new file mode 100644 index 0000000..4a8efd1 --- /dev/null +++ b/Meade.net/ThreadSafeNullableDouble.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading; + +namespace ASCOM.Meade.net +{ + public class ThreadSafeNullableDouble + { + private long _value; + + public ThreadSafeNullableDouble(in double? value) => _value = NullableDoubleToLong(value); + + public void Set(in double? value) => Interlocked.Exchange(ref _value, NullableDoubleToLong(value)); + + private static long NullableDoubleToLong(in double? value) => BitConverter.DoubleToInt64Bits(value ?? double.NaN); + + public static implicit operator ThreadSafeNullableDouble(in double? value) => new ThreadSafeNullableDouble(value); + + public static implicit operator double?(ThreadSafeNullableDouble @this) + { + var doubleValue = BitConverter.Int64BitsToDouble(Interlocked.Read(ref @this._value)); + return double.IsNaN(doubleValue) ? null as double? : doubleValue; + } + } +} \ No newline at end of file diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index d123a71..8e91bb7 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -40,6 +40,12 @@ namespace ASCOM.Meade.net.Wrapper short SlewSettleTime { get; set; } bool IsLongFormat { get; set; } + + bool MovingPrimary { get; set; } + + bool MovingSecondary { get; set; } + + DateTime EarliestNonSlewingTime { get; set; } } public class SharedResourcesWrapper : ISharedResourcesWrapper @@ -151,5 +157,23 @@ namespace ASCOM.Meade.net.Wrapper get => SharedResources.IsLongFormat; set => SharedResources.IsLongFormat = value; } + + public bool MovingPrimary + { + get => SharedResources.MovingPrimary; + set => SharedResources.MovingPrimary = value; + } + + public bool MovingSecondary + { + get => SharedResources.MovingSecondary; + set => SharedResources.MovingSecondary = value; + } + + public DateTime EarliestNonSlewingTime + { + get => SharedResources.EarliestNonSlewingTime; + set => SharedResources.EarliestNonSlewingTime = value; + } } } From 7afd364efa3592e915796a88d1d6905f1197273e Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Tue, 22 Jun 2021 17:43:25 +1000 Subject: [PATCH 13/23] Add tests for SharedResources properties Ensure that default values are correct and no error appears --- .../SharedResourcesUnitTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Meade.net.UnitTests/SharedResourcesUnitTests.cs b/Meade.net.UnitTests/SharedResourcesUnitTests.cs index e936814..8c5fb79 100644 --- a/Meade.net.UnitTests/SharedResourcesUnitTests.cs +++ b/Meade.net.UnitTests/SharedResourcesUnitTests.cs @@ -1,6 +1,7 @@  using System; using System.Globalization; +using ASCOM.DeviceInterface; using ASCOM.Meade.net; using ASCOM.Meade.net.Wrapper; using ASCOM.Utilities.Interfaces; @@ -618,5 +619,35 @@ namespace Meade.net.UnitTests _traceLoggerMock.Verify( x => x.LogIssue("Connect", "Unable to decode response from the telescope, This is likely a hardware serial communications error."), Times.Once); } + + [Test] + public void CheckIsParkedIsFalseByDefault() => Assert.That(SharedResources.IsParked, Is.False); + + [Test] + public void CheckParkedPositionIsNullByDefault() => Assert.That(SharedResources.ParkedPosition, Is.Null); + + [Test] + public void CheckIsLongFormatIsFalseByDefault() => Assert.That(SharedResources.IsLongFormat, Is.False); + + [Test] + public void CheckMovingPrimaryIsFalseBydefault() => Assert.That(SharedResources.MovingPrimary, Is.False); + + [Test] + public void CheckMovingSecondaryIsFalseBydefault() => Assert.That(SharedResources.MovingSecondary, Is.False); + + [Test] + public void CheckSideOfPierIsUnknownByDefault() => Assert.That(SharedResources.SideOfPier, Is.EqualTo(PierSide.pierUnknown)); + + [Test] + public void CheckSlewSettleTimeIsZeroByDefault() => Assert.That(SharedResources.SlewSettleTime, Is.EqualTo((short)0)); + + [Test] + public void CheckEarliestNonNonSlewingTimeIsMinValueByDefault() => Assert.That(SharedResources.EarliestNonSlewingTime, Is.EqualTo(DateTime.MinValue)); + + [Test] + public void CheckTargetDeclinationIsNullByDefault() => Assert.That(SharedResources.TargetDeclination.HasValue, Is.False); + + [Test] + public void CheckTargetRightAscensionIsNullByDefault() => Assert.That(SharedResources.TargetRightAscension.HasValue, Is.False); } } From 6dff32505e3d8ca4582e74defc30c108602d1ef1 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Wed, 23 Jun 2021 11:07:23 +1000 Subject: [PATCH 14/23] Clarify thread-safe value test intention --- Meade.net.UnitTests/ThreadSafeBoolTests.cs | 6 +++--- .../ThreadSafeDateTimeTests.cs | 9 +++------ Meade.net.UnitTests/ThreadSafeEnumTests.cs | 19 +++++++------------ .../ThreadSafeNullableDoubleTests.cs | 6 +++--- 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/Meade.net.UnitTests/ThreadSafeBoolTests.cs b/Meade.net.UnitTests/ThreadSafeBoolTests.cs index a757fd8..adeee40 100644 --- a/Meade.net.UnitTests/ThreadSafeBoolTests.cs +++ b/Meade.net.UnitTests/ThreadSafeBoolTests.cs @@ -7,7 +7,7 @@ namespace Meade.net.UnitTests { [TestCase(false)] [TestCase(true)] - public void WhenConvertedValueIsSame(bool value) + public void When_Assigned_ThenValueIsSame(bool value) { // given ThreadSafeBool sut = value; @@ -23,10 +23,10 @@ namespace Meade.net.UnitTests [TestCase(false, true)] [TestCase(true, false)] [TestCase(true, true)] - public void WhenSetValueIsChanged(bool value, bool setValue) + public void When_SetValue_ThenValueIsUpdated(bool initialValue, bool setValue) { // given - ThreadSafeBool sut = value; + ThreadSafeBool sut = initialValue; // when sut.Set(setValue); diff --git a/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs b/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs index 5fd619c..e20e46a 100644 --- a/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs +++ b/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs @@ -3,16 +3,13 @@ using NUnit.Framework; using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Meade.net.UnitTests { public class ThreadSafeDateTimeTests { [TestCaseSource(nameof(DateTimeSource))] - public void WhenConvertedValueIsSame(DateTime value) + public void When_Assigned_ThenValueIsSame(DateTime value) { // given ThreadSafeDateTime sut = value; @@ -25,10 +22,10 @@ namespace Meade.net.UnitTests } [TestCaseSource(nameof(DateTimeSetSource))] - public void WhenSetValueIsChanged(DateTime value, DateTime setValue) + public void When_SetValue_ThenValueIsUpdated(DateTime initialValue, DateTime setValue) { // given - ThreadSafeDateTime sut = value; + ThreadSafeDateTime sut = initialValue; // when sut.Set(setValue); diff --git a/Meade.net.UnitTests/ThreadSafeEnumTests.cs b/Meade.net.UnitTests/ThreadSafeEnumTests.cs index 5157cd7..f542eed 100644 --- a/Meade.net.UnitTests/ThreadSafeEnumTests.cs +++ b/Meade.net.UnitTests/ThreadSafeEnumTests.cs @@ -1,11 +1,6 @@ using ASCOM.DeviceInterface; using ASCOM.Meade.net; using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Meade.net.UnitTests { @@ -14,7 +9,7 @@ namespace Meade.net.UnitTests [TestCase(PierSide.pierUnknown)] [TestCase(PierSide.pierEast)] [TestCase(PierSide.pierWest)] - public void WhenConvertedValueIsSame(PierSide value) + public void When_Assigned_ThenValueIsSame(PierSide value) { // given ThreadSafeEnum sut = value; @@ -27,18 +22,18 @@ namespace Meade.net.UnitTests } [TestCase(PierSide.pierUnknown, PierSide.pierUnknown)] - [TestCase(PierSide.pierUnknown, PierSide.pierUnknown)] - [TestCase(PierSide.pierUnknown, PierSide.pierUnknown)] + [TestCase(PierSide.pierUnknown, PierSide.pierEast)] + [TestCase(PierSide.pierUnknown, PierSide.pierWest)] [TestCase(PierSide.pierEast, PierSide.pierUnknown)] - [TestCase(PierSide.pierEast, PierSide.pierWest)] [TestCase(PierSide.pierEast, PierSide.pierEast)] + [TestCase(PierSide.pierEast, PierSide.pierWest)] [TestCase(PierSide.pierWest, PierSide.pierUnknown)] - [TestCase(PierSide.pierWest, PierSide.pierWest)] [TestCase(PierSide.pierWest, PierSide.pierEast)] - public void WhenSetValueIsChanged(PierSide value, PierSide setValue) + [TestCase(PierSide.pierWest, PierSide.pierWest)] + public void When_SetValue_ThenValueIsUpdated(PierSide initialValue, PierSide setValue) { // given - ThreadSafeEnum sut = value; + ThreadSafeEnum sut = initialValue; // when sut.Set(setValue); diff --git a/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs b/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs index 3537f4e..ea7bd78 100644 --- a/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs +++ b/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs @@ -9,7 +9,7 @@ namespace Meade.net.UnitTests [TestCase(-12.34d)] [TestCase(0d)] [TestCase(null)] - public void WhenConvertedValueIsSame(double? value) + public void When_Assigned_ThenValueIsSame(double? value) { // given ThreadSafeNullableDouble sut = value; @@ -29,10 +29,10 @@ namespace Meade.net.UnitTests [TestCase(-12.34d, null)] [TestCase(0d, null)] [TestCase(null, null)] - public void WhenSetValueIsChanged(double? value, double? setValue) + public void When_SetValue_ThenValueIsUpdated(double? initialValue, double? setValue) { // given - ThreadSafeNullableDouble sut = value; + ThreadSafeNullableDouble sut = initialValue; // when sut.Set(setValue); From 6c274997692707a2eae4c59b4a89c50d3f5657c4 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Wed, 23 Jun 2021 16:21:08 +1000 Subject: [PATCH 15/23] Create generic ThreadSafeValue --- Meade.net.UnitTests/ThreadSafeBoolTests.cs | 4 ++-- .../ThreadSafeDateTimeTests.cs | 4 ++-- Meade.net.UnitTests/ThreadSafeEnumTests.cs | 4 ++-- .../ThreadSafeNullableDoubleTests.cs | 4 ++-- Meade.net/Meade.net.csproj | 5 +--- Meade.net/SharedResources.cs | 16 ++++++------- Meade.net/ThreadSafeBool.cs | 17 ------------- Meade.net/ThreadSafeDateTime.cs | 20 ---------------- Meade.net/ThreadSafeEnum.cs | 21 ---------------- Meade.net/ThreadSafeNullableDouble.cs | 24 ------------------- Meade.net/ThreadSafeValue.cs | 18 ++++++++++++++ 11 files changed, 35 insertions(+), 102 deletions(-) delete mode 100644 Meade.net/ThreadSafeBool.cs delete mode 100644 Meade.net/ThreadSafeDateTime.cs delete mode 100644 Meade.net/ThreadSafeEnum.cs delete mode 100644 Meade.net/ThreadSafeNullableDouble.cs create mode 100644 Meade.net/ThreadSafeValue.cs diff --git a/Meade.net.UnitTests/ThreadSafeBoolTests.cs b/Meade.net.UnitTests/ThreadSafeBoolTests.cs index adeee40..beb2ddf 100644 --- a/Meade.net.UnitTests/ThreadSafeBoolTests.cs +++ b/Meade.net.UnitTests/ThreadSafeBoolTests.cs @@ -10,7 +10,7 @@ namespace Meade.net.UnitTests public void When_Assigned_ThenValueIsSame(bool value) { // given - ThreadSafeBool sut = value; + ThreadSafeValue sut = value; // when bool actual = sut; @@ -26,7 +26,7 @@ namespace Meade.net.UnitTests public void When_SetValue_ThenValueIsUpdated(bool initialValue, bool setValue) { // given - ThreadSafeBool sut = initialValue; + ThreadSafeValue sut = initialValue; // when sut.Set(setValue); diff --git a/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs b/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs index e20e46a..3123a33 100644 --- a/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs +++ b/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs @@ -12,7 +12,7 @@ namespace Meade.net.UnitTests public void When_Assigned_ThenValueIsSame(DateTime value) { // given - ThreadSafeDateTime sut = value; + ThreadSafeValue sut = value; // when DateTime actual = sut; @@ -25,7 +25,7 @@ namespace Meade.net.UnitTests public void When_SetValue_ThenValueIsUpdated(DateTime initialValue, DateTime setValue) { // given - ThreadSafeDateTime sut = initialValue; + ThreadSafeValue sut = initialValue; // when sut.Set(setValue); diff --git a/Meade.net.UnitTests/ThreadSafeEnumTests.cs b/Meade.net.UnitTests/ThreadSafeEnumTests.cs index f542eed..da89b5c 100644 --- a/Meade.net.UnitTests/ThreadSafeEnumTests.cs +++ b/Meade.net.UnitTests/ThreadSafeEnumTests.cs @@ -12,7 +12,7 @@ namespace Meade.net.UnitTests public void When_Assigned_ThenValueIsSame(PierSide value) { // given - ThreadSafeEnum sut = value; + ThreadSafeValue sut = value; // when PierSide actual = sut; @@ -33,7 +33,7 @@ namespace Meade.net.UnitTests public void When_SetValue_ThenValueIsUpdated(PierSide initialValue, PierSide setValue) { // given - ThreadSafeEnum sut = initialValue; + ThreadSafeValue sut = initialValue; // when sut.Set(setValue); diff --git a/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs b/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs index ea7bd78..492a4e9 100644 --- a/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs +++ b/Meade.net.UnitTests/ThreadSafeNullableDoubleTests.cs @@ -12,7 +12,7 @@ namespace Meade.net.UnitTests public void When_Assigned_ThenValueIsSame(double? value) { // given - ThreadSafeNullableDouble sut = value; + ThreadSafeValue sut = value; // when double? actual = sut; @@ -32,7 +32,7 @@ namespace Meade.net.UnitTests public void When_SetValue_ThenValueIsUpdated(double? initialValue, double? setValue) { // given - ThreadSafeNullableDouble sut = initialValue; + ThreadSafeValue sut = initialValue; // when sut.Set(setValue); diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index 1a6b06e..8681147 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -146,10 +146,7 @@ - - - - + diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index b27a0e6..6567a07 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -502,7 +502,7 @@ namespace ASCOM.Meade.net ParkedPosition = parkedPosition; } - private static readonly ThreadSafeBool _isParked = false; + private static readonly ThreadSafeValue _isParked = false; public static bool IsParked { get => _isParked; @@ -516,7 +516,7 @@ namespace ASCOM.Meade.net private set => Interlocked.Exchange(ref _parkedPosition, value); } - private static readonly ThreadSafeEnum _sideOfPier = PierSide.pierUnknown; + private static readonly ThreadSafeValue _sideOfPier = PierSide.pierUnknown; /// /// Start with . /// As we do not know the physical declination axis position, we have to keep track manually. @@ -527,14 +527,14 @@ namespace ASCOM.Meade.net internal set => _sideOfPier.Set(value); } - private static readonly ThreadSafeNullableDouble _targetRightAscension = null as double?; + private static readonly ThreadSafeValue _targetRightAscension = null as double?; public static double? TargetRightAscension { get => _targetRightAscension; internal set => _targetRightAscension.Set(value); } - private static readonly ThreadSafeNullableDouble _targetDeclination = null as double?; + private static readonly ThreadSafeValue _targetDeclination = null as double?; public static double? TargetDeclination { get => _targetDeclination; @@ -548,28 +548,28 @@ namespace ASCOM.Meade.net internal set => Interlocked.Exchange(ref _slewSettleTime, value); } - private static readonly ThreadSafeBool _isLongFormat = false; + private static readonly ThreadSafeValue _isLongFormat = false; public static bool IsLongFormat { get => _isLongFormat; internal set => _isLongFormat.Set(value); } - private static readonly ThreadSafeBool _movingPrimary = false; + private static readonly ThreadSafeValue _movingPrimary = false; public static bool MovingPrimary { get => _movingPrimary; internal set => _movingPrimary.Set(value); } - private static readonly ThreadSafeBool _movingSecondary = false; + private static readonly ThreadSafeValue _movingSecondary = false; public static bool MovingSecondary { get => _movingSecondary; internal set => _movingSecondary.Set(value); } - private static readonly ThreadSafeDateTime _earliestNonSlewingTime = DateTime.MinValue; + private static readonly ThreadSafeValue _earliestNonSlewingTime = DateTime.MinValue; public static DateTime EarliestNonSlewingTime { get => _earliestNonSlewingTime; diff --git a/Meade.net/ThreadSafeBool.cs b/Meade.net/ThreadSafeBool.cs deleted file mode 100644 index b60d275..0000000 --- a/Meade.net/ThreadSafeBool.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Threading; - -namespace ASCOM.Meade.net -{ - public class ThreadSafeBool - { - private object _value; - - public ThreadSafeBool(in bool value) => _value = value; - - public void Set(in bool value) => Interlocked.Exchange(ref _value, value); - - public static implicit operator ThreadSafeBool(in bool value) => new ThreadSafeBool(value); - - public static implicit operator bool(ThreadSafeBool @this) => (bool)@this._value; - } -} \ No newline at end of file diff --git a/Meade.net/ThreadSafeDateTime.cs b/Meade.net/ThreadSafeDateTime.cs deleted file mode 100644 index c336ef2..0000000 --- a/Meade.net/ThreadSafeDateTime.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Threading; - -namespace ASCOM.Meade.net -{ - public class ThreadSafeDateTime - { - private long _value; - - public ThreadSafeDateTime(in DateTime value) => _value = DateTimeToLong(value); - - public void Set(in DateTime value) => Interlocked.Exchange(ref _value, DateTimeToLong(value)); - - private static long DateTimeToLong(in DateTime value) => value.ToUniversalTime().Ticks; - - public static implicit operator ThreadSafeDateTime(in DateTime value) => new ThreadSafeDateTime(value); - - public static implicit operator DateTime(ThreadSafeDateTime @this) => new DateTime(Interlocked.Read(ref @this._value), DateTimeKind.Utc); - } -} \ No newline at end of file diff --git a/Meade.net/ThreadSafeEnum.cs b/Meade.net/ThreadSafeEnum.cs deleted file mode 100644 index f942dfc..0000000 --- a/Meade.net/ThreadSafeEnum.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Threading; - -namespace ASCOM.Meade.net -{ - public class ThreadSafeEnum - where T: struct, Enum - { - private long _value; - - public ThreadSafeEnum(T value) => _value = EnumToLong(value); - - public void Set(T value) => Interlocked.Exchange(ref _value, EnumToLong(value)); - - private static long EnumToLong(T value) => Convert.ToInt64(value); - - public static implicit operator ThreadSafeEnum(T value) => new ThreadSafeEnum(value); - - public static implicit operator T(ThreadSafeEnum @this) => (T) Enum.ToObject(typeof(T), Interlocked.Read(ref @this._value)); - } -} \ No newline at end of file diff --git a/Meade.net/ThreadSafeNullableDouble.cs b/Meade.net/ThreadSafeNullableDouble.cs deleted file mode 100644 index 4a8efd1..0000000 --- a/Meade.net/ThreadSafeNullableDouble.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Threading; - -namespace ASCOM.Meade.net -{ - public class ThreadSafeNullableDouble - { - private long _value; - - public ThreadSafeNullableDouble(in double? value) => _value = NullableDoubleToLong(value); - - public void Set(in double? value) => Interlocked.Exchange(ref _value, NullableDoubleToLong(value)); - - private static long NullableDoubleToLong(in double? value) => BitConverter.DoubleToInt64Bits(value ?? double.NaN); - - public static implicit operator ThreadSafeNullableDouble(in double? value) => new ThreadSafeNullableDouble(value); - - public static implicit operator double?(ThreadSafeNullableDouble @this) - { - var doubleValue = BitConverter.Int64BitsToDouble(Interlocked.Read(ref @this._value)); - return double.IsNaN(doubleValue) ? null as double? : doubleValue; - } - } -} \ No newline at end of file diff --git a/Meade.net/ThreadSafeValue.cs b/Meade.net/ThreadSafeValue.cs new file mode 100644 index 0000000..652fa88 --- /dev/null +++ b/Meade.net/ThreadSafeValue.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; +using System.Threading; + +namespace ASCOM.Meade.net +{ + public class ThreadSafeValue + { + private object _value; + + public ThreadSafeValue(in T value) => _value = value; + + public void Set(in T value) => Interlocked.Exchange(ref _value, value); + + public static implicit operator ThreadSafeValue(in T value) => new ThreadSafeValue(value); + + public static implicit operator T([NotNull] ThreadSafeValue @this) => (T)(@this?._value ?? default); + } +} \ No newline at end of file From c6baab2b12ba6e65547dc35bd7ba0b1719bf552f Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Wed, 23 Jun 2021 13:11:33 +0100 Subject: [PATCH 16/23] Added tolerance in unit test to allow for rounding error. --- AstroMath.UnitTests/AstroMathsUnitTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs index 2e4e37c..c9dc655 100644 --- a/AstroMath.UnitTests/AstroMathsUnitTests.cs +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -123,7 +123,8 @@ namespace AstroMath.UnitTests var altAz = _astroMath.ConvertEqToHoz(hourAngle, latitude, equatorialCoordinates); - Assert.That(altAz.Altitude, Is.EqualTo(20.958562421092779)); + Assert.That(altAz.Altitude, Is.GreaterThan(20.958562421092770)); + Assert.That(altAz.Altitude, Is.LessThanOrEqualTo(20.958562421092779)); Assert.That(altAz.Azimuth, Is.EqualTo(281.2728706962269)); } From f1d100892bf0f74c2950087d59cc32f70fba9539 Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Wed, 23 Jun 2021 13:18:30 +0100 Subject: [PATCH 17/23] Removed nunit3 Test adapter --- Meade.net.UnitTests/Meade.net.UnitTests.csproj | 2 -- Meade.net.UnitTests/packages.config | 1 - 2 files changed, 3 deletions(-) diff --git a/Meade.net.UnitTests/Meade.net.UnitTests.csproj b/Meade.net.UnitTests/Meade.net.UnitTests.csproj index 803c477..3ab6018 100644 --- a/Meade.net.UnitTests/Meade.net.UnitTests.csproj +++ b/Meade.net.UnitTests/Meade.net.UnitTests.csproj @@ -1,6 +1,5 @@  - @@ -121,6 +120,5 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - \ No newline at end of file diff --git a/Meade.net.UnitTests/packages.config b/Meade.net.UnitTests/packages.config index 55f7ddc..ad73520 100644 --- a/Meade.net.UnitTests/packages.config +++ b/Meade.net.UnitTests/packages.config @@ -6,7 +6,6 @@ - \ No newline at end of file From a3408a86c37425a9cbd56517b24fcb0267a72d7e Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Sun, 27 Jun 2021 18:57:17 +1000 Subject: [PATCH 18/23] Update unit tests to support GW command SideOfPier also supports German EQ --- .../TelescopeUnitTests.cs | 14 ++- Meade.net.Telescope/Alignment.cs | 4 +- Meade.net.Telescope/Telescope.cs | 91 ++++++++++--------- Meade.net/SharedResources.cs | 15 +-- Meade.net/Wrapper/SharedResourcesWrapper.cs | 6 ++ 5 files changed, 72 insertions(+), 58 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index a917901..a5343bd 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -121,8 +121,9 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Object, _astroMathsMock.Object, _clockMock.Object, _novasMock.Object); } - private void ConnectTelescope(string productName = TelescopeList.Autostar497, string firmwareVersion = TelescopeList.Autostar497_31Ee) + private void ConnectTelescope(string productName = TelescopeList.Autostar497, string firmwareVersion = TelescopeList.Autostar497_31Ee, string alignmentStatus = "GT0") { + _sharedResourcesWrapperMock.Setup(x => x.SendChars("GW", false, 3)).Returns(alignmentStatus); _sharedResourcesWrapperMock.Setup(x => x.SendString("Gt", false)).Returns( () => _testProperties.SiteLatitudeString); _utilMock.Setup(x => x.DMSToDegrees(_testProperties.SiteLatitudeString)).Returns( () => _testProperties.SiteLatitudeValue); @@ -778,9 +779,8 @@ namespace Meade.net.Telescope.UnitTests { const char ack = (char)6; _sharedResourcesWrapperMock.Setup(x => x.SendChar(ack.ToString(), false)).Returns(telescopeMode); - _sharedResourcesWrapperMock.Setup(x => x.SendString("GW", false)).Returns($"{telescopeMode}N0"); - ConnectTelescope(productName, firmware); + ConnectTelescope(productName, firmware, $"{telescopeMode}N0"); var actualResult = _telescope.AlignmentMode; @@ -1942,7 +1942,7 @@ namespace Meade.net.Telescope.UnitTests _astroUtilsMock.Setup(x => x.ConditionHA(It.IsAny())).Returns(pHA => pHA < -12 ? pHA + 12 : pHA > 12 ? pHA - 12 : pHA); _astroUtilsMock.Setup(x => x.ConditionRA(It.IsAny())).Returns(pRA => pRA < 0 ? pRA + 24 : pRA >= 24 ? pRA - 24 : pRA); - ConnectTelescope(); + ConnectTelescope(firmwareVersion: TelescopeList.Autostar497_43Eg); Assert.That(_connectionInfo.SameDevice, Is.EqualTo(1)); _telescope.SlewToCoordinates(ra, dec); @@ -2056,7 +2056,8 @@ namespace Meade.net.Telescope.UnitTests // Setup DestinationSideOfPier _astroUtilsMock.Setup(x => x.ConditionHA(It.IsAny())).Returns(pHA => pHA < -12 ? pHA + 12 : pHA > 12 ? pHA - 12 : pHA); - ConnectTelescope(); + // Use firmware that supports GW + ConnectTelescope(firmwareVersion: TelescopeList.Autostar497_43Eg); // when _telescope.SlewToCoordinatesAsync(ra, dec); @@ -3203,7 +3204,6 @@ namespace Meade.net.Telescope.UnitTests _telescope.SlewToTarget(); _utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); - _astroUtilsMock.Verify(x => x.ConditionHA(It.IsAny()), Times.Once); } [Test] @@ -3298,7 +3298,6 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar("MS", false), Times.Once); _utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); - _astroUtilsMock.Verify(x => x.ConditionHA(It.IsAny()), Times.Once); } [Test] @@ -3419,7 +3418,6 @@ namespace Meade.net.Telescope.UnitTests Assert.That(_telescope.TargetDeclination, Is.EqualTo(_testProperties.declination)); _sharedResourcesWrapperMock.Verify(x => x.SendChar("MS", false), Times.Once); _utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); - _astroUtilsMock.Verify(x => x.ConditionHA(It.IsAny()), Times.Once); } [Test] diff --git a/Meade.net.Telescope/Alignment.cs b/Meade.net.Telescope/Alignment.cs index 7450c67..78ef928 100644 --- a/Meade.net.Telescope/Alignment.cs +++ b/Meade.net.Telescope/Alignment.cs @@ -5,6 +5,8 @@ namespace ASCOM.Meade.net NeedsAlignment, OneStarAligned, TwoStarAligned, - ThreeStarAligned + ThreeStarAligned, + AlignedOnHome, + ScopeWasParked, } } \ No newline at end of file diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index e10c5ea..402375e 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -360,9 +360,6 @@ namespace ASCOM.Meade.net var result = SharedResourcesWrapper.SendBool(command, raw); LogMessage("CommandBool", "Completed: {0}", result); return result; - // or - //throw new MethodNotImplementedException("CommandBool"); - // DO NOT have both these sections! One or the other } public string CommandString(string command, bool raw) @@ -372,10 +369,19 @@ namespace ASCOM.Meade.net // 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 - var result = SharedResourcesWrapper.SendString(command, raw); - LogMessage("CommandBool", "Completed: {0}", result); + string result; + // :GW# is not terminated with a # for some reason, see reported comment + // https://bitbucket.org/cjdskunkworks/meadeautostar497/issues/24/get-set-tracking#comment-60586901 + if (command == (raw ? ":GW#" : "GW")) + { + result = SharedResourcesWrapper.SendChars(command, raw, count: 3); + } + else + { + result = SharedResourcesWrapper.SendString(command, raw); + } + LogMessage("CommandString", "Completed: {0}", result); return result; - //throw new ASCOM.MethodNotImplementedException("CommandString"); } public void Dispose() @@ -416,7 +422,6 @@ namespace ASCOM.Meade.net $"Connected to port {ComPort}. Product: {SharedResourcesWrapper.ProductName} Version:{SharedResourcesWrapper.FirmwareVersion}"); _userNewerPulseGuiding = IsNewPulseGuidingSupported(); - _tracking = true; LogMessage("Connected Set", $"New Pulse Guiding Supported: {_userNewerPulseGuiding}"); IsConnected = true; @@ -620,17 +625,13 @@ namespace ASCOM.Meade.net return false; } - // true iff the mount will perform a meridian flip when required - // TODO: Needs checking what mounts actually support this - private bool IsMeridianFlipOnSlewSupported() - { - if (SharedResourcesWrapper.ProductName == TelescopeList.LX200CLASSIC) - { - return false; - } + private bool IsGWCommandSupported() => FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg); - return true; - } + // true iff the mount will perform a meridian flip when required + // According to "A User's Guide to the Meade LXD55 and LXD75 Telescopes" Autostar supports meridian flip so + // we assume that for any telescope that supports the GW command and is not in Alt-Az mode then + // meridian flip on slew is supported + private bool IsMeridianFlipOnSlewSupported() => IsGWCommandSupported() && AlignmentMode != AlignmentModes.algAltAz; private bool FirmwareIsGreaterThan(string minVersion) { @@ -957,7 +958,7 @@ namespace ASCOM.Meade.net CheckConnected("AlignmentMode Get"); - if (FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg)) + if (IsGWCommandSupported()) { var alignmentStatus = GetScopeAlignmentStatus(); return alignmentStatus.AlignmentMode; @@ -998,7 +999,7 @@ namespace ASCOM.Meade.net CheckConnected("AlignmentMode Set"); //todo tidy this up into a better solution that means can :GW#, :AL#, :AA#, & :AP# and checked for Autostar properly - if (!FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg)) + if (!IsGWCommandSupported()) throw new PropertyNotImplementedException("AlignmentMode", true); switch (value) @@ -1025,13 +1026,14 @@ namespace ASCOM.Meade.net private AlignmentStatus GetScopeAlignmentStatus() { - var alignmentString = SharedResourcesWrapper.SendString("GW"); + var alignmentString = CommandString("GW", false); //:GW# Get Scope Alignment Status //Returns: # // where: //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial - //tracking: T - tracking, N - not tracking - //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. + //tracking: T - tracking, N - not tracking, S - sleeping + //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned., H - Aligned on Home, P - Scope was parked + // https://www.cloudynights.com/topic/72166-lx-200-gps-serial-commands/ var alignmentStatus = new AlignmentStatus(); switch (alignmentString[0]) @@ -1046,8 +1048,8 @@ namespace ASCOM.Meade.net alignmentStatus.AlignmentMode = AlignmentModes.algGermanPolar; break; } - alignmentStatus.Tracking = alignmentString[0] == 'T'; - switch (alignmentString[1]) + alignmentStatus.Tracking = alignmentString[1] == 'T'; + switch (alignmentString[2]) { case '0': alignmentStatus.Status = Alignment.NeedsAlignment; @@ -1061,9 +1063,14 @@ namespace ASCOM.Meade.net case '3': alignmentStatus.Status = Alignment.ThreeStarAligned; break; + case 'H': + alignmentStatus.Status = Alignment.AlignedOnHome; + break; + case 'P': + alignmentStatus.Status = Alignment.ScopeWasParked; + break; } - return alignmentStatus; } @@ -1228,7 +1235,7 @@ namespace ASCOM.Meade.net switch (axis) { case TelescopeAxes.axisPrimary: return true; //RA or AZ - case TelescopeAxes.axisSecondary: return true; //Dev or Alt + case TelescopeAxes.axisSecondary: return true; //DEC or Alt case TelescopeAxes.axisTertiary: return false; //rotator / derotator default: throw new InvalidValueException("CanMoveAxis", axis.ToString(), "0 to 2"); } @@ -1890,24 +1897,25 @@ namespace ASCOM.Meade.net { get { - if (!FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg)) + if (!IsMeridianFlipOnSlewSupported()) { LogMessage("SideOfPier Get", "Not implemented"); throw new PropertyNotImplementedException("SideOfPier", false); } + + PierSide pierSide; + if (Slewing) + { + // because we update SideOfPier after initiating the slew command we return unknown while still slewing + pierSide = PierSide.pierUnknown; + } else { - var alignmentStatus = GetScopeAlignmentStatus(); - if (alignmentStatus.AlignmentMode != AlignmentModes.algPolar) - throw new PropertyNotImplementedException("SideOfPier", false); - - // while mount is slewing return unknown, this is required since - // DoSlewAsync updates _pierSide before slew is finished - var pierSide = Slewing ? PierSide.pierUnknown : SharedResourcesWrapper.SideOfPier; - - LogMessage("SideOfPier", "Get - " + pierSide); - return pierSide; + pierSide = SharedResourcesWrapper.SideOfPier; } + + LogMessage("SideOfPier", "Get - " + pierSide); + return pierSide; } // ReSharper disable once ValueParameterNotUsed set @@ -2594,19 +2602,18 @@ namespace ASCOM.Meade.net } } - private bool _tracking = true; public bool Tracking { get { - LogMessage("Tracking", $"Get - {_tracking}"); - if (FirmwareIsGreaterThan(TelescopeList.Autostar497_43Eg)) + LogMessage("Tracking", "Get"); + if (IsGWCommandSupported()) { var alignmentStatus = GetScopeAlignmentStatus(); - _tracking = alignmentStatus.Tracking; + return alignmentStatus.Tracking; } - return _tracking; + return true; } set { diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 6567a07..440b051 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -124,13 +124,17 @@ namespace ASCOM.Meade.net public static bool SendBool(string command, bool raw = false) { - var result = SendChar(command, raw); return result == "1"; } public static string SendChar(string command, bool raw = false) + { + return SendChars(command, raw, count: 1); + } + + public static string SendChars(string command, bool raw = false, int count = 1) { lock (LockObject) { @@ -141,14 +145,11 @@ namespace ASCOM.Meade.net try { - return SharedSerial.ReceiveCounted(1); + return SharedSerial.ReceiveCounted(count); } - catch (COMException ex) + catch (COMException ex) when (ex.Message.Contains("Timed out waiting for received data")) { - if (ex.Message.Contains("Timed out waiting for received data")) - throw new TimeoutException(ex.Message, ex); - - throw; + throw new TimeoutException(ex.Message, ex); } } } diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index 8e91bb7..84ecf4a 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -20,6 +20,7 @@ namespace ASCOM.Meade.net.Wrapper void SendBlind(string message, bool raw = false); bool SendBool(string command, bool raw = false); string SendChar(string message, bool raw = false); + string SendChars(string message, bool raw = false, int count = 1); string ReadTerminated(); @@ -94,6 +95,11 @@ namespace ASCOM.Meade.net.Wrapper return SharedResources.SendChar(message, raw); } + public string SendChars(string message, bool raw = false, int count = 1) + { + return SharedResources.SendChars(message, raw, count); + } + public string ReadTerminated() { return SharedResources.ReadTerminated(); From 90713de34bd9acf9bc90bc9355bda60e1a828a84 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Mon, 28 Jun 2021 12:45:26 +1000 Subject: [PATCH 19/23] Moved parked SiteLat/Long to ParkedPosition data --- Meade.net.Telescope/Telescope.cs | 38 ++++++++++---------------------- Meade.net/ParkedPosition.cs | 2 ++ 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 402375e..1cdb154 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1383,7 +1383,6 @@ namespace ASCOM.Meade.net } } - private double _lastGoodDeclination; public double Declination { @@ -1402,7 +1401,6 @@ namespace ASCOM.Meade.net double declination = _utilities.DMSToDegrees(result); LogMessage("Declination", $"Get - {result} convert to {declination} {_utilitiesExtra.DegreesToDMS(declination, ":", ":")}"); - _lastGoodDeclination = declination; return declination; } catch (ParkedException) @@ -1689,7 +1687,9 @@ namespace ASCOM.Meade.net Altitude = Altitude, Azimuth = Azimuth, RightAscension = RightAscension, - Declination = Declination + Declination = Declination, + SiteLatitude = SiteLatitude, + SiteLongitude = SiteLongitude }; break; case ParkedBehaviour.ReportCoordinates: @@ -1703,7 +1703,9 @@ namespace ASCOM.Meade.net Altitude = ParkedAltAz.Altitude, Azimuth = ParkedAltAz.Azimuth, RightAscension = raDec.RightAscension, - Declination = raDec.Declination + Declination = raDec.Declination, + SiteLatitude = latitude, + SiteLongitude = longitude }; break; default: @@ -1837,7 +1839,6 @@ namespace ASCOM.Meade.net return _utilities.HMSToHours(hms); } - double _lastGoodRightAsension; public double RightAscension { @@ -1856,7 +1857,6 @@ namespace ASCOM.Meade.net double rightAscension = HmToHours(result); LogMessage("RightAscension", $"Get - {result} convert to {rightAscension} {_utilitiesExtra.HoursToHMS(rightAscension)}"); - _lastGoodRightAsension = rightAscension; return rightAscension; } catch (ParkedException) @@ -1983,7 +1983,6 @@ namespace ASCOM.Meade.net } } - private double? _lastGoodSiteLatitude; public double SiteLatitude { get @@ -2002,19 +2001,14 @@ namespace ASCOM.Meade.net { var siteLatitude = _utilities.DMSToDegrees(latitude); LogMessage("SiteLatitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLatitude)}"); - - _lastGoodSiteLatitude = siteLatitude; return siteLatitude; } throw new InvalidOperationException("unable to get site latitude from telescope."); } - catch (ParkedException) + catch (ParkedException) when (ParkedBehaviour != ParkedBehaviour.NoCoordinates && SharedResourcesWrapper.ParkedPosition is var parkedPosition) { - if (ParkedBehaviour == ParkedBehaviour.NoCoordinates) - throw; - - return _lastGoodSiteLatitude.Value; + return parkedPosition.SiteLatitude; } } set @@ -2044,12 +2038,9 @@ namespace ASCOM.Meade.net //1 - Valid if (result != "1") throw new InvalidOperationException("Failed to set site latitude."); - - _lastGoodSiteLatitude = value; } } - private double _lastGoodSiteLongitude; public double SiteLongitude { @@ -2067,18 +2058,15 @@ namespace ASCOM.Meade.net double siteLongitude = -_utilities.DMSToDegrees(longitude); if (siteLongitude < -180) - siteLongitude = siteLongitude + 360; + siteLongitude += 360; LogMessage("SiteLongitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLongitude)}"); - _lastGoodSiteLongitude = siteLongitude; + return siteLongitude; } - catch (ParkedException) + catch (ParkedException) when (ParkedBehaviour != ParkedBehaviour.NoCoordinates && SharedResourcesWrapper.ParkedPosition is var parkedPosition) { - if (ParkedBehaviour == ParkedBehaviour.NoCoordinates) - throw; - - return _lastGoodSiteLongitude; + return parkedPosition.SiteLongitude; } } set @@ -2113,8 +2101,6 @@ namespace ASCOM.Meade.net //1 - Valid if (result != "1") throw new InvalidOperationException("Failed to set site longitude."); - - _lastGoodSiteLongitude = value; } } diff --git a/Meade.net/ParkedPosition.cs b/Meade.net/ParkedPosition.cs index 29bbb9e..4423b22 100644 --- a/Meade.net/ParkedPosition.cs +++ b/Meade.net/ParkedPosition.cs @@ -6,5 +6,7 @@ namespace ASCOM.Meade.net public double Azimuth { get; set; } public double RightAscension { get; set; } public double Declination { get; set; } + public double SiteLongitude { get; set; } + public double SiteLatitude { get; set; } } } \ No newline at end of file From 631aa91d9466e7d8668d7348d8b84d0f4485f5e3 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Mon, 28 Jun 2021 12:53:05 +1000 Subject: [PATCH 20/23] Moved IsTargetCoordinateInitRequired to SharedResourcesWrapper --- Meade.net.Telescope/Telescope.cs | 27 ++++++++++----------- Meade.net/SharedResources.cs | 7 ++++++ Meade.net/Wrapper/SharedResourcesWrapper.cs | 8 ++++++ 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 1cdb154..6505d85 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -142,7 +142,6 @@ namespace ASCOM.Meade.net private bool _isGuiding; - private bool _isTargetCoordinateInitRequired = true; // // PUBLIC COM INTERFACE ITelescopeV3 IMPLEMENTATION // @@ -648,16 +647,16 @@ namespace ASCOM.Meade.net if (SharedResourcesWrapper.ProductName != TelescopeList.LX200CLASSIC) return false; - if (!_isTargetCoordinateInitRequired) - return _isTargetCoordinateInitRequired; + if (!SharedResourcesWrapper.IsTargetCoordinateInitRequired) + return SharedResourcesWrapper.IsTargetCoordinateInitRequired; if (!IsConnected) return true; if (SharedResourcesWrapper.ProductName != TelescopeList.LX200CLASSIC) { - _isTargetCoordinateInitRequired = false; - return _isTargetCoordinateInitRequired; + SharedResourcesWrapper.IsTargetCoordinateInitRequired = false; + return SharedResourcesWrapper.IsTargetCoordinateInitRequired; } const double eps = 0.00001d; @@ -666,16 +665,16 @@ namespace ASCOM.Meade.net //target RA == 0 if (Math.Abs(rightTargetAscension) > eps) { - _isTargetCoordinateInitRequired = false; - return _isTargetCoordinateInitRequired; + SharedResourcesWrapper.IsTargetCoordinateInitRequired = false; + return SharedResourcesWrapper.IsTargetCoordinateInitRequired; } double targetDeclination = Declination; //target DE == 0 if (Math.Abs(targetDeclination) > eps) { - _isTargetCoordinateInitRequired = false; - return _isTargetCoordinateInitRequired; + SharedResourcesWrapper.IsTargetCoordinateInitRequired = false; + return SharedResourcesWrapper.IsTargetCoordinateInitRequired; } //target coordinates are equal current coordinates @@ -683,12 +682,12 @@ namespace ASCOM.Meade.net (Math.Abs(Declination - targetDeclination) <= eps)) { LogMessage("IsTargetCoordinateInitRequired", "0 diff -> false"); - _isTargetCoordinateInitRequired = false; - return _isTargetCoordinateInitRequired; + SharedResourcesWrapper.IsTargetCoordinateInitRequired = false; + return SharedResourcesWrapper.IsTargetCoordinateInitRequired; } - LogMessage("IsTargetCoordinateInitRequired", $"{_isTargetCoordinateInitRequired}"); - return _isTargetCoordinateInitRequired; + LogMessage("IsTargetCoordinateInitRequired", $"{SharedResourcesWrapper.IsTargetCoordinateInitRequired}"); + return SharedResourcesWrapper.IsTargetCoordinateInitRequired; } private void InitTargetCoordinates() @@ -702,7 +701,7 @@ namespace ASCOM.Meade.net SyncToCoordinates(raAndDec.RightAscension, raAndDec.Declination); //do it only once - _isTargetCoordinateInitRequired = false; + SharedResourcesWrapper.IsTargetCoordinateInitRequired = false; } catch (Exception ex) { diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 440b051..30c5cc2 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -576,5 +576,12 @@ namespace ASCOM.Meade.net get => _earliestNonSlewingTime; internal set => _earliestNonSlewingTime.Set(value); } + + private static readonly ThreadSafeValue _isTargetCoordinateInitRequired = true; + public static bool IsTargetCoordinateInitRequired + { + get => _isTargetCoordinateInitRequired; + internal set => _isTargetCoordinateInitRequired.Set(value); + } } } \ No newline at end of file diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index 84ecf4a..33f42a1 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -47,6 +47,8 @@ namespace ASCOM.Meade.net.Wrapper bool MovingSecondary { get; set; } DateTime EarliestNonSlewingTime { get; set; } + + bool IsTargetCoordinateInitRequired { get; set; } } public class SharedResourcesWrapper : ISharedResourcesWrapper @@ -181,5 +183,11 @@ namespace ASCOM.Meade.net.Wrapper get => SharedResources.EarliestNonSlewingTime; set => SharedResources.EarliestNonSlewingTime = value; } + + public bool IsTargetCoordinateInitRequired + { + get => SharedResources.IsTargetCoordinateInitRequired; + set => SharedResources.IsTargetCoordinateInitRequired = value; + } } } From 77c87a51fa2502fc17b29f89a4ceb06f0f5ac72d Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Mon, 28 Jun 2021 13:03:07 +1000 Subject: [PATCH 21/23] Moved IsGuiding to SharedResourcesWrapper --- .../TelescopeUnitTests.cs | 2 ++ Meade.net.Telescope/Telescope.cs | 14 ++++++-------- Meade.net/SharedResources.cs | 7 +++++++ Meade.net/Wrapper/SharedResourcesWrapper.cs | 8 ++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index a5343bd..0276cfe 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -145,6 +145,8 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.SetupGet(x => x.IsParked).Returns(() => _isParked); _sharedResourcesWrapperMock.SetupGet(x => x.ParkedPosition).Returns(() => _parkedPosition); + _sharedResourcesWrapperMock.SetupProperty(x => x.IsGuiding); + _astroMathsMock .Setup(x => x.ConvertHozToEq(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(() => new EquatorialCoordinates { Declination = _testProperties.declination, RightAscension = _testProperties.rightAscension }); diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 6505d85..7f4afcd 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -140,8 +140,6 @@ namespace ASCOM.Meade.net Initialise(nameof(Telescope)); } - private bool _isGuiding; - // // PUBLIC COM INTERFACE ITelescopeV3 IMPLEMENTATION // @@ -1607,7 +1605,7 @@ namespace ASCOM.Meade.net switch (rate.Compare(0)) { case ComparisonResult.Equals: - if (!_isGuiding) + if (!SharedResourcesWrapper.IsGuiding) { SetSlewingMinEndTime(); } @@ -1638,7 +1636,7 @@ namespace ASCOM.Meade.net switch (rate.Compare(0)) { case ComparisonResult.Equals: - if (!_isGuiding) + if (!SharedResourcesWrapper.IsGuiding) { SetSlewingMinEndTime(); } @@ -1731,7 +1729,7 @@ namespace ASCOM.Meade.net if (IsSlewingToTarget()) throw new InvalidOperationException("Unable to PulseGuide whilst slewing to target."); - _isGuiding = true; + SharedResourcesWrapper.IsGuiding = true; try { if (SharedResourcesWrapper.MovingPrimary && @@ -1814,7 +1812,7 @@ namespace ASCOM.Meade.net } finally { - _isGuiding = false; + SharedResourcesWrapper.IsGuiding = false; } } catch (Exception ex) @@ -2306,7 +2304,7 @@ namespace ASCOM.Meade.net private bool MovingAxis() { - if (_isGuiding) + if (SharedResourcesWrapper.IsGuiding) return false; return SharedResourcesWrapper.MovingPrimary || SharedResourcesWrapper.MovingSecondary; @@ -2358,7 +2356,7 @@ namespace ASCOM.Meade.net { CheckConnected("IsSlewingToTarget"); - if (_isGuiding) + if (SharedResourcesWrapper.IsGuiding) return false; string result; diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 30c5cc2..975b093 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -583,5 +583,12 @@ namespace ASCOM.Meade.net get => _isTargetCoordinateInitRequired; internal set => _isTargetCoordinateInitRequired.Set(value); } + + private static readonly ThreadSafeValue _isGuiding = false; + public static bool IsGuiding + { + get => _isGuiding; + internal set => _isGuiding.Set(value); + } } } \ No newline at end of file diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index 33f42a1..754f341 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -49,6 +49,8 @@ namespace ASCOM.Meade.net.Wrapper DateTime EarliestNonSlewingTime { get; set; } bool IsTargetCoordinateInitRequired { get; set; } + + bool IsGuiding { get; set; } } public class SharedResourcesWrapper : ISharedResourcesWrapper @@ -189,5 +191,11 @@ namespace ASCOM.Meade.net.Wrapper get => SharedResources.IsTargetCoordinateInitRequired; set => SharedResources.IsTargetCoordinateInitRequired = value; } + + public bool IsGuiding + { + get => SharedResources.IsGuiding; + set => SharedResources.IsGuiding = value; + } } } From 8478af26bf4aaf4476459e50948a23b309263d7f Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Mon, 28 Jun 2021 14:16:00 +1000 Subject: [PATCH 22/23] Implemented TrackingRate via GT --- .../TelescopeUnitTests.cs | 10 +++++++++ Meade.net.Telescope/Telescope.cs | 21 +++++-------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 0276cfe..7536c95 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -53,6 +53,7 @@ namespace Meade.net.Telescope.UnitTests private bool _isParked; private ParkedPosition _parkedPosition; + private string _trackingRate; [SetUp] public void Setup() @@ -134,6 +135,12 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Setup(x => x.SendString("GL", false)).Returns(() => _testProperties.telescopeTime); _sharedResourcesWrapperMock.Setup(x => x.SendString("GG", false)).Returns(() => _testProperties.telescopeUtcCorrection); + const string siderealTrackingRate = "+60.1"; + _trackingRate = siderealTrackingRate; + _sharedResourcesWrapperMock.Setup(x => x.SendString("GT", false)).Returns(() => _trackingRate); + _sharedResourcesWrapperMock.Setup(x => x.SendBlind("TL", false)).Callback(() => _trackingRate = "lunar"); + _sharedResourcesWrapperMock.Setup(x => x.SendBlind("TQ", false)).Callback(() => _trackingRate = siderealTrackingRate); + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => productName); _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => firmwareVersion); @@ -2672,7 +2679,10 @@ namespace Meade.net.Telescope.UnitTests _telescope.TrackingRate = rate; + Assert.That(_telescope.TrackingRate, Is.EqualTo(rate)); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(commandString, false), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendString("GT", false), Times.Once); } [Test] diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 7f4afcd..a3c5e1e 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -2606,26 +2606,17 @@ namespace ASCOM.Meade.net } } - private DriveRates _trackingRate = DriveRates.driveSidereal; - public DriveRates TrackingRate { get { - //todo implement this with the GW command - //var result = SerialPort.CommandTerminated(":GT#", "#"); + var rate = CommandString("GT", false); - //double rate = double.Parse(result); + if (rate == "+60.1") + return DriveRates.driveSidereal; - - //if (rate == 60.1) - // return DriveRates.driveLunar; - //else if (rate == 60.1) - // return DriveRates.driveSidereal; - - //return DriveRates.driveKing; - LogMessage("TrackingRate Get", $"{_trackingRate}"); - return _trackingRate; + // we only support two rates ATM so return lunar tracking rate + return DriveRates.driveLunar; } set { @@ -2657,8 +2648,6 @@ namespace ASCOM.Meade.net default: throw new ArgumentOutOfRangeException(nameof(value), value, null); } - - _trackingRate = value; } } From 64df8282a06fbedfee07e998ecf22e236489b4f3 Mon Sep 17 00:00:00 2001 From: Sebastian Godelet Date: Mon, 28 Jun 2021 16:33:46 +1000 Subject: [PATCH 23/23] Support Set Tracking when GW is supported --- .../TelescopeUnitTests.cs | 69 +++++++++++++------ Meade.net.Telescope/Telescope.cs | 15 ++-- .../SharedResourcesUnitTests.cs | 6 ++ 3 files changed, 64 insertions(+), 26 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 7536c95..0b9a1d9 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -18,20 +18,23 @@ namespace Meade.net.Telescope.UnitTests { public class TestProperties { - internal string telescopeRaResult = "HH:MM:SS"; - internal double rightAscension = 1.2; //todo rename to declination; - internal double declination = 45; + internal string telescopeRaResult { get; set; } = "HH:MM:SS"; + internal double rightAscension { get; set; } = 1.2; //todo rename to declination; + internal double declination { get; set; } = 45; - internal string SiteLatitudeString = "testLatString"; - internal double SiteLatitudeValue = 123.45; + internal string SiteLatitudeString { get; set; } = "testLatString"; + internal double SiteLatitudeValue { get; set; } = 123.45; - internal string telescopeDate = "10/15/20"; - internal string telescopeTime = "20:15:10"; - internal string telescopeUtcCorrection = "-1.0"; + internal string telescopeDate { get; set; } = "10/15/20"; + internal string telescopeTime { get; set; } = "20:15:10"; + internal string telescopeUtcCorrection { get; set; } = "-1.0"; - internal double hourAngle; - internal int telescopeAltitude = 45; - internal int telescopeAzimuth = 200; + internal double hourAngle { get; set; } + internal int telescopeAltitude { get; set; } = 45; + internal int telescopeAzimuth { get; set; } = 200; + + internal char[] AlignmentStatus { get; set; } + internal string TrackingRate { get; set; } } [TestFixture] @@ -53,7 +56,6 @@ namespace Meade.net.Telescope.UnitTests private bool _isParked; private ParkedPosition _parkedPosition; - private string _trackingRate; [SetUp] public void Setup() @@ -124,7 +126,12 @@ namespace Meade.net.Telescope.UnitTests private void ConnectTelescope(string productName = TelescopeList.Autostar497, string firmwareVersion = TelescopeList.Autostar497_31Ee, string alignmentStatus = "GT0") { - _sharedResourcesWrapperMock.Setup(x => x.SendChars("GW", false, 3)).Returns(alignmentStatus); + _testProperties.AlignmentStatus = alignmentStatus.ToCharArray(); + + _sharedResourcesWrapperMock.Setup(x => x.SendChars("GW", false, 3)).Returns(() => new string(_testProperties.AlignmentStatus)); + _sharedResourcesWrapperMock.Setup(x => x.SendBlind("AP", false)).Callback(() => _testProperties.AlignmentStatus[1] = 'T'); + _sharedResourcesWrapperMock.Setup(x => x.SendBlind("AL", false)).Callback(() => _testProperties.AlignmentStatus[1] = 'N'); + _sharedResourcesWrapperMock.Setup(x => x.SendString("Gt", false)).Returns( () => _testProperties.SiteLatitudeString); _utilMock.Setup(x => x.DMSToDegrees(_testProperties.SiteLatitudeString)).Returns( () => _testProperties.SiteLatitudeValue); @@ -136,10 +143,10 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Setup(x => x.SendString("GG", false)).Returns(() => _testProperties.telescopeUtcCorrection); const string siderealTrackingRate = "+60.1"; - _trackingRate = siderealTrackingRate; - _sharedResourcesWrapperMock.Setup(x => x.SendString("GT", false)).Returns(() => _trackingRate); - _sharedResourcesWrapperMock.Setup(x => x.SendBlind("TL", false)).Callback(() => _trackingRate = "lunar"); - _sharedResourcesWrapperMock.Setup(x => x.SendBlind("TQ", false)).Callback(() => _trackingRate = siderealTrackingRate); + _testProperties.TrackingRate = siderealTrackingRate; + _sharedResourcesWrapperMock.Setup(x => x.SendString("GT", false)).Returns(() => _testProperties.TrackingRate); + _sharedResourcesWrapperMock.Setup(x => x.SendBlind("TL", false)).Callback(() => _testProperties.TrackingRate = "lunar"); + _sharedResourcesWrapperMock.Setup(x => x.SendBlind("TQ", false)).Callback(() => _testProperties.TrackingRate = siderealTrackingRate); _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => productName); _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => firmwareVersion); @@ -1121,12 +1128,15 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.False); } - [Test] - public void CanSetTracking_Get_ReturnsFalse() + [TestCase(TelescopeList.Autostar497_30Ee, false)] + [TestCase(TelescopeList.Autostar497_43Eg, true)] + public void CanSetTracking_Get_ReturnsTrueIffGWCommandIsSupported(string firmware, bool supported) { + ConnectTelescope(firmwareVersion: firmware); + var result = _telescope.CanSetTracking; - Assert.That(result, Is.False); + Assert.That(result, Is.EqualTo(supported)); } [Test] @@ -2659,11 +2669,28 @@ namespace Meade.net.Telescope.UnitTests [TestCase(true)] [TestCase(false)] - public void Tracking_Set_ThenThrowsNotImplementedException(bool tracking) + public void Tracking_Set_WhenCanSetTrackingIsFalse_ThenThrowsNotImplementedException(bool tracking) { + // GW is not supported, so CanSetTracking is false + ConnectTelescope(firmwareVersion: TelescopeList.Autostar497_30Ee); + Assert.Throws( () => { _telescope.Tracking = tracking; } ); } + [TestCase(true, "AP")] + [TestCase(false, "AL")] + public void Tracking_Set_WhenCanSetTrackingIsTrue_ThenValueIsUpdated(bool tracking, string alignmentCommand) + { + // GW is supported, so CanSetTracking is true + ConnectTelescope(firmwareVersion: TelescopeList.Autostar497_43Eg); + + _telescope.Tracking = tracking; + + Assert.That(_telescope.Tracking, Is.EqualTo(tracking)); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(alignmentCommand, false), Times.Once); + } + [Test] public void TrackingRate_Set_WhenNotConnected_ThenThrowsException() { diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index a3c5e1e..2c8928e 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1309,8 +1309,9 @@ namespace ASCOM.Meade.net { get { - LogMessage("CanSetTracking", "Get - " + false); - return false; + var canSetTracking = IsGWCommandSupported(); + LogMessage("CanSetTracking", "Get - " + canSetTracking); + return canSetTracking; } } @@ -2600,9 +2601,13 @@ namespace ASCOM.Meade.net } set { - throw new ASCOM.NotImplementedException("Tracking Set"); - //LogMessage("Tracking Set", $"{value}"); - //_tracking = value; + if (!CanSetTracking) + { + throw new ASCOM.NotImplementedException("Tracking Set"); + } + + LogMessage("Tracking Set", $"{value}"); + SharedResourcesWrapper.SendBlind(value ? "AP" : "AL"); } } diff --git a/Meade.net.UnitTests/SharedResourcesUnitTests.cs b/Meade.net.UnitTests/SharedResourcesUnitTests.cs index 8c5fb79..b9becdf 100644 --- a/Meade.net.UnitTests/SharedResourcesUnitTests.cs +++ b/Meade.net.UnitTests/SharedResourcesUnitTests.cs @@ -649,5 +649,11 @@ namespace Meade.net.UnitTests [Test] public void CheckTargetRightAscensionIsNullByDefault() => Assert.That(SharedResources.TargetRightAscension.HasValue, Is.False); + + [Test] + public void CheckIsTargetCoordinateInitRequired() => Assert.That(SharedResources.IsTargetCoordinateInitRequired, Is.True); + + [Test] + public void CheckIsGuiding() => Assert.That(SharedResources.IsGuiding, Is.False); } }