Merged in feature/LocalServer (pull request #5)
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
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
//
|
||||
// ================
|
||||
// Shared Resources
|
||||
// ================
|
||||
//
|
||||
// This class is a container for all shared resources that may be needed
|
||||
// by the drivers served by the Local Server.
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
// * ALL DECLARATIONS MUST BE STATIC HERE!! INSTANCES OF THIS CLASS MUST NEVER BE CREATED!
|
||||
//
|
||||
// Written by: Bob Denny 29-May-2007
|
||||
// Modified by Chris Rowland and Peter Simpson to hamdle multiple hardware devices March 2011
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using ASCOM;
|
||||
using ASCOM.Utilities;
|
||||
|
||||
namespace ASCOM.Meade.net
|
||||
{
|
||||
public class ProfileProperties
|
||||
{
|
||||
// properies that are part of the profile
|
||||
public string ComPort { get; set; }
|
||||
public bool TraceLogger { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The resources shared by all drivers and devices, in this example it's a serial port with a shared SendMessage method
|
||||
/// an idea for locking the message and handling connecting is given.
|
||||
/// In reality extensive changes will probably be needed.
|
||||
/// Multiple drivers means that several applications connect to the same hardware device, aka a hub.
|
||||
/// Multiple devices means that there are more than one instance of the hardware, such as two focusers.
|
||||
/// In this case there needs to be multiple instances of the hardware connector, each with it's own connection count.
|
||||
/// </summary>
|
||||
public static class SharedResources
|
||||
{
|
||||
// object used for locking to prevent multiple drivers accessing common code at the same time
|
||||
private static readonly object lockObject = new object();
|
||||
|
||||
// Shared serial port. This will allow multiple drivers to use one single serial port.
|
||||
private static ASCOM.Utilities.Serial s_sharedSerial = new ASCOM.Utilities.Serial(); // Shared serial port
|
||||
private static int s_z = 0; // counter for the number of connections to the serial port
|
||||
|
||||
//
|
||||
// Public access to shared resources
|
||||
//
|
||||
|
||||
#region single serial port connector
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// SendMessage is a way that messages could be sent to the hardware without
|
||||
// conflicts between different drivers.
|
||||
//
|
||||
// All this is for a single connection, multiple connections would need multiple ports
|
||||
// and a way to handle connecting and disconnection from them - see the
|
||||
// multi driver handling section for ideas.
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Shared serial port
|
||||
/// </summary>
|
||||
public static ASCOM.Utilities.Serial SharedSerial
|
||||
{
|
||||
get { return s_sharedSerial; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// number of connections to the shared serial port
|
||||
/// </summary>
|
||||
public static int connections
|
||||
{
|
||||
get { return s_z; }
|
||||
set { s_z = value; }
|
||||
}
|
||||
|
||||
public static void SendBlind(string message)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
SharedSerial.ClearBuffers();
|
||||
SharedSerial.Transmit(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SendBool(string message)
|
||||
{
|
||||
SharedSerial.ClearBuffers();
|
||||
return SendChar(message) == "1";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example of a shared SendMessage method, the lock
|
||||
/// prevents different drivers tripping over one another.
|
||||
/// It needs error handling and assumes that the message will be sent unchanged
|
||||
/// and that the reply will always be terminated by a "#" character.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static string SendString(string message)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
SharedSerial.ClearBuffers();
|
||||
SharedSerial.Transmit(message);
|
||||
return SharedSerial.ReceiveTerminated("#").TrimEnd('#');
|
||||
}
|
||||
}
|
||||
|
||||
public static string SendChar(string message)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
SharedSerial.ClearBuffers();
|
||||
SharedSerial.Transmit(message);
|
||||
return SharedSerial.ReceiveCounted(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadTerminated()
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
return SharedSerial.ReceiveTerminated("#");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example of handling connecting to and disconnection from the
|
||||
/// shared serial port.
|
||||
/// Needs error handling
|
||||
/// the port name etc. needs to be set up first, this could be done by the driver
|
||||
/// checking Connected and if it's false setting up the port before setting connected to true.
|
||||
/// It could also be put here.
|
||||
/// </summary>
|
||||
public static bool Connected
|
||||
{
|
||||
set
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
if (s_z == 0)
|
||||
SharedSerial.Connected = true;
|
||||
s_z++;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_z--;
|
||||
if (s_z <= 0)
|
||||
{
|
||||
SharedSerial.Connected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
get { return SharedSerial.Connected; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Profile
|
||||
|
||||
internal static string driverID = "ASCOM.MeadeGeneric.Telescope";
|
||||
|
||||
// Constants used for Profile persistence
|
||||
internal static string comPortProfileName = "COM Port";
|
||||
internal static string traceStateProfileName = "Trace Level";
|
||||
|
||||
public static void WriteProfile(ProfileProperties profileProperties)
|
||||
{
|
||||
using (Profile driverProfile = new Profile())
|
||||
{
|
||||
driverProfile.DeviceType = "Telescope";
|
||||
driverProfile.WriteValue(driverID, traceStateProfileName, profileProperties.TraceLogger.ToString());
|
||||
driverProfile.WriteValue(driverID, comPortProfileName, profileProperties.ComPort);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string comPortDefault = "COM1";
|
||||
internal static string traceStateDefault = "false";
|
||||
|
||||
public static ProfileProperties ReadProfile()
|
||||
{
|
||||
ProfileProperties profileProperties = new ProfileProperties();
|
||||
using (Profile driverProfile = new Profile())
|
||||
{
|
||||
driverProfile.DeviceType = "Telescope";
|
||||
profileProperties.ComPort =
|
||||
driverProfile.GetValue(driverID, comPortProfileName, string.Empty, comPortDefault);
|
||||
profileProperties.TraceLogger = Convert.ToBoolean(driverProfile.GetValue(driverID,
|
||||
traceStateProfileName, string.Empty, traceStateDefault));
|
||||
}
|
||||
|
||||
return profileProperties;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetupDialog
|
||||
|
||||
public static void SetupDialog()
|
||||
{
|
||||
// consider only showing the setup dialog if not connected
|
||||
// or call a different dialog if connected
|
||||
if (SharedSerial.Connected)
|
||||
{
|
||||
System.Windows.Forms.MessageBox.Show("Already connected, please disconnect before altering settings");
|
||||
return;
|
||||
}
|
||||
|
||||
var profileProperties = ReadProfile();
|
||||
|
||||
using (SetupDialogForm F = new SetupDialogForm())
|
||||
{
|
||||
F.SetProfile(profileProperties);
|
||||
|
||||
var result = F.ShowDialog();
|
||||
if (result == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
profileProperties = F.GetProfile();
|
||||
|
||||
WriteProfile(profileProperties); // Persist device configuration values to the ASCOM Profile store
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Multi Driver handling
|
||||
|
||||
// this section illustrates how multiple drivers could be handled,
|
||||
// it's for drivers where multiple connections to the hardware can be made and ensures that the
|
||||
// hardware is only disconnected from when all the connected devices have disconnected.
|
||||
|
||||
// It is NOT a complete solution! This is to give ideas of what can - or should be done.
|
||||
//
|
||||
// An alternative would be to move the hardware control here, handle connecting and disconnecting,
|
||||
// and provide the device with a suitable connection to the hardware.
|
||||
//
|
||||
/// <summary>
|
||||
/// dictionary carrying device connections.
|
||||
/// The Key is the connection number that identifies the device, it could be the COM port name,
|
||||
/// USB ID or IP Address, the Value is the DeviceHardware class
|
||||
/// </summary>
|
||||
private static Dictionary<string, DeviceHardware> connectedDevices = new Dictionary<string, DeviceHardware>();
|
||||
|
||||
/// <summary>
|
||||
/// This is called in the driver Connect(true) property,
|
||||
/// it add the device id to the list of devices if it's not there and increments the device count.
|
||||
/// </summary>
|
||||
/// <param name="deviceId"></param>
|
||||
public static void Connect(string deviceId)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
if (!connectedDevices.ContainsKey(deviceId))
|
||||
connectedDevices.Add(deviceId, new DeviceHardware());
|
||||
connectedDevices[deviceId].count++; // increment the value
|
||||
|
||||
if (deviceId == "Serial")
|
||||
{
|
||||
if (connectedDevices[deviceId].count == 1)
|
||||
{
|
||||
var profileProperties = ReadProfile();
|
||||
SharedResources.SharedSerial.PortName = profileProperties.ComPort;
|
||||
SharedResources.SharedSerial.DTREnable = false;
|
||||
SharedResources.SharedSerial.RTSEnable = false;
|
||||
SharedResources.SharedSerial.DataBits = 8;
|
||||
SharedResources.SharedSerial.StopBits = SerialStopBits.One;
|
||||
SharedResources.SharedSerial.Parity = SerialParity.None;
|
||||
SharedResources.SharedSerial.Speed = SerialSpeed.ps9600;
|
||||
SharedResources.SharedSerial.Handshake = SerialHandshake.None;
|
||||
SharedResources.SharedSerial.Connected = true;
|
||||
|
||||
string firmware = SendString(":GVN#");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Disconnect(string deviceId)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
if (connectedDevices.ContainsKey(deviceId))
|
||||
{
|
||||
connectedDevices[deviceId].count--;
|
||||
if (connectedDevices[deviceId].count <= 0)
|
||||
{
|
||||
connectedDevices.Remove(deviceId);
|
||||
if (deviceId == "Serial")
|
||||
{
|
||||
SharedResources.SharedSerial.Connected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsConnected(string deviceId)
|
||||
{
|
||||
if (connectedDevices.ContainsKey(deviceId))
|
||||
return (connectedDevices[deviceId].count > 0);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static void Lock(Action action)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
public static T Lock<T>(Func<T> func)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
return func();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skeleton of a hardware class, all this does is hold a count of the connections,
|
||||
/// in reality extra code will be needed to handle the hardware in some way
|
||||
/// </summary>
|
||||
public class DeviceHardware
|
||||
{
|
||||
private int _count;
|
||||
|
||||
internal int count
|
||||
{
|
||||
set => _count = value;
|
||||
get => _count;
|
||||
}
|
||||
|
||||
internal DeviceHardware()
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//#region ServedClassName attribute
|
||||
///// <summary>
|
||||
///// This is only needed if the driver is targeted at platform 5.5, it is included with Platform 6
|
||||
///// </summary>
|
||||
//[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
//public sealed class ServedClassNameAttribute : Attribute
|
||||
//{
|
||||
// // See the attribute guidelines at
|
||||
// // http://go.microsoft.com/fwlink/?LinkId=85236
|
||||
|
||||
// /// <summary>
|
||||
// /// Gets or sets the 'friendly name' of the served class, as registered with the ASCOM Chooser.
|
||||
// /// </summary>
|
||||
// /// <value>The 'friendly name' of the served class.</value>
|
||||
// public string DisplayName { get; private set; }
|
||||
// /// <summary>
|
||||
// /// Initializes a new instance of the <see cref="ServedClassNameAttribute"/> class.
|
||||
// /// </summary>
|
||||
// /// <param name="servedClassName">The 'friendly name' of the served class.</param>
|
||||
// public ServedClassNameAttribute(string servedClassName)
|
||||
// {
|
||||
// DisplayName = servedClassName;
|
||||
// }
|
||||
//}
|
||||
//#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user