33 #include <sys/ioctl.h>
39 static std::unique_ptr<PegasusUPB> upb(
new PegasusUPB());
45 lastSensorData.reserve(21);
46 lastPowerData.reserve(4);
47 lastStepperData.reserve(4);
48 lastDewAggData.reserve(1);
84 IUFillNumber(&PowerSensorsN[SENSOR_VOLTAGE],
"SENSOR_VOLTAGE",
"Voltage (V)",
"%4.2f", 0, 999, 100, 0);
85 IUFillNumber(&PowerSensorsN[SENSOR_CURRENT],
"SENSOR_CURRENT",
"Current (A)",
"%4.2f", 0, 999, 100, 0);
86 IUFillNumber(&PowerSensorsN[SENSOR_POWER],
"SENSOR_POWER",
"Power (W)",
"%4.2f", 0, 999, 100, 0);
91 IUFillNumber(&PowerConsumptionN[CONSUMPTION_AVG_AMPS],
"CONSUMPTION_AVG_AMPS",
"Avg. Amps",
"%4.2f", 0, 999, 100, 0);
92 IUFillNumber(&PowerConsumptionN[CONSUMPTION_AMP_HOURS],
"CONSUMPTION_AMP_HOURS",
"Amp Hours",
"%4.2f", 0, 999, 100, 0);
93 IUFillNumber(&PowerConsumptionN[CONSUMPTION_WATT_HOURS],
"CONSUMPTION_WATT_HOURS",
"Watt Hours",
"%4.2f", 0, 999, 100, 0);
102 IUFillText(&DewControlsLabelsT[0],
"DEW_LABEL_1",
"Dew A",
"Dew A");
103 IUFillText(&DewControlsLabelsT[1],
"DEW_LABEL_2",
"Dew B",
"Dew B");
104 IUFillText(&DewControlsLabelsT[2],
"DEW_LABEL_3",
"Dew C",
"Dew C");
123 IUFillSwitchVector(&AutoDewV2SP, AutoDewV2S, 3,
getDeviceName(),
"AUTO_DEW",
"Auto Dew", DEW_TAB,
IP_RW,
ISR_NOFMANY, 60,
127 IUFillText(&DewControlsLabelsT[0],
"DEW_LABEL_1",
"Dew A", AutoDewV2S[0].label);
128 IUFillText(&DewControlsLabelsT[1],
"DEW_LABEL_2",
"Dew B", AutoDewV2S[1].label);
129 IUFillText(&DewControlsLabelsT[2],
"DEW_LABEL_3",
"Dew C", AutoDewV2S[2].label);
133 IUFillText(&PowerControlsLabelsT[0],
"POWER_LABEL_1",
"Port 1",
"Port 1");
134 IUFillText(&PowerControlsLabelsT[1],
"POWER_LABEL_2",
"Port 2",
"Port 2");
135 IUFillText(&PowerControlsLabelsT[2],
"POWER_LABEL_3",
"Port 3",
"Port 3");
136 IUFillText(&PowerControlsLabelsT[3],
"POWER_LABEL_4",
"Port 4",
"Port 4");
146 IUFillSwitch(&PowerControlS[0],
"POWER_CONTROL_1", portRC == -1 ?
"Port 1" : portLabel,
ISS_OFF);
151 IUFillSwitch(&PowerControlS[1],
"POWER_CONTROL_2", portRC == -1 ?
"Port 2" : portLabel,
ISS_OFF);
156 IUFillSwitch(&PowerControlS[2],
"POWER_CONTROL_3", portRC == -1 ?
"Port 3" : portLabel,
ISS_OFF);
161 IUFillSwitch(&PowerControlS[3],
"POWER_CONTROL_4", portRC == -1 ?
"Port 4" : portLabel,
ISS_OFF);
167 IUFillText(&PowerControlsLabelsT[0],
"POWER_LABEL_1",
"Port 1", PowerControlS[0].label);
168 IUFillText(&PowerControlsLabelsT[1],
"POWER_LABEL_2",
"Port 2", PowerControlS[1].label);
169 IUFillText(&PowerControlsLabelsT[2],
"POWER_LABEL_3",
"Port 3", PowerControlS[2].label);
170 IUFillText(&PowerControlsLabelsT[3],
"POWER_LABEL_4",
"Port 4", PowerControlS[3].label);
175 IUFillNumber(&PowerCurrentN[0],
"POWER_CURRENT_1", PowerControlS[0].label,
"%4.2f A", 0, 1000, 0, 0);
176 IUFillNumber(&PowerCurrentN[1],
"POWER_CURRENT_2", PowerControlS[1].label,
"%4.2f A", 0, 1000, 0, 0);
177 IUFillNumber(&PowerCurrentN[2],
"POWER_CURRENT_3", PowerControlS[2].label,
"%4.2f A", 0, 1000, 0, 0);
178 IUFillNumber(&PowerCurrentN[3],
"POWER_CURRENT_4", PowerControlS[3].label,
"%4.2f A", 0, 1000, 0, 0);
198 sprintf(tempLabel,
"%s %s",
"Dew:", AutoDewV2S[0].label);
201 sprintf(tempLabel,
"%s %s",
"Dew:", AutoDewV2S[1].label);
204 sprintf(tempLabel,
"%s %s",
"Dew:", AutoDewV2S[2].label);
212 IUFillSwitchVector(&PowerLEDSP, PowerLEDS, 2,
getDeviceName(),
"POWER_LED",
"LED", POWER_TAB,
IP_RW,
ISR_1OFMANY, 60,
215 IUFillNumber(&AdjustableOutputN[0],
"ADJUSTABLE_VOLTAGE_VALUE",
"Voltage (V)",
"%.f", 3, 12, 1, 12);
227 IUFillSwitchVector(&AutoDewSP, AutoDewS, 2,
getDeviceName(),
"AUTO_DEW",
"Auto Dew", DEW_TAB,
IP_RW,
ISR_1OFMANY, 60,
231 IUFillNumber(&AutoDewAggN[AUTO_DEW_AGG],
"AUTO_DEW_AGG_VALUE",
"Auto Dew Agg (50-250)",
"%.2f", 50, 250, 20, 0);
236 IUFillNumber(&DewPWMN[DEW_PWM_A],
"DEW_A", AutoDewV2S[0].label,
"%.2f %%", 0, 100, 10, 0);
237 IUFillNumber(&DewPWMN[DEW_PWM_B],
"DEW_B", AutoDewV2S[1].label,
"%.2f %%", 0, 100, 10, 0);
238 IUFillNumber(&DewPWMN[DEW_PWM_C],
"DEW_C", AutoDewV2S[2].label,
"%.2f %%", 0, 100, 10, 0);
242 IUFillNumber(&DewCurrentDrawN[DEW_PWM_A],
"DEW_CURRENT_A", AutoDewV2S[0].label,
"%4.2f A", 0, 1000, 10, 0);
243 IUFillNumber(&DewCurrentDrawN[DEW_PWM_B],
"DEW_CURRENT_B", AutoDewV2S[1].label,
"%4.2f A", 0, 1000, 10, 0);
244 IUFillNumber(&DewCurrentDrawN[DEW_PWM_C],
"DEW_CURRENT_C", AutoDewV2S[2].label,
"%4.2f A", 0, 1000, 10, 0);
259 IUFillText(&USBControlsLabelsT[0],
"USB_LABEL_1",
"USB3 Port1",
"USB3 Port1");
260 IUFillText(&USBControlsLabelsT[1],
"USB_LABEL_2",
"USB3 Port2",
"USB3 Port2");
261 IUFillText(&USBControlsLabelsT[2],
"USB_LABEL_3",
"USB3 Port3",
"USB3 Port3");
262 IUFillText(&USBControlsLabelsT[3],
"USB_LABEL_4",
"USB3 Port4",
"USB3 Port4");
263 IUFillText(&USBControlsLabelsT[4],
"USB_LABEL_5",
"USB2 Port5",
"USB2 Port5");
264 IUFillText(&USBControlsLabelsT[5],
"USB_LABEL_6",
"USB2 Port6",
"USB2 Port6");
277 IUFillSwitch(&USBControlV2S[0],
"PORT_1", USBRC == -1 ?
"USB3 Port1" : USBLabel,
ISS_ON);
281 IUFillSwitch(&USBControlV2S[1],
"PORT_2", USBRC == -1 ?
"USB3 Port2" : USBLabel,
ISS_ON);
285 IUFillSwitch(&USBControlV2S[2],
"PORT_3", USBRC == -1 ?
"USB3 Port3" : USBLabel,
ISS_ON);
289 IUFillSwitch(&USBControlV2S[3],
"PORT_4", USBRC == -1 ?
"USB3 Port4" : USBLabel,
ISS_ON);
293 IUFillSwitch(&USBControlV2S[4],
"PORT_5", USBRC == -1 ?
"USB2 Port5" : USBLabel,
ISS_ON);
297 IUFillSwitch(&USBControlV2S[5],
"PORT_6", USBRC == -1 ?
"USB2 Port6" : USBLabel,
ISS_ON);
303 IUFillText(&USBControlsLabelsT[0],
"USB_LABEL_1",
"USB3 Port1", USBControlV2S[0].label);
304 IUFillText(&USBControlsLabelsT[1],
"USB_LABEL_2",
"USB3 Port2", USBControlV2S[1].label);
305 IUFillText(&USBControlsLabelsT[2],
"USB_LABEL_3",
"USB3 Port3", USBControlV2S[2].label);
306 IUFillText(&USBControlsLabelsT[3],
"USB_LABEL_4",
"USB3 Port4", USBControlV2S[3].label);
307 IUFillText(&USBControlsLabelsT[4],
"USB_LABEL_5",
"USB2 Port5", USBControlV2S[4].label);
308 IUFillText(&USBControlsLabelsT[5],
"USB_LABEL_6",
"USB2 Port6", USBControlV2S[5].label);
327 IUFillNumber(&FocuserSettingsN[SETTING_MAX_SPEED],
"SETTING_MAX_SPEED",
"Max Speed (%)",
"%.f", 0, 900, 100, 400);
333 IUFillText(&FirmwareT[FIRMWARE_VERSION],
"VERSION",
"Version",
"NA");
334 IUFillText(&FirmwareT[FIRMWARE_UPTIME],
"UPTIME",
"Uptime (h)",
"NA");
340 addParameter(
"WEATHER_TEMPERATURE",
"Temperature (C)", -15, 35, 15);
341 addParameter(
"WEATHER_HUMIDITY",
"Humidity %", 0, 100, 15);
342 addParameter(
"WEATHER_DEWPOINT",
"Dew Point (C)", 0, 100, 15);
378 OverCurrentLP.
nlp = (version ==
UPB_V1) ? 4 : 7;
391 DewControlsLabelsTP.
ntp = (version ==
UPB_V1) ? 2 : 3;
397 DewPWMNP.
nnp = (version ==
UPB_V1) ? 2 : 3;
400 DewCurrentDrawNP.
nnp = (version ==
UPB_V1) ? 2 : 3;
420 setupComplete =
true;
470 setupComplete =
false;
478 return "Pegasus UPB";
484 bool PegasusUPB::Handshake()
486 char response[PEGASUS_LEN] = {0};
494 snprintf(response, PEGASUS_LEN,
"UPB2_OK");
499 int tty_rc = 0, nbytes_written = 0;
500 char command[PEGASUS_LEN] = {0};
501 tcflush(PortFD, TCIOFLUSH);
502 strncpy(command,
"P#\n", PEGASUS_LEN);
507 LOGF_ERROR(
"Serial write error: %s", errorMessage);
517 tcflush(PortFD, TCIOFLUSH);
520 tty_rc =
tty_nread_section(PortFD, response, PEGASUS_LEN, stopChar, 1, &nbytes_read);
527 LOGF_ERROR(
"Serial read error: %s", errorMessage);
532 cleanupResponse(response);
533 tcflush(PortFD, TCIOFLUSH);
539 setupComplete =
false;
541 version = strstr(response,
"UPB2_OK") ?
UPB_V2 :
UPB_V1;
554 if (!strcmp(name, PowerCycleAllSP.
name))
559 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
561 if (sendCommand(
cmd, res))
572 if (!strcmp(name, RebootSP.
name))
581 if (!strcmp(name, PowerControlSP.
name))
584 for (
int i = 0; i < n; i++)
586 if (!strcmp(names[i], PowerControlS[i].name) && states[i] != PowerControlS[i].s)
588 if (setPowerEnabled(i + 1, states[i] ==
ISS_ON) ==
false)
609 if (!strcmp(name, PowerOnBootSP.
name))
619 if ((!strcmp(name, AutoDewSP.
name)) && (version ==
UPB_V1))
630 AutoDewS[prevIndex].s =
ISS_ON;
639 if ((!strcmp(name, AutoDewV2SP.
name)) && (version ==
UPB_V2))
641 ISState Dew1 = AutoDewV2S[DEW_PWM_A].s;
642 ISState Dew2 = AutoDewV2S[DEW_PWM_B].s;
643 ISState Dew3 = AutoDewV2S[DEW_PWM_C].s;
645 if (toggleAutoDewV2())
647 Dew1 = AutoDewV2S[DEW_PWM_A].s;
648 Dew2 = AutoDewV2S[DEW_PWM_B].s;
649 Dew3 = AutoDewV2S[DEW_PWM_C].s;
658 AutoDewV2S[DEW_PWM_A].s = Dew1;
659 AutoDewV2S[DEW_PWM_B].s = Dew2;
660 AutoDewV2S[DEW_PWM_C].s = Dew3;
669 if (!strcmp(name, USBControlSP.
name))
673 if (setUSBHubEnabled(USBControlS[0].s ==
ISS_ON))
680 USBControlS[prevIndex].s =
ISS_ON;
689 if (!strcmp(name, USBControlV2SP.
name))
691 bool rc[6] = {
false};
692 std::fill_n(rc, 6,
true);
695 for (
int i = 0; i < USBControlV2SP.
nsp; i++)
696 ports[i] = USBControlV2S[i].s;
699 for (
int i = 0; i < USBControlV2SP.
nsp; i++)
701 if (ports[i] != USBControlV2S[i].s)
702 rc[i] = setUSBPortEnabled(i, USBControlV2S[i].s ==
ISS_ON);
706 if (rc[0] && rc[1] && rc[2] && rc[3] && rc[4] && rc[5])
713 for (
int i = 0; i < USBControlV2SP.
nsp; i++)
714 USBControlV2S[i].s = ports[i];
744 if (!strcmp(name, PowerLEDSP.
name) && (version ==
UPB_V1))
748 if (setPowerLEDEnabled(PowerLEDS[0].s ==
ISS_ON))
755 PowerLEDS[prevIndex].s =
ISS_ON;
763 if (strstr(name,
"FOCUS"))
778 if (!strcmp(name, AdjustableOutputNP.
name))
780 if (setAdjustableOutput(
static_cast<uint8_t
>(values[0])))
793 if (!strcmp(name, DewPWMNP.
name))
795 bool rc1 =
false, rc2 =
false, rc3 =
false;
796 for (
int i = 0; i < n; i++)
798 if (!strcmp(names[i], DewPWMN[DEW_PWM_A].name))
799 rc1 = setDewPWM(5,
static_cast<uint8_t
>(values[i] / 100.0 * 255.0));
800 else if (!strcmp(names[i], DewPWMN[DEW_PWM_B].name))
801 rc2 = setDewPWM(6,
static_cast<uint8_t
>(values[i] / 100.0 * 255.0));
802 else if (!strcmp(names[i], DewPWMN[DEW_PWM_C].name))
803 rc3 = setDewPWM(7,
static_cast<uint8_t
>(values[i] / 100.0 * 255.0));
814 if (!strcmp(name, AutoDewAggNP.
name))
816 if (setAutoDewAgg(values[0]))
818 AutoDewAggN[0].value = values[0];
831 if (!strcmp(name, FocuserSettingsNP.
name))
833 if (setFocuserMaxSpeed(values[0]))
835 FocuserSettingsN[0].value = values[0];
847 if (strstr(name,
"FOCUS_"))
850 if (strstr(name,
"WEATHER_"))
864 if (!strcmp(name, PowerControlsLabelsTP.
name))
867 PowerControlsLabelsTP.
s =
IPS_OK;
868 LOG_INFO(
"Power port labels saved. Driver must be restarted for the labels to take effect.");
870 IDSetText(&PowerControlsLabelsTP,
nullptr);
874 if (!strcmp(name, DewControlsLabelsTP.
name))
877 DewControlsLabelsTP.
s =
IPS_OK;
878 LOG_INFO(
"Dew labels saved. Driver must be restarted for the labels to take effect.");
880 IDSetText(&DewControlsLabelsTP,
nullptr);
884 if (!strcmp(name, USBControlsLabelsTP.
name))
887 USBControlsLabelsTP.
s =
IPS_OK;
888 LOG_INFO(
"USB labels saved. Driver must be restarted for the labels to take effect.");
890 IDSetText(&USBControlsLabelsTP,
nullptr);
901 bool PegasusUPB::sendCommand(
const char *
cmd,
char * res)
903 int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
908 if (!strcmp(
cmd,
"PS"))
910 strncpy(res,
"PS:1111:12", PEGASUS_LEN);
912 else if (!strcmp(
cmd,
"PA"))
914 strncpy(res,
"UPB2:12.0:0.9:10:24.8:37:9.1:1111:111111:153:153:0:0:0:0:0:70:0:0:0000000:0", PEGASUS_LEN);
916 else if (!strcmp(
cmd,
"PC"))
918 strncpy(res,
"0.40:0.00:0.03:26969", PEGASUS_LEN);
920 else if (!strcmp(
cmd,
"SA"))
922 strncpy(res,
"3000:0:0:10", PEGASUS_LEN);
924 else if (!strcmp(
cmd,
"SS"))
926 strncpy(res,
"999", PEGASUS_LEN);
928 else if (!strcmp(
cmd,
"PD"))
930 strncpy(res,
"210", PEGASUS_LEN);
932 else if (!strcmp(
cmd,
"PV"))
934 strncpy(res,
"Sim v1.0", PEGASUS_LEN);
938 strncpy(res,
cmd, PEGASUS_LEN);
944 for (
int i = 0; i < 2; i++)
946 char command[PEGASUS_LEN] = {0};
947 tcflush(PortFD, TCIOFLUSH);
948 snprintf(command, PEGASUS_LEN,
"%s\n",
cmd);
954 tcflush(PortFD, TCIOFLUSH);
962 tcflush(PortFD, TCIOFLUSH);
964 cleanupResponse(res);
984 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
985 snprintf(
cmd, PEGASUS_LEN,
"SM:%u", targetTicks);
986 if (sendCommand(
cmd, res))
1007 char res[PEGASUS_LEN] = {0};
1008 if (sendCommand(
"SH", res))
1010 return (!strcmp(res,
"SH"));
1021 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1022 snprintf(
cmd, PEGASUS_LEN,
"SR:%d", enabled ? 1 : 0);
1023 if (sendCommand(
cmd, res))
1025 return (!strcmp(res,
cmd));
1036 char cmd[PEGASUS_LEN] = {0};
1037 snprintf(
cmd, PEGASUS_LEN,
"SC:%u", ticks);
1038 return sendCommand(
cmd,
nullptr);
1046 char cmd[PEGASUS_LEN] = {0};
1047 snprintf(
cmd, PEGASUS_LEN,
"SB:%d", steps);
1048 return sendCommand(
cmd,
nullptr);
1054 bool PegasusUPB::setFocuserMaxSpeed(uint16_t maxSpeed)
1056 char cmd[PEGASUS_LEN] = {0};
1057 snprintf(
cmd, PEGASUS_LEN,
"SS:%d", maxSpeed);
1058 return sendCommand(
cmd,
nullptr);
1066 char cmd[PEGASUS_LEN] = {0};
1067 snprintf(
cmd, PEGASUS_LEN,
"SB:%d", enabled ? 1 : 0);
1068 return sendCommand(
cmd,
nullptr);
1074 bool PegasusUPB::setPowerEnabled(uint8_t port,
bool enabled)
1076 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1077 snprintf(
cmd, PEGASUS_LEN,
"P%d:%d", port, enabled ? 1 : 0);
1078 if (sendCommand(
cmd, res))
1080 return (!strcmp(res,
cmd));
1089 bool PegasusUPB::setPowerLEDEnabled(
bool enabled)
1091 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1092 snprintf(
cmd, PEGASUS_LEN,
"PL:%d", enabled ? 1 : 0);
1093 if (sendCommand(
cmd, res))
1095 return (!strcmp(res,
cmd));
1104 bool PegasusUPB::setAutoDewEnabled(
bool enabled)
1106 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1107 snprintf(
cmd, PEGASUS_LEN,
"PD:%d", enabled ? 1 : 0);
1108 if (sendCommand(
cmd, res))
1110 return (!strcmp(res,
cmd));
1119 bool PegasusUPB::setAutoDewAgg(uint8_t value)
1121 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0};
1122 snprintf(
cmd, PEGASUS_LEN,
"PD:%03d", value);
1123 snprintf(expected, PEGASUS_LEN,
"PD:%d", value);
1124 if (sendCommand(
cmd, res))
1126 return (!strcmp(res, expected));
1134 bool PegasusUPB::setAdjustableOutput(uint8_t voltage)
1136 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1137 snprintf(
cmd, PEGASUS_LEN,
"P8:%d", voltage);
1138 if (sendCommand(
cmd, res))
1140 return (!strcmp(res,
cmd));
1149 bool PegasusUPB::setPowerOnBoot()
1151 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1152 snprintf(
cmd, PEGASUS_LEN,
"PE:%d%d%d%d", PowerOnBootS[0].s ==
ISS_ON ? 1 : 0,
1153 PowerOnBootS[1].s ==
ISS_ON ? 1 : 0,
1154 PowerOnBootS[2].s ==
ISS_ON ? 1 : 0,
1155 PowerOnBootS[3].s ==
ISS_ON ? 1 : 0);
1156 if (sendCommand(
cmd, res))
1158 return (!strcmp(res,
"PE:1"));
1167 bool PegasusUPB::getPowerOnBoot()
1169 char res[PEGASUS_LEN] = {0};
1170 if (sendCommand(
"PS", res))
1172 std::vector<std::string> result = split(res,
":");
1173 if (result.size() != 3)
1175 LOGF_WARN(
"Received wrong number (%i) of power on boot data (%s). Retrying...", result.size(), res);
1179 const char *status = result[1].c_str();
1185 AdjustableOutputN[0].value = std::stod(result[2]);
1186 AdjustableOutputNP.
s =
IPS_OK;
1197 bool PegasusUPB::setDewPWM(uint8_t
id, uint8_t value)
1199 char cmd[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0};
1200 snprintf(
cmd, PEGASUS_LEN,
"P%d:%03d",
id, value);
1201 snprintf(expected, PEGASUS_LEN,
"P%d:%d",
id, value);
1202 if (sendCommand(
cmd, res))
1204 return (!strcmp(res, expected));
1213 bool PegasusUPB::setUSBHubEnabled(
bool enabled)
1215 char cmd[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1216 snprintf(
cmd, PEGASUS_LEN,
"PU:%d", enabled ? 1 : 0);
1217 snprintf(expected, PEGASUS_LEN,
"PU:%d", enabled ? 0 : 1);
1218 if (sendCommand(
cmd, res))
1220 return (!strcmp(res, expected));
1229 bool PegasusUPB::setUSBPortEnabled(uint8_t port,
bool enabled)
1231 char cmd[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1232 snprintf(
cmd, PEGASUS_LEN,
"U%d:%d", port + 1, enabled ? 1 : 0);
1233 snprintf(expected, PEGASUS_LEN,
"U%d:%d", port + 1, enabled ? 1 : 0);
1234 if (sendCommand(
cmd, res))
1236 return (!strcmp(res, expected));
1245 bool PegasusUPB::toggleAutoDewV2()
1247 char cmd[PEGASUS_LEN] = {0}, expected[PEGASUS_LEN] = {0}, res[PEGASUS_LEN] = {0};
1253 else if (AutoDewV2S[DEW_PWM_A].s ==
ISS_ON && AutoDewV2S[DEW_PWM_B].s ==
ISS_ON && AutoDewV2S[DEW_PWM_C].s ==
ISS_ON)
1255 else if (AutoDewV2S[DEW_PWM_A].s ==
ISS_ON && AutoDewV2S[DEW_PWM_B].s ==
ISS_ON)
1257 else if (AutoDewV2S[DEW_PWM_A].s ==
ISS_ON && AutoDewV2S[DEW_PWM_C].s ==
ISS_ON)
1259 else if (AutoDewV2S[DEW_PWM_B].s ==
ISS_ON && AutoDewV2S[DEW_PWM_C].s ==
ISS_ON)
1261 else if (AutoDewV2S[DEW_PWM_A].s ==
ISS_ON)
1263 else if (AutoDewV2S[DEW_PWM_B].s ==
ISS_ON)
1265 else if (AutoDewV2S[DEW_PWM_C].s ==
ISS_ON)
1268 snprintf(
cmd, PEGASUS_LEN,
"PD:%d", value);
1269 snprintf(expected, PEGASUS_LEN,
"PD:%d", value);
1270 if (sendCommand(
cmd, res))
1272 return (!strcmp(res, expected));
1310 if (getSensorData())
1325 bool PegasusUPB::sendFirmware()
1327 char res[PEGASUS_LEN] = {0};
1328 if (sendCommand(
"PV", res))
1331 IUSaveText(&FirmwareT[FIRMWARE_VERSION], res);
1342 bool PegasusUPB::sensorUpdated(
const std::vector<std::string> &result, uint8_t start, uint8_t end)
1344 if (lastSensorData.empty())
1347 for (uint8_t index = start; index <= end; index++)
1349 if (index >= lastSensorData.size() or result[index] != lastSensorData[index])
1359 bool PegasusUPB::stepperUpdated(
const std::vector<std::string> &result, u_int8_t index)
1361 if (lastStepperData.empty())
1364 return index >= lastStepperData.size() or result[index] != lastSensorData[index];
1370 bool PegasusUPB::getSensorData()
1372 char res[PEGASUS_LEN] = {0};
1373 if (sendCommand(
"PA", res))
1375 std::vector<std::string> result = split(res,
":");
1376 if ( (version ==
UPB_V1 && result.size() != 19) ||
1377 (version ==
UPB_V2 && result.size() != 21))
1379 LOGF_WARN(
"Received wrong number (%i) of detailed sensor data (%s). Retrying...", result.size(), res);
1383 if (result == lastSensorData)
1387 PowerSensorsN[SENSOR_VOLTAGE].value = std::stod(result[1]);
1388 PowerSensorsN[SENSOR_CURRENT].value = std::stod(result[2]);
1389 PowerSensorsN[SENSOR_POWER].value = std::stod(result[3]);
1392 if (sensorUpdated(result, 0, 2))
1400 if (sensorUpdated(result, 4, 6))
1409 const char * portStatus = result[7].c_str();
1410 PowerControlS[0].s = (portStatus[0] ==
'1') ?
ISS_ON :
ISS_OFF;
1411 PowerControlS[1].s = (portStatus[1] ==
'1') ?
ISS_ON :
ISS_OFF;
1412 PowerControlS[2].s = (portStatus[2] ==
'1') ?
ISS_ON :
ISS_OFF;
1413 PowerControlS[3].s = (portStatus[3] ==
'1') ?
ISS_ON :
ISS_OFF;
1415 if (sensorUpdated(result, 7, 7))
1419 const char * usb_status = result[8].c_str();
1422 USBControlS[0].s = (usb_status[0] ==
'0') ?
ISS_ON :
ISS_OFF;
1423 USBControlS[1].s = (usb_status[0] ==
'0') ?
ISS_OFF :
ISS_ON;
1430 if (sensorUpdated(result, 8, 8))
1439 USBControlV2S[0].s = (usb_status[0] ==
'1') ?
ISS_ON :
ISS_OFF;
1440 USBControlV2S[1].s = (usb_status[1] ==
'1') ?
ISS_ON :
ISS_OFF;
1441 USBControlV2S[2].s = (usb_status[2] ==
'1') ?
ISS_ON :
ISS_OFF;
1442 USBControlV2S[3].s = (usb_status[3] ==
'1') ?
ISS_ON :
ISS_OFF;
1443 USBControlV2S[4].s = (usb_status[4] ==
'1') ?
ISS_ON :
ISS_OFF;
1444 USBControlV2S[5].s = (usb_status[5] ==
'1') ?
ISS_ON :
ISS_OFF;
1447 if (sensorUpdated(result, 8, 8))
1456 DewPWMN[DEW_PWM_A].value = std::stod(result[index]) / 255.0 * 100.0;
1457 DewPWMN[DEW_PWM_B].value = std::stod(result[index + 1]) / 255.0 * 100.0;
1459 DewPWMN[DEW_PWM_C].value = std::stod(result[index + 2]) / 255.0 * 100.0;
1463 if (sensorUpdated(result, index, version ==
UPB_V1 ? index + 1 : index + 2))
1466 index = (version ==
UPB_V1) ? 11 : 12;
1468 const double ampDivision = (version ==
UPB_V1) ? 400.0 : 480.0;
1471 PowerCurrentN[0].value = std::stod(result[index]) / ampDivision;
1472 PowerCurrentN[1].value = std::stod(result[index + 1]) / ampDivision;
1473 PowerCurrentN[2].value = std::stod(result[index + 2]) / ampDivision;
1474 PowerCurrentN[3].value = std::stod(result[index + 3]) / ampDivision;
1479 if (sensorUpdated(result, index, index + 3))
1482 index = (version ==
UPB_V1) ? 15 : 16;
1484 DewCurrentDrawN[DEW_PWM_A].value = std::stod(result[index]) / ampDivision;
1485 DewCurrentDrawN[DEW_PWM_B].value = std::stod(result[index + 1]) / ampDivision;
1487 DewCurrentDrawN[DEW_PWM_C].value = std::stod(result[index + 2]) / 700;
1491 if (sensorUpdated(result, index, version ==
UPB_V1 ? index + 1 : index + 2))
1494 index = (version ==
UPB_V1) ? 17 : 19;
1498 if (sensorUpdated(result, index, index))
1500 const char * over_curent = result[index].c_str();
1515 index = (version ==
UPB_V1) ? 18 : 20;
1521 if (sensorUpdated(result, index, index))
1531 if (sensorUpdated(result, index, index))
1533 int value = std::stoi(result[index]);
1538 AutoDewV2S[DEW_PWM_A].s = AutoDewV2S[DEW_PWM_B].s = AutoDewV2S[DEW_PWM_C].s =
ISS_ON;
1542 AutoDewV2S[DEW_PWM_A].s =
ISS_ON;
1546 AutoDewV2S[DEW_PWM_B].s =
ISS_ON;
1550 AutoDewV2S[DEW_PWM_C].s =
ISS_ON;
1554 AutoDewV2S[DEW_PWM_A].s =
ISS_ON;
1555 AutoDewV2S[DEW_PWM_B].s =
ISS_ON;
1559 AutoDewV2S[DEW_PWM_A].s =
ISS_ON;
1560 AutoDewV2S[DEW_PWM_C].s =
ISS_ON;
1564 AutoDewV2S[DEW_PWM_B].s =
ISS_ON;
1565 AutoDewV2S[DEW_PWM_C].s =
ISS_ON;
1574 lastSensorData = result;
1584 bool PegasusUPB::getPowerData()
1586 char res[PEGASUS_LEN] = {0};
1587 if (sendCommand(
"PC", res))
1589 std::vector<std::string> result = split(res,
":");
1590 if (result.size() != 4)
1592 LOGF_WARN(
"Received wrong number (%i) of power sensor data (%s). Retrying...", result.size(), res);
1596 if (result == lastPowerData)
1599 PowerConsumptionN[CONSUMPTION_AVG_AMPS].value = std::stod(result[0]);
1600 PowerConsumptionN[CONSUMPTION_AMP_HOURS].value = std::stod(result[1]);
1601 PowerConsumptionN[CONSUMPTION_WATT_HOURS].value = std::stod(result[2]);
1602 PowerConsumptionNP.
s =
IPS_OK;
1607 std::chrono::milliseconds uptime(std::stol(result[3]));
1608 using dhours = std::chrono::duration<double, std::ratio<3600>>;
1609 std::stringstream ss;
1610 ss << std::fixed << std::setprecision(3) << dhours(uptime).count();
1611 IUSaveText(&FirmwareT[FIRMWARE_UPTIME], ss.str().c_str());
1616 IUSaveText(&FirmwareT[FIRMWARE_UPTIME],
"NA");
1617 LOGF_DEBUG(
"Failed to process uptime: %s", result[3].c_str());
1622 lastPowerData = result;
1632 bool PegasusUPB::getStepperData()
1634 char res[PEGASUS_LEN] = {0};
1635 if (sendCommand(
"SA", res))
1637 std::vector<std::string> result = split(res,
":");
1638 if (result.size() != 4)
1640 LOGF_WARN(
"Received wrong number (%i) of stepper sensor data (%s). Retrying...", result.size(), res);
1644 if (result == lastStepperData)
1648 focusMotorRunning = (std::stoi(result[1]) == 1);
1657 else if (stepperUpdated(result, 0))
1663 if (stepperUpdated(result, 1))
1666 uint16_t backlash = std::stoi(result[3]);
1672 if (stepperUpdated(result, 3))
1683 if (stepperUpdated(result, 3))
1690 lastStepperData = result;
1696 bool PegasusUPB::getDewAggData()
1698 char res[PEGASUS_LEN] = {0};
1699 if (sendCommand(
"DA", res))
1701 std::vector<std::string> result = split(res,
":");
1702 if (result.size() != 2)
1704 LOGF_WARN(
"Received wrong number (%i) of dew aggresiveness data (%s). Retrying...", result.size(), res);
1708 if (result == lastDewAggData)
1711 AutoDewAggN[0].value = std::stod(result[1]);
1715 lastDewAggData = result;
1723 bool PegasusUPB::reboot()
1725 return sendCommand(
"PF",
nullptr);
1731 std::vector<std::string> PegasusUPB::split(
const std::string &input,
const std::string ®ex)
1734 std::regex re(regex);
1735 std::sregex_token_iterator
1736 first{input.begin(), input.end(), re, -1},
1738 return {first, last};
1744 bool PegasusUPB::setupParams()
1752 char res[PEGASUS_LEN] = {0};
1753 if (sendCommand(
"SS", res))
1757 uint32_t
value = std::stol(res);
1758 if (value == UINT16_MAX)
1760 LOGF_WARN(
"Invalid maximum speed detected: %u. Please set maximum speed appropriate for your motor focus type (0-900)",
1766 FocuserSettingsN[SETTING_MAX_SPEED].value =
value;
1772 LOGF_WARN(
"Failed to process focuser max speed: %s", res);
1783 void PegasusUPB::cleanupResponse(
char *response)
1785 std::string s(response);
1786 s.erase(std::remove_if(s.begin(), s.end(),
1789 return std::isspace(x);
1791 strncpy(response, s.c_str(), PEGASUS_LEN);
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
const char * getDeviceName() const
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
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)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
Provides interface to implement focuser functionality.
ISwitchVectorProperty FocusBacklashSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
ISwitchVectorProperty FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INumber FocusBacklashN[1]
void initProperties(const char *groupName)
Initilize focuser properties. It is recommended to call this function within initProperties() of your...
bool saveConfigItems(FILE *fp)
saveConfigItems save focuser properties defined in the interface in config file
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process focus number properties.
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process focus switch properties.
ISwitch FocusBacklashS[2]
Provides interface to implement weather reporting functionality.
bool syncCriticalParameters()
updateWeatherState Send update weather state to client
void setParameterValue(std::string name, double value)
setParameterValue Update weather parameter value
bool setCriticalParameter(std::string param)
setCriticalParameter Set parameter that is considered critical to the operation of the observatory....
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process weather number properties.
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save parameters ranges in the config file.
ILightVectorProperty critialParametersLP
INumberVectorProperty ParametersNP
void addParameter(std::string name, std::string label, double numMinOk, double numMaxOk, double percWarning)
addParameter Add a physical weather measurable parameter to the weather driver. The weather value has...
void initProperties(const char *statusGroup, const char *paramsGroup)
Initilize focuser properties. It is recommended to call this function within initProperties() of your...
bool updateProperties()
updateProperties Define or Delete Rotator properties based on the connection status of the base devic...
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
const char * getDefaultName() override
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
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.
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
const char * FOCUS_TAB
FOCUS_TAB Where all the properties for focuser are located.
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 tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Implementations for common driver routines.
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
void IUFillLight(ILight *lp, const char *name, const char *label, IPState s)
Assign attributes for a light property. The light's auxiliary elements will be set to NULL.
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 IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char *dev, const char *name, const char *label, const char *group, IPState s)
Assign attributes for a light vector property. The vector's auxiliary elements will be set to NULL.
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 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 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 IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
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 IDSetLight(const ILightVectorProperty *lvp, const char *fmt,...)
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 IUGetConfigText(const char *dev, const char *property, const char *member, char *value, int len)
IUGetConfigText Opens configuration file and reads single text property.
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
#define LOGF_WARN(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOGF_ERROR(fmt,...)
@ value
the parser finished reading a JSON value