1 /* 2 Celestron driver 3 4 Copyright (C) 2015 Jasem Mutlaq 5 Copyright (C) 2017 Juan Menendez 6 7 This library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 This library is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with this library; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22 /* 23 Version with experimental pulse guide support. GC 04.12.2015 24 */ 25 26 #pragma once 27 28 #include <string> 29 #include "indicom.h" 30 31 #ifdef __FreeBSD__ 32 #include <stdint.h> 33 typedef uint8_t u_int8_t; 34 #endif 35 36 //#include <thread> 37 //#include <condition_variable> 38 //#include <atomic> 39 40 /* Starsense specific constants */ 41 #define ISNEXSTAR 0x11 42 #define ISSTARSENSE 0x13 43 #define MINSTSENSVER 1.18 44 #define MAX_RESP_SIZE 20 45 46 // device IDs 47 #define CELESTRON_DEV_RA 0x10 48 #define CELESTRON_DEV_DEC 0x11 49 #define CELESTRON_DEV_GPS 0xb0 50 // focuser device 51 #define CELESTRON_DEV_FOC 0x12 52 53 // motor commands 54 #define MC_GET_POSITION 0x01 // return 24 bit position 55 #define MC_GOTO_FAST 0x02 // send 24 bit target 56 #define MC_SET_POS_GUIDERATE 0x06 // use the 2 byte CelestronTrackRates to set the rate 57 #define MC_SET_NEG_GUIDERATE 0x07 // for Southern hemisphere, track mode EQ_S 58 #define MC_LEVEL_START 0x0b // move to switch position 59 #define MC_PEC_RECORD_START 0x0C // n/a Ack Start recording PEC position 60 #define MC_PEC_PLAYBACK 0x0D // 8 bits Ack Start(01)/stop(00) PEC playback 61 62 #define MTR_PECBIN 0x0E // current PEC index - 1 byte 0 - 255(88) 63 64 #define MC_LEVEL_DONE 0x12 // return 0xFF when move finished 65 #define MC_SLEW_DONE 0x13 // return 0xFF when move finished 66 #define MC_PEC_RECORD_DONE 0x15 // n/a 8 bits != 0 is PEC record completed 67 #define MC_PEC_RECORD_STOP 0x16 // n/a n/a Stop PEC recording 68 69 #define MC_GOTO_SLOW 0x17 // 16/24 bits Ack Goto position with slow, variable rate. Either 16 or 24 bit accuracy. 70 // Position is a signed fraction of a full rotation 71 #define MC_AT_INDEX 0x18 // n/a 8 bits FFH at index, 00H not 72 #define MC_SEEK_INDEX 0x19 // n/a n/a Seek PEC Index 73 #define MC_MOVE_POS 0x24 // start move positive direction, rate 0-9, 0 is stop 74 #define MC_MOVE_NEG 0x25 // start move negative direction, rate 0-9, 0 is stop 75 76 #define MTR_AUX_GUIDE 0x26 // aux guide command, rate -100 to 100, duration centiseconds 77 #define MTR_IS_AUX_GUIDE_ACTIVE 0x27 // return 0x00 when aux guide is not in progress 78 79 // command 0x30 and 0x31 are read/ write memory commands 80 #define MC_PEC_READ_DATA 0x30 // 8 PEC data value return 1 byte of data: 81 // 0x3f number of PEC bins (88) 82 // 0x40+i PEC data for bin i 83 #define MC_PEC_WRITE_DATA 0x31 // 16 PEC data address, PEC data value 84 // 0x40+i, value bin i 85 86 #define MC_SET_AUTOGUIDE_RATE 0x46 // 0 to 99 as % sidereal 87 #define MC_GET_AUTOGUIDE_RATE 0x47 // 0 to 99 as % sidereal 88 89 // focuser passthrough commands 90 #define FOC_CALIB_ENABLE 42 // send 0 to start or 1 to stop 91 #define FOC_CALIB_DONE 43 // returns 2 bytes [0] done, [1] state 0-12 92 #define FOC_GET_HS_POSITIONS 44 // returns 2 ints, low and high limits 93 94 // generic device commands 95 #define GET_VER 0xfe // return 2 or 4 bytes major.minor.build 96 97 typedef enum { GPS_OFF, GPS_ON } CELESTRON_GPS_STATUS; 98 typedef enum { SR_1, SR_2, SR_3, SR_4, SR_5, SR_6, SR_7, SR_8, SR_9 } CELESTRON_SLEW_RATE; 99 typedef enum { CTM_OFF, CTM_ALTAZ, CTM_EQN, CTM_EQS, CTM_RADEC } CELESTRON_TRACK_MODE; 100 typedef enum { RA_AXIS, DEC_AXIS } CELESTRON_AXIS; 101 typedef enum { CELESTRON_N, CELESTRON_S, CELESTRON_W, CELESTRON_E } CELESTRON_DIRECTION; 102 typedef enum { FW_MODEL, FW_VERSION, FW_RA, FW_DEC, FW_ISGEM, FW_CAN_AUX, FW_HAS_FOC } CELESTRON_FIRMWARE; 103 104 105 // PEC state machine 106 // the order matters because it's used to check what states are available. 107 // they do not match the the base TelescopePECState 108 typedef enum 109 { 110 NotKnown, // PEC has not been checked. 111 112 /// <summary> 113 /// PEC is not available, hardware has been checked, no other state is possible 114 /// </summary> 115 PEC_NOT_AVAILABLE, 116 117 /// <summary> 118 /// PEC is available but inactive, can seek index 119 /// Seek index is only available command 120 /// </summary> 121 PEC_AVAILABLE, 122 123 /// <summary> 124 /// The PEC index is being searched for, goes to PEC_INDEXED when found 125 /// </summary> 126 PEC_SEEKING, 127 128 /// <summary> 129 /// the PEC index has been found, can go to Playback or Recording 130 /// this is equivalent to TelescopePECState PEC_OFF 131 /// </summary> 132 PEC_INDEXED, 133 134 /// <summary> 135 /// PEC is being played back, stays in this state until stopped 136 /// equivalent to TelescopePECState PEC_ON 137 /// </summary> 138 PEC_PLAYBACK, 139 140 /// <summary> 141 /// PEC is being recorded, goes to PEC_INDEXED when completed 142 /// </summary> 143 PEC_RECORDING 144 145 } PEC_STATE; 146 147 // These values are sent to the hour angle axis motor using the MC_SET_POS|NEG_GUIDERATE 148 // commands to set the tracking rate. 149 typedef enum 150 { 151 CTR_SIDEREAL = 0xFFFF, 152 CTR_SOLAR = 0xFFFE, 153 CTR_LUNAR = 0xFFFD 154 } CELESTRON_TRACK_RATE; 155 156 typedef struct 157 { 158 std::string Model; 159 std::string Version; 160 //std::string GPSFirmware; 161 std::string RAFirmware; 162 std::string DEFirmware; 163 double controllerVersion; 164 char controllerVariant; 165 bool isGem; 166 bool canPec; 167 bool hasHomeIndex; 168 bool hasFocuser; 169 CELESTRON_TRACK_MODE celestronTrackMode; 170 } FirmwareInfo; 171 172 typedef struct 173 { 174 double ra; 175 double dec; 176 double az; 177 double alt; 178 CELESTRON_SLEW_RATE slewRate; 179 CELESTRON_TRACK_MODE trackMode; 180 CELESTRON_GPS_STATUS gpsStatus; 181 bool isSlewing; 182 uint32_t foc_position = 20000; 183 uint32_t foc_target = 20000; 184 } SimData; 185 186 187 /************************************************************************** 188 Utility functions 189 **************************************************************************/ 190 namespace Celestron 191 { 192 double trimDecAngle(double angle); 193 uint16_t dd2nex(double angle); 194 uint32_t dd2pnex(double angle); 195 double nex2dd(uint32_t value); 196 double pnex2dd(uint32_t value); 197 } 198 199 class CelestronDriver 200 { 201 public: CelestronDriver()202 CelestronDriver() {} 203 virtual ~CelestronDriver() = default; 204 205 // Misc. 206 const char *getDeviceName(); set_port_fd(int port_fd)207 void set_port_fd(int port_fd) 208 { 209 fd = port_fd; 210 } set_simulation(bool enable)211 void set_simulation(bool enable) 212 { 213 simulation = enable; 214 } 215 void set_device(const char *name); 216 217 // Simulation set_sim_slew_rate(CELESTRON_SLEW_RATE val)218 void set_sim_slew_rate(CELESTRON_SLEW_RATE val) 219 { 220 sim_data.slewRate = val; 221 } set_sim_track_mode(CELESTRON_TRACK_MODE val)222 void set_sim_track_mode(CELESTRON_TRACK_MODE val) 223 { 224 sim_data.trackMode = val; 225 } set_sim_gps_status(CELESTRON_GPS_STATUS val)226 void set_sim_gps_status(CELESTRON_GPS_STATUS val) 227 { 228 sim_data.gpsStatus = val; 229 } set_sim_slewing(bool isSlewing)230 void set_sim_slewing(bool isSlewing) 231 { 232 sim_data.isSlewing = isSlewing; 233 } set_sim_ra(double ra)234 void set_sim_ra(double ra) 235 { 236 sim_data.ra = ra; 237 } set_sim_dec(double dec)238 void set_sim_dec(double dec) 239 { 240 sim_data.dec = dec; 241 } set_sim_az(double az)242 void set_sim_az(double az) 243 { 244 sim_data.az = az; 245 } set_sim_alt(double alt)246 void set_sim_alt(double alt) 247 { 248 sim_data.alt = alt; 249 } get_sim_ra()250 double get_sim_ra() 251 { 252 return sim_data.ra; 253 } get_sim_dec()254 double get_sim_dec() 255 { 256 return sim_data.dec; 257 } get_sim_foc_offset()258 int get_sim_foc_offset() 259 { 260 return sim_data.foc_target - sim_data.foc_position; 261 } move_sim_foc(int offset)262 void move_sim_foc(int offset) 263 { 264 sim_data.foc_position += offset; 265 } 266 267 bool echo(); 268 bool check_connection(); 269 270 // Get info 271 bool get_firmware(FirmwareInfo *info); 272 bool get_version(char *version, size_t size); 273 bool get_variant(char *variant); 274 int model(); // returns model number, -1 if failed 275 bool get_model(char *model, size_t size, bool *isGem, bool *canPec, bool *hasHomeIndex); 276 bool get_dev_firmware(int dev, char *version, size_t size); 277 bool get_radec(double *ra, double *dec, bool precise); 278 bool get_azalt(double *az, double *alt, bool precise); 279 bool get_utc_date_time(double *utc_hours, int *yy, int *mm, int *dd, int *hh, int *minute, int *ss, bool *dst, 280 bool precise); 281 282 // Motion 283 bool start_motion(CELESTRON_DIRECTION dir, CELESTRON_SLEW_RATE rate); 284 bool stop_motion(CELESTRON_DIRECTION dir); 285 bool abort(); 286 bool slew_radec(double ra, double dec, bool precise); 287 bool slew_azalt(double az, double alt, bool precise); 288 bool sync(double ra, double dec, bool precise); 289 bool unsync(); 290 291 // Time & Location 292 bool set_location(double longitude, double latitude); 293 bool get_location(double* longitude, double *latitude); 294 bool set_datetime(struct ln_date *utc, double utc_offset, bool dst = false, bool precise = false); 295 296 // Track Mode, this is not the Indi track mode 297 bool get_track_mode(CELESTRON_TRACK_MODE *mode); 298 bool set_track_mode(CELESTRON_TRACK_MODE mode); 299 300 bool is_slewing(bool *slewing); 301 302 // Hibernate/Wakeup/ align 303 bool hibernate(); 304 bool wakeup(); 305 bool lastalign(); 306 bool startmovetoindex(); 307 bool indexreached(bool *atIndex); 308 309 // Pulse Guide 310 size_t send_pulse(CELESTRON_DIRECTION direction, unsigned char rate, unsigned char duration_msec); 311 bool get_pulse_status(CELESTRON_DIRECTION direction); 312 313 // get and set guide rate 314 // 0 to 255 corresponding to 0 to 100% sidereal 315 bool get_guide_rate(CELESTRON_AXIS axis, u_int8_t * rate); 316 bool set_guide_rate(CELESTRON_AXIS axis, u_int8_t rate); 317 318 // Pointing state, pier side, returns 'E' or 'W' 319 bool get_pier_side(char * sop); 320 321 // check if the mount is aligned using the mount J command 322 bool check_aligned(bool *isAligned); 323 324 // set the tracking rate, sidereal, solar or lunar 325 bool set_track_rate(CELESTRON_TRACK_RATE rate, CELESTRON_TRACK_MODE mode); 326 327 // focuser commands 328 bool foc_exists(); // read version 329 int foc_position(); // read position, return -1 if failed 330 bool foc_move(uint32_t steps); // start move 331 bool foc_moving(); // return true if moving 332 bool foc_limits(int * low, int * high); // read limits 333 bool foc_abort(); // stop move 334 335 // PEC management 336 337 PEC_STATE pecState { PEC_STATE::NotKnown }; 338 339 PEC_STATE updatePecState(); 340 341 bool PecSeekIndex(); 342 bool isPecAtIndex(bool force = false); // returns true if the PEC index has been found 343 344 size_t pecIndex(); // reads the current PEC index 345 int getPecValue(size_t index); // reads the current PEC value 346 bool setPecValue(size_t index, int data); 347 348 bool PecPlayback(bool start); 349 350 bool PecRecord(bool start); 351 bool isPecRecordDone(); 352 353 size_t getPecNumBins(); 354 355 const char *PecStateStr(PEC_STATE); 356 const char *PecStateStr(); 357 358 // PEC simulation properties 359 int simIndex; 360 int simRecordStart; 361 bool simSeekIndex = false; 362 363 protected: 364 void set_sim_response(const char *fmt, ...); 365 virtual int serial_write(const char *cmd, int nbytes, int *nbytes_written); 366 virtual int serial_read(int nbytes, int *nbytes_read); 367 virtual int serial_read_section(char stop_char, int *nbytes_read); 368 369 size_t send_command(const char *cmd, size_t cmd_len, char *resp, size_t resp_len, 370 bool ascii_cmd, bool ascii_resp); 371 size_t send_passthrough(int dest, int cmd_id, const char *payload, 372 size_t payload_len, char *resp, size_t response_len); 373 374 char response[MAX_RESP_SIZE]; 375 bool simulation = false; 376 SimData sim_data; 377 int fd = 0; 378 379 char sim_ra_guide_rate = 50; 380 char sim_dec_guide_rate = 50; 381 }; 382 383 class PecData 384 { 385 public: 386 PecData(); 387 388 // save PEC data to a file 389 bool Save(const char * filename); 390 391 // saves PEC data to mount 392 bool Save(CelestronDriver * driver); 393 394 // Loads PEC data from mount 395 bool Load(CelestronDriver * driver); 396 397 // Loads PEC data from file 398 bool Load(const char * fileName); 399 NumBins()400 size_t NumBins() 401 { 402 return numBins; 403 } 404 405 void RemoveDrift(); 406 407 const char *getDeviceName(); 408 // void set_device(const char *name); 409 410 private: 411 double wormArcSeconds = 7200; 412 double rateScale = 1024; 413 size_t numBins = 88; 414 const double SIDEREAL_ARCSEC_PER_SEC = 360.0 * 60.0 * 60.0 / (23.0 * 3600.0 + 56 * 60 + 4.09); 415 416 double data[255]; // numbins + 1 values, accumulated PEC offset in arc secs. First one zero 417 418 void Kalman(PecData newData, int num); 419 }; 420 421 422