33#define BACKLASH_READOUT 99999
34#define MAXTRAVEL_READOUT 99999
36#define currentDuty SettingsN[0].value
37#define currentDelay SettingsN[1].value
38#define currentTicks SettingsN[2].value
39#define currentMaxTravel MaxTravelN[0].value
40#define currentMinPosition MinMaxPositionN[0].value
41#define currentMaxPosition MinMaxPositionN[1].value
44#define SETTINGS_TAB "Settings"
46static std::unique_ptr<RoboFocus> roboFocus(
new RoboFocus());
59 IUFillNumber(&TemperatureN[0],
"TEMPERATURE",
"Celsius",
"%6.2f", 0, 65000., 0., 10000.);
64 IUFillNumber(&SettingsN[0],
"Duty cycle",
"Duty cycle",
"%6.0f", 0., 255., 0., 1.0);
65 IUFillNumber(&SettingsN[1],
"Step Delay",
"Step delay",
"%6.0f", 0., 255., 0., 1.0);
66 IUFillNumber(&SettingsN[2],
"Motor Steps",
"Motor steps per tick",
"%6.0f", 0., 255., 0., 1.0);
79 IUFillNumber(&MinMaxPositionN[0],
"MINPOS",
"Minimum Tick",
"%6.0f", 1., 65000., 0., 100.);
80 IUFillNumber(&MinMaxPositionN[1],
"MAXPOS",
"Maximum Tick",
"%6.0f", 1., 65000., 0., 55000.);
84 IUFillNumber(&MaxTravelN[0],
"MAXTRAVEL",
"Maximum travel",
"%6.0f", 1., 64000., 0., 10000.);
108 simulatedTemperature = 600.0;
109 simulatedPosition = 20000;
130 LOG_DEBUG(
"RoboFocus parameters readout complete, focuser ready for use.");
146 char firmeware[] =
"FV0000000";
151 LOG_INFO(
"Simulated Robofocus is online. Getting focus parameters...");
153 updateRFFirmware(firmeware);
157 if ((updateRFFirmware(firmeware)) < 0)
160 LOG_ERROR(
"Unknown error while reading Robofocus firmware.");
172unsigned char RoboFocus::CheckSum(
char *rf_cmd)
175 unsigned char val = 0;
177 for (
int i = 0; i < 8; i++)
178 substr[i] = rf_cmd[i];
180 val = CalculateSum(substr);
182 if (val != (
unsigned char)rf_cmd[8])
183 LOGF_WARN(
"Checksum: Wrong (%s,%ld), %x != %x", rf_cmd, strlen(rf_cmd), val,
184 (
unsigned char)rf_cmd[8]);
189unsigned char RoboFocus::CalculateSum(
const char *rf_cmd)
191 unsigned char val = 0;
193 for (
int i = 0; i < 8; i++)
194 val = val + (
unsigned char)rf_cmd[i];
199int RoboFocus::SendCommand(
char *rf_cmd)
201 int nbytes_written = 0, err_code = 0;
202 char rf_cmd_cks[32], robofocus_error[
MAXRBUF];
204 unsigned char val = 0;
206 val = CalculateSum(rf_cmd);
208 for (
int i = 0; i < 8; i++)
209 rf_cmd_cks[i] = rf_cmd[i];
211 rf_cmd_cks[8] = (
unsigned char)val;
217 tcflush(
PortFD, TCIOFLUSH);
219 LOGF_DEBUG(
"CMD (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X)", rf_cmd_cks[0],
220 rf_cmd_cks[1], rf_cmd_cks[2], rf_cmd_cks[3], rf_cmd_cks[4], rf_cmd_cks[5], rf_cmd_cks[6], rf_cmd_cks[7],
226 LOGF_ERROR(
"TTY error detected: %s", robofocus_error);
230 return nbytes_written;
233int RoboFocus::ReadResponse(
char *buf)
236 char robofocus_char[1];
241 bool externalMotion =
false;
251 LOGF_ERROR(
"TTY error detected: %s", robofocus_error);
255 switch (robofocus_char[0])
266 externalMotion =
true;
283 externalMotion =
true;
298 LOGF_ERROR(
"TTY error detected: %s", robofocus_error);
314 tcflush(
PortFD, TCIOFLUSH);
315 return (bytesRead + 1);
326int RoboFocus::updateRFPosition(
double *value)
336 *value = simulatedPosition;
340 strncpy(rf_cmd,
"FG000000", 9);
342 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
345 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
348 if (sscanf(rf_cmd,
"FD%6f", &temp) < 1)
351 *value = (double)temp;
358int RoboFocus::updateRFTemperature(
double *value)
366 strncpy(rf_cmd,
"FT000000", 9);
368 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
372 snprintf(rf_cmd, 32,
"FT%6g", simulatedTemperature);
373 else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
376 if (sscanf(rf_cmd,
"FT%6f", &temp) < 1)
379 *value = (double)temp / 2. - 273.15;
384int RoboFocus::updateRFBacklash(
double *value)
402 strncpy(rf_cmd,
"FB000000", 9);
423 sprintf(vl_tmp,
"%3d", (
int)*value);
427 sprintf(vl_tmp,
"0%2d", (
int)*value);
431 sprintf(vl_tmp,
"00%1d", (
int)*value);
433 rf_cmd[5] = vl_tmp[0];
434 rf_cmd[6] = vl_tmp[1];
435 rf_cmd[7] = vl_tmp[2];
438 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
441 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
444 if (sscanf(rf_cmd,
"FB%1d%5f", &sign, &temp) < 1)
447 *value = (double)temp;
449 if ((sign == 2) && (*value > 0))
457int RoboFocus::updateRFFirmware(
char *rf_cmd)
461 LOG_DEBUG(
"Querying RoboFocus Firmware...");
463 strncpy(rf_cmd,
"FV000000", 9);
465 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
469 strncpy(rf_cmd,
"SIM", 4);
470 else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
476int RoboFocus::updateRFMotorSettings(
double *duty,
double *delay,
double *ticks)
478 LOGF_DEBUG(
"Update Motor Settings: Duty (%g), Delay (%g), Ticks(%g)", *duty, *delay, *ticks);
491 if ((*duty == 0) && (*delay == 0) && (*ticks == 0))
493 strncpy(rf_cmd,
"FC000000", 9);
499 rf_cmd[2] = (char) * duty;
500 rf_cmd[3] = (char) * delay;
501 rf_cmd[4] = (char) * ticks;
508 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
511 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
514 *duty = (float)rf_cmd[2];
515 *delay = (float)rf_cmd[3];
516 *ticks = (float)rf_cmd[4];
521int RoboFocus::updateRFPositionRelativeInward(
double value)
528 LOGF_DEBUG(
"Update Relative Position Inward: %g", value);
532 simulatedPosition += value;
539 sprintf(rf_cmd,
"FI0%5d", (
int)value);
541 else if (value > 999)
543 sprintf(rf_cmd,
"FI00%4d", (
int)value);
547 sprintf(rf_cmd,
"FI000%3d", (
int)value);
551 sprintf(rf_cmd,
"FI0000%2d", (
int)value);
555 sprintf(rf_cmd,
"FI00000%1d", (
int)value);
558 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
564int RoboFocus::updateRFPositionRelativeOutward(
double value)
570 LOGF_DEBUG(
"Update Relative Position Outward: %g", value);
574 simulatedPosition -= value;
583 sprintf(rf_cmd,
"FO0%5d", (
int)value);
585 else if (value > 999)
587 sprintf(rf_cmd,
"FO00%4d", (
int)value);
591 sprintf(rf_cmd,
"FO000%3d", (
int)value);
595 sprintf(rf_cmd,
"FO0000%2d", (
int)value);
599 sprintf(rf_cmd,
"FO00000%1d", (
int)value);
602 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
608int RoboFocus::updateRFPositionAbsolute(
double value)
613 LOGF_DEBUG(
"Moving Absolute Position: %g", value);
617 simulatedPosition = value;
625 sprintf(rf_cmd,
"FG0%5d", (
int)value);
627 else if (value > 999)
629 sprintf(rf_cmd,
"FG00%4d", (
int)value);
633 sprintf(rf_cmd,
"FG000%3d", (
int)value);
637 sprintf(rf_cmd,
"FG0000%2d", (
int)value);
641 sprintf(rf_cmd,
"FG00000%1d", (
int)value);
644 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
650int RoboFocus::updateRFPowerSwitches(
int s,
int new_sn,
int *cur_s1LL,
int *cur_s2LR,
int *cur_s3RL,
int *cur_s4RR)
666 strncpy(rf_cmd_tmp,
"FP000000", 9);
668 if ((robofocus_rc = SendCommand(rf_cmd_tmp)) < 0)
671 if ((robofocus_rc = ReadResponse(rf_cmd_tmp)) < 0)
674 for (i = 0; i < 9; i++)
676 rf_cmd[i] = rf_cmd_tmp[i];
679 if (rf_cmd[new_sn + 4] ==
'2')
681 rf_cmd[new_sn + 4] =
'1';
685 rf_cmd[new_sn + 4] =
'2';
690 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
693 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
696 *cur_s1LL = *cur_s2LR = *cur_s3RL = *cur_s4RR =
ISS_OFF;
698 if (rf_cmd[4] ==
'2')
703 if (rf_cmd[5] ==
'2')
708 if (rf_cmd[6] ==
'2')
713 if (rf_cmd[7] ==
'2')
720int RoboFocus::updateRFMaxPosition(
double *value)
737 strncpy(rf_cmd,
"FL000000", 9);
747 sprintf(vl_tmp,
"%5d", (
int)*value);
749 else if (*value > 999)
751 sprintf(vl_tmp,
"0%4d", (
int)*value);
753 else if (*value > 99)
755 sprintf(vl_tmp,
"00%3d", (
int)*value);
759 sprintf(vl_tmp,
"000%2d", (
int)*value);
763 sprintf(vl_tmp,
"0000%1d", (
int)*value);
765 rf_cmd[3] = vl_tmp[0];
766 rf_cmd[4] = vl_tmp[1];
767 rf_cmd[5] = vl_tmp[2];
768 rf_cmd[6] = vl_tmp[3];
769 rf_cmd[7] = vl_tmp[4];
773 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
776 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
779 if (sscanf(rf_cmd,
"FL%1c%5f", waste, &temp) < 1)
782 *value = (double)temp;
807 snprintf(vl_tmp, 6,
"%5d", ticks);
809 else if (ticks > 999)
811 snprintf(vl_tmp, 6,
"0%4d", ticks);
815 snprintf(vl_tmp, 6,
"00%3d", ticks);
819 snprintf(vl_tmp, 6,
"000%2d", ticks);
823 snprintf(vl_tmp, 6,
"0000%1d", ticks);
825 rf_cmd[3] = vl_tmp[0];
826 rf_cmd[4] = vl_tmp[1];
827 rf_cmd[5] = vl_tmp[2];
828 rf_cmd[6] = vl_tmp[3];
829 rf_cmd[7] = vl_tmp[4];
832 if ((ret_read_tmp = SendCommand(rf_cmd)) < 0)
842 if (strcmp(name, PowerSwitchesSP.
name) == 0)
859 for (nset = i = 0; i < n; i++)
866 if (sp == &PowerSwitchesS[0])
872 else if (sp == &PowerSwitchesS[1])
878 else if (sp == &PowerSwitchesS[2])
884 else if (sp == &PowerSwitchesS[3])
893 cur_s1LL = cur_s2LR = cur_s3RL = cur_s4RR = 0;
895 if ((ret = updateRFPowerSwitches(new_s, new_sn, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
898 IDSetSwitch(&PowerSwitchesSP,
"Unknown error while reading Robofocus power switch settings");
907 IDSetNumber(&SettingsNP,
"Power switch settings absent or bogus.");
922 if (strcmp(name, SettingsNP.
name) == 0)
926 double new_delay = 0;
927 double new_ticks = 0;
930 for (nset = i = 0; i < n; i++)
936 if (eqp == &SettingsN[0])
938 new_duty = (values[i]);
939 nset +=
static_cast<int>(new_duty >= 0 && new_duty <= 255);
941 else if (eqp == &SettingsN[1])
943 new_delay = (values[i]);
944 nset +=
static_cast<int>(new_delay >= 0 && new_delay <= 255);
946 else if (eqp == &SettingsN[2])
948 new_ticks = (values[i]);
949 nset +=
static_cast<int>(new_ticks >= 0 && new_ticks <= 255);
961 if ((ret = updateRFMotorSettings(&new_duty, &new_delay, &new_ticks)) < 0)
963 IDSetNumber(&SettingsNP,
"Changing to new settings failed");
981 IDSetNumber(&SettingsNP,
"Settings absent or bogus.");
986 if (strcmp(name, MinMaxPositionNP.
name) == 0)
992 for (nset = i = 0; i < n; i++)
998 if (mmpp == &MinMaxPositionN[0])
1000 new_min = (values[i]);
1001 nset +=
static_cast<int>(new_min >= 1 && new_min <= 65000);
1003 else if (mmpp == &MinMaxPositionN[1])
1005 new_max = (values[i]);
1006 nset +=
static_cast<int>(new_max >= 1 && new_max <= 65000);
1029 IDSetNumber(&MinMaxPositionNP,
"Minimum and maximum limits absent or bogus.");
1035 if (strcmp(name, MaxTravelNP.
name) == 0)
1037 double new_maxt = 0;
1040 for (nset = i = 0; i < n; i++)
1046 if (mmpp == &MaxTravelN[0])
1048 new_maxt = (values[i]);
1049 nset +=
static_cast<int>(new_maxt >= 1 && new_maxt <= 64000);
1057 if ((ret = updateRFMaxPosition(&new_maxt)) < 0)
1060 IDSetNumber(&MaxTravelNP,
"Changing to new maximum travel failed");
1074 IDSetNumber(&MaxTravelNP,
"Maximum travel absent or bogus.");
1084void RoboFocus::GetFocusParams()
1092 double currentPosition = 0;
1093 if ((ret = updateRFPosition(¤tPosition)) < 0)
1096 LOGF_ERROR(
"Unknown error while reading Robofocus position: %d", ret);
1105 double currentTemperature = 0;
1108 if ((ret = updateRFTemperature(¤tTemperature)) < 0)
1111 LOG_ERROR(
"Unknown error while reading Robofocus temperature.");
1116 TemperatureN[0].value = currentTemperature;
1120 double currentBacklash = 0;
1123 if ((ret = updateRFBacklash(¤tBacklash)) < 0)
1126 LOG_ERROR(
"Unknown error while reading Robofocus backlash.");
1139 LOG_ERROR(
"Unknown error while reading Robofocus motor settings.");
1147 if ((ret = updateRFPowerSwitches(-1, -1, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
1150 LOG_ERROR(
"Unknown error while reading Robofocus power switch settings.");
1155 PowerSwitchesS[0].s = PowerSwitchesS[1].s = PowerSwitchesS[2].s = PowerSwitchesS[3].s =
ISS_OFF;
1159 PowerSwitchesS[0].s =
ISS_ON;
1163 PowerSwitchesS[1].s =
ISS_ON;
1167 PowerSwitchesS[2].s =
ISS_ON;
1171 PowerSwitchesS[3].s =
ISS_ON;
1180 targetPos = targetTicks;
1184 LOG_DEBUG(
"Error, requested position is out of range.");
1188 if ((ret = updateRFPositionAbsolute(targetPos)) < 0)
1190 LOGF_DEBUG(
"Read out of the absolute movement failed %3d", ret);
1222 int rc = updateRFPosition(&newPos);
1233 int nbytes_read = 0;
1238 nbytes_read = ReadResponse(rf_cmd);
1240 rf_cmd[nbytes_read - 1] = 0;
1242 if (nbytes_read != 9 || (sscanf(rf_cmd,
"FD0%5f", &newPos) <= 0))
1245 "Bogus position: (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X) - Bytes read: %d",
1246 rf_cmd[0], rf_cmd[1], rf_cmd[2], rf_cmd[3], rf_cmd[4], rf_cmd[5], rf_cmd[6], rf_cmd[7], rf_cmd[8],
1251 else if (nbytes_read < 0)
1254 LOG_ERROR(
"Read error! Reconnect and try again.");
1288 const char *buf =
"\r";
1295 double value = steps;
1296 return (updateRFBacklash(&value) == 0);
void addSimulationControl()
Add Simulation control to the driver.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
bool isSimulation() const
void RemoveTimer(int id)
Remove timer added with SetTimer.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusMaxPosNP
INDI::PropertyNumber FocusBacklashNP
INDI::PropertyNumber FocusAbsPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
virtual bool saveConfigItems(FILE *fp) override
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
void setPermission(IPerm permission)
virtual bool saveConfigItems(FILE *fp) override
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
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 updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
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
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
const char * getDefaultName() override
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Implementations for common driver routines.
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.
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *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 DEBUGF(priority, msg,...)
#define currentMinPosition
#define MAXTRAVEL_READOUT
#define currentMaxPosition