44 #define LX200_TIMEOUT 5
46 #define MANUAL_SLEWING_SPEED_ID 120
47 #define GOTO_SLEWING_SPEED_ID 140
48 #define MOVE_SPEED_ID 145
49 #define GUIDING_SPEED_ID 150
50 #define GUIDING_SPEED_RA_ID 151
51 #define GUIDING_SPEED_DEC_ID 152
52 #define CENTERING_SPEED_ID 170
53 #define SERVO_POINTING_PRECISION_ID 401
54 #define PEC_MAX_STEPS_ID 27
55 #define PEC_COUNTER_ID 501
56 #define PEC_STATUS_ID 509
57 #define PEC_START_TRAINING_ID 530
58 #define PEC_ABORT_TRAINING_ID 535
59 #define PEC_REPLAY_ON_ID 531
60 #define PEC_REPLAY_OFF_ID 532
61 #define PEC_ENABLE_AT_BOOT_ID 508
62 #define PEC_GUIDING_SPEED_ID 502
63 #define SERVO_FIRMWARE 400
64 #define FLIP_POINT_EAST_ID 227
65 #define FLIP_POINT_WEST_ID 228
66 #define FLIP_POINTS_ENABLED_ID 229
67 #define SET_SAFETY_LIMIT_TO_CURRENT_ID 220
68 #define EAST_SAFETY_LIMIT_ID 221
69 #define WEST_SAFETY_LIMIT_ID 222
70 #define WEST_GOTO_SAFETY_LIMIT_ID 223
90 return "Losmandy Gemini";
97 if (!activeConnection->
name().compare(
"CONNECTION_TCP"))
124 IUFillText(&VersionT[FIRMWARE_DATE],
"Build Date",
"",
"");
125 IUFillText(&VersionT[FIRMWARE_TIME],
"Build Time",
"",
"");
126 IUFillText(&VersionT[FIRMWARE_LEVEL],
"Software Level",
"",
"");
127 IUFillText(&VersionT[FIRMWARE_NAME],
"Product Name",
"",
"");
143 IUFillNumber(&ManualSlewingSpeedN[0],
"MANUAL_SLEWING_SPEED",
"Manual Slewing Speed",
"%g", 20, 2000., 10., 800);
147 IUFillNumber(&GotoSlewingSpeedN[0],
"GOTO_SLEWING_SPEED",
"Goto Slewing Speed",
"%g", 20, 2000., 10., 800);
151 IUFillNumber(&MoveSpeedN[0],
"MOVE_SPEED",
"Move Speed",
"%g", 20, 2000., 10., 10);
155 IUFillNumber(&GuidingSpeedBothN[GUIDING_BOTH],
"GUIDING_SPEED",
"Guide Speed RA/DEC",
"%g", 0.2, 0.8, 0.1, 0.5);
160 IUFillNumber(&GuidingSpeedN[GUIDING_WE],
"GUIDE_RATE_WE",
"W/E Rate",
"%g", 0.2, 0.8, 0.1, 0.5);
161 IUFillNumber(&GuidingSpeedN[GUIDING_NS],
"GUIDE_RATE_NS",
"N/S Rate",
"%g", 0.2, 0.8, 0.1, 0.5);
165 IUFillNumber(&CenteringSpeedN[0],
"CENTERING_SPEED",
"Centering Speed",
"%g", 20, 2000., 10., 10);
175 IUFillSwitch(&PECControlS[PEC_START_TRAINING],
"PEC_START_TRAINING",
"Start Training",
ISS_OFF);
176 IUFillSwitch(&PECControlS[PEC_ABORT_TRAINING],
"PEC_ABORT_TRAINING",
"Abort Training",
ISS_OFF);
180 IUFillText(&PECStateT[PEC_STATUS_ACTIVE],
"PEC_STATUS_ACTIVE",
"PEC active",
"");
181 IUFillText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"PEC_STATUS_FRESH_TRAINED",
"PEC freshly trained",
"");
182 IUFillText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"PEC_STATUS_TRAINING_IN_PROGRESS",
"PEC training in progress",
"");
183 IUFillText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"PEC_STATUS_TRAINING_COMPLETED",
"PEC training just completed",
"");
184 IUFillText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"PEC_STATUS_WILL_TRAIN",
"PEC will train soon",
"");
186 IUFillText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"PEC_STATUS_DATA_AVAILABLE",
"PEC Data available",
"");
190 IUFillText(&PECCounterT[0],
"PEC_COUNTER",
"Counter",
"");
194 IUFillNumber(&PECMaxStepsN[0],
"PEC_MAX_STEPS",
"PEC MaxSteps",
"%f", 0, 4294967296, 1, 0);
203 IUFillNumber(&PECGuidingSpeedN[0],
"PEC_GUIDING_SPEED",
"PEC GuidingSpeed",
"%f", 0.2, 0.8, 0.1, 0);
217 IUFillNumber(&FlipPositionN[FLIP_EAST_VALUE],
"FLIP_EAST_VALUE",
"East (dd:mm)",
"%060.4m", 0, 90, 0, 0.0);
218 IUFillNumber(&FlipPositionN[FLIP_WEST_VALUE],
"FLIP_WEST_VALUE",
"West (dd:mm)",
"%060.4m", 0, 90, 0, 0.0);
232 IUFillNumber(&SafetyLimitsN[EAST_SAFETY],
"EAST_SAFTEY",
"East Safety(dd:mm)",
"%060.4m", 0, 180, 0, 0.0);
233 IUFillNumber(&SafetyLimitsN[WEST_SAFETY],
"WEST_SAFTEY",
"West Safety(dd:mm)",
"%060.4m", 0, 180, 0, 0.0);
234 IUFillNumber(&SafetyLimitsN[WEST_GOTO],
"WEST_GOTO",
"West Goto (dd:mm)",
"%060.4m", 0, 180, 0, 0.0);
238 gemini_software_level_ = 0.0;
243 bool LX200Gemini::getRefractionJNOW(
int &data)
249 char response[2] = { 0 };
250 int rc = 0, nbytes_read = 0, nbytes_written = 0;
253 tcflush(
PortFD, TCIFLUSH);
255 const char *
cmd =
":p?#";
261 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
270 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
273 tcflush(
PortFD, TCIFLUSH);
276 data = atoi(response);
280 bool LX200Gemini::getRefraction(
bool &on)
287 bool success = getRefractionJNOW(data);
292 if((data != 2) && (data != 0))
294 LOGF_WARN(
"Mount Precess being reset to JNOW: %i", data);
296 return setRefraction(2);
299 if((data != 2) && (data != 0)) {
300 LOGF_WARN(
"Mount Precess being reset to JNOW: %i", data);
302 return setRefraction(0);
308 bool LX200Gemini::setRefraction(
int data)
313 int rc = 0, nbytes_written = 0;
315 tcflush(
PortFD, TCIFLUSH);
318 snprintf(
cmd, 5,
":p%i#", data);
324 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
327 tcflush(
PortFD, TCIFLUSH);
332 bool LX200Gemini::setRefraction(
bool on)
339 getRefractionJNOW(data);
342 if((data != 2) && (data != 0))
344 LOGF_WARN(
"Mount Precess being reset to JNOW %i ", data);
346 return setRefraction(2);
348 if((data != 2) && (data != 0)) {
349 LOGF_WARN(
"Mount Precess being reset to JNOW %i", data);
351 return setRefraction(0);
355 void LX200Gemini::syncState() {
361 if (gemini_software_level_ >= 5.0)
366 sscanf(value,
"%f", &guiding_value);
367 GuidingSpeedN[GUIDING_WE].value = guiding_value;
376 sscanf(value,
"%f", &guiding_value);
377 GuidingSpeedN[GUIDING_NS].value = guiding_value;
384 if (gemini_software_level_ >= 5.2)
388 uint32_t pec_at_boot_value;
389 sscanf(value,
"%u", &pec_at_boot_value);
390 if(pec_at_boot_value)
392 PECEnableAtBootS[0].s =
ISS_ON;
394 PECEnableAtBootS[0].s =
ISS_OFF;
402 if(gemini_software_level_ >= 6.0)
407 sscanf(value,
"%c", &servo_value);
408 if(servo_value & RA_PRECISION_ENABLED)
410 ServoPrecisionS[SERVO_RA].s =
ISS_ON;
412 ServoPrecisionS[SERVO_RA].s =
ISS_OFF;
414 if(servo_value & DEC_PRECISION_ENABLED)
416 ServoPrecisionS[SERVO_DEC].s =
ISS_ON;
418 ServoPrecisionS[SERVO_DEC].s =
ISS_OFF;
429 char valueString[32] = {0};
430 uint32_t flip_value = 0;
431 sscanf(value,
"%u", &flip_value);
432 snprintf(valueString, 32,
"%i", flip_value);
435 if(flip_value & FLIP_EAST) {
436 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_ON;
438 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
440 if(flip_value & FLIP_WEST) {
441 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_ON;
443 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
446 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
447 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
462 FlipPositionN[FLIP_EAST_VALUE].value = eastSexa;
465 FlipPositionN[FLIP_WEST_VALUE].value = westSexa;
478 sscanf(value,
"%f", &max_value);
479 PECMaxStepsN[0].value = max_value;
487 char valueString[32] = {0};
488 uint32_t pec_counter = 0;
489 sscanf(value,
"%u", &pec_counter);
490 snprintf(valueString, 32,
"%i", pec_counter);
501 sscanf(value,
"%f", &guiding_value);
502 PECGuidingSpeedN[0].value = guiding_value;
511 sscanf(value,
"%f", &guiding_value);
512 GuidingSpeedBothN[GUIDING_BOTH].value = guiding_value;
520 uint32_t pec_status = 0;
521 sscanf(value,
"%u", &pec_status);
523 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"Yes");
526 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"No");
530 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"Yes");
532 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"No");
535 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"Yes");
537 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"No");
540 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"Yes");
542 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"No");
544 if(pec_status & 16) {
545 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"Yes");
547 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"No");
549 if(pec_status & 32) {
550 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"Yes");
552 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"No");
569 SafetyLimitsN[EAST_SAFETY].value = eastSafeSexa;
572 SafetyLimitsN[WEST_SAFETY].value = westSafeSexa;
575 SafetyLimitsN[WEST_GOTO].value = westGotoSexa;
599 VersionTP.
tp[FIRMWARE_DATE].text =
new char[64];
601 VersionTP.
tp[FIRMWARE_TIME].text =
new char[64];
603 VersionTP.
tp[FIRMWARE_LEVEL].text =
new char[64];
605 VersionTP.
tp[FIRMWARE_NAME].text =
new char[128];
607 sscanf(VersionTP.
tp[FIRMWARE_LEVEL].text,
"%f", &gemini_software_level_);
613 if (gemini_software_level_ < 5.0)
617 if (gemini_software_level_ >= 5.2)
621 uint32_t pec_at_boot_value;
622 sscanf(value,
"%i", &pec_at_boot_value);
623 if(pec_at_boot_value)
625 PECEnableAtBootS[0].s =
ISS_ON;
627 PECEnableAtBootS[0].s =
ISS_OFF;
640 float guiding_speed_value;
641 sscanf(value,
"%f", &guiding_speed_value);
642 PECGuidingSpeedN[0].value = guiding_speed_value;
650 if (gemini_software_level_ >= 5.0) {
653 char valueString[32] = {0};
654 uint32_t pec_counter = 0;
655 sscanf(value,
"%u", &pec_counter);
656 snprintf(valueString, 32,
"%i", pec_counter);
669 float max_steps_value;
670 sscanf(value,
"%f", &max_steps_value);
671 PECMaxStepsN[0].value = max_steps_value;
681 uint32_t pec_status = 0;
682 sscanf(value,
"%u", &pec_status);
684 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"Yes");
687 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"No");
692 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"Yes");
694 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"No");
698 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"Yes");
700 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"No");
703 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"Yes");
705 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"No");
707 if(pec_status & 16) {
708 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"Yes");
710 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"No");
712 if(pec_status & 32) {
713 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"Yes");
715 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"Yes");
724 if (gemini_software_level_ >= 6.0)
728 char valueString[32] = {0};
729 uint32_t flip_value = 0;
730 sscanf(value,
"%u", &flip_value);
731 snprintf(valueString, 32,
"%i", flip_value);
734 if(flip_value & FLIP_EAST) {
735 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_ON;
737 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
739 if(flip_value & FLIP_WEST) {
740 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_ON;
742 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
745 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
746 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
757 if (gemini_software_level_ >= 6.0)
766 FlipPositionN[FLIP_EAST_VALUE].value = eastSexa;
769 FlipPositionN[FLIP_WEST_VALUE].value = westSexa;
789 SafetyLimitsN[EAST_SAFETY].value = eastSafeSexa;
792 SafetyLimitsN[WEST_SAFETY].value = westSafeSexa;
795 SafetyLimitsN[WEST_GOTO].value = westGotoSexa;
806 if (gemini_software_level_ >= 6.0)
811 sscanf(value,
"%c", &servo_value);
812 if(servo_value & RA_PRECISION_ENABLED) {
813 ServoPrecisionS[SERVO_RA].s =
ISS_ON;
815 ServoPrecisionS[SERVO_RA].s =
ISS_OFF;
817 if(servo_value & DEC_PRECISION_ENABLED) {
818 ServoPrecisionS[SERVO_DEC].s =
ISS_ON;
820 ServoPrecisionS[SERVO_DEC].s =
ISS_OFF;
830 bool refractionSetting =
false;
831 if(getRefraction(refractionSetting))
833 if(refractionSetting)
835 RefractionControlS[0].s =
ISS_ON;
837 RefractionControlS[0].s =
ISS_OFF;
839 RefractionControlSP.
s =
IPS_OK;
850 sscanf(value,
"%u", &speed);
851 ManualSlewingSpeedN[0].value = speed;
852 ManualSlewingSpeedNP.
s =
IPS_OK;
861 sscanf(value,
"%u", &speed);
862 GotoSlewingSpeedN[0].value = speed;
869 if (gemini_software_level_ >= 5.0)
873 sscanf(value,
"%u", &speed);
874 MoveSpeedN[0].value = speed;
885 float guidingSpeed = 0.0;
886 sscanf(value,
"%f", &guidingSpeed);
887 GuidingSpeedBothN[GUIDING_BOTH].value = guidingSpeed;
895 if (gemini_software_level_ >= 5.0)
899 float guidingSpeed = 0.0;
900 sscanf(value,
"%f", &guidingSpeed);
901 GuidingSpeedN[GUIDING_WE].value = guidingSpeed;
909 if (gemini_software_level_ >= 5.0)
913 float guidingSpeed = 0.0;
914 sscanf(value,
"%f", &guidingSpeed);
915 GuidingSpeedN[GUIDING_NS].value = guidingSpeed;
926 sscanf(value,
"%u", &speed);
927 CenteringSpeedN[0].value = speed;
936 updateParkingState();
937 updateMovementState();
969 if (!strcmp(name, PECStateTP.
name))
974 if (!strcmp(name, PECCounterTP.
name))
988 if (!strcmp(name, StartupModeSP.
name))
993 LOG_INFO(
"Startup mode will take effect on future connections.");
998 if (!strcmp(name, ParkSettingsSP.
name))
1006 if (gemini_software_level_ >= 5.0 && !strcmp(name,
PECStateSP.
name))
1009 for(
int i = 0; i<n; ++i)
1016 char valueString[16] = {0};
1033 char valueString[16] = {0};
1049 if (gemini_software_level_ >= 6.0 && !strcmp(name, ServoPrecisionSP.
name))
1054 uint8_t precisionEnabled = 0;
1055 for(
int i = 0; i<n; ++i) {
1056 if (!strcmp(names[i], ServoPrecisionS[SERVO_RA].name))
1058 if(ServoPrecisionS[SERVO_RA].s ==
ISS_ON)
1060 precisionEnabled |= 1;
1064 if (!strcmp(names[i], ServoPrecisionS[SERVO_DEC].name)) {
1065 if(ServoPrecisionS[SERVO_DEC].s ==
ISS_ON) {
1066 precisionEnabled |= 2;
1070 char valueString[16] = {0};
1072 snprintf(valueString, 16,
"%u", precisionEnabled);
1074 if(precisionEnabled & 1)
1076 LOGF_INFO(
"ServoPrecision: RA ON <%i>", (
int)precisionEnabled);
1078 LOGF_INFO(
"ServoPrecision: RA OFF <%i>", (
int)precisionEnabled);
1081 if(precisionEnabled & 2)
1083 LOGF_INFO(
"ServoPrecision: DEC ON <%i>", (
int)precisionEnabled);
1085 LOGF_INFO(
"ServoPrecision: DEC OFF <%i>", (
int)precisionEnabled);
1100 if (gemini_software_level_ >= 6.0 && !strcmp(name, RefractionControlSP.
name))
1103 for(
int i = 0; i<n; ++i) {
1104 if (!strcmp(names[i], RefractionControlS[0].name))
1106 if(RefractionControlS[0].s ==
ISS_ON)
1108 if(!setRefraction(
true))
1114 RefractionControlSP.
s =
IPS_OK;
1118 }
else if(RefractionControlS[0].s ==
ISS_OFF) {
1119 if(!setRefraction(
false))
1125 RefractionControlSP.
s =
IPS_OK;
1134 if (gemini_software_level_ >= 6.0 && !strcmp(name, FlipControlSP.
name))
1139 int32_t flipEnabled = 0;
1140 for(
int i = 0; i<n; ++i)
1142 if (!strcmp(names[i], FlipControlS[FLIP_EAST_CONTROL].name)) {
1143 if(FlipControlS[FLIP_EAST_CONTROL].s ==
ISS_ON)
1146 LOGF_INFO(
"FlipControl: EAST ON <%i>", flipEnabled);
1148 flipEnabled &= 0xfffffffe;
1149 LOGF_INFO(
"FlipControl: EAST OFF <%i>", flipEnabled);
1153 if (!strcmp(names[i], FlipControlS[FLIP_WEST_CONTROL].name)) {
1154 if(FlipControlS[FLIP_WEST_CONTROL].s ==
ISS_ON)
1157 LOGF_INFO(
"FlipControl: WEST ON <%i>", flipEnabled);
1159 flipEnabled &= 0xfffffffd;
1160 LOGF_INFO(
"FlipControl: WEST OFF <%i>", flipEnabled);
1164 char valueString[16] = {0};
1165 snprintf(valueString, 16,
"%i", flipEnabled);
1166 LOGF_INFO(
"FlipControl: <%s>", valueString);
1178 if (!strcmp(name, SetSafetyLimitToCurrentSP.
name))
1180 char valueString[16] = {0};
1183 SetSafetyLimitToCurrentS[0].s =
ISS_OFF;
1190 SetSafetyLimitToCurrentSP.
s =
IPS_OK;
1196 if (gemini_software_level_ >= 5.0 && !strcmp(name, PECControlSP.
name))
1199 for(
int i = 0; i<n; ++i) {
1200 if (!strcmp(names[i], PECControlS[PEC_START_TRAINING].name))
1202 char valueString[16] = {0};
1209 }
else if (!strcmp(names[i], PECControlS[PEC_ABORT_TRAINING].name))
1211 char valueString[16] = {0};
1235 char valueString[16] = {0};
1236 snprintf(valueString, 16,
"%2.0f", values[0]);
1238 if (!strcmp(name, ManualSlewingSpeedNP.
name))
1240 LOGF_DEBUG(
"Trying to set manual slewing speed of: %f", values[0]);
1245 IDSetNumber(&ManualSlewingSpeedNP,
"Error setting manual slewing speed");
1249 ManualSlewingSpeedNP.
s =
IPS_OK;
1250 ManualSlewingSpeedN[0].value = values[0];
1251 IDSetNumber(&ManualSlewingSpeedNP,
"Manual slewing speed set to %f", values[0]);
1255 if (!strcmp(name, GotoSlewingSpeedNP.
name))
1257 LOGF_DEBUG(
"Trying to set goto slewing speed of: %f", values[0]);
1262 IDSetNumber(&GotoSlewingSpeedNP,
"Error setting goto slewing speed");
1266 GotoSlewingSpeedNP.
s =
IPS_OK;
1267 GotoSlewingSpeedN[0].value = values[0];
1268 IDSetNumber(&GotoSlewingSpeedNP,
"Goto slewing speed set to %f", values[0]);
1272 if (gemini_software_level_ >= 5.0 && !strcmp(name, MoveSpeedNP.
name))
1274 LOGF_DEBUG(
"Trying to set move speed of: %f", values[0]);
1279 IDSetNumber(&MoveSpeedNP,
"Error setting move speed");
1284 MoveSpeedN[0].value = values[0];
1285 IDSetNumber(&MoveSpeedNP,
"Move speed set to %f", values[0]);
1289 if (gemini_software_level_ >= 5.0 && !strcmp(name, GuidingSpeedBothNP.
name))
1291 LOGF_DEBUG(
"Trying to set guiding speed of: %f", values[0]);
1293 for(
int i = 0; i<n; ++i) {
1294 if (!strcmp(names[i], GuidingSpeedBothN[GUIDING_BOTH].name))
1297 snprintf(valueString, 16,
"%1.1f", values[0]);
1302 IDSetNumber(&GuidingSpeedBothNP,
"Error setting guiding speed");
1309 GuidingSpeedBothN[GUIDING_BOTH].value = values[0];
1310 GuidingSpeedBothNP.
s =
IPS_OK;
1311 IDSetNumber(&GuidingSpeedBothNP,
"Guiding speed set to %f", values[0]);
1315 if (!strcmp(name, GuidingSpeedNP.
name))
1318 for(
int i = 0; i<n; ++i) {
1319 if (!strcmp(names[i], GuidingSpeedN[GUIDING_WE].name))
1322 snprintf(valueString, 16,
"%1.1f", values[i]);
1324 GuidingSpeedN[GUIDING_WE].value = values[i];
1326 IDSetNumber(&GuidingSpeedNP,
"Error Setting Guiding WE");
1331 if (!strcmp(names[i], GuidingSpeedN[GUIDING_NS].name))
1334 snprintf(valueString, 16,
"%1.1f", values[i]);
1338 GuidingSpeedN[GUIDING_NS].value = values[i];
1340 IDSetNumber(&GuidingSpeedNP,
"Error Setting Guiding WE");
1347 IDSetNumber(&GuidingSpeedNP,
"Guiding speed set to RA:%f DEC:%f", GuidingSpeedN[GUIDING_WE].value, GuidingSpeedN[GUIDING_NS].value);
1351 if (!strcmp(name, SafetyLimitsNP.
name))
1353 double eastSafeD = 0;
1354 double westSafeD = 0;
1355 double westGotoD = 0;
1357 for(
int i = 0; i<n; ++i) {
1358 if (!strcmp(names[i], SafetyLimitsN[EAST_SAFETY].name))
1360 eastSafeD = values[i];
1362 if (!strcmp(names[i], SafetyLimitsN[WEST_SAFETY].name))
1364 westSafeD = values[i];
1366 if (!strcmp(names[i], SafetyLimitsN[WEST_GOTO].name))
1368 westGotoD = values[i];
1371 char eastSafe[32] = {0};
1372 SafetyLimitsN[EAST_SAFETY].value = eastSafeD;
1373 fs_sexa(eastSafe, eastSafeD, 2, 60);
1375 char westSafe[32] = {0};
1376 SafetyLimitsN[WEST_SAFETY].value = westSafeD;
1377 fs_sexa(westSafe, westSafeD, 2, 60);
1379 char westGoto[32] = {0};
1380 SafetyLimitsN[WEST_GOTO].value = westGotoD;
1381 fs_sexa(westGoto, westGotoD, 2, 60);
1383 char *colon = strchr(eastSafe,
':');
1387 colon = strchr(westSafe,
':');
1391 colon = strchr(westGoto,
':');
1402 IDSetNumber(&SafetyLimitsNP,
"Error Setting Limits");
1405 IDSetNumber(&SafetyLimitsNP,
"Limits EastSafe:%s, WestSafe:%s, WestGoto:%s", eastSafe, westSafe, westGoto);
1409 if (gemini_software_level_ >= 6.0 && !strcmp(name, FlipPositionNP.
name))
1414 for(
int i = 0; i<n; ++i) {
1415 if (!strcmp(names[i], FlipPositionN[FLIP_EAST_VALUE].name))
1419 if (!strcmp(names[i], FlipPositionN[FLIP_WEST_VALUE].name))
1424 char east[32] = {0};
1425 FlipPositionN[FLIP_EAST_VALUE].value = eastD;
1428 char west[32] = {0};
1429 FlipPositionN[FLIP_WEST_VALUE].value = westD;
1432 char *colon = strchr(east,
':');
1436 colon = strchr(west,
':');
1445 IDSetNumber(&FlipPositionNP,
"Error Setting Flip Points");
1448 IDSetNumber(&FlipPositionNP,
"FlipPoints East:%s, West:%s", east, west);
1452 if (!strcmp(name, CenteringSpeedNP.
name))
1454 LOGF_DEBUG(
"Trying to set centering speed of: %f", values[0]);
1459 IDSetNumber(&CenteringSpeedNP,
"Error setting centering speed");
1464 CenteringSpeedN[0].value = values[0];
1465 IDSetNumber(&CenteringSpeedNP,
"Centering speed set to %f", values[0]);
1469 if (!strcmp(name, PECMaxStepsNP.
name))
1472 PECMaxStepsN[0].value = values[0];
1473 IDSetNumber(&PECMaxStepsNP,
"Max steps set to %f", values[0]);
1476 if (gemini_software_level_ >= 5.0 && !strcmp(name, PECGuidingSpeedNP.
name))
1479 PECGuidingSpeedN[0].value = values[0];
1480 IDSetNumber(&PECGuidingSpeedNP,
"Guiding Speed set to %f", values[0]);
1495 char response[8] = { 0 };
1496 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1500 tcflush(
PortFD, TCIFLUSH);
1502 char ack[1] = { 0x06 };
1508 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1517 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1523 tcflush(
PortFD, TCIFLUSH);
1528 if (response[0] ==
'b')
1530 LOG_DEBUG(
"Mount is waiting for selection of the startup mode.");
1531 char cmd[4] =
"bC#";
1533 if (startupMode == WARM_START)
1534 strncpy(
cmd,
"bW#", 4);
1535 else if (startupMode == WARM_RESTART)
1536 strncpy(
cmd,
"bR#", 4);
1544 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1548 tcflush(
PortFD, TCIFLUSH);
1553 else if (response[0] ==
'B')
1555 LOG_DEBUG(
"Initial startup message is being displayed.");
1557 else if (response[0] ==
'S')
1561 else if (response[0] ==
'G')
1563 updateParkingState();
1564 updateMovementState();
1565 LOG_DEBUG(
"Startup complete with equatorial mount selected.");
1567 else if (response[0] ==
'A')
1569 LOG_DEBUG(
"Startup complete with Alt-Az mount selected.");
1577 LX200Gemini::MovementState movementState = getMovementState();
1579 if (movementState == TRACKING || movementState == GUIDING || movementState == NO_MOVEMENT)
1597 updateMovementState();
1615 updateMovementState();
1618 LOG_INFO(
"Slew is complete. Tracking...");
1623 updateParkingState();
1651 void LX200Gemini::syncSideOfPier()
1654 const char *
cmd =
":Gm#";
1656 char response[8] = { 0 };
1657 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1661 tcflush(
PortFD, TCIOFLUSH);
1667 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1675 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1679 response[nbytes_read - 1] =
'\0';
1681 tcflush(
PortFD, TCIOFLUSH);
1693 if (ha >= -5.0 && ha <= 5.0)
1698 else if (ha <= -7.0 || ha >= 7.0)
1709 LOGF_DEBUG(
"RES: <%s>, lst %f, ha %f, pierSide %d", response, lst, ha, pointingState);
1717 char cmd[6] =
":hP#";
1721 if (parkSetting == PARK_STARTUP)
1722 strncpy(
cmd,
":hC#", 5);
1723 else if (parkSetting == PARK_ZENITH)
1724 strncpy(
cmd,
":hZ#", 5);
1727 int rc = 0, nbytes_written = 0;
1731 tcflush(
PortFD, TCIOFLUSH);
1737 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1741 tcflush(
PortFD, TCIOFLUSH);
1746 updateParkingState();
1757 updateParkingState();
1758 updateMovementState();
1762 bool LX200Gemini::sleepMount()
1764 const char *
cmd =
":hN#";
1767 int rc = 0, nbytes_written = 0;
1771 tcflush(
PortFD, TCIOFLUSH);
1777 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1781 tcflush(
PortFD, TCIOFLUSH);
1787 bool LX200Gemini::wakeupMount()
1789 const char *
cmd =
":hW#";
1792 int rc = 0, nbytes_written = 0;
1796 tcflush(
PortFD, TCIOFLUSH);
1802 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1806 tcflush(
PortFD, TCIOFLUSH);
1818 void LX200Gemini::updateMovementState()
1820 LX200Gemini::MovementState movementState = getMovementState();
1822 switch (movementState)
1825 if (priorParkingState == PARKED)
1847 void LX200Gemini::updateParkingState()
1849 LX200Gemini::ParkingState parkingState = getParkingState();
1851 if (parkingState != priorParkingState)
1853 if (parkingState == PARKED)
1855 else if (parkingState == NOT_PARKED)
1858 priorParkingState = parkingState;
1861 LX200Gemini::MovementState LX200Gemini::getMovementState()
1863 const char *
cmd =
":Gv#";
1864 char response[2] = { 0 };
1865 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1869 tcflush(
PortFD, TCIOFLUSH);
1875 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1876 return LX200Gemini::MovementState::NO_MOVEMENT;
1883 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1884 return LX200Gemini::MovementState::NO_MOVEMENT;
1889 tcflush(
PortFD, TCIOFLUSH);
1893 switch (response[0])
1896 return LX200Gemini::MovementState::NO_MOVEMENT;
1899 return LX200Gemini::MovementState::TRACKING;
1902 return LX200Gemini::MovementState::GUIDING;
1905 return LX200Gemini::MovementState::CENTERING;
1908 return LX200Gemini::MovementState::SLEWING;
1911 return LX200Gemini::MovementState::STALLED;
1914 return LX200Gemini::MovementState::NO_MOVEMENT;
1918 LX200Gemini::ParkingState LX200Gemini::getParkingState()
1920 const char *
cmd =
":h?#";
1921 char response[2] = { 0 };
1922 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1926 tcflush(
PortFD, TCIOFLUSH);
1932 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1933 return LX200Gemini::ParkingState::NOT_PARKED;
1940 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1941 return LX200Gemini::ParkingState::NOT_PARKED;
1946 tcflush(
PortFD, TCIOFLUSH);
1950 switch (response[0])
1953 return LX200Gemini::ParkingState::NOT_PARKED;
1956 return LX200Gemini::ParkingState::PARKED;
1959 return LX200Gemini::ParkingState::PARK_IN_PROGRESS;
1962 return LX200Gemini::ParkingState::NOT_PARKED;
1976 bool LX200Gemini::getGeminiProperty(uint32_t propertyNumber,
char* value)
1980 char prefix[16] = {0};
1983 switch(propertyNumber) {
1991 if(gemini_software_level_ < 5.0)
1993 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
1998 if(gemini_software_level_ < 5.2)
2000 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2009 if(gemini_software_level_ < 6)
2011 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2019 snprintf(prefix, 16,
"<%d:", propertyNumber);
2021 uint8_t checksum = calculateChecksum(prefix);
2023 snprintf(
cmd, 16,
"%s%c#", prefix, checksum);
2031 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
2039 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
2043 value[nbytes - 1] =
'\0';
2045 tcflush(
PortFD, TCIFLUSH);
2058 return GotoInternal(
ra,
dec,
true);
2063 return GotoInternal(
ra,
dec,
false);
2069 char FlipNum[17] = {0};
2071 int nbytes_write = 0, nbytes_read = 0;
2072 const char *command =
":MM#";
2092 if (nbytes_read < 1)
2099 tcflush(
fd, TCIFLUSH);
2103 error_type = FlipNum[0] -
'0';
2104 if ((error_type >= 0) && (error_type <= 9))
2114 bool LX200Gemini::GotoInternal(
double ra,
double dec,
bool flip)
2116 const struct timespec timeout = {0, 100000000L};
2120 char RAStr[64] = {0}, DecStr[64] = {0};
2165 nanosleep(&timeout,
nullptr);
2182 LOGF_ERROR(
"Error %s to JNow RA %s - DEC %s", flip ?
"Flipping" :
"Slewing", RAStr, DecStr);
2191 LOGF_INFO(
"%s to RA: %s - DEC: %s", flip ?
"Flipping" :
"Slewing", RAStr, DecStr);
2196 bool LX200Gemini::setGeminiProperty(uint32_t propertyNumber,
char* value)
2199 int nbytes_written = 0;
2200 char prefix[16] = {0};
2202 switch(propertyNumber) {
2210 if(gemini_software_level_ < 5.0)
2212 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2217 if(gemini_software_level_ < 5.2)
2219 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2225 if(gemini_software_level_ < 6)
2227 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2235 snprintf(prefix, 16,
">%d:%s", propertyNumber, value);
2237 uint8_t checksum = calculateChecksum(prefix);
2239 snprintf(
cmd, 16,
"%s%c#", prefix, checksum);
2247 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
2251 tcflush(
PortFD, TCIFLUSH);
2259 return setGeminiProperty(131 + mode, empty);
2267 uint8_t LX200Gemini::calculateChecksum(
char *
cmd)
2269 uint8_t result =
cmd[0];
2271 for (
size_t i = 1; i < strlen(
cmd); i++)
2272 result = result ^
cmd[i];
2274 result = result % 128;
The Interface class is the base class for all INDI connection plugins.
virtual std::string name()=0
const char * getDeviceName() const
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
bool isSimulation() const
Connection::Interface * getActiveConnection()
virtual bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
TelescopeStatus TrackState
ISwitchVectorProperty MovementNSSP
ISwitchVectorProperty AbortSP
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
ISwitchVectorProperty PECStateSP
ISwitchVectorProperty TrackModeSP
ISwitchVectorProperty SlewRateSP
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
INumberVectorProperty EqNP
@ TELESCOPE_HAS_PIER_SIDE
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
void setPECState(TelescopePECState state)
ISwitchVectorProperty ParkSP
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
ISwitchVectorProperty MovementWESP
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual bool Goto(double ra, double dec) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool ISNewText(const char *dev, const char *name, char **texts, char **names, int n) override
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
virtual int SendPulseCmd(int8_t direction, uint32_t duration_msec) override
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool checkConnection() override
virtual const char * getDefaultName() override
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
virtual bool isSlewComplete() override
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool Flip(double ra, double dec) override
Move and flip the scope to the supplied RA and DEC coordinates.
virtual bool Park() override
Park the telescope to its home position.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual void slewError(int slewCode)
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 bool ReadScopeStatus() override
Read telescope status.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
@ LX200_HAS_PULSE_GUIDING
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void setLX200Capability(uint32_t cap)
const char * GUIDE_TAB
GUIDE_TAB Where all the properties for guiding are located.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
double rangeHA(double r)
rangeHA Limits the hour angle value to be between -12 —> 12
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
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[].
void tty_set_gemini_udp_format(int enabled)
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.
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text'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 IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
int IUGetConfigOnSwitch(const ISwitchVectorProperty *property, int *index)
IUGetConfigOnSwitch Opens configuration file and reads a single switch vector property to find the in...
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
#define DEBUGFDEVICE(device, priority, msg,...)
int SendPulseCmd(int fd, int direction, int duration_msec, bool wait_after_command, int max_wait_ms)
int setObjectRA(int fd, double ra, bool addSpace)
int getLX200EquatorialFormat()
int setObjectDEC(int fd, double dec, bool addSpace)
#define getVersionDate(fd, x)
#define getVersionTime(fd, x)
#define getLX200DEC(fd, x)
#define getVersionNumber(fd, x)
#define getLX200RA(fd, x)
#define getProductName(fd, x)
#define GUIDING_SPEED_RA_ID
#define CENTERING_SPEED_ID
#define FLIP_POINT_EAST_ID
#define FLIP_POINT_WEST_ID
#define EAST_SAFETY_LIMIT_ID
#define SERVO_POINTING_PRECISION_ID
#define PEC_START_TRAINING_ID
#define PEC_GUIDING_SPEED_ID
#define MANUAL_SLEWING_SPEED_ID
#define WEST_SAFETY_LIMIT_ID
#define PEC_ENABLE_AT_BOOT_ID
#define GOTO_SLEWING_SPEED_ID
#define PEC_ABORT_TRAINING_ID
#define SET_SAFETY_LIMIT_TO_CURRENT_ID
#define GUIDING_SPEED_DEC_ID
#define FLIP_POINTS_ENABLED_ID
#define PEC_REPLAY_OFF_ID
#define WEST_GOTO_SAFETY_LIMIT_ID
const char * CONNECTION_TAB
@ value
the parser finished reading a JSON value