32 #define mydev "Optec TCF-S"
33 #define currentPosition FocusAbsPosN[0].value
36 static std::unique_ptr<TCFS> tcfs(
new TCFS());
60 if (strcmp(
me,
"indi_tcfs3_focus") == 0)
70 LOG_DEBUG(
"TCF-S3 detected. Updating maximum position value to 9999.");
82 LOG_DEBUG(
"TCF-S detected. Updating maximum position value to 7000.");
103 IUFillNumber(&FocusTemperatureN[0],
"FOCUS_TEMPERATURE_VALUE",
"Temperature (c)",
"%.3f", -50.0, 80, 0, 0);
114 IUFillNumber(&FocusModeAN[0],
"FOCUS_SLOPE_A",
"Slope A",
"%.0f", -999, 999, 10, 0);
116 IUFillNumber(&FocusModeAN[2],
"FOCUS_DELAY_A",
"Delay A",
"%.2f", 0.00, 9.99, 1.0, 0);
118 IUFillNumber(&FocusModeBN[0],
"FOCUS_SLOPE_B",
"Slope B",
"%.0f", -999, 999, 10, 0);
120 IUFillNumber(&FocusModeBN[2],
"FOCUS_DELAY_B",
"Delay B",
"%.2f", 0.00, 9.99, 1.0, 0);
257 LOG_INFO(
"TCF-S: Simulating connection.");
264 if (strcmp(response,
"WAKE") == 0)
267 tcflush(
PortFD, TCIOFLUSH);
272 LOG_INFO(
"Successfully connected to TCF-S Focuser in Manual Mode.");
279 tcflush(
PortFD, TCIOFLUSH);
280 LOG_ERROR(
"Failed connection to TCF-S Focuser.");
290 for(
int retry = 0; retry < 5; retry++)
294 if (strcmp(response,
"!") == 0)
296 tcflush(
PortFD, TCIOFLUSH);
301 tcflush(
PortFD, TCIOFLUSH);
323 bool TCFS::ISNewNumber(
const char *dev,
const char *name,
double values[],
char *names[],
int n)
334 if (!strcmp(name, FocusModeANP.
name))
339 if (read_tcfs(response) ==
false)
342 IDSetNumber(&FocusModeANP,
"Error reading TCF-S reply.");
346 if (read_tcfs(response) ==
false)
349 IDSetNumber(&FocusModeANP,
"Error reading TCF-S reply.");
353 dispatch_command(
FDELAY, FocusModeAN[2].value * 100,
MODE_A);
354 if (read_tcfs(response) ==
false)
357 IDSetNumber(&FocusModeANP,
"Error reading TCF-S reply.");
366 if (!strcmp(name, FocusModeBNP.
name))
371 if (read_tcfs(response) ==
false)
374 IDSetNumber(&FocusModeBNP,
"Error reading TCF-S reply.");
378 if (read_tcfs(response) ==
false)
381 IDSetNumber(&FocusModeBNP,
"Error reading TCF-S reply.");
384 dispatch_command(
FDELAY, FocusModeBN[2].value * 100,
MODE_B);
385 if (read_tcfs(response) ==
false)
388 IDSetNumber(&FocusModeBNP,
"Error reading TCF-S reply.");
419 LOG_WARN(
"The focuser can only be moved in Manual mode.");
425 LOG_WARN(
"The focuser is in motion. Wait until it has stopped");
428 if (!strcmp(FocusPowerSP.
name, name))
436 if (!strcmp(sp->name,
"FOCUS_SLEEP"))
445 if (read_tcfs(response) ==
false)
449 IDSetSwitch(&FocusPowerSP,
"Error reading TCF-S reply.");
458 if (strcmp(response,
"ZZZ") == 0)
461 IDSetSwitch(&FocusPowerSP,
"Focuser is set into sleep mode.");
475 IDSetSwitch(&FocusPowerSP,
"Focuser sleep mode operation failed. Response: %s.", response);
484 if (strcmp(response,
"WAKE") == 0)
501 IDSetSwitch(&FocusPowerSP,
"Focuser wake up operation failed. Response: %s", response);
514 LOG_WARN(
"Focuser is still in sleep mode. Wake up in order to issue commands.");
520 if (!strcmp(FocusModeSP.
name, name))
527 if (!strcmp(sp->name,
"Manual"))
533 IDSetSwitch(&FocusModeSP,
"Error switching to manual mode. No reply from TCF-S. Try again.");
539 else if (!strcmp(sp->name,
"Auto A"))
541 if(FocusStartModeSP.
sp[0].s ==
ISS_ON)
544 uint32_t startPos = -FocusTemperatureN[0].value * FocusModeAN[0].value
545 + FocusModeAN[1].value;
546 LOGF_DEBUG(
"Autocomp A T=%.1f; m=%f; i=%f; p0=%d;",
547 FocusTemperatureN[0].value,
548 FocusModeAN[0].value,
549 FocusModeAN[1].value,
561 IDSetSwitch(&FocusModeSP,
"Error switching to Auto Mode A, No reply from TCF-S. Try again.");
569 if(FocusStartModeSP.
sp[0].s ==
ISS_ON)
572 uint32_t startPos = -FocusTemperatureN[0].value * FocusModeBN[0].value
573 + FocusModeBN[1].value;
574 LOGF_DEBUG(
"Autocomp B T=%.1f; m=%f; i=%f; p0=%d;",
575 FocusTemperatureN[0].value,
576 FocusModeBN[0].value,
577 FocusModeBN[1].value,
589 IDSetSwitch(&FocusModeSP,
"Error switching to Auto Mode B, No reply from TCF-S. Try again.");
606 LOG_WARN(
"Focuser is in auto mode. Change to manual in order to issue commands.");
612 if (!strcmp(FocusStartModeSP.
name, name))
622 if (!strcmp(FocusGotoSP.
name, name))
628 LOG_WARN(
"The focuser can only be moved in Manual mode.");
638 if (!strcmp(sp->name,
"FOCUS_MIN"))
642 IDSetSwitch(&FocusGotoSP,
"Moving focuser to minimum position...");
645 else if (!strcmp(sp->name,
"FOCUS_CENTER"))
652 IDSetSwitch(&FocusGotoSP,
"Moving focuser to center position %d...", isTCFS3 ? 5000 : 3500);
656 else if (!strcmp(sp->name,
"FOCUS_MAX"))
658 unsigned int delta = 0;
664 else if (!strcmp(sp->name,
"FOCUS_HOME"))
666 dispatch_command(
FHOME);
672 if (strcmp(response,
"DONE") == 0)
676 IDSetSwitch(&FocusGotoSP,
"Moving focuser to new calculated position based on temperature...");
683 IDSetSwitch(&FocusGotoSP,
"Failed to move focuser to home position!");
692 if (!strcmp(FocusTelemetrySP.
name, name))
702 if (!strcmp(sp->name,
"FOCUS_TELEMETRY_OFF"))
704 dispatch_command(
FQUIET, 1);
709 dispatch_command(
FQUIET, 0);
711 if (read_tcfs(response) ==
false)
715 IDSetSwitch(&FocusTelemetrySP,
"Error reading TCF-S reply.");
722 if (strcmp(response,
"DONE") == 0)
726 quiet ?
"Focuser Telemetry is off." :
"Focuser Telemetry is on.");
737 IDSetSwitch(&FocusTelemetrySP,
"Focuser telemetry mode failed. Response: %s.", response);
748 LOGF_DEBUG(
"Moving to absolute position %d using offset %d", targetTicks, delta);
774 targetPosition -= targetTicks;
775 dispatch_command(
FIN);
777 LOGF_DEBUG(
"Moving inward by %d steps to position %d", targetTicks, targetPosition);
782 targetPosition += targetTicks;
783 dispatch_command(
FOUT);
785 LOGF_DEBUG(
"Moving outward by %d steps to position %d", targetTicks, targetPosition);
793 simulated_position = targetPosition;
812 bool TCFS::dispatch_command(TCFSCommand command_type,
int val, TCFSMode m)
814 int err_code = 0, nbytes_written = 0;
817 switch (command_type)
893 snprintf(command,
TCFS_MAX_CMD,
"FZ%cxx%01d", m ==
MODE_A ?
'A' :
'B', val >= 0 ? 0 : 1);
913 tcflush(
PortFD, TCIOFLUSH);
919 LOGF_ERROR(
"TTY error detected: %s", tcfs_error);
928 static double lastPosition = -1, lastTemperature = -1000;
941 LOGF_DEBUG(
"%s Motion in Progress...", __FUNCTION__);
942 if (read_tcfs(response,
true) ==
false)
947 LOGF_DEBUG(
"%s READY %s", __FUNCTION__, response );
948 if(strcmp(response,
"*") == 0)
960 const char* mode = (FocusModeSP.
sp[1].s ==
ISS_ON) ?
"A" :
"B";
968 IDSetSwitch(&FocusModeSP,
"Error switching to Auto Mode %s. No reply from TCF-S. Try again.", mode);
983 float f_temperature = 0;
987 if (FocusTelemetrySP.
sp[1].s ==
ISS_ON)
989 LOGF_DEBUG(
"%s %s", __FUNCTION__,
"Telemetry is off");
993 for(
int i = 0; i < 2; i++)
995 if (read_tcfs(response,
true) ==
false)
1000 LOGF_DEBUG(
"%s Received %s", __FUNCTION__, response);
1001 if(sscanf(response,
"P=%d", &f_position) == 1)
1010 else if(sscanf(response,
"T=%f", &f_temperature) == 1)
1012 FocusTemperatureNP.
np[0].value = f_temperature;
1014 if (lastTemperature != FocusTemperatureNP.
np[0].value)
1016 lastTemperature = FocusTemperatureNP.
np[0].value;
1029 if (sp !=
nullptr && strcmp(sp->name,
"FOCUS_CENTER") == 0)
1031 bool rc = read_tcfs(response,
true);
1042 if (strcmp(response,
"CENTER") == 0)
1051 LOG_INFO(
"Focuser moved to center position.");
1060 dispatch_command(
FPOSRO);
1062 if (read_tcfs(response) ==
false)
1069 snprintf(response,
TCFS_MAX_CMD,
"P=%04d", (
int)simulated_position);
1071 sscanf(response,
"P=%d", &f_position);
1082 if (read_tcfs(response,
true) ==
false)
1089 if (strstr(response,
"ER") !=
nullptr)
1097 strncpy(response,
"*", 2);
1099 if (strcmp(response,
"*") == 0)
1101 LOGF_DEBUG(
"Moving focuser %d steps to position %d.", targetTicks, targetPosition);
1112 LOGF_ERROR(
"Unable to read response from focuser #%s#.", response);
1126 dispatch_command(
FTMPRO);
1128 if (read_tcfs(response) ==
false)
1132 LOG_ERROR(
"Failed to read temperature. Is sensor connected?");
1139 snprintf(response,
TCFS_MAX_CMD,
"T=%0.1f", simulated_temperature);
1141 int rc = sscanf(response,
"T=%f", &f_temperature);
1145 FocusTemperatureNP.
np[0].value = f_temperature;
1147 if (fabs(lastTemperature - FocusTemperatureNP.
np[0].value) > 0.01)
1149 lastTemperature = FocusTemperatureNP.
np[0].value;
1156 LOGF_ERROR(
"Failed to read temperature: %s", response);
1164 bool TCFS::read_tcfs(
char *response,
bool silent)
1166 int err_code = 0, nbytes_read = 0;
1181 LOGF_ERROR(
"TTY error detected: %s", err_msg);
1188 response[nbytes_read - 2] =
'\0';
1190 tcflush(
PortFD, TCIOFLUSH);
1192 if (strstr(response,
"ER="))
1195 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...
const char * getDeviceName() const
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.
ISwitchVectorProperty FocusMotionSP
INumberVectorProperty FocusAbsPosNP
INumberVectorProperty FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
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.
Connection::Serial * serialConnection
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
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
Process the client newNumber command.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool Disconnect() override
Disconnect from device.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
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.
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the 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.
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