1 /*******************************************************************************
2  Dome Simulator
3  Copyright(c) 2014 Jasem Mutlaq. All rights reserved.
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8  .
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Library General Public License for more details.
13  .
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB.  If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 *******************************************************************************/
19 #include "dome_simulator.h"
20 
21 #include "indicom.h"
22 
23 #include <cmath>
24 #include <memory>
25 #include <unistd.h>
26 
27 // We declare an auto pointer to domeSim.
28 static std::unique_ptr<DomeSim> domeSim(new DomeSim());
29 
30 #define DOME_SPEED    10.0 /* 10 degrees per second, constant */
31 #define SHUTTER_TIMER 5.0  /* Shutter closes/open in 5 seconds */
32 
DomeSim()33 DomeSim::DomeSim()
34 {
35     targetAz        = 0;
36     shutterTimer    = 0;
37     prev_az         = 0;
38     prev_alt        = 0;
39 
40     SetDomeCapability(DOME_CAN_ABORT | DOME_CAN_ABS_MOVE | DOME_CAN_REL_MOVE | DOME_CAN_PARK | DOME_HAS_SHUTTER);
41 }
42 
43 /************************************************************************************
44  *
45 * ***********************************************************************************/
initProperties()46 bool DomeSim::initProperties()
47 {
48     INDI::Dome::initProperties();
49 
50     SetParkDataType(PARK_AZ);
51 
52     addAuxControls();
53 
54     return true;
55 }
56 
SetupParms()57 bool DomeSim::SetupParms()
58 {
59     targetAz     = 0;
60     shutterTimer = SHUTTER_TIMER;
61 
62     DomeAbsPosN[0].value = 0;
63 
64     DomeParamN[0].value = 5;
65 
66     IDSetNumber(&DomeAbsPosNP, nullptr);
67     IDSetNumber(&DomeParamNP, nullptr);
68 
69     if (InitPark())
70     {
71         // If loading parking data is successful, we just set the default parking values.
72         SetAxis1ParkDefault(90);
73     }
74     else
75     {
76         // Otherwise, we set all parking data to default in case no parking data is found.
77         SetAxis1Park(90);
78         SetAxis1ParkDefault(90);
79     }
80 
81     return true;
82 }
83 
getDefaultName()84 const char *DomeSim::getDefaultName()
85 {
86     return "Dome Simulator";
87 }
88 
updateProperties()89 bool DomeSim::updateProperties()
90 {
91     INDI::Dome::updateProperties();
92 
93     if (isConnected())
94     {
95         SetupParms();
96     }
97 
98     return true;
99 }
100 
Connect()101 bool DomeSim::Connect()
102 {
103     SetTimer(1000); //  start the timer
104     return true;
105 }
106 
Disconnect()107 bool DomeSim::Disconnect()
108 {
109     return true;
110 }
111 
TimerHit()112 void DomeSim::TimerHit()
113 {
114     int nexttimer = 1000;
115 
116     if (!isConnected())
117         return; //  No need to reset timer if we are not connected anymore
118 
119     if (DomeAbsPosNP.s == IPS_BUSY)
120     {
121         if (targetAz > DomeAbsPosN[0].value)
122         {
123             DomeAbsPosN[0].value += DOME_SPEED;
124         }
125         else if (targetAz < DomeAbsPosN[0].value)
126         {
127             DomeAbsPosN[0].value -= DOME_SPEED;
128         }
129 
130         DomeAbsPosN[0].value = range360(DomeAbsPosN[0].value);
131 
132         if (fabs(targetAz - DomeAbsPosN[0].value) <= DOME_SPEED)
133         {
134             DomeAbsPosN[0].value = targetAz;
135             LOG_INFO("Dome reached requested azimuth angle.");
136 
137             if (getDomeState() == DOME_PARKING)
138                 SetParked(true);
139             else if (getDomeState() == DOME_UNPARKING)
140                 SetParked(false);
141             else
142                 setDomeState(DOME_SYNCED);
143         }
144 
145         IDSetNumber(&DomeAbsPosNP, nullptr);
146     }
147 
148     if (DomeShutterSP.s == IPS_BUSY)
149     {
150         if (shutterTimer-- <= 0)
151         {
152             shutterTimer    = 0;
153             DomeShutterSP.s = IPS_OK;
154             LOGF_INFO("Shutter is %s.", (DomeShutterS[0].s == ISS_ON ? "open" : "closed"));
155             IDSetSwitch(&DomeShutterSP, nullptr);
156 
157             if (getDomeState() == DOME_UNPARKING)
158                 SetParked(false);
159         }
160     }
161     SetTimer(nexttimer);
162 }
163 
Move(DomeDirection dir,DomeMotionCommand operation)164 IPState DomeSim::Move(DomeDirection dir, DomeMotionCommand operation)
165 {
166     if (operation == MOTION_START)
167     {
168         targetAz       = (dir == DOME_CW) ? 1e6 : -1e6;
169         DomeAbsPosNP.s = IPS_BUSY;
170     }
171     else
172     {
173         targetAz       = 0;
174         DomeAbsPosNP.s = IPS_IDLE;
175     }
176 
177     IDSetNumber(&DomeAbsPosNP, nullptr);
178     return ((operation == MOTION_START) ? IPS_BUSY : IPS_OK);
179 }
180 
MoveAbs(double az)181 IPState DomeSim::MoveAbs(double az)
182 {
183     targetAz = az;
184 
185     // Requested position is within one cycle, let's declare it done
186     if (fabs(az - DomeAbsPosN[0].value) < DOME_SPEED)
187         return IPS_OK;
188 
189     // It will take a few cycles to reach final position
190     return IPS_BUSY;
191 }
192 
MoveRel(double azDiff)193 IPState DomeSim::MoveRel(double azDiff)
194 {
195     targetAz = DomeAbsPosN[0].value + azDiff;
196     ;
197 
198     if (targetAz < DomeAbsPosN[0].min)
199         targetAz += DomeAbsPosN[0].max;
200     if (targetAz > DomeAbsPosN[0].max)
201         targetAz -= DomeAbsPosN[0].max;
202 
203     // Requested position is within one cycle, let's declare it done
204     if (fabs(targetAz - DomeAbsPosN[0].value) < DOME_SPEED)
205         return IPS_OK;
206 
207     // It will take a few cycles to reach final position
208     return IPS_BUSY;
209 }
210 
Park()211 IPState DomeSim::Park()
212 {
213     targetAz = DomeParamN[0].value;
214     Dome::ControlShutter(SHUTTER_CLOSE);
215     Dome::MoveAbs(GetAxis1Park());
216 
217     return IPS_BUSY;
218 }
219 
UnPark()220 IPState DomeSim::UnPark()
221 {
222     return Dome::ControlShutter(SHUTTER_OPEN);
223 }
224 
ControlShutter(ShutterOperation operation)225 IPState DomeSim::ControlShutter(ShutterOperation operation)
226 {
227     INDI_UNUSED(operation);
228     shutterTimer = SHUTTER_TIMER;
229     return IPS_BUSY;
230 }
231 
Abort()232 bool DomeSim::Abort()
233 {
234     // If we abort while in the middle of opening/closing shutter, alert.
235     if (DomeShutterSP.s == IPS_BUSY)
236     {
237         DomeShutterSP.s = IPS_ALERT;
238         IDSetSwitch(&DomeShutterSP, "Shutter operation aborted. Status: unknown.");
239         return false;
240     }
241 
242     return true;
243 }
244 
SetCurrentPark()245 bool DomeSim::SetCurrentPark()
246 {
247     SetAxis1Park(DomeAbsPosN[0].value);
248     return true;
249 }
250 
SetDefaultPark()251 bool DomeSim::SetDefaultPark()
252 {
253     // By default set position to 90
254     SetAxis1Park(90);
255     return true;
256 }
257