1 /*
2     Filter Interface
3     Copyright (C) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com)
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 */
20 
21 #pragma once
22 
23 #include "indibase.h"
24 
25 #include <stdint.h>
26 
27 // Alias
28 using FI = INDI::FocuserInterface;
29 
30 namespace INDI
31 {
32 
33 /**
34  * \class FocuserInterface
35    \brief Provides interface to implement focuser functionality.
36 
37    A focuser can be an independent device, or an embedded focuser within another device (e.g. Camera or mount).
38 
39    When developing a driver for a fully indepdent focuser device, use INDI::Focuser directly. To add focus functionality to
40    an existing mount or camera driver, subclass INDI::FocuserInterface. In your driver, then call the necessary focuser interface functions.
41 
42    <table>
43    <tr><th>Function</th><th>Where to call it from your driver</th></tr>
44    <tr><td>FI::SetCapability</td><td>Constructor</td></tr>
45    <tr><td>FI::initProperties</td><td>initProperties()</td></tr>
46    <tr><td>FI::updateProperties</td><td>updateProperties()</td></tr>
47    <tr><td>FI::processNumber</td><td>ISNewNumber(...) Check if the property name contains FOCUS_* and then call FI::processNumber(..) for such properties</td></tr>
48    <tr><td>FI::processSwitch</td><td>ISNewSwitch(...)</td></tr>
49    </table>
50 
51    The interface supports three types of focusers:
52    + **Absolute Position**: Focusers that know their absolute position in steps on power up. You can issue GOTO to an absolute position. By definition,
53    position 0 (zero) is where the focuser is completely @a retracted (i.e. closest to the OTA) and it increases positively as it move @a outwards. When moving
54    @a inward, the position value decreases. @warning Negative values are not accepted for absolute focusers.
55    + **Relateive Position**: Focusers that can move in specific steps inwward or outward, but have no information on absolute position on power up.
56    + **DC Motor**: Focusers without any position feedback. The only way to reliably control them is by using timers and moving them for specific pulses in or
57    out.
58 
59    Implement and overwrite the rest of the virtual functions as needed. INDI GPhoto driver is a good example to check for an actual implementation
60    of a focuser interface within a CCD driver.
61 \author Jasem Mutlaq
62 */
63 class FocuserInterface
64 {
65     public:
66         enum FocusDirection
67         {
68             FOCUS_INWARD,
69             FOCUS_OUTWARD
70         };
71 
72         enum
73         {
74             FOCUSER_CAN_ABS_MOVE       = 1 << 0, /*!< Can the focuser move by absolute position? */
75             FOCUSER_CAN_REL_MOVE       = 1 << 1, /*!< Can the focuser move by relative position? */
76             FOCUSER_CAN_ABORT          = 1 << 2, /*!< Is it possible to abort focuser motion? */
77             FOCUSER_CAN_REVERSE        = 1 << 3, /*!< Is it possible to reverse focuser motion? */
78             FOCUSER_CAN_SYNC           = 1 << 4, /*!< Can the focuser sync to a custom position */
79             FOCUSER_HAS_VARIABLE_SPEED = 1 << 5, /*!< Can the focuser move in different configurable speeds? */
80             FOCUSER_HAS_BACKLASH       = 1 << 6  /*!< Can the focuser compensate for backlash? */
81         } FocuserCapability;
82 
83         /**
84          * @brief GetFocuserCapability returns the capability of the focuser
85          */
GetCapability()86         uint32_t GetCapability() const
87         {
88             return capability;
89         }
90 
91         /**
92          * @brief FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
93          * @param cap pointer to focuser capability struct.
94          */
SetCapability(uint32_t cap)95         void SetCapability(uint32_t cap)
96         {
97             capability = cap;
98         }
99 
100         /**
101          * @return True if the focuser has absolute position encoders.
102          */
CanAbsMove()103         bool CanAbsMove()
104         {
105             return capability & FOCUSER_CAN_ABS_MOVE;
106         }
107 
108         /**
109          * @return True if the focuser has relative position encoders.
110          */
CanRelMove()111         bool CanRelMove()
112         {
113             return capability & FOCUSER_CAN_REL_MOVE;
114         }
115 
116         /**
117          * @return True if the focuser motion can be aborted.
118          */
CanAbort()119         bool CanAbort()
120         {
121             return capability & FOCUSER_CAN_ABORT;
122         }
123 
124         /**
125          * @return True if the focuser motion can be reversed.
126          */
CanReverse()127         bool CanReverse()
128         {
129             return capability & FOCUSER_CAN_REVERSE;
130         }
131 
132         /**
133          * @return True if the focuser motion can be reversed.
134          */
CanSync()135         bool CanSync()
136         {
137             return capability & FOCUSER_CAN_SYNC;
138         }
139 
140         /**
141          * @return True if the focuser has multiple speeds.
142          */
HasVariableSpeed()143         bool HasVariableSpeed()
144         {
145             return capability & FOCUSER_HAS_VARIABLE_SPEED;
146         }
147 
148         /**
149          * @return True if the focuser supports backlash.
150          */
HasBacklash()151         bool HasBacklash()
152         {
153             return capability & FOCUSER_HAS_BACKLASH;
154         }
155 
156     protected:
157         explicit FocuserInterface(DefaultDevice * defaultDevice);
158         virtual ~FocuserInterface() = default;
159 
160         /**
161          * \brief Initilize focuser properties. It is recommended to call this function within
162          * initProperties() of your primary device
163          * \param groupName Group or tab name to be used to define focuser properties.
164          */
165         void initProperties(const char * groupName);
166 
167         /**
168          * @brief updateProperties Define or Delete Rotator properties based on the connection status of the base device
169          * @return True if successful, false otherwise.
170          */
171         bool updateProperties();
172 
173         /** \brief Process focus number properties */
174         bool processNumber(const char * dev, const char * name, double values[], char * names[], int n);
175 
176         /** \brief Process focus switch properties */
177         bool processSwitch(const char * dev, const char * name, ISState * states, char * names[], int n);
178 
179         /**
180          * @brief SetFocuserSpeed Set Focuser speed
181          * @param speed focuser speed
182          * @return true if successful, false otherwise
183          */
184         virtual bool SetFocuserSpeed(int speed);
185 
186         /**
187          * \brief MoveFocuser the focuser in a particular direction with a specific speed for a
188          * finite duration.
189          * \param dir Direction of focuser, either FOCUS_INWARD or FOCUS_OUTWARD.
190          * \param speed Speed of focuser if supported by the focuser.
191          * \param duration The timeout in milliseconds before the focus motion halts. Pass 0 to move indefinitely.
192          * \return Return IPS_OK if motion is completed and focuser reached requested position.
193          * Return IPS_BUSY if focuser started motion to requested position and is in progress.
194          * Return IPS_ALERT if there is an error.
195          */
196         virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration);
197 
198         /**
199          * \brief MoveFocuser the focuser to an absolute position.
200          * \param ticks The new position of the focuser.
201          * \return Return IPS_OK if motion is completed and focuser reached requested position. Return
202          * IPS_BUSY if focuser started motion to requested position and is in progress.
203          * Return IPS_ALERT if there is an error.
204          */
205         virtual IPState MoveAbsFocuser(uint32_t targetTicks);
206 
207         /**
208          * \brief MoveFocuser the focuser to an relative position.
209          * \param dir Direction of focuser, either FOCUS_INWARD or FOCUS_OUTWARD.
210          * \param ticks The relative ticks to move.
211          * \return Return IPS_OK if motion is completed and focuser reached requested position. Return
212          * IPS_BUSY if focuser started motion to requested position and is in progress.
213          * Return IPS_ALERT if there is an error.
214          */
215         virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks);
216 
217         /**
218          * @brief ReverseFocuser Reverse focuser motion direction
219          * @param enabled If true, normal default focuser motion is reversed. If false, the direction is set to the default focuser motion.
220          * @return True if successful, false otherwise.
221          */
222         virtual bool ReverseFocuser(bool enabled);
223 
224         /**
225          * @brief SyncFocuser Set current position to ticks without moving the focuser.
226          * @param ticks Desired new sync position.
227          * @return True if successful, false otherwise.
228          */
229         virtual bool SyncFocuser(uint32_t ticks);
230 
231         /**
232          * @brief SetFocuserMaxPosition Set Focuser Maximum position limit in the hardware.
233          * @param ticks maximum steps permitted
234          * @return True if successful, false otherwise.
235          * @note If setting maximum position limit in the hardware is not available or not supported, do not override this function as the default
236          * implementation will always return true.
237          */
238         virtual bool SetFocuserMaxPosition(uint32_t ticks);
239 
240         /**
241          * @brief SetFocuserBacklash Set the focuser backlash compensation value
242          * @param steps value in absolute steps to compensate
243          * @return True if successful, false otherwise.
244          */
245         virtual bool SetFocuserBacklash(int32_t steps);
246 
247         /**
248          * @brief SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation
249          * @param enable flag to enable or disable backlash compensation
250          * @return True if successful, false otherwise.
251          */
252         virtual bool SetFocuserBacklashEnabled(bool enabled);
253 
254         /**
255          * @brief AbortFocuser all focus motion
256          * @return True if abort is successful, false otherwise.
257          */
258         virtual bool AbortFocuser();
259 
260         /**
261          * @brief saveConfigItems save focuser properties defined in the interface in config file
262          * @param fp pointer to config file
263          * @return Always return true
264          */
265         bool saveConfigItems(FILE * fp);
266 
267         // Focuser Speed (if variable speeds are supported)
268         INumberVectorProperty FocusSpeedNP;
269         INumber FocusSpeedN[1];
270 
271         // Focuser Motion switch.
272         // For absolute focusers, this controls the directoin of FocusRelPos when updated.
273         // For DC speed based focusers, this moves the focuser continues in the CW/CCW directions until stopped.
274         ISwitchVectorProperty FocusMotionSP;
275         ISwitch FocusMotionS[2];
276 
277         // Timer for user with DC focusers to run focuser in specific direction for this duration
278         INumberVectorProperty FocusTimerNP;
279         INumber FocusTimerN[1];
280 
281         // Absolute Focuser Position in steps
282         INumberVectorProperty FocusAbsPosNP;
283         INumber FocusAbsPosN[1];
284 
285         // Relative Focuser position to be commanded
286         INumberVectorProperty FocusRelPosNP;
287         INumber FocusRelPosN[1];
288 
289         // Absolute Focuser position is 0 to this maximum limit. By Default, it is set to 200,000.
290         INumberVectorProperty FocusMaxPosNP;
291         INumber FocusMaxPosN[1];
292 
293         // Sync
294         INumberVectorProperty FocusSyncNP;
295         INumber FocusSyncN[1];
296 
297         // Abort Focuser
298         ISwitchVectorProperty FocusAbortSP;
299         ISwitch FocusAbortS[1];
300 
301         // Reverse Focuser
302         ISwitchVectorProperty FocusReverseSP;
303         ISwitch FocusReverseS[2];
304 
305         // Backlash toogle
306         ISwitchVectorProperty FocusBacklashSP;
307         ISwitch FocusBacklashS[2];
308 
309         // Backlash steps
310         INumberVectorProperty FocusBacklashNP;
311         INumber FocusBacklashN[1];
312 
313         uint32_t capability;
314 
315         double lastTimerValue = { 0 };
316 
317         DefaultDevice * m_defaultDevice { nullptr };
318 };
319 }
320