33#define USBFOCUSV3_TIMEOUT 5
37static std::unique_ptr<USBFocusV3> usbFocusV3(
new USBFocusV3());
83 TemperatureNP[0].
fill(
"TEMPERATURE",
"Celsius",
"%6.2f", -50., 70., 0., 0.);
88 MaxPositionNP[0].
fill(
"MAXPOSITION",
"Maximum position",
"%5.0f", 1., 65535., 0., 65535.);
93 TemperatureSettingNP[0].
fill(
"COEFFICIENT",
"Coefficient",
"%3.0f", 0., 999., 1., 15.);
94 TemperatureSettingNP[1].
fill(
"THRESHOLD",
"Threshold",
"%3.0f", 0., 999., 1., 10.);
105 TemperatureCompensateSP[0].
fill(
"ENABLE",
"Enable",
ISS_OFF);
106 TemperatureCompensateSP[1].
fill(
"DISABLE",
"Disable",
ISS_ON);
121 FWversionNP[0].
fill(
"FIRMWARE",
"Firmware Version",
"%5.0f", 0., 65535., 1., 0.);
164 LOG_INFO(
"USBFocusV3 parameters updated, focuser ready for use.");
190 LOG_INFO(
"USBFocusV3 is online. Getting focus parameters...");
193 LOG_INFO(
"Error retrieving data from USBFocusV3, trying resync...");
195 while (--tries > 0 && Resync());
197 LOG_INFO(
"Error retrieving data from USBFocusV3, please ensure controller "
198 "is powered and the port is correct.");
207bool USBFocusV3::Resync()
210 int nbytes_written = 0, nbytes_read = 0, rc = -1;
217 tcflush(
PortFD, TCIOFLUSH);
219 for (
int resync = 0; resync <
UFOCMDLEN; resync++)
226 LOGF_ERROR(
"Error writing resync: %s.", errstr);
231 if (rc ==
TTY_OK && nbytes_read > 0)
242bool USBFocusV3::sendCommand(
const char *
cmd,
char *resp)
244 pthread_mutex_lock(&cmdlock);
246 int nbytes_written = 0, nbytes_read = 0, rc = -1;
250 tcflush(
PortFD, TCIOFLUSH);
254 LOGF_WARN(
"Error writing command %s: %s.",
cmd, errstr);
255 pthread_mutex_unlock(&cmdlock);
264 LOGF_WARN(
"Error reading response for command %s: %s.",
cmd, errstr);
265 pthread_mutex_unlock(&cmdlock);
270 if (moving && nbytes_read > 0 && resp[0] ==
UFORSACK)
277 memmove(&resp[0], &resp[1], nbytes_read);
283 LOGF_WARN(
"Invalid response for command %s: %s.",
cmd, resp);
284 pthread_mutex_unlock(&cmdlock);
288 int rc = sscanf(resp,
"%s\n\r", resp);
291 LOGF_WARN(
"Invalid response for command %s: missing cr+lf",
cmd);
292 pthread_mutex_unlock(&cmdlock);
297 pthread_mutex_unlock(&cmdlock);
302bool USBFocusV3::sendCommandSpecial(
const char *
cmd,
char *resp)
304 pthread_mutex_lock(&cmdlock);
306 int nbytes_written = 0, nbytes_read = 0, rc = -1;
310 tcflush(
PortFD, TCIOFLUSH);
314 LOGF_WARN(
"Error writing command %s: %s.",
cmd, errstr);
315 pthread_mutex_unlock(&cmdlock);
325 LOGF_WARN(
"Error reading response for command %s: %s.",
cmd, errstr);
326 pthread_mutex_unlock(&cmdlock);
329 resp[nbytes_read] =
'\0';
332 pthread_mutex_unlock(&cmdlock);
336bool USBFocusV3::Ack()
339 tcflush(
PortFD, TCIOFLUSH);
346 LOGF_ERROR(
"USBFocusV3 not properly identified! Answer was: %s.", resp);
358 sscanf(resp,
"C=%u-%u-%u-%u-%u-%u-%u", &direction, &stepmode, &speed, &stepsdeg, &tcomp_thr, &firmware, &maxpos);
362bool USBFocusV3::updateStepMode()
372 LOGF_ERROR(
"Unknown error: focuser step value (%d)", stepmode);
378bool USBFocusV3::updateRotDir()
388 LOGF_ERROR(
"Unknown error: rotation direction (%d)", direction);
395bool USBFocusV3::updateTemperature()
409 int rc = sscanf(resp,
"T=%f", &temp);
413 TemperatureNP[0].setValue(temp);
418 LOGF_DEBUG(
"Unknown error: focuser temperature value (%s)", resp);
425 LOGF_ERROR(
"Unknown error: focuser temperature value (%s)", resp);
432bool USBFocusV3::updateFWversion()
434 FWversionNP[0].setValue(firmware);
438bool USBFocusV3::updatePosition()
452 int rc = sscanf(resp,
"P=%u", &pos);
461 LOGF_DEBUG(
"Unknown error: focuser position value (%s)", resp);
468 LOGF_ERROR(
"Unknown error: focuser position value (%s)", resp);
475bool USBFocusV3::updateMaxPos()
477 MaxPositionNP[0].setValue(maxpos);
482bool USBFocusV3::updateTempCompSettings()
484 TemperatureSettingNP[0].setValue(stepsdeg);
485 TemperatureSettingNP[1].setValue(tcomp_thr);
489bool USBFocusV3::updateTempCompSign()
499 int rc = sscanf(resp,
"A=%u", &sign);
503 TempCompSignSP.
reset();
511 LOGF_ERROR(
"Unknown error: temp. comp. sign (%d)", sign);
517 LOGF_ERROR(
"Unknown error: temp. comp. sign value (%s)", resp);
524bool USBFocusV3::updateSpeed()
546 currentSpeed = drvspeed;
551 LOGF_ERROR(
"Unknown error: focuser speed value (%d)", speed);
558bool USBFocusV3::setAutoTempCompThreshold(
unsigned int thr)
564 if (!sendCommand(
cmd, resp))
573 LOG_ERROR(
"setAutoTempCompThreshold error: did not receive DONE.");
578bool USBFocusV3::setTemperatureCoefficient(
unsigned int coefficient)
584 if (!sendCommand(
cmd, resp))
589 stepsdeg = coefficient;
593 LOG_ERROR(
"setTemperatureCoefficient error: did not receive DONE.");
598bool USBFocusV3::reset()
609bool USBFocusV3::MoveFocuserUF(FocusDirection dir,
unsigned int rticks)
618 LOGF_WARN(
"Requested %u ticks but inward movement has been limited to %u ticks", rticks, ticks);
622 ticks = MaxPositionNP[0].getValue() -
FocusAbsPosNP[0].getValue();
623 LOGF_WARN(
"Requested %u ticks but outward movement has been limited to %u ticks", rticks, ticks);
632 if (backlashMove ==
false && backlashIn ==
true && backlashSteps != 0)
634 ticks += backlashSteps;
635 backlashTargetPos = targetPos - backlashSteps;
642 if (backlashMove ==
false && backlashIn ==
false && backlashSteps != 0)
644 ticks += backlashSteps;
645 backlashTargetPos = targetPos + backlashSteps;
651 return sendCommand(
cmd,
nullptr);
654bool USBFocusV3::setStepMode(FocusStepMode mode)
664 if (!sendCommand(
cmd, resp))
671bool USBFocusV3::setRotDir(
unsigned int dir)
681 if (!sendCommand(
cmd, resp))
688bool USBFocusV3::setMaxPos(
unsigned int maxp)
693 if (maxp >= 1 && maxp <= 65535)
699 LOGF_ERROR(
"Focuser max. pos. value %d out of bounds", maxp);
703 if (!sendCommand(
cmd, resp))
713 LOG_ERROR(
"setMaxPos error: did not receive DONE.");
718bool USBFocusV3::setSpeed(
unsigned short drvspeed)
747 LOGF_ERROR(
"Focuser speed value %d out of bounds", drvspeed);
751 if (!sendCommand(
cmd, resp))
760 LOG_ERROR(
"setSpeed error: did not receive DONE.");
765bool USBFocusV3::setTemperatureCompensation(
bool enable)
775 if (!sendCommand(
cmd, resp))
781bool USBFocusV3::setTempCompSign(
unsigned int sign)
788 if (!sendCommand(
cmd, resp))
796 LOG_ERROR(
"setTempCompSign error: did not receive DONE.");
809 StepModeSP.
update(states, names, n);
811 if (current_mode != target_mode)
836 RotDirSP.
update(states, names, n);
838 if (current_mode != target_mode)
840 if (!setRotDir(target_mode))
858 TemperatureCompensateSP.
update(states, names, n);
861 if (last_index != target_index)
863 if (!setTemperatureCompensation((TemperatureCompensateSP[0].getState() ==
ISS_ON)))
866 TemperatureCompensateSP.
reset();
868 TemperatureCompensateSP.
apply();
873 TemperatureCompensateSP.
apply();
880 TempCompSignSP.
update(states, names, n);
882 if (current_mode != target_mode)
884 if (!setTempCompSign(target_mode))
886 TempCompSignSP.
reset();
889 TempCompSignSP.
apply();
894 TempCompSignSP.
apply();
920 MaxPositionNP.
update(values, names, n);
921 if (!setMaxPos(MaxPositionNP[0].getValue()))
924 MaxPositionNP.
apply();
928 MaxPositionNP.
apply();
934 TemperatureSettingNP.
update(values, names, n);
935 if (!setAutoTempCompThreshold(TemperatureSettingNP[1].getValue()) ||
936 !setTemperatureCoefficient(TemperatureSettingNP[
UFOPNSIGN].getValue()))
939 TemperatureSettingNP.
apply();
944 TemperatureSettingNP.
apply();
950void USBFocusV3::GetFocusParams()
954 if (updatePosition())
959 MaxPositionNP.
apply();
963 if (updateTemperature())
964 TemperatureNP.
apply();
966 if (updateTempCompSettings())
967 TemperatureSettingNP.
apply();
969 if (updateTempCompSign())
970 TempCompSignSP.
apply();
975 if (updateStepMode())
981 if (updateFWversion())
987 if (!setSpeed(speed))
990 currentSpeed = speed;
1002 targetPos = targetTicks;
1029 "Requested %u ticks but relative inward movement has been limited to %u ticks", ticks, aticks);
1034 aticks = MaxPositionNP[0].getValue() -
FocusAbsPosNP[0].getValue();
1036 "Requested %u ticks but relative outward movement has been limited to %u ticks", ticks, aticks);
1040 if (!MoveFocuserUF(dir, (
unsigned int)ticks))
1056 if (updatePosition())
1065 if (updateTemperature())
1067 if (fabs(lastTemperature - TemperatureNP[0].getValue()) >= 0.5)
1069 TemperatureNP.
apply();
1070 lastTemperature = TemperatureNP[0].getValue();
1076 float remaining = CalcTimeLeft(focusMoveStart, focusMoveRequest);
1092 if (backlashMove && (fabs(backlashTargetPos -
FocusAbsPosNP[0].getValue()) < 1))
1096 backlashMove =
false;
1107 LOG_INFO(
"Focuser reached requested position.");
1125 backlashMove =
false;
1130float USBFocusV3::CalcTimeLeft(timeval start,
float req)
1138 gettimeofday(&now,
nullptr);
1141 (double)(now.tv_sec * 1000.0 + now.tv_usec / 1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec / 1000);
1142 timesince = timesince / 1000;
1143 timeleft = req - timesince;
1149 backlashIn = steps < 0;
1150 backlashSteps = std::abs(steps);
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 loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
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.
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.
@ FOCUSER_HAS_VARIABLE_SPEED
INDI::PropertyNumber FocusSpeedNP
INDI::PropertyNumber FocusTimerNP
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 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
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
bool update(const ISState states[], const char *const names[], int n)
int findOnSwitchIndex() const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
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 void TimerHit() override
Callback function to be called once SetTimer duration elapses.
bool getControllerStatus()
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
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 SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual const char * getDefaultName() override
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
virtual bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
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.
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.
#define LOGF_INFO(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 USBFOCUSV3_TIMEOUT