33 #define BACKLASH_READOUT 99999
34 #define MAXTRAVEL_READOUT 99999
36 #define currentSpeed SpeedN[0].value
37 #define currentPosition FocusAbsPosN[0].value
38 #define currentTemperature TemperatureN[0].value
39 #define currentBacklash FocusBacklashN[0].value
40 #define currentDuty SettingsN[0].value
41 #define currentDelay SettingsN[1].value
42 #define currentTicks SettingsN[2].value
43 #define currentRelativeMovement FocusRelPosN[0].value
44 #define currentAbsoluteMovement FocusAbsPosN[0].value
45 #define currentSetBacklash SetBacklashN[0].value
46 #define currentMinPosition MinMaxPositionN[0].value
47 #define currentMaxPosition MinMaxPositionN[1].value
48 #define currentMaxTravel FocusMaxPosN[0].value
50 #define SETTINGS_TAB "Settings"
52 static std::unique_ptr<RoboFocus> roboFocus(
new RoboFocus());
65 IUFillNumber(&TemperatureN[0],
"TEMPERATURE",
"Celsius",
"%6.2f", 0, 65000., 0., 10000.);
70 IUFillNumber(&SettingsN[0],
"Duty cycle",
"Duty cycle",
"%6.0f", 0., 255., 0., 1.0);
71 IUFillNumber(&SettingsN[1],
"Step Delay",
"Step delay",
"%6.0f", 0., 255., 0., 1.0);
72 IUFillNumber(&SettingsN[2],
"Motor Steps",
"Motor steps per tick",
"%6.0f", 0., 255., 0., 1.0);
85 IUFillNumber(&MinMaxPositionN[0],
"MINPOS",
"Minimum Tick",
"%6.0f", 1., 65000., 0., 100.);
86 IUFillNumber(&MinMaxPositionN[1],
"MAXPOS",
"Maximum Tick",
"%6.0f", 1., 65000., 0., 55000.);
90 IUFillNumber(&MaxTravelN[0],
"MAXTRAVEL",
"Maximum travel",
"%6.0f", 1., 64000., 0., 10000.);
124 simulatedTemperature = 600.0;
125 simulatedPosition = 20000;
151 LOG_DEBUG(
"RoboFocus parameters readout complete, focuser ready for use.");
171 char firmeware[] =
"FV0000000";
176 LOG_INFO(
"Simulated Robofocus is online. Getting focus parameters...");
178 updateRFFirmware(firmeware);
182 if ((updateRFFirmware(firmeware)) < 0)
185 LOG_ERROR(
"Unknown error while reading Robofocus firmware.");
197 unsigned char RoboFocus::CheckSum(
char *rf_cmd)
200 unsigned char val = 0;
202 for (
int i = 0; i < 8; i++)
203 substr[i] = rf_cmd[i];
205 val = CalculateSum(substr);
207 if (val != (
unsigned char)rf_cmd[8])
208 LOGF_WARN(
"Checksum: Wrong (%s,%ld), %x != %x", rf_cmd, strlen(rf_cmd), val,
209 (
unsigned char)rf_cmd[8]);
214 unsigned char RoboFocus::CalculateSum(
const char *rf_cmd)
216 unsigned char val = 0;
218 for (
int i = 0; i < 8; i++)
219 val = val + (
unsigned char)rf_cmd[i];
224 int RoboFocus::SendCommand(
char *rf_cmd)
226 int nbytes_written = 0, err_code = 0;
227 char rf_cmd_cks[32], robofocus_error[
MAXRBUF];
229 unsigned char val = 0;
231 val = CalculateSum(rf_cmd);
233 for (
int i = 0; i < 8; i++)
234 rf_cmd_cks[i] = rf_cmd[i];
236 rf_cmd_cks[8] = (
unsigned char)val;
242 tcflush(
PortFD, TCIOFLUSH);
244 LOGF_DEBUG(
"CMD (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X)", rf_cmd_cks[0],
245 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],
251 LOGF_ERROR(
"TTY error detected: %s", robofocus_error);
255 return nbytes_written;
258 int RoboFocus::ReadResponse(
char *buf)
261 char robofocus_char[1];
266 bool externalMotion =
false;
276 LOGF_ERROR(
"TTY error detected: %s", robofocus_error);
280 switch (robofocus_char[0])
291 externalMotion =
true;
308 externalMotion =
true;
323 LOGF_ERROR(
"TTY error detected: %s", robofocus_error);
339 tcflush(
PortFD, TCIOFLUSH);
340 return (bytesRead + 1);
351 int RoboFocus::updateRFPosition(
double *value)
361 *
value = simulatedPosition;
365 strncpy(rf_cmd,
"FG000000", 9);
367 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
370 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
373 if (sscanf(rf_cmd,
"FD%6f", &temp) < 1)
376 *
value = (double)temp;
383 int RoboFocus::updateRFTemperature(
double *value)
391 strncpy(rf_cmd,
"FT000000", 9);
393 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
397 snprintf(rf_cmd, 32,
"FT%6g", simulatedTemperature);
398 else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
401 if (sscanf(rf_cmd,
"FT%6f", &temp) < 1)
404 *
value = (double)temp / 2. - 273.15;
409 int RoboFocus::updateRFBacklash(
double *value)
427 strncpy(rf_cmd,
"FB000000", 9);
448 sprintf(vl_tmp,
"%3d", (
int)*value);
452 sprintf(vl_tmp,
"0%2d", (
int)*value);
456 sprintf(vl_tmp,
"00%1d", (
int)*value);
458 rf_cmd[5] = vl_tmp[0];
459 rf_cmd[6] = vl_tmp[1];
460 rf_cmd[7] = vl_tmp[2];
463 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
466 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
469 if (sscanf(rf_cmd,
"FB%1d%5f", &sign, &temp) < 1)
472 *
value = (double)temp;
474 if ((sign == 2) && (*
value > 0))
482 int RoboFocus::updateRFFirmware(
char *rf_cmd)
486 LOG_DEBUG(
"Querying RoboFocus Firmware...");
488 strncpy(rf_cmd,
"FV000000", 9);
490 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
494 strncpy(rf_cmd,
"SIM", 4);
495 else if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
501 int RoboFocus::updateRFMotorSettings(
double *duty,
double *delay,
double *ticks)
503 LOGF_DEBUG(
"Update Motor Settings: Duty (%g), Delay (%g), Ticks(%g)", *duty, *delay, *ticks);
516 if ((*duty == 0) && (*delay == 0) && (*ticks == 0))
518 strncpy(rf_cmd,
"FC000000", 9);
524 rf_cmd[2] = (char) * duty;
525 rf_cmd[3] = (char) * delay;
526 rf_cmd[4] = (char) * ticks;
533 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
536 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
539 *duty = (float)rf_cmd[2];
540 *delay = (float)rf_cmd[3];
541 *ticks = (float)rf_cmd[4];
546 int RoboFocus::updateRFPositionRelativeInward(
double value)
553 LOGF_DEBUG(
"Update Relative Position Inward: %g", value);
557 simulatedPosition +=
value;
564 sprintf(rf_cmd,
"FI0%5d", (
int)value);
566 else if (value > 999)
568 sprintf(rf_cmd,
"FI00%4d", (
int)value);
572 sprintf(rf_cmd,
"FI000%3d", (
int)value);
576 sprintf(rf_cmd,
"FI0000%2d", (
int)value);
580 sprintf(rf_cmd,
"FI00000%1d", (
int)value);
583 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
589 int RoboFocus::updateRFPositionRelativeOutward(
double value)
595 LOGF_DEBUG(
"Update Relative Position Outward: %g", value);
599 simulatedPosition -=
value;
608 sprintf(rf_cmd,
"FO0%5d", (
int)value);
610 else if (value > 999)
612 sprintf(rf_cmd,
"FO00%4d", (
int)value);
616 sprintf(rf_cmd,
"FO000%3d", (
int)value);
620 sprintf(rf_cmd,
"FO0000%2d", (
int)value);
624 sprintf(rf_cmd,
"FO00000%1d", (
int)value);
627 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
633 int RoboFocus::updateRFPositionAbsolute(
double value)
638 LOGF_DEBUG(
"Moving Absolute Position: %g", value);
642 simulatedPosition =
value;
650 sprintf(rf_cmd,
"FG0%5d", (
int)value);
652 else if (value > 999)
654 sprintf(rf_cmd,
"FG00%4d", (
int)value);
658 sprintf(rf_cmd,
"FG000%3d", (
int)value);
662 sprintf(rf_cmd,
"FG0000%2d", (
int)value);
666 sprintf(rf_cmd,
"FG00000%1d", (
int)value);
669 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
675 int RoboFocus::updateRFPowerSwitches(
int s,
int new_sn,
int *cur_s1LL,
int *cur_s2LR,
int *cur_s3RL,
int *cur_s4RR)
691 strncpy(rf_cmd_tmp,
"FP000000", 9);
693 if ((robofocus_rc = SendCommand(rf_cmd_tmp)) < 0)
696 if ((robofocus_rc = ReadResponse(rf_cmd_tmp)) < 0)
699 for (i = 0; i < 9; i++)
701 rf_cmd[i] = rf_cmd_tmp[i];
704 if (rf_cmd[new_sn + 4] ==
'2')
706 rf_cmd[new_sn + 4] =
'1';
710 rf_cmd[new_sn + 4] =
'2';
715 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
718 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
721 *cur_s1LL = *cur_s2LR = *cur_s3RL = *cur_s4RR =
ISS_OFF;
723 if (rf_cmd[4] ==
'2')
728 if (rf_cmd[5] ==
'2')
733 if (rf_cmd[6] ==
'2')
738 if (rf_cmd[7] ==
'2')
745 int RoboFocus::updateRFMaxPosition(
double *value)
762 strncpy(rf_cmd,
"FL000000", 9);
772 sprintf(vl_tmp,
"%5d", (
int)*value);
774 else if (*value > 999)
776 sprintf(vl_tmp,
"0%4d", (
int)*value);
778 else if (*value > 99)
780 sprintf(vl_tmp,
"00%3d", (
int)*value);
784 sprintf(vl_tmp,
"000%2d", (
int)*value);
788 sprintf(vl_tmp,
"0000%1d", (
int)*value);
790 rf_cmd[3] = vl_tmp[0];
791 rf_cmd[4] = vl_tmp[1];
792 rf_cmd[5] = vl_tmp[2];
793 rf_cmd[6] = vl_tmp[3];
794 rf_cmd[7] = vl_tmp[4];
798 if ((robofocus_rc = SendCommand(rf_cmd)) < 0)
801 if ((robofocus_rc = ReadResponse(rf_cmd)) < 0)
804 if (sscanf(rf_cmd,
"FL%1c%5f", waste, &temp) < 1)
807 *
value = (double)temp;
883 snprintf(vl_tmp, 6,
"%5d", ticks);
885 else if (ticks > 999)
887 snprintf(vl_tmp, 6,
"0%4d", ticks);
891 snprintf(vl_tmp, 6,
"00%3d", ticks);
895 snprintf(vl_tmp, 6,
"000%2d", ticks);
899 snprintf(vl_tmp, 6,
"0000%1d", ticks);
901 rf_cmd[3] = vl_tmp[0];
902 rf_cmd[4] = vl_tmp[1];
903 rf_cmd[5] = vl_tmp[2];
904 rf_cmd[6] = vl_tmp[3];
905 rf_cmd[7] = vl_tmp[4];
908 if ((ret_read_tmp = SendCommand(rf_cmd)) < 0)
918 if (strcmp(name, PowerSwitchesSP.
name) == 0)
935 for (nset = i = 0; i < n; i++)
942 if (sp == &PowerSwitchesS[0])
948 else if (sp == &PowerSwitchesS[1])
954 else if (sp == &PowerSwitchesS[2])
960 else if (sp == &PowerSwitchesS[3])
969 cur_s1LL = cur_s2LR = cur_s3RL = cur_s4RR = 0;
971 if ((ret = updateRFPowerSwitches(new_s, new_sn, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
974 IDSetSwitch(&PowerSwitchesSP,
"Unknown error while reading Robofocus power switch settings");
983 IDSetNumber(&SettingsNP,
"Power switch settings absent or bogus.");
998 if (strcmp(name, SettingsNP.
name) == 0)
1001 double new_duty = 0;
1002 double new_delay = 0;
1003 double new_ticks = 0;
1006 for (nset = i = 0; i < n; i++)
1012 if (eqp == &SettingsN[0])
1014 new_duty = (values[i]);
1015 nset +=
static_cast<int>(new_duty >= 0 && new_duty <= 255);
1017 else if (eqp == &SettingsN[1])
1019 new_delay = (values[i]);
1020 nset +=
static_cast<int>(new_delay >= 0 && new_delay <= 255);
1022 else if (eqp == &SettingsN[2])
1024 new_ticks = (values[i]);
1025 nset +=
static_cast<int>(new_ticks >= 0 && new_ticks <= 255);
1037 if ((ret = updateRFMotorSettings(&new_duty, &new_delay, &new_ticks)) < 0)
1039 IDSetNumber(&SettingsNP,
"Changing to new settings failed");
1057 IDSetNumber(&SettingsNP,
"Settings absent or bogus.");
1111 if (strcmp(name, MinMaxPositionNP.
name) == 0)
1117 for (nset = i = 0; i < n; i++)
1123 if (mmpp == &MinMaxPositionN[0])
1125 new_min = (values[i]);
1126 nset +=
static_cast<int>(new_min >= 1 && new_min <= 65000);
1128 else if (mmpp == &MinMaxPositionN[1])
1130 new_max = (values[i]);
1131 nset +=
static_cast<int>(new_max >= 1 && new_max <= 65000);
1154 IDSetNumber(&MinMaxPositionNP,
"Minimum and maximum limits absent or bogus.");
1160 if (strcmp(name, MaxTravelNP.
name) == 0)
1162 double new_maxt = 0;
1165 for (nset = i = 0; i < n; i++)
1171 if (mmpp == &MaxTravelN[0])
1173 new_maxt = (values[i]);
1174 nset +=
static_cast<int>(new_maxt >= 1 && new_maxt <= 64000);
1182 if ((ret = updateRFMaxPosition(&new_maxt)) < 0)
1185 IDSetNumber(&MaxTravelNP,
"Changing to new maximum travel failed");
1199 IDSetNumber(&MaxTravelNP,
"Maximum travel absent or bogus.");
1304 void RoboFocus::GetFocusParams()
1315 LOGF_ERROR(
"Unknown error while reading Robofocus position: %d", ret);
1326 LOG_ERROR(
"Unknown error while reading Robofocus temperature.");
1338 LOG_ERROR(
"Unknown error while reading Robofocus backlash.");
1350 LOG_ERROR(
"Unknown error while reading Robofocus motor settings.");
1358 if ((ret = updateRFPowerSwitches(-1, -1, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0)
1361 LOG_ERROR(
"Unknown error while reading Robofocus power switch settings.");
1366 PowerSwitchesS[0].s = PowerSwitchesS[1].s = PowerSwitchesS[2].s = PowerSwitchesS[3].s =
ISS_OFF;
1370 PowerSwitchesS[0].s =
ISS_ON;
1374 PowerSwitchesS[1].s =
ISS_ON;
1378 PowerSwitchesS[2].s =
ISS_ON;
1382 PowerSwitchesS[3].s =
ISS_ON;
1402 targetPos = targetTicks;
1406 LOG_DEBUG(
"Error, requested position is out of range.");
1410 if ((ret = updateRFPositionAbsolute(targetPos)) < 0)
1412 LOGF_DEBUG(
"Read out of the absolute movement failed %3d", ret);
1444 int rc = updateRFPosition(&newPos);
1455 int nbytes_read = 0;
1460 nbytes_read = ReadResponse(rf_cmd);
1462 rf_cmd[nbytes_read - 1] = 0;
1464 if (nbytes_read != 9 || (sscanf(rf_cmd,
"FD0%5f", &newPos) <= 0))
1467 "Bogus position: (%#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X %#02X) - Bytes read: %d",
1468 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],
1473 else if (nbytes_read < 0)
1476 LOG_ERROR(
"Read error! Reconnect and try again.");
1510 const char *buf =
"\r";
1517 double value = steps;
1518 return (updateRFBacklash(&value) == 0);
const char * getDeviceName() const
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.
INumberVectorProperty FocusBacklashNP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INumber FocusBacklashN[1]
INumberVectorProperty FocusMaxPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
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
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 updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
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.
virtual bool Handshake() override
perform handshake with device to check communication
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.
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.
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
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,...)
@ value
the parser finished reading a JSON value
#define currentTemperature
#define currentMinPosition
#define MAXTRAVEL_READOUT
#define currentMaxPosition