diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2013-08-21 11:02:52 +0200 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2013-08-21 11:02:52 +0200 |
commit | cd10b439d0465afa6bce38188a4e9d8a5e74d859 (patch) | |
tree | 54480623232fb0e8e94fd37a5c9e31603301dd35 /positioner.h | |
parent | 5b76eec1afbe435b5d1dfabaaa9546f8e400cba7 (diff) | |
download | vdr-cd10b439d0465afa6bce38188a4e9d8a5e74d859.tar.gz vdr-cd10b439d0465afa6bce38188a4e9d8a5e74d859.tar.bz2 |
Added basic support for positioners to control steerable satellite dishes
Diffstat (limited to 'positioner.h')
-rw-r--r-- | positioner.h | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/positioner.h b/positioner.h new file mode 100644 index 00000000..6e019ed6 --- /dev/null +++ b/positioner.h @@ -0,0 +1,171 @@ +/* + * 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.1 2013/06/10 14:27:14 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 +/-14.5 degrees (integer value 145) 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 betwen the current actual position of the dish and + ///< the position stored with teh 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 |