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; + } } }