summaryrefslogtreecommitdiff
path: root/positioner.h
blob: 6e019ed646a25e236be90bda5c27a21f80e29ab2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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