Adding a rotor controller to Tracker
Rotor Control Interface
Through the Tracking view, Tracker supports a range of rotor controllers. These make use of simple and consistent interfaces, which allows new controllers to be easily added.
COM registration:
In addition to the usual COM registration requirements it is also necessary to create a registry key that Tracker can use to find the rotor control at runtime. This key, using the VersionIndependentProgID as its name, should be stored under HKLM/SOFTWARE/Sumus Technology Limited/RotorControls and have a Name entry which gives a human readable name for the rotor control. A sample registry file is given below:
HKCR {
Tracker.RotorControl.SPID.1 = s 'Rotor Class' {
CLSID = s '{B1897217-FAE3-4E1E-8FE6-4CAD83BED3C7}'
}
Tracker.RotorControl.SPID = s 'Rotor Class' {
CLSID = s '{B1897217-FAE3-4E1E-8FE6-4CAD83BED3C7}'
CurVer = s 'Tracker.RotorControl.SPID.1'
}
NoRemove CLSID {
ForceRemove {B1897217-FAE3-4E1E-8FE6-4CAD83BED3C7} = s 'Rotor Class' {
ProgID = s 'Tracker.RotorControl.SPID.1'
VersionIndependentProgID = s 'Tracker.RotorControl.SPID'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%' {
val ThreadingModel = s 'Apartment'
}
'TypeLib' = s '{89435DF5-1321-4E8E-954B-5934B6E994D0}'
}
}
}
HKLM {
NoRemove SOFTWARE {
'Sumus Technology Limited' {
'RotorControls' {
'Tracker.RotorControl.SPID' {
val Name = s 'SPID MD-01'
}
}
}
}
}
Interfaces:
There are three interfaces that can be implemented by the rotor control, although only the IRotorControl interface is required.
In addition there is one interface that is implemented by the application, and can be called by the rotor control, assuming the rotor control has implemented the IRotorControlFeedback interface.
IRotorControl
This is the only interface that must be implemented.
HRESULT Initiate( [out] BSTR* pMessage )
This method will be called if and only if the rotor control is being loaded from storage. Message can be used to pass error information on failure.
HRESULT SetPosition( [in] double AzimuthDegrees, [in] double ElevationDegrees, [in] BSTR Reason, [in] double TimeRemainingSeconds, [in] double MaxElevationDegrees )
Reason can be one of TRACK, SLEW, PREPOSITION, or PARK.
If Reason is TRACK or SLEW then TimeRemaingingSeconds gives the time remaining in the current pass.
If Reason is PREPOSITION then TimeRemaingingSeconds gives the time before the start of the pass.
If Reason is PARK then TimeRemaingingSeconds is undefined.
If Reason is TRACK, SLEW or PREPOSITION then MaxElevationDegrees gives the maximum elevation of the current or upcoming pass, else it is undefined.
HRESULT GetPosition( [out] double* pAzimuthDegrees, [out] double* pElevationDegrees )
Retrieves the actual pointing position of the rotor control.
HRESULT WriteRaw( [in] VARIANT command, [out] VARIANT* pResponse )
NOT CURRENTLY USED.
HRESULT GetNumProperties( [out] int* pNumProperties )
Must return the number of properties supported by the rotor of control. This would typically be the same as the number of UI elements in the rotor control's edit dialog, although additional properties could be used to store information such as the rotor's control version number, for example.
HRESULT GetProperty( [in] int iProperty, [out] VARIANT* pValue, [out] BSTR* pName )
Will be called multiple times with the value of Property set from 0 to GetNumProperties - 1. Name is used when persisting the properties and must be unique for each property. This is called when persisting the properties of the rotor control.
HRESULT SetProperty( [in] int iProperty, [in] VARIANT value )
Will be called multiple times with the value of Property set from 0 to GetNumProperties - 1. This is called when loading the state of the rotor control from storage.
HRESULT Edit( [out] HWND* phWnd, [in] HWND hWndParent )
The rotor control should pass back a handle to a window which is no larger than 300 by 170 (width by height) in size, with the parent window given by hWndParent. The window should have the following style: DS_CONTROL | WS_CHILD
Sample code for window creation would look something like:
pProperties = new CProperties( NULL, hWndParent );
pProperties->Create( CProperties::IDD, NULL );
*phWnd = pProperties->GetSafeHwnd( );
Whenever any changes to the fields in the dialog are made by the user the parent window should be notified so that the Apply button can be enabled. This is done with the code:
::PostMessage( hWndParent, WM_USER_NOTIFY_CHANGE, 0, 0 );
HRESULT Apply( [out] BSTR* pMessage )
Indicates that the user has hit the Apply button and the rotor control should respond appropriately, by reading values from its own configuration UI and applying any necessary changes. The pMessage parameter can be used to pass error information on failure.
IRotorControlFeedback
The implementation of this interface is optional.
If implemented then the main application will call the only method with an IMessageFeedback interface pointer as the only parameter.
The rotor control implementation will then be able to make calls on the IMessageFeedback interface, to send messages, position information, etc.
HRESULT SetInterface( [in] IUnknown* pUnknown )
Set the IMessageFeedback interface pointer so the rotor control can call back into the main application. If pUnknown is NULL then the rotor control should release any interface pointer it is already holding. Some sample pseudo-code:
if (pUnknown == NULL) {
m_messageFeedback = NULL;
} else {
pUnknown->QueryInterface(IID_IMessageFeedback, (void**)&m_messageFeedback);
}
IRotorControlTLETracking
This interface can be implemented on more advanced rotor controllers which are capable of tracking using a given TLE and their own position. Such rotor controls have an embedded implementation of the SGP4 algorithm and so do not require a stream of positioning commands in order to track a satellite.
Such rotor controls also require their position and the time, which can be passed through the interface.
HRESULT Track( [in] BOOL Track )
Set the tracking status.
HRESULT SetTLE( [in] BSTR SatelliteName, [in] BSTR TLELine1, [in] BSTR TLELine2 )
Set the name of the satellite to be tracked, together with both lines of the associated TLE.
HRESULT SetPointingOffsets( [in] double AzimuthOffsetDegrees, [in] double ElevationOffsetDegrees )
Set the azimuth and elevation pointing offsets in degrees. These offsets are configured in Tracker. If the rotor control is unable to honor such a request it should return E_NOTIMPL.
HRESULT SetSystemLocation( [in] BOOL Automatic, [in] double LongitudeDegrees, [in] double LatitudeDegrees, [in] double AltitudeMeters )
Set the rotor control geodetic location. At present Automatic is always FALSE, but the rotor control always has the option of determining its own location if it is capable of doing so.
HRESULT SetSystemTime( [in] BOOL Automatic, [in] unsigned long SecondsSince1970 )
Set the system time, expressed in seconds since midnight, January 1st, 1970. At present Automatic is always FALSE, but the rotor control always has the option of determining the current time fot itself, if it is capable of doing so.
HRESULT SetEpochOffset( [in] double Seconds )
Set a time offset which applies only to the TLE. This offset is configured in Tracker. The system time remains unchanged. If the rotor control is unable to honor such a request it should return E_NOTIMPL.
HRESULT SetMinimumElevation( [in] double ElevationDegrees )
Set the minimum elevation at which the rotor control will begin tracking. If the rotor control is unable to honor such a request it should return E_NOTIMPL.
HRESULT SetParkPosition( [in] double AzimuthDegrees, [in] double ElevationDegrees )
Set the park position of the rotor control. If the rotor control is unable to honor such a request it should return E_NOTIMPL.
IMessageFeedback
This interface is implemented by the application and called by the rotor control. A pointer to this interface is passed to the rotor control through the IRotorControlFeedback interface, if implemented by the rotor control. Once the rotor control has a pointer to the IMessageFeedback interface calls can be made on it.
HRESULT InformationMessage( [in] BSTR Message )
Sends the associated Message, which will be displayed as an information message within Tracker. The rotor control message should ensure it provides sufficient context for the message to be understood.
HRESULT WarningMessage( [in] BSTR Message )
Sends the associated Message, which will be displayed as a warning message within Tracker. The rotor control message should ensure it provides sufficient context for the message to be understood.
HRESULT ErrorMessage( [in] BSTR Message )
Sends the associated Message, which will be displayed as an error message within Tracker. The rotor control message should ensure it provides sufficient context for the message to be understood.
HRESULT ReportPositionCommanded( [in] double AzimuthDegrees, [in] double ElevationDegrees )
Reports the last pointing position commanded.
HRESULT ReportPosition( [in] double AzimuthDegrees, [in] double ElevationDegrees )
Reports the current pointing position of the rotor control.
HRESULT ReportPositionAndDifferential( [in] double AzimuthDegrees, [in] double ElevationDegrees, [in] double AzimuthDegreesDifferential, [in] double ElevationDegreesDifferential )
Reports the current pointing position of the rotor control, together with the differences between the last pointing position commanded and the current pointing position.
HRESULT SetValue( [in] BSTR Name, [in] BSTR Value )
NOT IMPLEMENTED.
HRESULT SetValueHighlighted( [in] BSTR Name, [in] BSTR Value, [in] DWORD RGBForeground, [in] DWORD RGBBackground )
NOT IMPLEMENTED.
HRESULT ClearValues( [in] BSTR Name, [in] BSTR Value )
NOT IMPLEMENTED.