001: /**
002: * The LX200 class encapsulates an LX200 telescope.
003: * Copyright (C) 1999-2001 Mark Hale
004: * @author Mark Hale
005: */package JSci.astro.telescope;
006:
007: import java.io.*;
008: import javax.comm.*;
009:
010: public final class LX200 extends Object {
011: private SerialPort serial;
012: private InputStreamReader in;
013: private OutputStreamWriter out;
014: /**
015: * Focus rates.
016: */
017: public final static int FOCUS_FAST = 1;
018: public final static int FOCUS_SLOW = 2;
019: /**
020: * Focus directions.
021: */
022: public final static int FOCUS_IN = 1;
023: public final static int FOCUS_OUT = 2;
024: /**
025: * Slew rates.
026: */
027: public final static int SLEW_SLEW = 1;
028: public final static int SLEW_FIND = 2;
029: public final static int SLEW_CENTER = 3;
030: public final static int SLEW_GUIDE = 4;
031: /**
032: * Slew directions.
033: */
034: public final static int SLEW_NORTH = 1;
035: public final static int SLEW_EAST = 2;
036: public final static int SLEW_SOUTH = 3;
037: public final static int SLEW_WEST = 4;
038:
039: /**
040: * Convert RA from a string to a number.
041: */
042: public static float raToFloat(String ra) {
043: final float hrs = Integer.valueOf(ra.substring(0, 2))
044: .floatValue();
045: final float mins = Integer.valueOf(ra.substring(3, 5))
046: .floatValue();
047: final float secs = Integer.valueOf(ra.substring(6, 8))
048: .floatValue();
049: return hrs + mins / 60.0f + secs / 600.0f;
050: }
051:
052: /**
053: * Convert dec from a string to a number.
054: */
055: public static float decToFloat(String dec) {
056: final float degs = Integer.valueOf(dec.substring(0, 3))
057: .floatValue();
058: final float mins = Integer.valueOf(dec.substring(4, 6))
059: .floatValue();
060: final float secs = Integer.valueOf(dec.substring(7, 9))
061: .floatValue();
062: if (degs >= 0.0)
063: return degs + mins / 60.0f + secs / 600.0f;
064: else
065: return degs - mins / 60.0f - secs / 600.0f;
066: }
067:
068: /**
069: * Convert alt from a string to a number.
070: */
071: public static float altToFloat(String alt) {
072: final float degs = Integer.valueOf(alt.substring(0, 3))
073: .floatValue();
074: final float mins = Integer.valueOf(alt.substring(4, 6))
075: .floatValue();
076: final float secs = Integer.valueOf(alt.substring(7, 9))
077: .floatValue();
078: if (degs >= 0.0)
079: return degs + mins / 60.0f + secs / 600.0f;
080: else
081: return degs - mins / 60.0f - secs / 600.0f;
082: }
083:
084: /**
085: * Convert az from a string to a number.
086: */
087: public static float azToFloat(String az) {
088: final float degs = Integer.valueOf(az.substring(0, 3))
089: .floatValue();
090: final float mins = Integer.valueOf(az.substring(4, 6))
091: .floatValue();
092: final float secs = Integer.valueOf(az.substring(7, 9))
093: .floatValue();
094: return degs + mins / 60.0f + secs / 600.0f;
095: }
096:
097: /**
098: * Constructs an LX200 object.
099: */
100: public LX200(String port) {
101: try {
102: CommPortIdentifier portID = CommPortIdentifier
103: .getPortIdentifier(port);
104: serial = (SerialPort) portID.open("LX200", 10);
105: serial.setSerialPortParams(9600, SerialPort.DATABITS_8,
106: SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
107: in = new InputStreamReader(serial.getInputStream());
108: out = new OutputStreamWriter(serial.getOutputStream());
109: setHighPrecision(true);
110: setLongFormat(true);
111: } catch (NoSuchPortException e) {
112: System.err
113: .println("Port does not exist: " + e.getMessage());
114: e.printStackTrace();
115: } catch (PortInUseException e) {
116: System.err.println("Port is in use by another process: "
117: + e.getMessage());
118: e.printStackTrace();
119: } catch (UnsupportedCommOperationException e) {
120: } catch (IOException e) {
121: }
122: }
123:
124: /**
125: * Sets high precision.
126: */
127: public synchronized void setHighPrecision(boolean setHigh)
128: throws IOException {
129: final boolean isHigh = toggleHighPrecision();
130: if (setHigh != isHigh)
131: toggleHighPrecision();
132: }
133:
134: private boolean toggleHighPrecision() throws IOException {
135: char reply[] = new char[14];
136: sendCmd("#:P#");
137: in.read(reply, 0, 14);
138: return (reply[0] == 'H');
139: }
140:
141: /**
142: * Sets long format.
143: */
144: public synchronized void setLongFormat(boolean setLong)
145: throws IOException {
146: final boolean isLong = isLongFormatEnabled();
147: if (setLong != isLong)
148: sendCmd("#:U#");
149: }
150:
151: private boolean isLongFormatEnabled() throws IOException {
152: sendCmd("#:GR#");
153: String reply = readString();
154: return (reply.length() == 9);
155: }
156:
157: /**
158: * Set focus rate.
159: */
160: public synchronized void setFocusRate(int rate) throws IOException {
161: switch (rate) {
162: case FOCUS_FAST:
163: sendCmd("#:FF#");
164: break;
165: case FOCUS_SLOW:
166: sendCmd("#:FS#");
167: break;
168: }
169: }
170:
171: /**
172: * Start focus.
173: */
174: public synchronized void startFocus(int direction)
175: throws IOException {
176: switch (direction) {
177: case FOCUS_IN:
178: sendCmd("#:F+#");
179: break;
180: case FOCUS_OUT:
181: sendCmd("#:F-#");
182: break;
183: }
184: }
185:
186: /**
187: * Stop focus.
188: */
189: public synchronized void stopFocus() throws IOException {
190: sendCmd("#:FQ#");
191: }
192:
193: /**
194: * Set slew rate.
195: */
196: public synchronized void setSlewRate(int rate) throws IOException {
197: switch (rate) {
198: case SLEW_SLEW:
199: sendCmd("#:RS#");
200: break;
201: case SLEW_FIND:
202: sendCmd("#:RM#");
203: break;
204: case SLEW_CENTER:
205: sendCmd("#:RC#");
206: break;
207: case SLEW_GUIDE:
208: sendCmd("#:RG#");
209: break;
210: }
211: }
212:
213: /**
214: * Start slewing the scope.
215: * @param direction the direction to start slewing in.
216: */
217: public synchronized void startSlew(int direction)
218: throws IOException {
219: switch (direction) {
220: case SLEW_NORTH:
221: sendCmd("#:Mn#");
222: break;
223: case SLEW_EAST:
224: sendCmd("#:Me#");
225: break;
226: case SLEW_SOUTH:
227: sendCmd("#:Ms#");
228: break;
229: case SLEW_WEST:
230: sendCmd("#:Mw#");
231: break;
232: }
233: }
234:
235: /**
236: * Stop slewing the scope.
237: * @param direction the direction to stop slewing in.
238: */
239: public synchronized void stopSlew(int direction) throws IOException {
240: switch (direction) {
241: case SLEW_NORTH:
242: sendCmd("#:Qn#");
243: break;
244: case SLEW_EAST:
245: sendCmd("#:Qe#");
246: break;
247: case SLEW_SOUTH:
248: sendCmd("#:Qs#");
249: break;
250: case SLEW_WEST:
251: sendCmd("#:Qw#");
252: break;
253: }
254: }
255:
256: /**
257: * Returns the current RA.
258: */
259: public synchronized String getRA() throws IOException {
260: sendCmd("#:GR#");
261: return readString();
262: }
263:
264: /**
265: * Returns the current dec.
266: */
267: public synchronized String getDec() throws IOException {
268: sendCmd("#:GD#");
269: return readString();
270: }
271:
272: /**
273: * Returns the current alt.
274: */
275: public synchronized String getAlt() throws IOException {
276: sendCmd("#:GA#");
277: return readString();
278: }
279:
280: /**
281: * Returns the current az.
282: */
283: public synchronized String getAz() throws IOException {
284: sendCmd("#:GZ#");
285: return readString();
286: }
287:
288: /**
289: * Sets the object/target coordinates.
290: */
291: public synchronized boolean setObjectCoords(String ra, String dec)
292: throws IOException {
293: boolean rc;
294: sendCmd("#:Sr" + ra + "#");
295: rc = readBoolean();
296: sendCmd("#:Sd" + dec + "#");
297: rc &= readBoolean();
298: return rc;
299: }
300:
301: /**
302: * Slew to the object coordinates.
303: * @return 0 if slew is possible,
304: * 1 if object is below the horizon,
305: * 2 if object is below the higher.
306: */
307: public synchronized int slewToObject() throws IOException {
308: sendCmd("#:MS#");
309: final int rc = in.read();
310: if (rc == '0') {
311: return 0;
312: } else if (rc == '1') {
313: readString();
314: return 1;
315: } else if (rc == '2') {
316: readString();
317: return 2;
318: } else
319: return -1;
320: }
321:
322: /**
323: * Checks the scope's position.
324: * @param ra RA to check against.
325: * @param dec dec to check against.
326: */
327: public synchronized boolean checkPosition(float ra, float dec)
328: throws IOException {
329: final float raError = raToFloat(getRA()) - ra;
330: final float decError = decToFloat(getDec()) - dec;
331: return (Math.abs(raError) <= 1.0 / (15.0 * 30.0))
332: && (Math.abs(decError) <= 1.0 / 30.0);
333: }
334:
335: /**
336: * Check whether the scope is moving.
337: */
338: public synchronized boolean isMoving() throws IOException {
339: final String oldRA = getRA();
340: final String oldDec = getDec();
341: try {
342: Thread.sleep(20000);
343: } catch (InterruptedException e) {
344: }
345: final String newRA = getRA();
346: final String newDec = getDec();
347: return !(newRA.equals(oldRA) && newDec.equals(oldDec));
348: }
349:
350: /**
351: * Returns the local time.
352: */
353: public synchronized String getLocalTime() throws IOException {
354: sendCmd("#:GL#");
355: return readString();
356: }
357:
358: /**
359: * Sets the local time.
360: */
361: public synchronized boolean setLocalTime(String time)
362: throws IOException {
363: sendCmd("#:SL" + time + "#");
364: return readBoolean();
365: }
366:
367: /**
368: * Synchronize the scope coordinates to the object coordinates.
369: */
370: public synchronized void syncCoords() throws IOException {
371: sendCmd("#:CM#");
372: readString();
373: }
374:
375: /**
376: * Sends a command to the scope.
377: */
378: private void sendCmd(String cmd) throws IOException {
379: out.write(cmd);
380: out.flush();
381: }
382:
383: /**
384: * Reads a boolean from the scope.
385: */
386: private boolean readBoolean() throws IOException {
387: return (in.read() == '1');
388: }
389:
390: /**
391: * Reads a string from the scope, dropping the terminating #.
392: */
393: private String readString() throws IOException {
394: StringBuffer msg = new StringBuffer();
395: int ch = in.read();
396: while (ch != '#') {
397: msg.append(ch);
398: ch = in.read();
399: }
400: return msg.toString();
401: }
402:
403: /**
404: * Closes the connection to the scope.
405: */
406: public synchronized void close() throws IOException {
407: in.close();
408: out.close();
409: serial.close();
410: }
411: }
|