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);
241 gemini_software_level_ = 0.0;
246bool LX200Gemini::getRefractionJNOW(
int &data)
252 char response[2] = { 0 };
253 int rc = 0, nbytes_read = 0, nbytes_written = 0;
256 tcflush(
PortFD, TCIFLUSH);
258 const char *
cmd =
":p?#";
264 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
273 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
276 tcflush(
PortFD, TCIFLUSH);
279 data = atoi(response);
283bool LX200Gemini::getRefraction(
bool &on)
290 bool success = getRefractionJNOW(data);
295 if((data != 2) && (data != 0))
297 LOGF_WARN(
"Mount Precess being reset to JNOW: %i", data);
299 return setRefraction(2);
304 if((data != 2) && (data != 0))
306 LOGF_WARN(
"Mount Precess being reset to JNOW: %i", data);
308 return setRefraction(0);
314bool LX200Gemini::setRefraction(
int data)
319 int rc = 0, nbytes_written = 0;
321 tcflush(
PortFD, TCIFLUSH);
324 snprintf(
cmd, 5,
":p%i#", data);
330 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
333 tcflush(
PortFD, TCIFLUSH);
338bool LX200Gemini::setRefraction(
bool on)
345 getRefractionJNOW(data);
349 if((data != 2) && (data != 0))
351 LOGF_WARN(
"Mount Precess being reset to JNOW %i ", data);
353 return setRefraction(2);
357 if((data != 2) && (data != 0))
359 LOGF_WARN(
"Mount Precess being reset to JNOW %i", data);
361 return setRefraction(0);
365void LX200Gemini::syncState()
372 if (gemini_software_level_ >= 5.0)
377 sscanf(value,
"%f", &guiding_value);
378 GuidingSpeedN[GUIDING_WE].value = guiding_value;
389 sscanf(value,
"%f", &guiding_value);
390 GuidingSpeedN[GUIDING_NS].value = guiding_value;
399 if (gemini_software_level_ >= 5.2)
403 uint32_t pec_at_boot_value;
404 sscanf(value,
"%u", &pec_at_boot_value);
405 if(pec_at_boot_value)
407 PECEnableAtBootS[0].s =
ISS_ON;
411 PECEnableAtBootS[0].s =
ISS_OFF;
421 if(gemini_software_level_ >= 6.0)
426 sscanf(value,
"%c", &servo_value);
427 if(servo_value & RA_PRECISION_ENABLED)
429 ServoPrecisionS[SERVO_RA].s =
ISS_ON;
433 ServoPrecisionS[SERVO_RA].s =
ISS_OFF;
435 if(servo_value & DEC_PRECISION_ENABLED)
437 ServoPrecisionS[SERVO_DEC].s =
ISS_ON;
441 ServoPrecisionS[SERVO_DEC].s =
ISS_OFF;
454 char valueString[32] = {0};
455 uint32_t flip_value = 0;
456 sscanf(value,
"%u", &flip_value);
457 snprintf(valueString, 32,
"%i", flip_value);
461 if(flip_value & FLIP_EAST)
463 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_ON;
467 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
469 if(flip_value & FLIP_WEST)
471 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_ON;
475 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
480 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
481 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
498 FlipPositionN[FLIP_EAST_VALUE].value = eastSexa;
501 FlipPositionN[FLIP_WEST_VALUE].value = westSexa;
516 sscanf(value,
"%f", &max_value);
517 PECMaxStepsN[0].value = max_value;
527 char valueString[32] = {0};
528 uint32_t pec_counter = 0;
529 sscanf(value,
"%u", &pec_counter);
530 snprintf(valueString, 32,
"%i", pec_counter);
543 sscanf(value,
"%f", &guiding_value);
544 PECGuidingSpeedN[0].value = guiding_value;
555 sscanf(value,
"%f", &guiding_value);
556 GuidingSpeedBothN[GUIDING_BOTH].value = guiding_value;
566 uint32_t pec_status = 0;
567 sscanf(value,
"%u", &pec_status);
570 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"Yes");
575 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"No");
580 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"Yes");
584 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"No");
588 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"Yes");
592 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"No");
596 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"Yes");
600 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"No");
604 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"Yes");
608 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"No");
612 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"Yes");
616 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"No");
635 SafetyLimitsN[EAST_SAFETY].value = eastSafeSexa;
638 SafetyLimitsN[WEST_SAFETY].value = westSafeSexa;
641 SafetyLimitsN[WEST_GOTO].value = westGotoSexa;
667 VersionTP.
tp[FIRMWARE_DATE].
text =
new char[64];
669 VersionTP.
tp[FIRMWARE_TIME].
text =
new char[64];
671 VersionTP.
tp[FIRMWARE_LEVEL].
text =
new char[64];
673 VersionTP.
tp[FIRMWARE_NAME].
text =
new char[128];
675 sscanf(VersionTP.
tp[FIRMWARE_LEVEL].
text,
"%f", &gemini_software_level_);
681 if (gemini_software_level_ < 5.0)
685 if (gemini_software_level_ >= 5.2)
689 uint32_t pec_at_boot_value;
690 sscanf(value,
"%i", &pec_at_boot_value);
691 if(pec_at_boot_value)
693 PECEnableAtBootS[0].s =
ISS_ON;
697 PECEnableAtBootS[0].s =
ISS_OFF;
712 float guiding_speed_value;
713 sscanf(value,
"%f", &guiding_speed_value);
714 PECGuidingSpeedN[0].value = guiding_speed_value;
724 if (gemini_software_level_ >= 5.0)
728 char valueString[32] = {0};
729 uint32_t pec_counter = 0;
730 sscanf(value,
"%u", &pec_counter);
731 snprintf(valueString, 32,
"%i", pec_counter);
746 float max_steps_value;
747 sscanf(value,
"%f", &max_steps_value);
748 PECMaxStepsN[0].value = max_steps_value;
760 uint32_t pec_status = 0;
761 sscanf(value,
"%u", &pec_status);
764 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"Yes");
769 IUSaveText(&PECStateT[PEC_STATUS_ACTIVE],
"No");
775 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"Yes");
779 IUSaveText(&PECStateT[PEC_STATUS_FRESH_TRAINED],
"No");
784 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"Yes");
788 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_IN_PROGRESS],
"No");
792 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"Yes");
796 IUSaveText(&PECStateT[PEC_STATUS_TRAINING_COMPLETED],
"No");
800 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"Yes");
804 IUSaveText(&PECStateT[PEC_STATUS_WILL_TRAIN],
"No");
808 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"Yes");
812 IUSaveText(&PECStateT[PEC_STATUS_DATA_AVAILABLE],
"Yes");
823 if (gemini_software_level_ >= 6.0)
827 char valueString[32] = {0};
828 uint32_t flip_value = 0;
829 sscanf(value,
"%u", &flip_value);
830 snprintf(valueString, 32,
"%i", flip_value);
834 if(flip_value & FLIP_EAST)
836 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_ON;
840 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
842 if(flip_value & FLIP_WEST)
844 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_ON;
848 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
853 FlipControlS[FLIP_EAST_CONTROL].s =
ISS_OFF;
854 FlipControlS[FLIP_WEST_CONTROL].s =
ISS_OFF;
867 if (gemini_software_level_ >= 6.0)
876 FlipPositionN[FLIP_EAST_VALUE].value = eastSexa;
879 FlipPositionN[FLIP_WEST_VALUE].value = westSexa;
901 SafetyLimitsN[EAST_SAFETY].value = eastSafeSexa;
904 SafetyLimitsN[WEST_SAFETY].value = westSafeSexa;
907 SafetyLimitsN[WEST_GOTO].value = westGotoSexa;
920 if (gemini_software_level_ >= 6.0)
925 sscanf(value,
"%c", &servo_value);
926 if(servo_value & RA_PRECISION_ENABLED)
928 ServoPrecisionS[SERVO_RA].s =
ISS_ON;
932 ServoPrecisionS[SERVO_RA].s =
ISS_OFF;
934 if(servo_value & DEC_PRECISION_ENABLED)
936 ServoPrecisionS[SERVO_DEC].s =
ISS_ON;
940 ServoPrecisionS[SERVO_DEC].s =
ISS_OFF;
952 bool refractionSetting =
false;
953 if(getRefraction(refractionSetting))
955 if(refractionSetting)
957 RefractionControlS[0].s =
ISS_ON;
961 RefractionControlS[0].s =
ISS_OFF;
963 RefractionControlSP.
s =
IPS_OK;
976 sscanf(value,
"%u", &speed);
977 ManualSlewingSpeedN[0].value = speed;
978 ManualSlewingSpeedNP.
s =
IPS_OK;
989 sscanf(value,
"%u", &speed);
990 GotoSlewingSpeedN[0].value = speed;
999 if (gemini_software_level_ >= 5.0)
1003 sscanf(value,
"%u", &speed);
1004 MoveSpeedN[0].value = speed;
1017 float guidingSpeed = 0.0;
1018 sscanf(value,
"%f", &guidingSpeed);
1019 GuidingSpeedBothN[GUIDING_BOTH].value = guidingSpeed;
1020 GuidingSpeedBothNP.
s =
IPS_OK;
1029 if (gemini_software_level_ >= 5.0)
1033 float guidingSpeed = 0.0;
1034 sscanf(value,
"%f", &guidingSpeed);
1035 GuidingSpeedN[GUIDING_WE].value = guidingSpeed;
1045 if (gemini_software_level_ >= 5.0)
1049 float guidingSpeed = 0.0;
1050 sscanf(value,
"%f", &guidingSpeed);
1051 GuidingSpeedN[GUIDING_NS].value = guidingSpeed;
1064 sscanf(value,
"%u", &speed);
1065 CenteringSpeedN[0].value = speed;
1076 updateParkingState();
1077 updateMovementState();
1109 if (!strcmp(name, PECStateTP.
name))
1114 if (!strcmp(name, PECCounterTP.
name))
1128 if (!strcmp(name, StartupModeSP.
name))
1133 LOG_INFO(
"Startup mode will take effect on future connections.");
1138 if (!strcmp(name, ParkSettingsSP.
name))
1149 for(
int i = 0; i < n; ++i)
1157 char valueString[16] = {0};
1176 char valueString[16] = {0};
1192 if (gemini_software_level_ >= 6.0 && !strcmp(name, ServoPrecisionSP.
name))
1197 uint8_t precisionEnabled = 0;
1198 for(
int i = 0; i < n; ++i)
1200 if (!strcmp(names[i], ServoPrecisionS[SERVO_RA].name))
1202 if(ServoPrecisionS[SERVO_RA].s ==
ISS_ON)
1204 precisionEnabled |= 1;
1208 if (!strcmp(names[i], ServoPrecisionS[SERVO_DEC].name))
1210 if(ServoPrecisionS[SERVO_DEC].s ==
ISS_ON)
1212 precisionEnabled |= 2;
1216 char valueString[16] = {0};
1218 snprintf(valueString, 16,
"%u", precisionEnabled);
1220 if(precisionEnabled & 1)
1222 LOGF_INFO(
"ServoPrecision: RA ON <%i>", (
int)precisionEnabled);
1226 LOGF_INFO(
"ServoPrecision: RA OFF <%i>", (
int)precisionEnabled);
1229 if(precisionEnabled & 2)
1231 LOGF_INFO(
"ServoPrecision: DEC ON <%i>", (
int)precisionEnabled);
1235 LOGF_INFO(
"ServoPrecision: DEC OFF <%i>", (
int)precisionEnabled);
1252 if (gemini_software_level_ >= 6.0 && !strcmp(name, RefractionControlSP.
name))
1255 for(
int i = 0; i < n; ++i)
1257 if (!strcmp(names[i], RefractionControlS[0].name))
1259 if(RefractionControlS[0].s ==
ISS_ON)
1261 if(!setRefraction(
true))
1269 RefractionControlSP.
s =
IPS_OK;
1274 else if(RefractionControlS[0].s ==
ISS_OFF)
1276 if(!setRefraction(
false))
1284 RefractionControlSP.
s =
IPS_OK;
1293 if (gemini_software_level_ >= 6.0 && !strcmp(name, FlipControlSP.
name))
1298 int32_t flipEnabled = 0;
1299 for(
int i = 0; i < n; ++i)
1301 if (!strcmp(names[i], FlipControlS[FLIP_EAST_CONTROL].name))
1303 if(FlipControlS[FLIP_EAST_CONTROL].s ==
ISS_ON)
1306 LOGF_INFO(
"FlipControl: EAST ON <%i>", flipEnabled);
1310 flipEnabled &= 0xfffffffe;
1311 LOGF_INFO(
"FlipControl: EAST OFF <%i>", flipEnabled);
1315 if (!strcmp(names[i], FlipControlS[FLIP_WEST_CONTROL].name))
1317 if(FlipControlS[FLIP_WEST_CONTROL].s ==
ISS_ON)
1320 LOGF_INFO(
"FlipControl: WEST ON <%i>", flipEnabled);
1324 flipEnabled &= 0xfffffffd;
1325 LOGF_INFO(
"FlipControl: WEST OFF <%i>", flipEnabled);
1329 char valueString[16] = {0};
1330 snprintf(valueString, 16,
"%i", flipEnabled);
1331 LOGF_INFO(
"FlipControl: <%s>", valueString);
1345 if (!strcmp(name, SetSafetyLimitToCurrentSP.
name))
1347 char valueString[16] = {0};
1350 SetSafetyLimitToCurrentS[0].s =
ISS_OFF;
1359 SetSafetyLimitToCurrentSP.
s =
IPS_OK;
1365 if (gemini_software_level_ >= 5.0 && !strcmp(name, PECControlSP.
name))
1368 for(
int i = 0; i < n; ++i)
1370 if (!strcmp(names[i], PECControlS[PEC_START_TRAINING].name))
1372 char valueString[16] = {0};
1380 else if (!strcmp(names[i], PECControlS[PEC_ABORT_TRAINING].name))
1382 char valueString[16] = {0};
1406 char valueString[16] = {0};
1407 snprintf(valueString, 16,
"%2.0f", values[0]);
1409 if (!strcmp(name, ManualSlewingSpeedNP.
name))
1411 LOGF_DEBUG(
"Trying to set manual slewing speed of: %f", values[0]);
1416 IDSetNumber(&ManualSlewingSpeedNP,
"Error setting manual slewing speed");
1420 ManualSlewingSpeedNP.
s =
IPS_OK;
1421 ManualSlewingSpeedN[0].value = values[0];
1422 IDSetNumber(&ManualSlewingSpeedNP,
"Manual slewing speed set to %f", values[0]);
1426 if (!strcmp(name, GotoSlewingSpeedNP.
name))
1428 LOGF_DEBUG(
"Trying to set goto slewing speed of: %f", values[0]);
1433 IDSetNumber(&GotoSlewingSpeedNP,
"Error setting goto slewing speed");
1437 GotoSlewingSpeedNP.
s =
IPS_OK;
1438 GotoSlewingSpeedN[0].value = values[0];
1439 IDSetNumber(&GotoSlewingSpeedNP,
"Goto slewing speed set to %f", values[0]);
1443 if (gemini_software_level_ >= 5.0 && !strcmp(name, MoveSpeedNP.
name))
1445 LOGF_DEBUG(
"Trying to set move speed of: %f", values[0]);
1450 IDSetNumber(&MoveSpeedNP,
"Error setting move speed");
1455 MoveSpeedN[0].value = values[0];
1456 IDSetNumber(&MoveSpeedNP,
"Move speed set to %f", values[0]);
1460 if (gemini_software_level_ >= 5.0 && !strcmp(name, GuidingSpeedBothNP.
name))
1462 LOGF_DEBUG(
"Trying to set guiding speed of: %f", values[0]);
1464 for(
int i = 0; i < n; ++i)
1466 if (!strcmp(names[i], GuidingSpeedBothN[GUIDING_BOTH].name))
1469 snprintf(valueString, 16,
"%1.1f", values[0]);
1474 IDSetNumber(&GuidingSpeedBothNP,
"Error setting guiding speed");
1481 GuidingSpeedBothN[GUIDING_BOTH].value = values[0];
1482 GuidingSpeedBothNP.
s =
IPS_OK;
1483 IDSetNumber(&GuidingSpeedBothNP,
"Guiding speed set to %f", values[0]);
1487 if (!strcmp(name, GuidingSpeedNP.
name))
1490 for(
int i = 0; i < n; ++i)
1492 if (!strcmp(names[i], GuidingSpeedN[GUIDING_WE].name))
1495 snprintf(valueString, 16,
"%1.1f", values[i]);
1498 GuidingSpeedN[GUIDING_WE].value = values[i];
1500 IDSetNumber(&GuidingSpeedNP,
"Error Setting Guiding WE");
1505 if (!strcmp(names[i], GuidingSpeedN[GUIDING_NS].name))
1508 snprintf(valueString, 16,
"%1.1f", values[i]);
1512 GuidingSpeedN[GUIDING_NS].value = values[i];
1514 IDSetNumber(&GuidingSpeedNP,
"Error Setting Guiding WE");
1521 IDSetNumber(&GuidingSpeedNP,
"Guiding speed set to RA:%f DEC:%f", GuidingSpeedN[GUIDING_WE].value, GuidingSpeedN[GUIDING_NS].value);
1525 if (!strcmp(name, SafetyLimitsNP.
name))
1527 double eastSafeD = 0;
1528 double westSafeD = 0;
1529 double westGotoD = 0;
1531 for(
int i = 0; i < n; ++i)
1533 if (!strcmp(names[i], SafetyLimitsN[EAST_SAFETY].name))
1535 eastSafeD = values[i];
1537 if (!strcmp(names[i], SafetyLimitsN[WEST_SAFETY].name))
1539 westSafeD = values[i];
1541 if (!strcmp(names[i], SafetyLimitsN[WEST_GOTO].name))
1543 westGotoD = values[i];
1546 char eastSafe[32] = {0};
1547 SafetyLimitsN[EAST_SAFETY].value = eastSafeD;
1548 fs_sexa(eastSafe, eastSafeD, 2, 60);
1550 char westSafe[32] = {0};
1551 SafetyLimitsN[WEST_SAFETY].value = westSafeD;
1552 fs_sexa(westSafe, westSafeD, 2, 60);
1554 char westGoto[32] = {0};
1555 SafetyLimitsN[WEST_GOTO].value = westGotoD;
1556 fs_sexa(westGoto, westGotoD, 2, 60);
1558 char *colon = strchr(eastSafe,
':');
1563 colon = strchr(westSafe,
':');
1568 colon = strchr(westGoto,
':');
1580 IDSetNumber(&SafetyLimitsNP,
"Error Setting Limits");
1583 IDSetNumber(&SafetyLimitsNP,
"Limits EastSafe:%s, WestSafe:%s, WestGoto:%s", eastSafe, westSafe, westGoto);
1587 if (gemini_software_level_ >= 6.0 && !strcmp(name, FlipPositionNP.
name))
1592 for(
int i = 0; i < n; ++i)
1594 if (!strcmp(names[i], FlipPositionN[FLIP_EAST_VALUE].name))
1598 if (!strcmp(names[i], FlipPositionN[FLIP_WEST_VALUE].name))
1603 char east[32] = {0};
1604 FlipPositionN[FLIP_EAST_VALUE].value = eastD;
1607 char west[32] = {0};
1608 FlipPositionN[FLIP_WEST_VALUE].value = westD;
1611 char *colon = strchr(east,
':');
1616 colon = strchr(west,
':');
1626 IDSetNumber(&FlipPositionNP,
"Error Setting Flip Points");
1629 IDSetNumber(&FlipPositionNP,
"FlipPoints East:%s, West:%s", east, west);
1633 if (!strcmp(name, CenteringSpeedNP.
name))
1635 LOGF_DEBUG(
"Trying to set centering speed of: %f", values[0]);
1640 IDSetNumber(&CenteringSpeedNP,
"Error setting centering speed");
1645 CenteringSpeedN[0].value = values[0];
1646 IDSetNumber(&CenteringSpeedNP,
"Centering speed set to %f", values[0]);
1650 if (!strcmp(name, PECMaxStepsNP.
name))
1653 PECMaxStepsN[0].value = values[0];
1654 IDSetNumber(&PECMaxStepsNP,
"Max steps set to %f", values[0]);
1657 if (gemini_software_level_ >= 5.0 && !strcmp(name, PECGuidingSpeedNP.
name))
1660 PECGuidingSpeedN[0].value = values[0];
1661 IDSetNumber(&PECGuidingSpeedNP,
"Guiding Speed set to %f", values[0]);
1676 char response[8] = { 0 };
1677 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1681 tcflush(
PortFD, TCIFLUSH);
1683 char ack[1] = { 0x06 };
1689 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1698 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1704 tcflush(
PortFD, TCIFLUSH);
1709 if (response[0] ==
'b')
1711 LOG_DEBUG(
"Mount is waiting for selection of the startup mode.");
1712 char cmd[4] =
"bC#";
1714 if (startupMode == WARM_START)
1715 strncpy(
cmd,
"bW#", 4);
1716 else if (startupMode == WARM_RESTART)
1717 strncpy(
cmd,
"bR#", 4);
1725 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1729 tcflush(
PortFD, TCIFLUSH);
1734 else if (response[0] ==
'B')
1736 LOG_DEBUG(
"Initial startup message is being displayed.");
1738 else if (response[0] ==
'S')
1742 else if (response[0] ==
'G')
1744 updateParkingState();
1745 updateMovementState();
1746 LOG_DEBUG(
"Startup complete with equatorial mount selected.");
1748 else if (response[0] ==
'A')
1750 LOG_DEBUG(
"Startup complete with Alt-Az mount selected.");
1758 LX200Gemini::MovementState movementState = getMovementState();
1760 if (movementState == TRACKING || movementState == GUIDING || movementState == NO_MOVEMENT)
1778 updateMovementState();
1797 updateMovementState();
1800 LOG_INFO(
"Slew is complete. Tracking...");
1805 updateParkingState();
1833void LX200Gemini::syncSideOfPier()
1836 const char *
cmd =
":Gm#";
1838 char response[8] = { 0 };
1839 int rc = 0, nbytes_read = 0, nbytes_written = 0;
1843 tcflush(
PortFD, TCIOFLUSH);
1849 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1857 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
1861 response[nbytes_read - 1] =
'\0';
1863 tcflush(
PortFD, TCIOFLUSH);
1875 if (ha >= -5.0 && ha <= 5.0)
1880 else if (ha <= -7.0 || ha >= 7.0)
1891 LOGF_DEBUG(
"RES: <%s>, lst %f, ha %f, pierSide %d", response, lst, ha, pointingState);
1899 char cmd[6] =
":hP#";
1903 if (parkSetting == PARK_STARTUP)
1904 strncpy(
cmd,
":hC#", 5);
1905 else if (parkSetting == PARK_ZENITH)
1906 strncpy(
cmd,
":hZ#", 5);
1909 int rc = 0, nbytes_written = 0;
1913 tcflush(
PortFD, TCIOFLUSH);
1919 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1923 tcflush(
PortFD, TCIOFLUSH);
1928 updateParkingState();
1939 updateParkingState();
1940 updateMovementState();
1944bool LX200Gemini::sleepMount()
1946 const char *
cmd =
":hN#";
1949 int rc = 0, nbytes_written = 0;
1953 tcflush(
PortFD, TCIOFLUSH);
1959 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1963 tcflush(
PortFD, TCIOFLUSH);
1969bool LX200Gemini::wakeupMount()
1971 const char *
cmd =
":hW#";
1974 int rc = 0, nbytes_written = 0;
1978 tcflush(
PortFD, TCIOFLUSH);
1984 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
1988 tcflush(
PortFD, TCIOFLUSH);
2000void LX200Gemini::updateMovementState()
2002 LX200Gemini::MovementState movementState = getMovementState();
2004 switch (movementState)
2007 if (priorParkingState == PARKED)
2029void LX200Gemini::updateParkingState()
2031 LX200Gemini::ParkingState parkingState = getParkingState();
2033 if (parkingState != priorParkingState)
2035 if (parkingState == PARKED)
2037 else if (parkingState == NOT_PARKED)
2040 priorParkingState = parkingState;
2043LX200Gemini::MovementState LX200Gemini::getMovementState()
2045 const char *
cmd =
":Gv#";
2046 char response[2] = { 0 };
2047 int rc = 0, nbytes_read = 0, nbytes_written = 0;
2051 tcflush(
PortFD, TCIOFLUSH);
2057 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
2058 return LX200Gemini::MovementState::NO_MOVEMENT;
2065 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
2066 return LX200Gemini::MovementState::NO_MOVEMENT;
2071 tcflush(
PortFD, TCIOFLUSH);
2075 switch (response[0])
2078 return LX200Gemini::MovementState::NO_MOVEMENT;
2081 return LX200Gemini::MovementState::TRACKING;
2084 return LX200Gemini::MovementState::GUIDING;
2087 return LX200Gemini::MovementState::CENTERING;
2090 return LX200Gemini::MovementState::SLEWING;
2093 return LX200Gemini::MovementState::STALLED;
2096 return LX200Gemini::MovementState::NO_MOVEMENT;
2100LX200Gemini::ParkingState LX200Gemini::getParkingState()
2102 const char *
cmd =
":h?#";
2103 char response[2] = { 0 };
2104 int rc = 0, nbytes_read = 0, nbytes_written = 0;
2108 tcflush(
PortFD, TCIOFLUSH);
2114 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
2115 return LX200Gemini::ParkingState::NOT_PARKED;
2122 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
2123 return LX200Gemini::ParkingState::NOT_PARKED;
2128 tcflush(
PortFD, TCIOFLUSH);
2132 switch (response[0])
2135 return LX200Gemini::ParkingState::NOT_PARKED;
2138 return LX200Gemini::ParkingState::PARKED;
2141 return LX200Gemini::ParkingState::PARK_IN_PROGRESS;
2144 return LX200Gemini::ParkingState::NOT_PARKED;
2158bool LX200Gemini::getGeminiProperty(uint32_t propertyNumber,
char* value)
2162 char prefix[16] = {0};
2165 switch(propertyNumber)
2174 if(gemini_software_level_ < 5.0)
2176 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2181 if(gemini_software_level_ < 5.2)
2183 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2192 if(gemini_software_level_ < 6)
2194 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2202 snprintf(prefix, 16,
"<%d:", propertyNumber);
2204 uint8_t checksum = calculateChecksum(prefix);
2206 snprintf(
cmd, 16,
"%s%c#", prefix, checksum);
2214 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
2222 LOGF_ERROR(
"Error reading from device %s (%d)", errmsg, rc);
2226 value[nbytes - 1] =
'\0';
2228 tcflush(
PortFD, TCIFLUSH);
2236 return ::SendPulseCmd(
PortFD, direction, duration_msec,
true, 1000);
2241 return GotoInternal(
ra,
dec,
true);
2246 return GotoInternal(
ra,
dec,
false);
2252 char FlipNum[17] = {0};
2254 int nbytes_write = 0, nbytes_read = 0;
2255 const char *command =
":MM#";
2275 if (nbytes_read < 1)
2282 tcflush(
fd, TCIFLUSH);
2286 error_type = FlipNum[0] -
'0';
2287 if ((error_type >= 0) && (error_type <= 9))
2297bool LX200Gemini::GotoInternal(
double ra,
double dec,
bool flip)
2299 const struct timespec timeout = {0, 100000000L};
2303 char RAStr[64] = {0}, DecStr[64] = {0};
2350 nanosleep(&timeout,
nullptr);
2368 LOGF_ERROR(
"Error %s to JNow RA %s - DEC %s", flip ?
"Flipping" :
"Slewing", RAStr, DecStr);
2377 LOGF_INFO(
"%s to RA: %s - DEC: %s", flip ?
"Flipping" :
"Slewing", RAStr, DecStr);
2382bool LX200Gemini::setGeminiProperty(uint32_t propertyNumber,
char* value)
2385 int nbytes_written = 0;
2386 char prefix[16] = {0};
2388 switch(propertyNumber)
2397 if(gemini_software_level_ < 5.0)
2399 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2404 if(gemini_software_level_ < 5.2)
2406 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2412 if(gemini_software_level_ < 6)
2414 LOGF_ERROR(
"Error Gemini Firmware Level %f does not support command %i ", gemini_software_level_, propertyNumber);
2422 snprintf(prefix, 16,
">%d:%s", propertyNumber, value);
2424 uint8_t checksum = calculateChecksum(prefix);
2426 snprintf(
cmd, 16,
"%s%c#", prefix, checksum);
2434 LOGF_ERROR(
"Error writing to device %s (%d)", errmsg, rc);
2438 tcflush(
PortFD, TCIFLUSH);
2446 return setGeminiProperty(131 + mode, empty);
2454uint8_t LX200Gemini::calculateChecksum(
char *
cmd)
2456 uint8_t result =
cmd[0];
2458 for (
size_t i = 1; i < strlen(
cmd); i++)
2459 result = result ^
cmd[i];
2461 result = result % 128;
The Interface class is the base class for all INDI connection plugins.
virtual std::string name()=0
void setConnectionType(int type)
TODO should be renamed to setDefaultConnectionType.
void setDefaultPort(uint32_t addressPort)
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...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isNameMatch(const char *otherName) const
bool update(const ISState states[], const char *const names[], int n)
int findOnSwitchIndex() const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
TelescopeStatus TrackState
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Connection::TCP * tcpConnection
void setPECState(TelescopePECState state)
@ TELESCOPE_HAS_PIER_SIDE
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
void setPierSide(TelescopePierSide side)
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.
@ LX200_HAS_PULSE_GUIDING
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...
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 * CONNECTION_TAB
CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlle...
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.
INDI::PropertySwitch ParkSP
INDI::PropertySwitch AbortSP
INDI::PropertySwitch MovementNSSP
INDI::PropertyNumber EqNP
INDI::PropertySwitch PECStateSP
INDI::PropertySwitch SlewRateSP
INDI::PropertySwitch TrackModeSP
INDI::PropertySwitch MovementWESP
INDI::PropertyNumber LocationNP
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 sidereal 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 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