79a77d4e1d
Feature/LocalServer * Major refactor. Switching over to a local server hub style driver allowing multiple programs to control the telescope at one time without the need for the POTH Hub * Unified the setup dialog * Implemented shared serial port, Both Telescope and Driver can connect at the same time. * Ported the focuser implementation from the non server based version. * Ported the telescope driver code. * Fixed problem with # not being stripped from the returned string ends. Fixed issue with RA being returned as degress rather than hours. * Telescope passes validation * Added a lock around the focuser move. * Reimplemented CommandBlind and CommandString * Corrected version information * Removed the Altitude support as there's a bug in the Autostar and Audiostar firmware
571 lines
19 KiB
C#
571 lines
19 KiB
C#
//tabs=4
|
|
// --------------------------------------------------------------------------------
|
|
// TODO fill in this information for your driver, then remove this line!
|
|
//
|
|
// ASCOM Focuser driver for Meade.net
|
|
//
|
|
// Description: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
|
|
// nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam
|
|
// erat, sed diam voluptua. At vero eos et accusam et justo duo
|
|
// dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
|
|
// sanctus est Lorem ipsum dolor sit amet.
|
|
//
|
|
// Implements: ASCOM Focuser interface version: <To be completed by driver developer>
|
|
// Author: (XXX) Your N. Here <your@email.here>
|
|
//
|
|
// Edit Log:
|
|
//
|
|
// Date Who Vers Description
|
|
// ----------- --- ----- -------------------------------------------------------
|
|
// dd-mmm-yyyy XXX 6.0.0 Initial edit, created from ASCOM driver template
|
|
// --------------------------------------------------------------------------------
|
|
//
|
|
|
|
|
|
// This is used to define code in the template that is specific to one class implementation
|
|
// unused code canbe deleted and this definition removed.
|
|
#define Focuser
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using System.Runtime.InteropServices;
|
|
|
|
using ASCOM;
|
|
using ASCOM.Astrometry;
|
|
using ASCOM.Astrometry.AstroUtils;
|
|
using ASCOM.Utilities;
|
|
using ASCOM.DeviceInterface;
|
|
using System.Globalization;
|
|
using System.Collections;
|
|
using System.Reflection;
|
|
using ASCOM.Utilities.Interfaces;
|
|
|
|
namespace ASCOM.Meade.net
|
|
{
|
|
//
|
|
// Your driver's DeviceID is ASCOM.Meade.net.Focuser
|
|
//
|
|
// The Guid attribute sets the CLSID for ASCOM.Meade.net.Focuser
|
|
// The ClassInterface/None addribute prevents an empty interface called
|
|
// _Meade.net from being created and used as the [default] interface
|
|
//
|
|
// TODO Replace the not implemented exceptions with code to implement the function or
|
|
// throw the appropriate ASCOM exception.
|
|
//
|
|
|
|
/// <summary>
|
|
/// ASCOM Focuser Driver for Meade.net.
|
|
/// </summary>
|
|
[Guid("a32ac647-bf0f-42f9-8ab0-d166fa5884ad")]
|
|
[ProgId("ASCOM.MeadeGeneric.focuser")]
|
|
[ServedClassName("Meade.net Focuser")]
|
|
[ClassInterface(ClassInterfaceType.None)]
|
|
public class Focuser : ReferenceCountedObjectBase, IFocuserV3
|
|
{
|
|
/// <summary>
|
|
/// ASCOM DeviceID (COM ProgID) for this driver.
|
|
/// The DeviceID is used by ASCOM applications to load the driver at runtime.
|
|
/// </summary>
|
|
//internal static string driverID = "ASCOM.Meade.net.Focuser";
|
|
internal static string driverID = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType);
|
|
// TODO Change the descriptive string for your driver then remove this line
|
|
/// <summary>
|
|
/// Driver description that displays in the ASCOM Chooser.
|
|
/// </summary>
|
|
private static string driverDescription = "Meade Generic";
|
|
|
|
internal static string comPortProfileName = "COM Port"; // Constants used for Profile persistence
|
|
internal static string comPortDefault = "COM1";
|
|
internal static string traceStateProfileName = "Trace Level";
|
|
internal static string traceStateDefault = "false";
|
|
|
|
internal static string comPort; // Variables to hold the currrent device configuration
|
|
|
|
/// <summary>
|
|
/// Private variable to hold the connected state
|
|
/// </summary>
|
|
private bool connectedState;
|
|
|
|
/// <summary>
|
|
/// Private variable to hold an ASCOM Utilities object
|
|
/// </summary>
|
|
private Util utilities;
|
|
|
|
/// <summary>
|
|
/// Private variable to hold an ASCOM AstroUtilities object to provide the Range method
|
|
/// </summary>
|
|
private AstroUtils astroUtilities;
|
|
|
|
/// <summary>
|
|
/// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify)
|
|
/// </summary>
|
|
internal static TraceLogger tl;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="Meade.net"/> class.
|
|
/// Must be public for COM registration.
|
|
/// </summary>
|
|
public Focuser()
|
|
{
|
|
tl = new TraceLogger("", "Meade.net");
|
|
ReadProfile(); // Read device configuration from the ASCOM Profile store
|
|
|
|
tl.LogMessage("Focuser", "Starting initialisation");
|
|
|
|
connectedState = false; // Initialise connected to false
|
|
utilities = new Util(); //Initialise util object
|
|
astroUtilities = new AstroUtils(); // Initialise astro utilities object
|
|
|
|
tl.LogMessage("Focuser", "Completed initialisation");
|
|
}
|
|
|
|
|
|
//
|
|
// PUBLIC COM INTERFACE IFocuserV3 IMPLEMENTATION
|
|
//
|
|
|
|
#region Common properties and methods.
|
|
|
|
/// <summary>
|
|
/// Displays the Setup Dialog form.
|
|
/// If the user clicks the OK button to dismiss the form, then
|
|
/// the new settings are saved, otherwise the old values are reloaded.
|
|
/// THIS IS THE ONLY PLACE WHERE SHOWING USER INTERFACE IS ALLOWED!
|
|
/// </summary>
|
|
public void SetupDialog()
|
|
{
|
|
SharedResources.SetupDialog();
|
|
ReadProfile();
|
|
}
|
|
|
|
public ArrayList SupportedActions
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("SupportedActions Get", "Returning empty arraylist");
|
|
return new ArrayList();
|
|
}
|
|
}
|
|
|
|
public string Action(string actionName, string actionParameters)
|
|
{
|
|
LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters);
|
|
throw new ASCOM.ActionNotImplementedException("Action " + actionName + " is not implemented by this driver");
|
|
}
|
|
|
|
public void CommandBlind(string command, bool raw)
|
|
{
|
|
CheckConnected("CommandBlind");
|
|
// Call CommandString and return as soon as it finishes
|
|
//this.CommandString(command, raw);
|
|
SharedResources.SendBlind(command);
|
|
// or
|
|
//throw new ASCOM.MethodNotImplementedException("CommandBlind");
|
|
// DO NOT have both these sections! One or the other
|
|
}
|
|
|
|
public bool CommandBool(string command, bool raw)
|
|
{
|
|
CheckConnected("CommandBool");
|
|
//string ret = CommandString(command, raw);
|
|
// TODO decode the return string and return true or false
|
|
// or
|
|
throw new ASCOM.MethodNotImplementedException("CommandBool");
|
|
// DO NOT have both these sections! One or the other
|
|
}
|
|
|
|
public string CommandString(string command, bool raw)
|
|
{
|
|
CheckConnected("CommandString");
|
|
// it's a good idea to put all the low level communication with the device here,
|
|
// then all communication calls this function
|
|
// you need something to ensure that only one command is in progress at a time
|
|
return SharedResources.SendString(command);
|
|
|
|
throw new ASCOM.MethodNotImplementedException("CommandString");
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
// Clean up the tracelogger and util objects
|
|
tl.Enabled = false;
|
|
tl.Dispose();
|
|
tl = null;
|
|
utilities.Dispose();
|
|
utilities = null;
|
|
astroUtilities.Dispose();
|
|
astroUtilities = null;
|
|
}
|
|
|
|
public bool Connected
|
|
{
|
|
get
|
|
{
|
|
LogMessage("Connected", "Get {0}", IsConnected);
|
|
return IsConnected;
|
|
}
|
|
set
|
|
{
|
|
tl.LogMessage("Connected", "Set {0}", value);
|
|
if (value == IsConnected)
|
|
return;
|
|
|
|
if (value)
|
|
{
|
|
LogMessage("Connected Set", "Connecting to port {0}", comPort);
|
|
SharedResources.Connect("Serial");
|
|
connectedState = true;
|
|
}
|
|
else
|
|
{
|
|
LogMessage("Connected Set", "Disconnecting from port {0}", comPort);
|
|
SharedResources.Disconnect("Serial");
|
|
connectedState = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public string Description
|
|
{
|
|
// TODO customise this device description
|
|
get
|
|
{
|
|
tl.LogMessage("Description Get", driverDescription);
|
|
return driverDescription;
|
|
}
|
|
}
|
|
|
|
public string DriverInfo
|
|
{
|
|
get
|
|
{
|
|
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
|
// TODO customise this driver description
|
|
string driverInfo = "Information about the driver itself. Version: " + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor);
|
|
tl.LogMessage("DriverInfo Get", driverInfo);
|
|
return driverInfo;
|
|
}
|
|
}
|
|
|
|
public string DriverVersion
|
|
{
|
|
get
|
|
{
|
|
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
|
string driverVersion = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor);
|
|
tl.LogMessage("DriverVersion Get", driverVersion);
|
|
return driverVersion;
|
|
}
|
|
}
|
|
|
|
public short InterfaceVersion
|
|
{
|
|
// set by the driver wizard
|
|
get
|
|
{
|
|
LogMessage("InterfaceVersion Get", "3");
|
|
return Convert.ToInt16("3");
|
|
}
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
//string name = "Short driver name - please customise";
|
|
string name = driverDescription;
|
|
tl.LogMessage("Name Get", name);
|
|
return name;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IFocuser Implementation
|
|
|
|
public bool Absolute
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("Absolute Get", false.ToString());
|
|
return false; // This is a relative focuser
|
|
}
|
|
}
|
|
|
|
public void Halt()
|
|
{
|
|
tl.LogMessage("Halt", "Halting");
|
|
SharedResources.SendBlind(":FQ#");
|
|
//:FQ# Halt Focuser Motion
|
|
//Returns: Nothing
|
|
}
|
|
|
|
public bool IsMoving
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("IsMoving Get", false.ToString());
|
|
return false; // This focuser always moves instantaneously so no need for IsMoving ever to be True
|
|
}
|
|
}
|
|
|
|
public bool Link
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("Link Get", this.Connected.ToString());
|
|
return this.Connected; // Direct function to the connected method, the Link method is just here for backwards compatibility
|
|
}
|
|
set
|
|
{
|
|
tl.LogMessage("Link Set", value.ToString());
|
|
this.Connected = value; // Direct function to the connected method, the Link method is just here for backwards compatibility
|
|
}
|
|
}
|
|
|
|
private readonly int _maxIncrement = 7000;
|
|
public int MaxIncrement
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("MaxIncrement Get", _maxIncrement.ToString());
|
|
return _maxIncrement; // Maximum change in one move
|
|
}
|
|
}
|
|
|
|
private readonly int _maxStep = 7000;
|
|
public int MaxStep
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("MaxStep Get", _maxStep.ToString());
|
|
return _maxStep;
|
|
}
|
|
}
|
|
|
|
public void Move(int Position)
|
|
{
|
|
tl.LogMessage("Move", Position.ToString());
|
|
|
|
//todo implement backlash compensation
|
|
//todo implement direction reverse
|
|
//todo implement dynamic braking
|
|
|
|
if (Position < -MaxIncrement || Position > MaxIncrement)
|
|
{
|
|
throw new ASCOM.InvalidValueException($"position out of range {-MaxIncrement} < {Position} < {MaxIncrement}");
|
|
}
|
|
|
|
if (Position == 0)
|
|
return;
|
|
|
|
if (Position > 0)
|
|
{
|
|
//desired move direction is out
|
|
MoveFocuser(true, Math.Abs(Position));
|
|
}
|
|
else
|
|
{
|
|
//desired move direction is in
|
|
MoveFocuser(false, Math.Abs(Position));
|
|
}
|
|
}
|
|
|
|
private void MoveFocuser(bool directionOut, int steps)
|
|
{
|
|
SharedResources.Lock(() =>
|
|
{
|
|
SharedResources.SendBlind(directionOut ? ":F+#" : ":F-#");
|
|
//:F+# Start Focuser moving inward (toward objective)
|
|
//Returns: None
|
|
|
|
//:F-# Start Focuser moving outward (away from objective)
|
|
//Returns: None
|
|
|
|
utilities.WaitForMilliseconds(steps);
|
|
|
|
Halt();
|
|
});
|
|
}
|
|
|
|
public int Position
|
|
{
|
|
get
|
|
{
|
|
throw new ASCOM.PropertyNotImplementedException("Position", false);
|
|
//return focuserPosition; // Return the focuser position
|
|
}
|
|
}
|
|
|
|
public double StepSize
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("StepSize Get", "Not implemented");
|
|
throw new ASCOM.PropertyNotImplementedException("StepSize", false);
|
|
}
|
|
}
|
|
|
|
public bool TempComp
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("TempComp Get", false.ToString());
|
|
return false;
|
|
}
|
|
set
|
|
{
|
|
tl.LogMessage("TempComp Set", "Not implemented");
|
|
throw new ASCOM.PropertyNotImplementedException("TempComp", false);
|
|
}
|
|
}
|
|
|
|
public bool TempCompAvailable
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("TempCompAvailable Get", false.ToString());
|
|
return false; // Temperature compensation is not available in this driver
|
|
}
|
|
}
|
|
|
|
public double Temperature
|
|
{
|
|
get
|
|
{
|
|
tl.LogMessage("Temperature Get", "Not implemented");
|
|
throw new ASCOM.PropertyNotImplementedException("Temperature", false);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private properties and methods
|
|
// here are some useful properties and methods that can be used as required
|
|
// to help with driver development
|
|
|
|
#region ASCOM Registration
|
|
|
|
// Register or unregister driver for ASCOM. This is harmless if already
|
|
// registered or unregistered.
|
|
//
|
|
/// <summary>
|
|
/// Register or unregister the driver with the ASCOM Platform.
|
|
/// This is harmless if the driver is already registered/unregistered.
|
|
/// </summary>
|
|
/// <param name="bRegister">If <c>true</c>, registers the driver, otherwise unregisters it.</param>
|
|
private static void RegUnregASCOM(bool bRegister)
|
|
{
|
|
using (var P = new ASCOM.Utilities.Profile())
|
|
{
|
|
P.DeviceType = "Focuser";
|
|
if (bRegister)
|
|
{
|
|
P.Register(driverID, driverDescription);
|
|
}
|
|
else
|
|
{
|
|
P.Unregister(driverID);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This function registers the driver with the ASCOM Chooser and
|
|
/// is called automatically whenever this class is registered for COM Interop.
|
|
/// </summary>
|
|
/// <param name="t">Type of the class being registered, not used.</param>
|
|
/// <remarks>
|
|
/// This method typically runs in two distinct situations:
|
|
/// <list type="numbered">
|
|
/// <item>
|
|
/// In Visual Studio, when the project is successfully built.
|
|
/// For this to work correctly, the option <c>Register for COM Interop</c>
|
|
/// must be enabled in the project settings.
|
|
/// </item>
|
|
/// <item>During setup, when the installer registers the assembly for COM Interop.</item>
|
|
/// </list>
|
|
/// This technique should mean that it is never necessary to manually register a driver with ASCOM.
|
|
/// </remarks>
|
|
[ComRegisterFunction]
|
|
public static void RegisterASCOM(Type t)
|
|
{
|
|
RegUnregASCOM(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// This function unregisters the driver from the ASCOM Chooser and
|
|
/// is called automatically whenever this class is unregistered from COM Interop.
|
|
/// </summary>
|
|
/// <param name="t">Type of the class being registered, not used.</param>
|
|
/// <remarks>
|
|
/// This method typically runs in two distinct situations:
|
|
/// <list type="numbered">
|
|
/// <item>
|
|
/// In Visual Studio, when the project is cleaned or prior to rebuilding.
|
|
/// For this to work correctly, the option <c>Register for COM Interop</c>
|
|
/// must be enabled in the project settings.
|
|
/// </item>
|
|
/// <item>During uninstall, when the installer unregisters the assembly from COM Interop.</item>
|
|
/// </list>
|
|
/// This technique should mean that it is never necessary to manually unregister a driver from ASCOM.
|
|
/// </remarks>
|
|
[ComUnregisterFunction]
|
|
public static void UnregisterASCOM(Type t)
|
|
{
|
|
RegUnregASCOM(false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Returns true if there is a valid connection to the driver hardware
|
|
/// </summary>
|
|
private bool IsConnected
|
|
{
|
|
get
|
|
{
|
|
// TODO check that the driver hardware connection exists and is connected to the hardware
|
|
return connectedState;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this function to throw an exception if we aren't connected to the hardware
|
|
/// </summary>
|
|
/// <param name="message"></param>
|
|
private void CheckConnected(string message)
|
|
{
|
|
if (!IsConnected)
|
|
{
|
|
throw new ASCOM.NotConnectedException(message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read the device configuration from the ASCOM Profile store
|
|
/// </summary>
|
|
internal void ReadProfile()
|
|
{
|
|
var profileProperties = SharedResources.ReadProfile();
|
|
tl.Enabled = profileProperties.TraceLogger;
|
|
comPort = profileProperties.ComPort;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Log helper function that takes formatted strings and arguments
|
|
/// </summary>
|
|
/// <param name="identifier"></param>
|
|
/// <param name="message"></param>
|
|
/// <param name="args"></param>
|
|
internal static void LogMessage(string identifier, string message, params object[] args)
|
|
{
|
|
var msg = string.Format(message, args);
|
|
tl.LogMessage(identifier, msg);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|