Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ASCOM.Driver/OpenAstroTracker/LocalServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ private static void RegisterObjects()
key.CreateSubKey("Programmable");
using (RegistryKey key2 = key.CreateSubKey("LocalServer32"))
{
key2.SetValue(null, Application.ExecutablePath);
key2.SetValue(null, "\"" + Application.ExecutablePath + "\"");
}
}
//
Expand Down
24 changes: 12 additions & 12 deletions ASCOM.Driver/OpenAstroTracker/OpenAstroTracker.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
Expand All @@ -62,37 +62,37 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="ASCOM.Astrometry, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Attributes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Cache, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Controls, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DeviceInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DriverAccess, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Exceptions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Internal.Extensions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.SettingsProvider, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities.Video, Version=6.1.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll</HintPath>
<HintPath>..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
Expand Down
4 changes: 4 additions & 0 deletions ASCOM.Driver/OpenAstroTracker/SharedResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ public static string SendMessage(string message)
else
{
LogMessage(LoggingFlags.Serial, $"SendMessage Nr{messageNr,0:0000} - Not connected or Empty Message: " + message);
if (!SharedSerial.Connected)
{
throw new ASCOM.NotConnectedException($"SendMessage called while serial port is disconnected. Command: {message}");
}
}
LogMessage(LoggingFlags.Serial, $"SendMessage Nr{messageNr,0:0000} - Releasing lock");
}
Expand Down
33 changes: 30 additions & 3 deletions ASCOM.Driver/TelescopeDriver/Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,23 @@ public Telescope()
/// ''' the new settings are saved, otherwise the old values are reloaded.
/// ''' THIS IS THE ONLY PLACE WHERE SHOWING USER INTERFACE IS ALLOWED!
/// ''' </summary>
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

public void SetupDialog()
{
// When started by COM (-embedding), Windows denies this process foreground
// privilege, so SetupDialogForm.ShowDialog() opens but never gets focus.
// Call SetForegroundWindow on the main form's handle to regain foreground
// status before showing the modal setup dialog. SetupDialog() runs on the
// main STA thread, so we can call these APIs directly.
var mainForm = System.Windows.Forms.Application.OpenForms.Count > 0
? System.Windows.Forms.Application.OpenForms[0] : null;
if (mainForm != null)
{
mainForm.WindowState = System.Windows.Forms.FormWindowState.Normal;
SetForegroundWindow(mainForm.Handle);
}
using (var f = new SetupDialogForm(Profile, this, (s) => this.LogMessage(LoggingFlags.Setup, s)))
{
if (f.ShowDialog() == DialogResult.OK)
Expand All @@ -93,6 +108,9 @@ public void SetupDialog()
SharedResources.SetTraceFlags(Profile.TraceFlags);
}
}
// Re-minimize frmMain after setup dialog is dismissed
if (mainForm != null && Server.StartedByCOM)
mainForm.WindowState = System.Windows.Forms.FormWindowState.Minimized;
}

public ArrayList SupportedActions
Expand Down Expand Up @@ -1353,19 +1371,28 @@ private void CheckConnected(string message)
throw new NotConnectedException(message);
}

private int PollUntilZero(string command)
private int PollUntilZero(string command, int maxAttempts = 120)
{
// Takes a command to be sent via CommandString, and resends every 1000ms until a 0 is returned. Returns 0 only when complete.
// maxAttempts caps the wait to prevent hanging indefinitely if the mount stalls or communication fails (default: 120s).
string retVal = "";
while (retVal != "0")
int attempts = 0;
while (retVal != "0" && attempts < maxAttempts)
{
retVal = CommandString(command);
LogMessage(LoggingFlags.Scope, $"PollUntilZero - Command: {command}, Response: {retVal}");
LogMessage(LoggingFlags.Scope, $"PollUntilZero - Command: {command}, Response: {retVal}, Attempt: {attempts + 1}/{maxAttempts}");
if (retVal == "0")
break;
attempts++;
Thread.Sleep(1000);
}

if (attempts >= maxAttempts)
{
LogMessage(LoggingFlags.Scope, $"PollUntilZero - Timed out after {maxAttempts} attempts for command: {command}");
throw new System.TimeoutException($"Mount did not complete operation within {maxAttempts} seconds. Command: {command}");
}

return System.Convert.ToInt32(retVal);
}

Expand Down
59 changes: 44 additions & 15 deletions OATCommunications/CommunicationHandlers/TcpCommunicationHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using OATCommunications.ClientAdapters;
using OATCommunications.ClientAdapters;
using OATCommunications.Utilities;
using System;
using System.Collections.Generic;
Expand All @@ -16,6 +16,7 @@ public class TcpCommunicationHandler : CommunicationHandler
private IPAddress _ip;
private int _port;
private TcpClient _client;
private NetworkStream _stream;
private List<string> _available;
private Action<string> _addCallback;

