32#define mydev "Optec TCF-S"
35static std::unique_ptr<TCFS> tcfs(
new TCFS());
59 if (strcmp(
me,
"indi_tcfs3_focus") == 0)
69 LOG_DEBUG(
"TCF-S3 detected. Updating maximum position value to 9999.");
81 LOG_DEBUG(
"TCF-S detected. Updating maximum position value to 7000.");
102 IUFillNumber(&FocusTemperatureN[0],
"FOCUS_TEMPERATURE_VALUE",
"Temperature (c)",
"%.3f", -50.0, 80, 0, 0);
113 IUFillNumber(&FocusModeAN[0],
"FOCUS_SLOPE_A",
"Slope A",
"%.0f", -999, 999, 10, 0);
115 IUFillNumber(&FocusModeAN[2],
"FOCUS_DELAY_A",
"Delay A",
"%.2f", 0.00, 9.99, 1.0, 0);
117 IUFillNumber(&FocusModeBN[0],
"FOCUS_SLOPE_B",
"Slope B",
"%.0f", -999, 999, 10, 0);
119 IUFillNumber(&FocusModeBN[2],
"FOCUS_DELAY_B",
"Delay B",
"%.2f", 0.00, 9.99, 1.0, 0);
256 LOG_INFO(
"TCF-S: Simulating connection.");
263 if (strcmp(response,
"WAKE") == 0)
266 tcflush(
PortFD, TCIOFLUSH);
271 LOG_INFO(
"Successfully connected to TCF-S Focuser in Manual Mode.");
278 tcflush(
PortFD, TCIOFLUSH);
279 LOG_ERROR(
"Failed connection to TCF-S Focuser.");
289 for(
int retry = 0; retry < 5; retry++)
293 if (strcmp(response,
"!") == 0)
295 tcflush(
PortFD, TCIOFLUSH);
300 tcflush(
PortFD, TCIOFLUSH);
333 if (!strcmp(name, FocusModeANP.
name))
338 if (read_tcfs(response) ==
false)
341 IDSetNumber(&FocusModeANP,
"Error reading TCF-S reply.");
345 if (read_tcfs(response) ==
false)
348 IDSetNumber(&FocusModeANP,
"Error reading TCF-S reply.");
352 dispatch_command(
FDELAY, FocusModeAN[2].value * 100,
MODE_A);
353 if (read_tcfs(response) ==
false)
356 IDSetNumber(&FocusModeANP,
"Error reading TCF-S reply.");
365 if (!strcmp(name, FocusModeBNP.
name))
370 if (read_tcfs(response) ==
false)
373 IDSetNumber(&FocusModeBNP,
"Error reading TCF-S reply.");
377 if (read_tcfs(response) ==
false)
380 IDSetNumber(&FocusModeBNP,
"Error reading TCF-S reply.");
383 dispatch_command(
FDELAY, FocusModeBN[2].value * 100,
MODE_B);
384 if (read_tcfs(response) ==
false)
387 IDSetNumber(&FocusModeBNP,
"Error reading TCF-S reply.");
398 return Focuser::ISNewNumber(dev, name, values, names, n);
418 LOG_WARN(
"The focuser can only be moved in Manual mode.");
424 LOG_WARN(
"The focuser is in motion. Wait until it has stopped");
427 if (!strcmp(FocusPowerSP.
name, name))
435 if (!strcmp(sp->name,
"FOCUS_SLEEP"))
444 if (read_tcfs(response) ==
false)
448 IDSetSwitch(&FocusPowerSP,
"Error reading TCF-S reply.");
457 if (strcmp(response,
"ZZZ") == 0)
460 IDSetSwitch(&FocusPowerSP,
"Focuser is set into sleep mode.");
474 IDSetSwitch(&FocusPowerSP,
"Focuser sleep mode operation failed. Response: %s.", response);
483 if (strcmp(response,
"WAKE") == 0)
500 IDSetSwitch(&FocusPowerSP,
"Focuser wake up operation failed. Response: %s", response);
513 LOG_WARN(
"Focuser is still in sleep mode. Wake up in order to issue commands.");
519 if (!strcmp(FocusModeSP.
name, name))
526 if (!strcmp(sp->name,
"Manual"))
532 IDSetSwitch(&FocusModeSP,
"Error switching to manual mode. No reply from TCF-S. Try again.");
538 else if (!strcmp(sp->name,
"Auto A"))
543 uint32_t startPos = -FocusTemperatureN[0].value * FocusModeAN[0].value
544 + FocusModeAN[1].value;
545 LOGF_DEBUG(
"Autocomp A T=%.1f; m=%f; i=%f; p0=%d;",
546 FocusTemperatureN[0].value,
547 FocusModeAN[0].value,
548 FocusModeAN[1].value,
560 IDSetSwitch(&FocusModeSP,
"Error switching to Auto Mode A, No reply from TCF-S. Try again.");
571 uint32_t startPos = -FocusTemperatureN[0].value * FocusModeBN[0].value
572 + FocusModeBN[1].value;
573 LOGF_DEBUG(
"Autocomp B T=%.1f; m=%f; i=%f; p0=%d;",
574 FocusTemperatureN[0].value,
575 FocusModeBN[0].value,
576 FocusModeBN[1].value,
588 IDSetSwitch(&FocusModeSP,
"Error switching to Auto Mode B, No reply from TCF-S. Try again.");
605 LOG_WARN(
"Focuser is in auto mode. Change to manual in order to issue commands.");
611 if (!strcmp(FocusStartModeSP.
name, name))
621 if (!strcmp(FocusGotoSP.
name, name))
627 LOG_WARN(
"The focuser can only be moved in Manual mode.");
637 if (!strcmp(sp->name,
"FOCUS_MIN"))
641 IDSetSwitch(&FocusGotoSP,
"Moving focuser to minimum position...");
644 else if (!strcmp(sp->name,
"FOCUS_CENTER"))
651 IDSetSwitch(&FocusGotoSP,
"Moving focuser to center position %d...", isTCFS3 ? 5000 : 3500);
655 else if (!strcmp(sp->name,
"FOCUS_MAX"))
657 unsigned int delta = 0;
663 else if (!strcmp(sp->name,
"FOCUS_HOME"))
665 dispatch_command(
FHOME);
671 if (strcmp(response,
"DONE") == 0)
675 IDSetSwitch(&FocusGotoSP,
"Moving focuser to new calculated position based on temperature...");
682 IDSetSwitch(&FocusGotoSP,
"Failed to move focuser to home position!");
691 if (!strcmp(FocusTelemetrySP.
name, name))
701 if (!strcmp(sp->name,
"FOCUS_TELEMETRY_OFF"))
703 dispatch_command(
FQUIET, 1);
708 dispatch_command(
FQUIET, 0);
710 if (read_tcfs(response) ==
false)
714 IDSetSwitch(&FocusTelemetrySP,
"Error reading TCF-S reply.");
721 if (strcmp(response,
"DONE") == 0)
725 quiet ?
"Focuser Telemetry is off." :
"Focuser Telemetry is on.");
736 IDSetSwitch(&FocusTelemetrySP,
"Focuser telemetry mode failed. Response: %s.", response);
747 LOGF_DEBUG(
"Moving to absolute position %d using offset %d", targetTicks, delta);
773 targetPosition -= targetTicks;
774 dispatch_command(
FIN);
776 LOGF_DEBUG(
"Moving inward by %d steps to position %d", targetTicks, targetPosition);
781 targetPosition += targetTicks;
782 dispatch_command(
FOUT);
784 LOGF_DEBUG(
"Moving outward by %d steps to position %d", targetTicks, targetPosition);
792 simulated_position = targetPosition;
811bool TCFS::dispatch_command(TCFSCommand command_type,
int val, TCFSMode m)
813 int err_code = 0, nbytes_written = 0;
816 switch (command_type)
892 snprintf(command,
TCFS_MAX_CMD,
"FZ%cxx%01d", m ==
MODE_A ?
'A' :
'B', val >= 0 ? 0 : 1);
912 tcflush(
PortFD, TCIOFLUSH);
918 LOGF_ERROR(
"TTY error detected: %s", tcfs_error);
927 static double lastPosition = -1, lastTemperature = -1000;
940 LOGF_DEBUG(
"%s Motion in Progress...", __FUNCTION__);
941 if (read_tcfs(response,
true) ==
false)
946 LOGF_DEBUG(
"%s READY %s", __FUNCTION__, response );
947 if(strcmp(response,
"*") == 0)
959 const char* mode = (FocusModeSP.
sp[1].
s ==
ISS_ON) ?
"A" :
"B";
967 IDSetSwitch(&FocusModeSP,
"Error switching to Auto Mode %s. No reply from TCF-S. Try again.", mode);
982 float f_temperature = 0;
988 LOGF_DEBUG(
"%s %s", __FUNCTION__,
"Telemetry is off");
992 for(
int i = 0; i < 2; i++)
994 if (read_tcfs(response,
true) ==
false)
999 LOGF_DEBUG(
"%s Received %s", __FUNCTION__, response);
1000 if(sscanf(response,
"P=%d", &f_position) == 1)
1009 else if(sscanf(response,
"T=%f", &f_temperature) == 1)
1011 FocusTemperatureNP.
np[0].
value = f_temperature;
1013 if (lastTemperature != FocusTemperatureNP.
np[0].
value)
1015 lastTemperature = FocusTemperatureNP.
np[0].
value;
1028 if (sp !=
nullptr && strcmp(sp->name,
"FOCUS_CENTER") == 0)
1030 bool rc = read_tcfs(response,
true);
1041 if (strcmp(response,
"CENTER") == 0)
1050 LOG_INFO(
"Focuser moved to center position.");
1059 dispatch_command(
FPOSRO);
1061 if (read_tcfs(response) ==
false)
1068 snprintf(response,
TCFS_MAX_CMD,
"P=%04d", (
int)simulated_position);
1070 sscanf(response,
"P=%d", &f_position);
1081 if (read_tcfs(response,
true) ==
false)
1088 if (strstr(response,
"ER") !=
nullptr)
1096 strncpy(response,
"*", 2);
1098 if (strcmp(response,
"*") == 0)
1100 LOGF_DEBUG(
"Moving focuser %d steps to position %d.", targetTicks, targetPosition);
1111 LOGF_ERROR(
"Unable to read response from focuser #%s#.", response);
1125 dispatch_command(
FTMPRO);
1127 if (read_tcfs(response) ==
false)
1131 LOG_ERROR(
"Failed to read temperature. Is sensor connected?");
1138 snprintf(response,
TCFS_MAX_CMD,
"T=%0.1f", simulated_temperature);
1140 int rc = sscanf(response,
"T=%f", &f_temperature);
1144 FocusTemperatureNP.
np[0].
value = f_temperature;
1146 if (fabs(lastTemperature - FocusTemperatureNP.
np[0].
value) > 0.01)
1148 lastTemperature = FocusTemperatureNP.
np[0].
value;
1155 LOGF_ERROR(
"Failed to read temperature: %s", response);
1163bool TCFS::read_tcfs(
char *response,
bool silent)
1165 int err_code = 0, nbytes_read = 0;
1180 LOGF_ERROR(
"TTY error detected: %s", err_msg);
1187 response[nbytes_read - 2] =
'\0';
1189 tcflush(
PortFD, TCIOFLUSH);
1191 if (strstr(response,
"ER="))
1194 sscanf(response,
"ER=%d", &errorCode);
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
INDI::PropertySwitch getSwitch(const char *name) const
virtual bool Disconnect()
Disconnect from device.
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
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)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertySwitch FocusMotionSP
INDI::PropertyNumber FocusMaxPosNP
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,...
Connection::Serial * serialConnection
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isNameMatch(const char *otherName) const
virtual bool saveConfigItems(FILE *fp) override
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
const char * getDefaultName() override
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
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 updateProperties() override
Updates the state and definition of properties based on the current connection status....
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 Disconnect() override
Disconnect from device.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
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 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.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
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.
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
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 IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
#define LOGF_INFO(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 TCFS_ERROR_BUFFER