33 #define AXIS_TAB "Axis Settings"
43 SetTelescopeCapability(TELESCOPE_CAN_SYNC | TELESCOPE_HAS_LOCATION, 0);
48 return (
const char *)
"Digital Setting Circle";
56 IUFillNumber(&EncoderN[AXIS1_ENCODER],
"AXIS1_ENCODER",
"Axis 1",
"%0.f", 0, 1e6, 0, 0);
57 IUFillNumber(&EncoderN[AXIS2_ENCODER],
"AXIS2_ENCODER",
"Axis 2",
"%0.f", 0, 1e6, 0, 0);
58 IUFillNumber(&EncoderN[AXIS1_RAW_ENCODER],
"AXIS1_RAW_ENCODER",
"RAW Axis 1",
"%0.f", -1e6, 1e6, 0, 0);
59 IUFillNumber(&EncoderN[AXIS2_RAW_ENCODER],
"AXIS2_RAW_ENCODER",
"RAW Axis 2",
"%0.f", -1e6, 1e6, 0, 0);
64 IUFillNumber(&AxisSettingsN[AXIS1_TICKS],
"AXIS1_TICKS",
"#1 ticks/rev",
"%g", 256, 1e6, 0, 4096);
65 IUFillNumber(&AxisSettingsN[AXIS1_DEGREE_OFFSET],
"AXIS1_DEGREE_OFFSET",
"#1 Degrees Offset",
"%g", -180, 180, 30,
67 IUFillNumber(&AxisSettingsN[AXIS2_TICKS],
"AXIS2_TICKS",
"#2 ticks/rev",
"%g", 256, 1e6, 0, 4096);
68 IUFillNumber(&AxisSettingsN[AXIS2_DEGREE_OFFSET],
"AXIS2_DEGREE_OFFSET",
"#2 Degrees Offset",
"%g", -180, 180, 30,
87 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS1_SCALE],
"OFFSET_AXIS1_SCALE",
"#1 Ticks Scale",
"%g", 0, 1e6, 0, 1);
88 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS1_OFFSET],
"OFFSET_AXIS1_OFFSET",
"#1 Ticks Offset",
"%g", -1e6, 1e6, 0, 0);
89 IUFillNumber(&EncoderOffsetN[AXIS1_DEGREE_OFFSET],
"AXIS1_DEGREE_OFFSET",
"#1 Degrees Offset",
"%g", -180, 180, 30, 0);
90 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS2_SCALE],
"OFFSET_AIXS2_SCALE",
"#2 Ticks Scale",
"%g", 0, 1e6, 0, 1);
91 IUFillNumber(&EncoderOffsetN[OFFSET_AXIS2_OFFSET],
"OFFSET_AXIS2_OFFSET",
"#2 Ticks Offset",
"%g", -1e6, 1e6, 0, 0);
92 IUFillNumber(&EncoderOffsetN[AXIS2_DEGREE_OFFSET],
"AXIS2_DEGREE_OFFSET",
"#2 Degrees Offset",
"%g", -180, 180, 30, 0);
104 IUFillNumber(&SimEncoderN[AXIS1_ENCODER],
"AXIS1_ENCODER",
"Axis 1",
"%0.f", -1e6, 1e6, 0, 0);
105 IUFillNumber(&SimEncoderN[AXIS2_ENCODER],
"AXIS2_ENCODER",
"Axis 2",
"%0.f", -1e6, 1e6, 0, 0);
111 InitAlignmentProperties(
this);
122 defineProperty(&EncoderNP);
123 defineProperty(&AxisSettingsNP);
124 defineProperty(&AxisRangeSP);
125 defineProperty(&ReverseSP);
127 defineProperty(&MountTypeSP);
130 defineProperty(&SimEncoderNP);
132 SetAlignmentSubsystemActive(
true);
136 deleteProperty(EncoderNP.name);
137 deleteProperty(AxisSettingsNP.name);
138 deleteProperty(AxisRangeSP.name);
139 deleteProperty(ReverseSP.name);
141 deleteProperty(MountTypeSP.name);
144 deleteProperty(SimEncoderNP.name);
163 bool DSC::ISNewText(
const char *dev,
const char *name,
char *texts[],
char *names[],
int n)
165 ProcessAlignmentTextProperties(
this, name, texts, names, n);
170 bool DSC::ISNewNumber(
const char *dev,
const char *name,
double values[],
char *names[],
int n)
174 if (strcmp(name, AxisSettingsNP.name) == 0)
177 AxisSettingsNP.s =
IPS_OK;
190 if (strcmp(name, SimEncoderNP.name) == 0)
198 ProcessAlignmentNumberProperties(
this, name, values, names, n);
208 if (strcmp(name, ReverseSP.name) == 0)
216 if (strcmp(name, MountTypeSP.name) == 0)
224 if (strcmp(name, AxisRangeSP.name) == 0)
229 if (AxisRangeS[AXIS_FULL_STEP].s ==
ISS_ON)
231 LOGF_INFO(
"Axis range is from 0 to %.f", AxisSettingsN[AXIS1_TICKS].value);
235 LOGF_INFO(
"Axis range is from -%.f to %.f",
236 AxisSettingsN[AXIS1_TICKS].value / 2, AxisSettingsN[AXIS1_TICKS].value / 2);
242 ProcessAlignmentSwitchProperties(
this, name, states, names, n);
256 char CR[1] = { 0x51 };
258 char response[16] = { 0 };
259 int rc = 0, nbytes_read = 0, nbytes_written = 0;
265 snprintf(response, 16,
"%06.f\t%06.f", SimEncoderN[AXIS1_ENCODER].value, SimEncoderN[AXIS2_ENCODER].value);
269 tcflush(PortFD, TCIFLUSH);
275 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
284 if (nbytes_read < 12)
288 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
296 double Axis1Encoder = 0, Axis2Encoder = 0;
297 std::regex rgx(R
"((\+?\-?\d+)\s(\+?\-?\d+))");
299 std::string input(response);
301 if (std::regex_search(input, match, rgx))
303 Axis1Encoder = atof(match.str(1).c_str());
304 Axis2Encoder = atof(match.str(2).c_str());
308 LOGF_ERROR(
"Error processing response: %s", response);
314 LOGF_DEBUG(
"Raw Axis encoders. Axis1: %g Axis2: %g", Axis1Encoder, Axis2Encoder);
316 EncoderN[AXIS1_RAW_ENCODER].value = Axis1Encoder;
317 EncoderN[AXIS2_RAW_ENCODER].value = Axis2Encoder;
320 if (AxisRangeS[AXIS_HALF_STEP].s ==
ISS_ON)
322 if (Axis1Encoder < 0)
323 Axis1Encoder += AxisSettingsN[AXIS1_TICKS].value;
325 if (Axis2Encoder < 0)
326 Axis2Encoder += AxisSettingsN[AXIS2_TICKS].value;
330 double Axis1 = Axis1Encoder;
331 if (ReverseS[AXIS1_ENCODER].s ==
ISS_ON)
332 Axis1 = AxisSettingsN[AXIS1_TICKS].value - Axis1;
336 Axis1Diff += AxisSettingsN[AXIS1_TICKS].value;
337 else if (Axis1Diff > AxisSettingsN[AXIS1_TICKS].value)
338 Axis1Diff -= AxisSettingsN[AXIS1_TICKS].value;
341 double Axis2 = Axis2Encoder;
342 if (ReverseS[AXIS2_ENCODER].s ==
ISS_ON)
343 Axis2 = AxisSettingsN[AXIS2_TICKS].value - Axis2;
345 LOGF_DEBUG(
"Axis encoders after reverse. Axis1: %g Axis2: %g", Axis1, Axis2);
355 EncoderN[AXIS1_ENCODER].value = Axis1;
356 EncoderN[AXIS2_ENCODER].value = Axis2;
360 double Axis1Degrees = (Axis1 / AxisSettingsN[AXIS1_TICKS].value * 360.0) + AxisSettingsN[AXIS1_DEGREE_OFFSET].value;
361 double Axis2Degrees = (Axis2 / AxisSettingsN[AXIS2_TICKS].value * 360.0) + AxisSettingsN[AXIS2_DEGREE_OFFSET].value;
363 Axis1Degrees =
range360(Axis1Degrees);
364 Axis2Degrees =
range360(Axis2Degrees);
373 if (MountTypeS[MOUNT_EQUATORIAL].s ==
ISS_ON)
375 encoderEquatorialCoordinates.rightascension = Axis1Degrees / 15.0;
377 encoderEquatorialCoordinates.rightascension += LST;
378 encoderEquatorialCoordinates.rightascension =
range24(encoderEquatorialCoordinates.rightascension);
380 encoderEquatorialCoordinates.declination =
rangeDec(Axis2Degrees);
383 eq = TelescopeEquatorialToSky();
387 encoderHorizontalCoordinates.azimuth = Axis1Degrees;
388 encoderHorizontalCoordinates.azimuth += 180;
389 encoderHorizontalCoordinates.azimuth =
range360(encoderHorizontalCoordinates.azimuth);
391 encoderHorizontalCoordinates.altitude = Axis2Degrees;
394 eq = TelescopeHorizontalToSky();
396 char AzStr[64], AltStr[64];
397 fs_sexa(AzStr, Axis1Degrees, 2, 3600);
398 fs_sexa(AltStr, Axis2Degrees, 2, 3600);
399 LOGF_DEBUG(
"Current Az: %s Current Alt: %s", AzStr, AltStr);
403 NewRaDec(
eq.rightascension,
eq.declination);
413 if (MountTypeS[MOUNT_EQUATORIAL].s ==
ISS_ON)
416 RaDec.rightascension =
range24(LST - encoderEquatorialCoordinates.rightascension);
417 RaDec.declination = encoderEquatorialCoordinates.declination;
421 AltAz.azimuth = encoderHorizontalCoordinates.azimuth;
422 AltAz.altitude = encoderHorizontalCoordinates.altitude;
429 if (MountTypeS[MOUNT_EQUATORIAL].s ==
ISS_ON)
430 NewEntry.
TelescopeDirection = TelescopeDirectionVectorFromLocalHourAngleDeclination(RaDec);
439 if (!CheckForDuplicateSyncPoint(NewEntry))
441 GetAlignmentDatabase().push_back(NewEntry);
457 double RightAscension, Declination;
460 if (GetAlignmentDatabase().size() > 1)
469 lha = lha * 360 / 24;
470 eq.rightascension = lha;
471 eq.declination = encoderEquatorialCoordinates.declination;
472 TDV = TelescopeDirectionVectorFromLocalHourAngleDeclination(
eq);
474 if (!TransformTelescopeToCelestial(TDV, RightAscension, Declination))
476 RightAscension = encoderEquatorialCoordinates.rightascension;
477 Declination = encoderEquatorialCoordinates.declination;
484 RightAscension = encoderEquatorialCoordinates.rightascension;
485 Declination = encoderEquatorialCoordinates.declination;
488 eq.rightascension = RightAscension;
489 eq.declination = Declination;
497 double RightAscension, Declination;
499 if (!TransformTelescopeToCelestial(TDV, RightAscension, Declination))
504 switch (GetApproximateMountAlignment())
512 RotatedTDV.RotateAroundY(90.0 - m_Location.latitude);
513 AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, encoderHorizontalCoordinates);
519 RotatedTDV.RotateAroundY(-90.0 - m_Location.latitude);
520 AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, encoderHorizontalCoordinates);
525 RightAscension = EquatorialCoordinates.rightascension;
526 Declination = EquatorialCoordinates.declination;
529 eq.rightascension = RightAscension;
530 eq.declination = Declination;
536 UpdateLocation(latitude, longitude, elevation);
547 defineProperty(&SimEncoderNP);
551 deleteProperty(SimEncoderNP.name);
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual const char * getDefaultName() override
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
std::unique_ptr< DSC > dsc(new DSC())
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
double range24(double r)
range24 Limits a number to be between 0-24 range.
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
double rangeDec(double decdegrees)
rangeDec Limits declination value to be in -90 to 90 range.
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[].
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Implementations for common driver routines.
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#define LOGF_INFO(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOGF_ERROR(fmt,...)
#define DEBUGF(priority, msg,...)
Namespace to encapsulate the INDI Alignment Subsystem classes. For more information see "INDI Alignme...
void HorizontalToEquatorial(IHorizontalCoordinates *object, IGeographicCoordinates *observer, double JD, IEquatorialCoordinates *position)
HorizontalToEquatorial Calculate Equatorial EOD Coordinates from horizontal coordinates.
const char * getDeviceName()
Entry in the in memory alignment database.
double RightAscension
Right ascension in decimal hours. N.B. libnova works in decimal degrees so conversion is always neede...
double ObservationJulianDate
TelescopeDirectionVector TelescopeDirection
Normalised vector giving telescope pointing direction. This is referred to elsewhere as the "apparent...
double Declination
Declination in decimal degrees.
int PrivateDataSize
This size in bytes of any private data.
Holds a nomalised direction vector (direction cosines)