Expand Down Expand Up @@ -67,12 +68,17 @@ protected override void RunJob(Job job)
while ((attempt < 4) && (_client != null))
{
Log.WriteLine("TCP: [{0}] Attempt {1} to send command.", command, attempt);
if (!_client.Connected)

// Only (re)connect when the stream has been closed due to an error, or on first use.
if (_stream == null)
{
try
{
_client = new TcpClient();
_client.Connect(_ip, _port);
_client.ReceiveTimeout = 1000;
_client.SendTimeout = 1000;
_stream = _client.GetStream();
}
catch (Exception e)
{
Expand All @@ -82,21 +88,19 @@ protected override void RunJob(Job job)
}
}

_client.ReceiveTimeout = 1000;
_client.SendTimeout = 1000;

string error = String.Empty;

var stream = _client.GetStream();
var bytes = Encoding.ASCII.GetBytes(command);
try
{
stream.Write(bytes, 0, bytes.Length);
_stream.Write(bytes, 0, bytes.Length);
Log.WriteLine("TCP: [{0}] Sent command!", command);
}
catch (Exception e)
{
Log.WriteLine("TCP: [{0}] Unable to write command to stream: {1}", command, e.Message);
_stream.Close();
_stream = null;
job.OnFulFilled(new CommandResponse("", false, $"Failed to send message: {e.Message}"));
return;
}
Expand All @@ -110,13 +114,12 @@ protected override void RunJob(Job job)
Log.WriteLine("TCP: [{0}] No reply needed to command", command);
break;

case ResponseType.DoubleFullResponse:
case ResponseType.DigitResponse:
case ResponseType.FullResponse:
{
Log.WriteLine("TCP: [{0}] Expecting a {1} reply to command, waiting...", command, job.ResponseType.ToString());
var response = new byte[256];
var respCount = stream.Read(response, 0, response.Length);
var respCount = _stream.Read(response, 0, response.Length);
respString = Encoding.ASCII.GetString(response, 0, respCount);
Log.WriteLine("TCP: [{0}] Received reply to command -> [{1}], trimming", command, respString);
int hashPos = respString.IndexOf('#');
Expand All @@ -128,22 +131,43 @@ protected override void RunJob(Job job)
attempt = 10;
}
break;

case ResponseType.DoubleFullResponse:
{
Log.WriteLine("TCP: [{0}] Expecting a DoubleFullResponse reply to command, waiting...", command);
var response = new byte[256];
var respCount = _stream.Read(response, 0, response.Length);
respString = Encoding.ASCII.GetString(response, 0, respCount);
Log.WriteLine("TCP: [{0}] Received first reply to command -> [{1}], trimming", command, respString);
int hashPos = respString.IndexOf('#');
if (hashPos > 0)
{
respString = respString.Substring(0, hashPos);
}
Log.WriteLine("TCP: [{0}] Returning first reply to command -> [{1}]", command, respString);
// Read and discard the second response
var response2 = new byte[256];
_stream.Read(response2, 0, response2.Length);
attempt = 10;
}
break;
}
}
catch (Exception e)
{
Log.WriteLine("TCP: [{0}] Failed to read reply to command. {1} thrown", command, e.GetType().Name);
if (job.ResponseType != ResponseType.NoResponse)
{
respString = "0#";
}
_stream.Close();
_stream = null;
respString = string.Empty;
}

stream.Close();
attempt++;
// Stream is intentionally left open for the next command.
}

job.OnFulFilled(new CommandResponse(respString));
bool succeeded = job.ResponseType == ResponseType.NoResponse || !string.IsNullOrEmpty(respString);
job.OnFulFilled(new CommandResponse(respString, succeeded, succeeded ? string.Empty : $"Failed to read reply to [{command}]"));

}

public override bool Connected
Expand Down Expand Up @@ -185,6 +209,11 @@ public override void Disconnect()
waitQuit.WaitOne();

Log.WriteLine("TCP: Closing port.");
if (_stream != null)
{
_stream.Close();
_stream = null;
}
_client.Close();
_client = null;
Log.WriteLine("TCP: Disconnected...");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public async Task<bool> RefreshMountState()
MountState.Declination = GetCompactDec(parts[6]);
success = true;
}
doneEvent.Set();
});

await doneEvent.WaitAsync();
Expand Down Expand Up @@ -273,6 +274,7 @@ public async Task<bool> Slew(TelescopePosition position)
SendCommand($":MS#,n", (moveResult) =>
{
success = success && moveResult.Success && moveResult.Data == "1";
doneEvent.Set();
});

await doneEvent.WaitAsync();
Expand Down Expand Up @@ -361,8 +363,6 @@ public async Task<bool> SetLocation(double lat, double lon, double altitudeInMet
bool success = false;
AsyncAutoResetEvent doneEvent = new AsyncAutoResetEvent();


await doneEvent.WaitAsync();
// Longitude
success = await SetSiteLongitude((float)lon) == "1";

Expand Down