vdr/positioner.h

172 lines
9.5 KiB
C++

/*
* positioner.h: Steerable dish positioning
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: positioner.h 3.3 2013/12/28 11:15:56 kls Exp $
*/
#ifndef __POSITIONER_H
#define __POSITIONER_H
#include "thread.h"
#include "tools.h"
/// A steerable satellite dish generally points to the south on the northern hemisphere,
/// and to the north on the southern hemisphere (unless you're located directly on the
/// equator, in which case the general direction is "up"). Therefore, moving the dish
/// "east" or "west" means something different on either hemisphere. From the local dish
/// motor's point of view, it makes more sense to speak of turning the dish "left" or
/// "right", which is independent of the actual hemisphere the dish is located in.
/// In the cPositioner class context, when a dish on the northern hemisphere moves "east",
/// it is considered to be moving "left". Imagine standing behind the dish and looking
/// towards the satellites, and clearly "east" is "left". On the southern hemisphere
/// the same move to the "left" would go to the "west". So on the hardware level it is
/// clear what "left" and "right" means. The user interface may present different labels
/// to the viewer, depending on the hemisphere the dish is on.
/// All angles in this context are given in "degrees * 10", which allows for an angular
/// resolution of 0.1 degrees.
class cPositioner {
private:
mutable cMutex mutex;
static cPositioner *positioner;
int capabilities;
int frontend; // file descriptor of the DVB frontend
mutable int lastLongitude; // the longitude the dish has last been moved to
int targetLongitude; // the longitude the dish is supposed to be moved to
mutable int lastHourAngle; // the hour angle the positioner has last been moved to
int targetHourAngle; // the hour angle the positioner is supposed to be moved to
int swingTime;
cTimeMs movementStart;
protected:
cPositioner(void);
virtual ~cPositioner();
void SetCapabilities(int Capabilities) { capabilities = Capabilities; }
///< A derived class shall call this function in its constructor to set the
///< capability flags it supports.
int Frontend(void) const { return frontend; }
///< Returns the file descriptor of the DVB frontend the positioner is
///< connected to. If the positioner is not connected to any DVB device,
///< -1 will be returned.
static int CalcHourAngle(int Longitude);
///< Takes the longitude and latitude of the dish location from the system
///< setup and the given Longitude to calculate the "hour angle" to which to move
///< the dish to in order to point to the satellite at orbital position Longitude.
///< An hour angle of zero means the dish shall point directly towards the
///< celestial equator (which is south on the northern hemisphere, and north on
///< the southern hemisphere). Negative values mean that the dish needs to be
///< moved to the left (as seen from behind the dish), while positive values
///< require a movement to the right.
static int CalcLongitude(int HourAngle);
///< Returns the longitude of the satellite position the dish points at when the
///< positioner is moved to the given HourAngle.
void StartMovementTimer(int Longitude);
///< Starts a timer that estimates how long it will take to move the dish from
///< the current position to the one given by Longitude. The default implementation
///< of CurrentLongitude() uses this timer.
public:
enum ePositionerCapabilities {
pcCanNothing = 0x0000,
pcCanDrive = 0x0001,
pcCanStep = 0x0002,
pcCanHalt = 0x0004,
pcCanSetLimits = 0x0008,
pcCanDisableLimits = 0x0010,
pcCanEnableLimits = 0x0020,
pcCanStorePosition = 0x0040,
pcCanRecalcPositions = 0x0080,
pcCanGotoPosition = 0x0100,
pcCanGotoAngle = 0x0200,
};
enum ePositionerDirection { pdLeft, pdRight };
static int NormalizeAngle(int Angle);
///< Normalizes the given Angle into the range -1800...1800.
int Capabilities(void) const { return capabilities; }
///< Returns a flag word defining all the things this positioner is
///< capable of.
void SetFrontend(int Frontend) { frontend = Frontend; }
///< This function is called whenever the positioner is connected to
///< a DVB frontend.
static int HorizonLongitude(ePositionerDirection Direction);
///< Returns the longitude of the satellite position that is just at the
///< horizon when looking in the given Direction. Note that this function
///< only delivers reasonable values for site latitudes between +/-81 degrees.
///< Beyond these limits (i.e. near the north or south pole) a constant value
///< of 0 will be returned.
int HardLimitLongitude(ePositionerDirection Direction) const;
///< Returns the longitude of the positioner's hard limit in the given
///< Direction. Note that the value returned here may be larger (or smaller,
///< depending on the Direction) than that returned by HorizonLongitude(),
///< which would mean that it lies below that horizon.
int LastLongitude(void) const { return lastLongitude; }
///< Returns the longitude the dish has last been moved to.
int TargetLongitude(void) const { return targetLongitude; }
///< Returns the longitude the dish is supposed to be moved to. Once the target
///< longitude has been reached, this is the same as the value returned by
///< CurrentLongitude().
virtual cString Error(void) const { return NULL; }
///< Returns a short, single line string indicating an error condition (if
///< the positioner is able to report any errors).
///< NULL means there is no error.
virtual void Drive(ePositionerDirection Direction) {}
///< Continuously move the dish to the given Direction until Halt() is
///< called or it hits the soft or hard limit.
virtual void Step(ePositionerDirection Direction, uint Steps = 1) {}
///< Move the dish the given number of Steps in the given Direction.
///< The maximum number of steps a particular positioner can do in a single
///< call may be limited.
///< A "step" is the smallest possible movement the positioner can make, which
///< is typically 0.1 degrees.
virtual void Halt(void) {}
///< Stop any ongoing motion of the dish.
virtual void SetLimit(ePositionerDirection Direction) {}
///< Set the soft limit of the dish movement in the given Direction to the
///< current position.
virtual void DisableLimits(void) {}
///< Disables the soft limits for the dish movement.
virtual void EnableLimits(void) {}
///< Enables the soft limits for the dish movement.
virtual void StorePosition(uint Number) {}
///< Store the current position as a satellite position with the given Number.
///< Number can be in the range 1...255. However, a particular positioner
///< may only have a limited number of satellite positions it can store.
virtual void RecalcPositions(uint Number) {}
///< Take the difference between the current actual position of the dish and
///< the position stored with the given Number, and apply the difference to
///< all stored positions.
virtual void GotoPosition(uint Number, int Longitude);
///< Move the dish to the satellite position stored under the given Number.
///< Number must be one of the values previously used with StorePosition().
///< The special value 0 shall move the dish to a "reference position",
///< which usually is due south (or north, if you're on the southern hemisphere).
///< Longitude will be used to calculate how long it takes to move the dish
///< from its current position to the given Longitude.
///< A derived class must call the base class function to have the target
///< longitude stored.
virtual void GotoAngle(int Longitude);
///< Move the dish to the given angular position. Longitude can be in the range
///< -1800...+1800. A positive sign indicates a position east of Greenwich,
///< while western positions have a negative sign. The absolute value is in
///< "degrees * 10", which allows for a resolution of 1/10 of a degree.
///< A derived class must call the base class function to have the target
///< longitude stored.
virtual int CurrentLongitude(void) const;
///< Returns the longitude the dish currently points to. If the dish is in motion,
///< this may be an estimate based on the angular speed of the positioner.
///< The default implementation takes the last and target longitude as well as
///< the rotation speed of the positioner to calculate the estimated current
///< longitude the dish points to.
virtual bool IsMoving(void) const;
///< Returns true if the dish is currently moving as a result of a call to
///< GotoPosition() or GotoAngle().
static cPositioner *GetPositioner(void);
///< Returns a previously created positioner. If no plugin has created
///< a positioner, there will always be the default DiSEqC positioner.
static void DestroyPositioner(void);
///< Destroys a previously created positioner.
};
#endif //__POSITIONER_H