1 /*
2  *  scope_equinox.cpp
3  *  PHD Guiding
4  *
5  *  Created by Craig Stark.
6  *  Copyright (c) 2008-2010 Craig Stark.
7  *  All rights reserved.
8  *
9  *  This source code is distributed under the following "BSD" license
10  *  Redistribution and use in source and binary forms, with or without
11  *  modification, are permitted provided that the following conditions are met:
12  *    Redistributions of source code must retain the above copyright notice,
13  *     this list of conditions and the following disclaimer.
14  *    Redistributions in binary form must reproduce the above copyright notice,
15  *     this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *    Neither the name of Craig Stark, Stark Labs nor the names of its
18  *     contributors may be used to endorse or promote products derived from
19  *     this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  *  POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 #include "phd.h"
36 
37 #ifdef GUIDE_EQUINOX
38 
39 #if defined (__APPLE__)
40 #include <CoreServices/CoreServices.h>
41 //#include <CoreServices/AppleEvents.h>
42 //#include <Foundation/Foundation.h>
43 //#include <AppleEvents.h>
44 //#include <AEDataModel.h>
45 
46 // Code originally from Darryl @ Equinox
47 
E6AESendRoutine(double ewCorrection,double nsCorrection,int mountcode)48 OSErr ScopeEquinox::E6AESendRoutine(double ewCorrection, double nsCorrection, int mountcode)
49 {
50 // correction values (+- seconds) to send to E6
51 
52     OSErr err;
53     FourCharCode E6Sig = 'MPj6';  // the Equinox 6 creator signature
54     if (mountcode == SCOPE_EQMAC)
55         E6Sig = 'EQMC';
56     FourCharCode phdSig = 'PhDG';  // ***** you need to fill in your app signature here ******
57     AEAddressDesc addDesc;
58 
59     AEEventClass evClass = 'phdG';  // the phd guide class.
60     AEEventID evID = 'evGD';  // the phd guide event.
61     AEKeyword  keyObject;
62     AESendMode mode = kAEWaitReply;  //  you want something back
63 
64     // create Apple Event with Equinox 6 signature
65 
66     err = AECreateDesc( typeApplSignature, (Ptr) &E6Sig, sizeof(FourCharCode), &addDesc );  // make a description
67     if( err != noErr ) return err;
68 
69     err = AECreateAppleEvent( evClass, evID, &addDesc, kAutoGenerateReturnID, kAnyTransactionID, &E6Event );  // create the AE
70     if( err != noErr ) {
71         AEDisposeDesc( &addDesc );
72         return err;
73     }
74 
75     // create the return Apple Event with your signature (so I know where to send it)
76 
77     err = AECreateDesc( typeApplSignature, (Ptr) &phdSig, sizeof(FourCharCode), &addDesc );
78     if( err != noErr ) {
79         AEDisposeDesc( &E6Event );
80         return err;
81     }
82 
83     err = AECreateAppleEvent( evClass, evID, &addDesc, kAutoGenerateReturnID, kAnyTransactionID, &E6Return );
84     if( err != noErr ) {
85         AEDisposeDesc( &E6Event );
86         AEDisposeDesc( &addDesc );
87         return err;
88     }
89 
90     // put the correction values into parameters - I have used doubles for a ew and ns seconds correction
91 
92     keyObject = 'prEW';  // EW correction AE parameter (+ = east, - = west)
93     err = AEPutParamPtr( &E6Event, keyObject, typeIEEE64BitFloatingPoint,  &ewCorrection, sizeof(double) );
94     if( err != noErr ) {
95         AEDisposeDesc( &E6Event );
96         AEDisposeDesc( &addDesc );
97         return err;
98     }
99 
100     keyObject = 'prNS';  // NS correction AE parameter (+ = north, - = south)
101     err = AEPutParamPtr( &E6Event, keyObject, typeIEEE64BitFloatingPoint, &nsCorrection, sizeof(double) );
102     if( err != noErr ) {
103         AEDisposeDesc( &E6Event );
104         AEDisposeDesc( &addDesc );
105         return err;
106     }
107 
108     // you now have the send AE, the return AE and the correction values in AE parameters - so send it!
109 
110     err = AESendMessage( &E6Event, &E6Return, mode, kAEDefaultTimeout );  // you can specify a wait time (in ticks)
111     if( err != noErr ) {  // Note: an error of -600 means E6 is not currently running
112         AEDisposeDesc( &E6Event );
113         AEDisposeDesc( &addDesc );
114         return err;
115     }
116 
117     // at this point you have received the return AE from E6, so go read the return code (what do you want returned ??)
118     // the return code could indicate that E6 got the AE, can do it, or can't for some reason. You do NOT want to wait
119     // until the corrections have been applied - you should time that on your own.
120 
121     keyObject = 'prRC';  // get return code
122     Size returnSize;
123     DescType returnType;
124     err = AEGetParamPtr( &E6Return, keyObject, typeSInt16, &returnType, &E6ReturnCode, sizeof(SInt16), &returnSize );
125 
126     AEDisposeDesc( &E6Event );
127     AEDisposeDesc( &addDesc );
128     return 0;
129 }
130 
Connect()131 bool ScopeEquinox::Connect()
132 {
133     // Check the E6 connection by sending 0,0 to it and checking E6Return
134     OSErr err = E6AESendRoutine(0.0,0.0,SCOPE_EQUINOX);
135     wxString prefix = "E6";
136 //  if (mountcode == SCOPE_EQMAC) prefix = "EQMAC";
137     if (E6ReturnCode == -1) {
138         wxMessageBox (prefix + " responded it's not connected to a mount",_("Error"));
139         return true;
140     }
141     else if (err == -600) {
142         wxMessageBox (prefix + " not running",_("Error"));
143         return true;
144     }
145 
146     Scope::Connect();
147 
148     return false;
149 }
150 
Guide(GUIDE_DIRECTION direction,int duration)151 Mount::MOVE_RESULT ScopeEquinox::Guide(GUIDE_DIRECTION direction, int duration)
152 {
153     double NSTime = 0.0;
154     double EWTime = 0.0;
155 
156     switch (direction) {
157         case NORTH:
158             NSTime = (double) duration / 1000.0;
159             break;
160         case SOUTH:
161             NSTime = (double) duration / -1000.0;
162             break;
163         case EAST:
164             EWTime = (double) duration / 1000.0;
165             break;
166         case WEST:
167             EWTime = (double) duration / -1000.0;
168             break;
169         case NONE:
170             break;
171     }
172 
173     OSErr err = E6AESendRoutine(EWTime, NSTime,SCOPE_EQUINOX);
174     wxString prefix = "E6";
175     //if (mountcode == SCOPE_EQMAC) prefix = "EQMAC";
176     if (E6ReturnCode == -1) {
177         pFrame->Alert(prefix + _(" responded it's not connected to a mount"));
178         return MOVE_ERROR;
179     }
180     else if (err == -600) {
181         pFrame->Alert(prefix + _(" not running"));
182         return MOVE_ERROR;
183     }
184     wxMilliSleep(duration);
185 
186     return MOVE_OK;
187 }
188 
189 #endif
190 #endif /* GUIDE_EQUINOX */
191