diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index c931d76..e5dddec 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -100,10 +100,17 @@ 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) + .SetupProperty(x => x.SlewSettleTime) + .SetupProperty(x => x.IsLongFormat); + _astroMathsMock = new Mock(); _clockMock = new Mock(); @@ -997,20 +1004,85 @@ 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] + 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)] + 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] @@ -1230,6 +1302,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); @@ -1619,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; @@ -1629,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)] @@ -1847,6 +1928,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); /// @@ -2360,6 +2478,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_ThenValueIsPreserved(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() { @@ -2442,6 +2600,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_ThenValueIsPreserved(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() { @@ -2726,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; @@ -2796,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); @@ -2803,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); } @@ -2822,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"); @@ -2839,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); @@ -2973,9 +3182,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; @@ -3057,9 +3263,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; @@ -3183,9 +3386,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; diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index c4f65dc..2980a5c 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. @@ -418,8 +416,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 +439,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) { @@ -484,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)}"); @@ -631,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 /// @@ -705,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; } @@ -720,12 +724,12 @@ 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; + SharedResourcesWrapper.IsLongFormat = result.Length > 6; - if (IsLongFormat != setLongFormat) + if (SharedResourcesWrapper.IsLongFormat != setLongFormat) { _utilities.WaitForMilliseconds(500); SharedResourcesWrapper.SendBlind("U"); @@ -734,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 @@ -754,8 +758,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 +820,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 +871,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); @@ -934,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(); } @@ -1040,7 +1044,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 +1151,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 +1351,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); @@ -1391,7 +1395,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}"); @@ -1449,7 +1453,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 +1461,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 @@ -1518,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}"); @@ -1569,7 +1570,7 @@ namespace ASCOM.Meade.net SetSlewingMinEndTime(); } - _movingPrimary = false; + SharedResourcesWrapper.MovingPrimary = false; SharedResourcesWrapper.SendBlind("Qe"); //:Qe# Halt eastward Slews //Returns: Nothing @@ -1581,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. - _pierSide = 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. - _pierSide = PierSide.pierUnknown; + SharedResourcesWrapper.MovingPrimary = true; break; } break; @@ -1603,7 +1600,7 @@ namespace ASCOM.Meade.net { SetSlewingMinEndTime(); } - _movingSecondary = false; + SharedResourcesWrapper.MovingSecondary = false; SharedResourcesWrapper.SendBlind("Qn"); //:Qn# Halt northward Slews //Returns: Nothing @@ -1615,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; @@ -1672,7 +1669,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 } @@ -1691,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."); @@ -1728,8 +1725,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 +1848,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 +1856,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 +1988,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 +2055,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."); @@ -2079,14 +2071,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; } } @@ -2172,7 +2164,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 +2193,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") { @@ -2280,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 @@ -2293,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}"); @@ -2303,7 +2293,7 @@ namespace ASCOM.Meade.net private void SetSlewingMinEndTime() { - _earliestNonSlewingTime = _clock.UtcNow + GetTotalSlewingSettleTime(); + SharedResourcesWrapper.EarliestNonSlewingTime = _clock.UtcNow + GetTotalSlewingSettleTime(); } private TimeSpan GetTotalSlewingSettleTime() @@ -2345,8 +2335,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 +2423,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 { @@ -2482,7 +2473,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); @@ -2496,23 +2487,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 +2514,8 @@ namespace ASCOM.Meade.net //double targetRa = HmsToDouble(result); //return targetRa; - LogMessage("TargetRightAscension Get", $"{_targetRightAscension}"); - return _targetRightAscension; + LogMessage("TargetRightAscension Get", $"{targetRightAscension}"); + return targetRightAscension; } set { @@ -2538,7 +2529,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(',','.'); @@ -2549,13 +2540,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 +2726,7 @@ namespace ASCOM.Meade.net //:SLHH:MM:SS# //Set the local Time //Returns: - //0 – Invalid + //0 - Invalid //1 - Valid if (timeResult != "1") { @@ -2747,8 +2738,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 +2787,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.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..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; @@ -29,7 +30,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 +161,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 +240,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 +424,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"); }); @@ -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); } } diff --git a/Meade.net.UnitTests/ThreadSafeBoolTests.cs b/Meade.net.UnitTests/ThreadSafeBoolTests.cs new file mode 100644 index 0000000..beb2ddf --- /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 When_Assigned_ThenValueIsSame(bool value) + { + // given + ThreadSafeValue 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 When_SetValue_ThenValueIsUpdated(bool initialValue, bool setValue) + { + // given + ThreadSafeValue sut = initialValue; + + // 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..3123a33 --- /dev/null +++ b/Meade.net.UnitTests/ThreadSafeDateTimeTests.cs @@ -0,0 +1,61 @@ +using ASCOM.Meade.net; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Meade.net.UnitTests +{ + public class ThreadSafeDateTimeTests + { + [TestCaseSource(nameof(DateTimeSource))] + public void When_Assigned_ThenValueIsSame(DateTime value) + { + // given + ThreadSafeValue sut = value; + + // when + DateTime actual = sut; + + // then + Assert.That(actual, Is.EqualTo(value)); + } + + [TestCaseSource(nameof(DateTimeSetSource))] + public void When_SetValue_ThenValueIsUpdated(DateTime initialValue, DateTime setValue) + { + // given + ThreadSafeValue sut = initialValue; + + // 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..da89b5c --- /dev/null +++ b/Meade.net.UnitTests/ThreadSafeEnumTests.cs @@ -0,0 +1,46 @@ +using ASCOM.DeviceInterface; +using ASCOM.Meade.net; +using NUnit.Framework; + +namespace Meade.net.UnitTests +{ + public class ThreadSafeEnumTests + { + [TestCase(PierSide.pierUnknown)] + [TestCase(PierSide.pierEast)] + [TestCase(PierSide.pierWest)] + public void When_Assigned_ThenValueIsSame(PierSide value) + { + // given + ThreadSafeValue sut = value; + + // when + PierSide actual = sut; + + // then + Assert.That(actual, Is.EqualTo(value)); + } + + [TestCase(PierSide.pierUnknown, PierSide.pierUnknown)] + [TestCase(PierSide.pierUnknown, PierSide.pierEast)] + [TestCase(PierSide.pierUnknown, PierSide.pierWest)] + [TestCase(PierSide.pierEast, PierSide.pierUnknown)] + [TestCase(PierSide.pierEast, PierSide.pierEast)] + [TestCase(PierSide.pierEast, PierSide.pierWest)] + [TestCase(PierSide.pierWest, PierSide.pierUnknown)] + [TestCase(PierSide.pierWest, PierSide.pierEast)] + [TestCase(PierSide.pierWest, PierSide.pierWest)] + public void When_SetValue_ThenValueIsUpdated(PierSide initialValue, PierSide setValue) + { + // given + ThreadSafeValue sut = initialValue; + + // 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..492a4e9 --- /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 When_Assigned_ThenValueIsSame(double? value) + { + // given + ThreadSafeValue 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 When_SetValue_ThenValueIsUpdated(double? initialValue, double? setValue) + { + // given + ThreadSafeValue sut = initialValue; + + // 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.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 /// diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index 4711710..8681147 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -146,6 +146,7 @@ + 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 47730ef..6567a07 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: // @@ -19,7 +19,9 @@ 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; using ASCOM.Utilities; using ASCOM.Utilities.Interfaces; @@ -49,7 +51,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 +75,7 @@ namespace ASCOM.Meade.net public static IProfileFactory ProfileFactory { - get => _profileFactory ?? ( _profileFactory = new ProfileFactory()); + get => _profileFactory ?? (_profileFactory = new ProfileFactory()); set => _profileFactory = value; } @@ -122,7 +124,7 @@ namespace ASCOM.Meade.net public static bool SendBool(string command, bool raw = false) { - + var result = SendChar(command, raw); return result == "1"; @@ -244,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"; @@ -273,7 +275,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 +313,7 @@ namespace ASCOM.Meade.net } #endregion - + #region Multi Driver handling public static string ProductName { get; private set; } = string.Empty; @@ -334,7 +336,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 +352,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 +365,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,15 +495,85 @@ namespace ASCOM.Meade.net Count = 0; } } - + public static void SetParked(bool atPark, ParkedPosition parkedPosition) { IsParked = atPark; ParkedPosition = parkedPosition; } - public static bool IsParked { get; private set; } + private static readonly ThreadSafeValue _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 ThreadSafeValue _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 => _sideOfPier; + internal set => _sideOfPier.Set(value); + } + + private static readonly ThreadSafeValue _targetRightAscension = null as double?; + public static double? TargetRightAscension + { + get => _targetRightAscension; + internal set => _targetRightAscension.Set(value); + } + + private static readonly ThreadSafeValue _targetDeclination = null as double?; + public static double? TargetDeclination + { + get => _targetDeclination; + internal set => _targetDeclination.Set(value); + } + + private static int _slewSettleTime; + public static short SlewSettleTime + { + get => Convert.ToInt16(_slewSettleTime); + internal set => Interlocked.Exchange(ref _slewSettleTime, value); + } + + private static readonly ThreadSafeValue _isLongFormat = false; + public static bool IsLongFormat + { + get => _isLongFormat; + internal set => _isLongFormat.Set(value); + } + + private static readonly ThreadSafeValue _movingPrimary = false; + public static bool MovingPrimary + { + get => _movingPrimary; + internal set => _movingPrimary.Set(value); + } + + private static readonly ThreadSafeValue _movingSecondary = false; + public static bool MovingSecondary + { + get => _movingSecondary; + internal set => _movingSecondary.Set(value); + } + + private static readonly ThreadSafeValue _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/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 diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index d7b078c..8e91bb7 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,20 @@ 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; } + + short SlewSettleTime { get; set; } + + bool IsLongFormat { get; set; } + + bool MovingPrimary { get; set; } + + bool MovingSecondary { get; set; } + + DateTime EarliestNonSlewingTime { get; set; } } public class SharedResourcesWrapper : ISharedResourcesWrapper @@ -74,7 +89,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 +127,53 @@ 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; + } + + public short SlewSettleTime + { + get => SharedResources.SlewSettleTime; + set => SharedResources.SlewSettleTime = value; + } + + public bool IsLongFormat + { + 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; + } } }