View Javadoc

1   /*
2   Copyright (C) 2007 Dirk Huenniger
3   
4   This library is free software; syou can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
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  Lesser General Public License for more details.
13  
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17   */
18  package org.indi.examples;
19  
20  import java.io.IOException;
21  import java.util.Date;
22  
23  import org.indi.clientmessages.GetProperties;
24  import org.indi.objects.Number;
25  import org.indi.objects.NumberVector;
26  import org.indi.objects.Permission;
27  import org.indi.objects.State;
28  import org.indi.objects.Switch;
29  import org.indi.objects.SwitchRule;
30  import org.indi.objects.SwitchVector;
31  import org.indi.reactor.TimerCallback;
32  import org.indi.server.BasicDevice;
33  import org.indi.server.IndiServer;
34  
35  /**
36   * A simple telescope simulator. The telescope can be connected as well as
37   * dsiconnected. It can be asked to move to a specified position and keeps
38   * tracking when it reaches its target
39   * 
40   * @author Dirk Hünniger
41   * 
42   */
43  public class SimpleTelescopeSimulator extends BasicDevice implements
44  	TimerCallback {
45      /**
46       * the switchvector hosting the switch to connect/disconnect the device
47       */
48      private final SwitchVector powerswitch;
49      /**
50       * the name of the switchvector hosting the switch to connect/disconnect the
51       * device
52       */
53      private final String powervectorname = "CONNECTION";
54      /**
55       * the name of the device
56       */
57      private final String name = "Simple Telescope Simulator";
58      /**
59       * the name of the only group in the device
60       */
61      private final String groupname = "Main Control";
62      /**
63       * the name of the vector hosting the position the telescope is pointing to
64       */
65      private final String coordvectorname = "EQUATORIAL_EOD_COORD";
66      /**
67       * the name of the indiobjects.Number to host the declination
68       */
69      private final String decname = "DEC";
70      /**
71       * the name of the indiobjects.Number to host the right ascension
72       */
73      private final String raname = "RA";
74      /**
75       * the Switch to connect/ disconnect the device
76       */
77      private Switch connectswitch = null;
78      /**
79       * the Number vector to keep the coordinates of the telescope
80       */
81      private NumberVector coordinates = null;
82      /**
83       * the time between the calls of the onTimer method in milliseconds
84       */
85      private final long timeout = 250;
86      /**
87       * the siderial movement of the stars in degrees per second
88       */
89      private final double sidrate = 0.004178;
90      /**
91       * the slew rate a which the motor can move the telescope in degrees per
92       * second
93       */
94      private final double slewrate = 1.0;
95      /**
96       * the last time when on timer was called in milliseconds since epoch
97       */
98      private Double lastTime = null;
99      /**
100      * the indiobjects.Number representing the right ascentsion the telescope is
101      * poiting to
102      */
103     private Number ra = null;
104     /**
105      * the indiobjects.Number representing the declination the telescope is
106      * pointing to
107      */
108     private Number dec = null;
109     /**
110      * the right ascension to point to as requested by the user
111      */
112     private double targetRA;
113     /**
114      * the declination to point to as requested by the user
115      */
116     private double targetDEC;
117 
118     /**
119      * class constructor
120      * 
121      * @param server
122      *                the server to host this device
123      */
124     public SimpleTelescopeSimulator(IndiServer server) {
125 	super(server);
126 	this.powerswitch = new SwitchVector(this.name, this.powervectorname,
127 		"Connection", this.groupname, State.Idle, Permission.ReadWrite,
128 		SwitchRule.OneOfMany, 0);
129 	this.connectswitch = new Switch("CONNECT", "Connect", Switch.State.Off);
130 	this.powerswitch.add(this.connectswitch);
131 	this.powerswitch.add(new Switch("DISCONNECT", "Disconnect",
132 		Switch.State.On));
133 	this.coordinates = new NumberVector(this.name, this.coordvectorname,
134 		"Equatorial JNow", this.groupname, State.Idle,
135 		Permission.ReadWrite, 0);
136 	this.ra = new Number(this.raname, /* 1st Number name */
137 	"RA  H:M:S", /* Number label */
138 	"%f", /* Format. Refer to the Indi WhitePaper for number formats */
139 	0., /* Minimum value */
140 	24., /* Maximum value */
141 	0., /* Steps */
142 	0. /* Initial value */);
143 	this.coordinates.add(this.ra);
144 	this.dec = new Number(this.decname, "Dec D:M:S", "%f", -90., 90., 0.,
145 		0.);
146 	this.coordinates.add(this.dec);
147 	def(this.powerswitch);
148 	def(this.coordinates);
149 	timer(this.timeout);
150     }
151 
152     @Override
153     public void onNew(SwitchVector vector) {
154 	if (!((this.powervectorname.equals(vector.getName())) && (this.name
155 		.equals(vector.getDevice())))) {
156 	    return;
157 	}
158 	this.powerswitch.update(vector);
159 	switch (this.connectswitch.getState()) {
160 	case On:
161 	    this.powerswitch.setState(State.Ok);
162 	    set(this.powerswitch, "Connection to Simple Telescope Simulator"
163 		    + " is successful.");
164 	    break;
165 	case Off:
166 	    this.powerswitch.setState(State.Idle);
167 	    set(this.powerswitch,
168 		    "Simple Telescope Simulator has been disconneced.");
169 	    this.coordinates.setState(State.Idle);
170 	    set(this.coordinates);
171 	    break;
172 	}
173     }
174 
175     @Override
176     public void onNew(NumberVector vector) {
177 	if (!((this.coordvectorname.equals(vector.getName())) && (this.name
178 		.equals(vector.getDevice())))) {
179 	    return;
180 	}
181 	if (this.connectswitch.getState() == Switch.State.Off) {
182 	    msg("Position discaded because Telescope is disconnected");
183 	    return;
184 	}
185 	if (this.powerswitch.getState() == State.Idle) {
186 	    this.coordinates.setState(State.Idle);
187 	    set(this.coordinates, "Telescope is offline");
188 	}
189 	double newra = 0, newdec = 0;
190 	int nset = 0;
191 	for (Number n : vector.getChlidren()) {
192 	    String name = n.getName();
193 	    if (name.equals(this.raname)) {
194 		newra = n.getDouble();
195 		nset += ((newra >= 0.) && (newra <= 24.)) ? 1 : 0;
196 	    }
197 	    if (name.equals(this.decname)) {
198 		newdec = n.getDouble();
199 		nset += ((newdec >= -90.) && (newdec <= 90.)) ? 1 : 0;
200 	    }
201 	    if (nset == 2) {
202 		this.targetRA = newra;
203 		this.targetDEC = newdec;
204 		this.coordinates.setState(State.Busy);
205 		set(this.coordinates, "Moving to RA Dec"
206 			+ Double.toString(newra) + " "
207 			+ Double.toString(newdec));
208 	    } else {
209 		this.coordinates.setState(State.Idle);
210 		set(this.coordinates, "RA or Dec absent or bogus");
211 	    }
212 	}
213     }
214 
215     @Override
216     public void onGetProperties(GetProperties o) {
217 	def(this.powerswitch);
218 	def(this.coordinates);
219     }
220 
221     /**
222      * Create an Indiserver hosting a SimpleTelescope simultor an wait for
223      * events.
224      * 
225      * @param args
226      *                command line arguments (ignored)
227      * @throws IOException
228      */
229     public static void main(String[] args) throws IOException {
230 	IndiServer s = new IndiServer();
231 	new SimpleTelescopeSimulator(s);
232 	while (true) {
233 	    s.reactor.handleEvents(10);
234 	}
235     }
236 
237     @Override
238     public void onTimer() {
239 	double time = new Date().getTime();
240 	if (this.lastTime == null) {
241 	    this.lastTime = time;
242 	}
243 	double dt = (time - this.lastTime) / 1000.0;
244 	this.lastTime = time;
245 	switch (this.coordinates.getState()) {
246 	case Idle:
247 	    this.ra.addDouble((this.sidrate * dt / 15.));
248 	    set(this.coordinates);
249 	    break;
250 	case Busy:
251 	    double da = this.slewrate * dt;
252 	    int nlocked = 0;
253 	    double dx = this.targetRA - this.ra.getDouble();
254 	    if (Math.abs(dx) <= da / 15.) {
255 		this.ra.setDouble(this.targetRA);
256 		nlocked++;
257 	    } else if (dx > 0) {
258 		this.ra.addDouble(da / 15.);
259 	    } else {
260 		this.ra.subtractDouble(da / 15.);
261 	    }
262 
263 	    dx = this.targetDEC - this.dec.getDouble();
264 	    if (Math.abs(dx) <= da) {
265 		this.dec.setDouble(this.targetDEC);
266 		nlocked++;
267 	    } else if (dx > 0) {
268 		this.dec.addDouble(da);
269 	    } else {
270 		this.dec.subtractDouble(da);
271 	    }
272 	    if (nlocked == 2) {
273 		this.coordinates.setState(State.Ok);
274 		msg("Now tracking");
275 	    }
276 	    set(this.coordinates);
277 	    break;
278 	case Ok:
279 	    set(this.coordinates);
280 	    break;
281 	case Alert:
282 	    set(this.coordinates);
283 	    break;
284 	}
285 	timer(this.timeout);
286     }
287 }