31#define STEELDRIVE_MAX_RETRIES 3
32#define STEELDRIVE_TIMEOUT 2
33#define STEELDRIVE_MAXBUF 16
34#define STEELDRIVE_CMD 9
35#define STEELDRIVE_CMD_LONG 11
36#define STEELDRIVE_TEMPERATURE_FREQ 20
37#define STEELDIVE_POSITION_THRESHOLD 5
39#define FOCUS_SETTINGS_TAB "Settings"
60 IUFillNumber(&TemperatureN[0],
"TEMPERATURE",
"Celsius",
"%6.2f", -50, 70., 0., 0.);
92 IUFillSwitchVector(&ModelSP, ModelS, 5,
getDeviceName(),
"Model",
"",
FOCUS_SETTINGS_TAB,
IP_RW,
ISR_1OFMANY, 0,
102 IUFillNumber(&AccelerationN[0],
"Ramp",
"",
"%3.0f", 1500., 3000., 100., 2000.);
107 IUFillNumber(&SyncN[0],
"Position (steps)",
"",
"%3.0f", 0., 200000., 100., 0.);
111 IUFillText(&VersionT[0],
"HW Rev.",
"",
nullptr);
112 IUFillText(&VersionT[1],
"FW Rev.",
"",
nullptr);
120 updateFocusMaxRange(fSettings[4].maxTrip, fSettings[4].gearRatio);
148 LOG_INFO(
"SteelDrive parameters updated, focuser ready for use.");
174 LOG_INFO(
"SteelDrive is online. Getting focus parameters...");
175 temperatureUpdateCounter = 0;
179 LOG_INFO(
"Error retrieving data from SteelDrive, please ensure SteelDrive controller is "
180 "powered and the port is correct.");
186 return "Baader SteelDrive";
192bool SteelDrive::Ack()
194 int nbytes_written = 0, nbytes_read = 0, rc = -1;
199 tcflush(
PortFD, TCIOFLUSH);
204 LOGF_ERROR(
":FVERSIO# getHWVersion error: %s.", errstr);
218 LOGF_ERROR(
"getHWVersion error: %s.", errstr);
222 resp[nbytes_read] =
'\0';
226 rc = sscanf(resp,
":FV%s#", hwVer);
234bool SteelDrive::updateVersion()
236 int nbytes_written = 0, nbytes_read = 0, rc = -1;
247 memset(hwdate, 0,
sizeof(hwdate));
248 memset(hwrev, 0,
sizeof(hwrev));
249 memset(fwdate, 0,
sizeof(fwdate));
250 memset(fwrev, 0,
sizeof(fwrev));
252 tcflush(
PortFD, TCIOFLUSH);
257 LOGF_ERROR(
":FVERSIO# getHWVersion write error: %s.", errstr);
271 LOGF_ERROR(
"FVERSIO# getHWVersion read error: %s.", errstr);
275 resp[nbytes_read] =
'\0';
279 rc = sscanf(resp,
":FV%s#", hardware_string);
283 snprintf(hwrev,
sizeof(hwrev),
"%.3s", hardware_string);
284 snprintf(hwdate,
sizeof(hwdate),
"%.4s", hardware_string + 3);
285 char mon[3], year[3];
286 memset(mon, 0,
sizeof(mon));
287 memset(year, 0,
sizeof(year));
288 snprintf(mon,
sizeof(mon),
"%.2s", hwdate);
289 snprintf(year,
sizeof(year),
"%.2s", hwdate + 2);
290 snprintf(hardware_string,
MAXRBUF,
"Version: %s Date: %s.%s", hwrev, mon, year);
295 LOGF_ERROR(
"Unknown error: getHWVersion value (%s)", resp);
299 tcflush(
PortFD, TCIOFLUSH);
304 LOGF_ERROR(
":FNFIRMW# getSWVersion write error: %s.", errstr);
318 LOGF_ERROR(
"FNFIRMW# getSWVersion read error: %s.", errstr);
322 resp[nbytes_read] =
'\0';
326 rc = sscanf(resp,
":FN%s#", firmware_string);
330 snprintf(fwrev,
sizeof(fwrev),
"%.3s", firmware_string);
331 snprintf(fwdate,
sizeof(fwdate),
"%.4s", firmware_string + 3);
332 char mon[3], year[3];
333 memset(mon, 0,
sizeof(mon));
334 memset(year, 0,
sizeof(year));
335 snprintf(mon,
sizeof(mon),
"%.2s", fwdate);
336 snprintf(year,
sizeof(year),
"%.2s", fwdate + 2);
337 snprintf(firmware_string,
MAXRBUF,
"Version: %s Date: %s.%s", fwrev, mon, year);
342 LOGF_ERROR(
"Unknown error: getSWVersion value (%s)", resp);
352bool SteelDrive::updateTemperature()
354 int nbytes_written = 0, nbytes_read = 0, rc = -1;
359 tcflush(
PortFD, TCIOFLUSH);
364 LOGF_ERROR(
":F5ASKT0# updateTemperature write error: %s.", errstr);
378 LOGF_ERROR(
":F5ASKT0# updateTemperature read error: %s.", errstr);
382 resp[nbytes_read] =
'\0';
390 TemperatureN[0].value = ((double)
temperature) / 100.0;
396 rc = sscanf(resp,
":F5%s#", junk);
399 TemperatureN[0].value = 0;
400 LOG_DEBUG(
"Temperature probe is not connected.");
403 LOGF_ERROR(
"Unknown error: focuser temperature value (%s)", resp);
415bool SteelDrive::updatePosition()
417 int nbytes_written = 0, nbytes_read = 0, rc = -1;
420 unsigned short pos = 0;
425 tcflush(
PortFD, TCIOFLUSH);
430 LOGF_ERROR(
":F8ASKS0# updatePosition write error: %s.", errstr);
445 resp[nbytes_read] =
'\0';
446 LOGF_DEBUG(
":F8ASKS0# updatePosition read error: %s. Retry: %d. Bytes: %d. Buffer (%s)", errstr, retries,
455 LOG_ERROR(
"UpdatePosition: failed to read.");
459 resp[nbytes_read] =
'\0';
463 rc = sscanf(resp,
":F8%hu#", &pos);
471 LOGF_ERROR(
"Unknown error: focuser position value (%s)", resp);
481bool SteelDrive::updateSpeed()
483 int nbytes_written = 0, nbytes_read = 0, rc = -1;
486 unsigned short speed;
488 tcflush(
PortFD, TCIOFLUSH);
493 LOGF_ERROR(
":FGSPMAX# updateSpeed write error: %s.", errstr);
507 LOGF_ERROR(
":FGSPMAX# updateSpeed read error: %s.", errstr);
511 resp[nbytes_read] =
'\0';
515 rc = sscanf(resp,
":FG%hu#", &speed);
523 LOGF_ERROR(
"Unknown error: focuser speed value (%s)", resp);
533bool SteelDrive::updateAcceleration()
535 int nbytes_written = 0, nbytes_read = 0, rc = -1;
538 unsigned short accel;
540 tcflush(
PortFD, TCIOFLUSH);
545 LOGF_ERROR(
":FHSPMIN# updateAcceleration write error: %s.", errstr);
559 LOGF_ERROR(
":FHSPMIN# updateAcceleration read error: %s.", errstr);
563 resp[nbytes_read] =
'\0';
567 rc = sscanf(resp,
":FH%hu#", &accel);
571 AccelerationN[0].value = accel;
575 LOGF_ERROR(
"Unknown error: updateAcceleration value (%s)", resp);
584bool SteelDrive::updateTemperatureSettings()
586 int nbytes_written = 0, nbytes_read = 0, rc = -1;
592 tcflush(
PortFD, TCIOFLUSH);
597 LOGF_ERROR(
":F7ASKC0# updateTemperatureSettings write error: %s.", errstr);
611 LOGF_ERROR(
":F7ASKC0# updateTemperatureSettings read error: %s.", errstr);
615 resp[nbytes_read] =
'\0';
619 rc = sscanf(resp,
":F7%s#", tResp);
623 snprintf(coeff,
sizeof(coeff),
"%.3s", tResp);
624 snprintf(enabled,
sizeof(enabled),
"%.1s", tResp + 3);
625 snprintf(selectedFocuser,
sizeof(selectedFocuser),
"%.1s", tResp + 4);
627 TemperatureSettingN[
FOCUS_T_COEFF].value = atof(coeff) / 1000.0;
630 if (enabled[0] ==
'0')
631 TemperatureCompensateS[1].s =
ISS_ON;
633 TemperatureCompensateS[0].s =
ISS_ON;
637 LOGF_ERROR(
"Unknown error: updateTemperatureSettings value (%s)", resp);
647bool SteelDrive::updateCustomSettings()
649 int nbytes_written = 0, nbytes_read = 0, rc = -1;
657 tcflush(
PortFD, TCIOFLUSH);
663 LOGF_ERROR(
":FEASKGR# updateCustomSettings write error: %s.", errstr);
677 LOGF_ERROR(
":FEASKGR# updateCustomSettings read error: %s.", errstr);
681 resp[nbytes_read] =
'\0';
685 rc = sscanf(resp,
":FE%d#", &gearR);
689 gearRatio = ((double)gearR) / 100000.0;
693 LOGF_ERROR(
"Unknown error: updateCustomSettings value (%s)", resp);
697 tcflush(
PortFD, TCIOFLUSH);
703 LOGF_ERROR(
":F8ASKS1# updateCustomSettings write error: %s.", errstr);
717 LOGF_ERROR(
":F8ASKS1# updateCustomSettings read error: %s.", errstr);
721 resp[nbytes_read] =
'\0';
725 rc = sscanf(resp,
":F%s#", tResp);
729 snprintf(selectedFocuser,
sizeof(selectedFocuser),
"%.1s", tResp);
730 snprintf(maxTrip,
sizeof(maxTrip),
"%.7s", tResp + 1);
732 int sFocuser = atoi(selectedFocuser);
735 ModelS[sFocuser].s =
ISS_ON;
737 fSettings[sFocuser].
maxTrip = (atof(maxTrip) * gearRatio) / 100.0;
738 fSettings[sFocuser].
gearRatio = gearRatio;
743 LOGF_DEBUG(
"Updated max trip: %g gear ratio: %g", fSettings[sFocuser].maxTrip,
744 fSettings[sFocuser].gearRatio);
748 LOGF_ERROR(
"Unknown error: updateCustomSettings value (%s)", resp);
758bool SteelDrive::setTemperatureSamples(
unsigned int targetSamples,
unsigned int *finalSample)
760 int nbytes_written = 0, rc = -1;
767 for (
int i = maxSample; i > 0;)
769 if (targetSamples & maxSample)
781 else if (sample == 32)
783 else if (sample == 64)
790 tcflush(
PortFD, TCIOFLUSH);
797 LOGF_ERROR(
"%s setTemperatureSamples write error: %s.",
cmd, errstr);
802 *finalSample = sample;
810bool SteelDrive::setTemperatureCompensation()
812 int nbytes_written = 0, rc = -1;
817 bool enable = TemperatureCompensateS[0].s ==
ISS_ON;
820 snprintf(
cmd,
STEELDRIVE_CMD + 1,
":F%02d%03d%d#", selectedFocus, (
int)(coeff * 1000), enable ? 2 : 0);
822 tcflush(
PortFD, TCIOFLUSH);
829 LOGF_ERROR(
"setTemperatureCoefficient error: %s.", errstr);
839bool SteelDrive::setCustomSettings(
double maxTrip,
double gearRatio)
841 int nbytes_written = 0, rc = -1;
845 unsigned short mmTrip = (
unsigned short int)(maxTrip / gearRatio * 100.0);
849 tcflush(
PortFD, TCIOFLUSH);
856 LOGF_ERROR(
"setCustomSettings error: %s.", errstr);
862 tcflush(
PortFD, TCIOFLUSH);
869 LOGF_ERROR(
"setCustomSettings error: %s.", errstr);
879bool SteelDrive::Sync(
unsigned int position)
881 int nbytes_written = 0, rc = -1;
887 tcflush(
PortFD, TCIOFLUSH);
898 simPosition = position;
906bool SteelDrive::moveFocuser(
unsigned int position)
908 int nbytes_written = 0, rc = -1;
914 LOGF_ERROR(
"Requested position value out of bound: %d", position);
923 tcflush(
PortFD, TCIOFLUSH);
935 targetPos = position;
943bool SteelDrive::startMotion(FocusDirection dir)
945 int nbytes_written = 0, rc = -1;
953 tcflush(
PortFD, TCIOFLUSH);
970bool SteelDrive::setSpeed(
unsigned short speed)
972 int nbytes_written = 0, rc = -1;
978 tcflush(
PortFD, TCIOFLUSH);
989 currentSpeed = speed;
997bool SteelDrive::setAcceleration(
unsigned short accel)
999 int nbytes_written = 0, rc = -1;
1005 tcflush(
PortFD, TCIOFLUSH);
1012 LOGF_ERROR(
"setAcceleration error: %s.", errstr);
1026 if (strcmp(TemperatureCompensateSP.
name, name) == 0)
1031 bool rc = setTemperatureCompensation();
1037 TemperatureCompensateS[last_index].s =
ISS_ON;
1042 TemperatureCompensateSP.
s =
IPS_OK;
1047 if (strcmp(ModelSP.
name, name) == 0)
1053 double focusMaxPos = floor(fSettings[i].maxTrip / fSettings[i].gearRatio) * 100;
1080 if (strcmp(name, AccelerationNP.
name) == 0)
1082 if (setAcceleration((
int)values[0]))
1098 if (strcmp(name, TemperatureSettingNP.
name) == 0)
1101 unsigned int targetSamples;
1104 targetSamples = (int)values[0];
1106 targetSamples = (int)values[1];
1108 unsigned int finalSample = targetSamples;
1110 if (setTemperatureSamples(targetSamples, &finalSample))
1118 TemperatureSettingNP.
s =
IPS_OK;
1131 if (strcmp(name, CustomSettingNP.
name) == 0)
1139 LOG_WARN(
"You can not set custom values for a non-custom focuser.");
1144 double maxTrip, gearRatio;
1148 maxTrip = values[0];
1149 gearRatio = values[1];
1153 maxTrip = values[1];
1154 gearRatio = values[0];
1157 if (setCustomSettings(maxTrip, gearRatio))
1163 updateFocusMaxRange(maxTrip, gearRatio);
1175 if (strcmp(name, SyncNP.
name) == 0)
1177 if (Sync((
unsigned int)values[0]))
1183 if (updatePosition())
1204void SteelDrive::GetFocusParams()
1206 if (updateVersion())
1209 if (updateTemperature())
1212 if (updateTemperatureSettings())
1215 if (updatePosition())
1221 if (updateAcceleration())
1224 if (updateCustomSettings())
1235 rc = setSpeed(speed);
1240 currentSpeed = speed;
1250 if (speed != (
int)currentSpeed)
1252 bool rc = setSpeed(speed);
1258 gettimeofday(&focusMoveStart,
nullptr);
1259 focusMoveRequest = duration / 1000.0;
1275 targetPos = targetTicks;
1279 rc = moveFocuser(targetPos);
1291 double newPosition = 0;
1299 rc = moveFocuser(newPosition);
1316 bool rc = updatePosition();
1329 LOG_DEBUG(
"Position read timeout during motion (hardware busy) - will retry next cycle.");
1334 temperatureUpdateCounter = 0;
1335 rc = updateTemperature();
1338 if (fabs(lastTemperature - TemperatureN[0].value) >= 0.5)
1339 lastTemperature = TemperatureN[0].value;
1347 float remaining = CalcTimeLeft(focusMoveStart, focusMoveRequest);
1381 else if (remaining <= 0)
1402 if (fabs(simPosition - targetPos) < 100)
1417 LOG_INFO(
"Focuser reached requested position.");
1429 int nbytes_written = 0, rc = -1;
1432 tcflush(
PortFD, TCIOFLUSH);
1439 LOGF_ERROR(
":F3STOP0# Stop error: %s.", errstr);
1460float SteelDrive::CalcTimeLeft(timeval start,
float req)
1468 gettimeofday(&now,
nullptr);
1471 (double)(now.tv_sec * 1000.0 + now.tv_usec / 1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec / 1000);
1472 timesince = timesince / 1000;
1473 timeleft = req - timesince;
1491 return saveFocuserConfig();
1497bool SteelDrive::saveFocuserConfig()
1499 int nbytes_written = 0, rc = -1;
1502 tcflush(
PortFD, TCIOFLUSH);
1509 LOGF_ERROR(
":FFPOWER# saveFocuserConfig error: %s.", errstr);
1527void SteelDrive::updateFocusMaxRange(
double maxTrip,
double gearRatio)
1529 double maxSteps = floor(maxTrip / gearRatio * 100.0);
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.
@ FOCUSER_HAS_VARIABLE_SPEED
INDI::PropertySwitch FocusMotionSP
INDI::PropertyNumber FocusSpeedNP
INDI::PropertyNumber FocusTimerNP
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 debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser the focuser in a particular direction with a specific speed for a finite duration.
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 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 void TimerHit() override
Callback function to be called once SetTimer duration elapses.
const char * getDefaultName() override
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool saveConfigItems(FILE *fp) override
virtual IPState MoveRelFocuser(FocusDirection dir, unsigned int ticks) override
virtual bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
#define FOCUS_SETTINGS_TAB
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
void tty_set_debug(int debug)
tty_set_debug Enable or disable debug which prints verbose information.
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.
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
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 IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text'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.
void IDSetText(const ITextVectorProperty *tvp, const char *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 STEELDRIVE_TIMEOUT
#define STEELDRIVE_MAX_RETRIES
std::unique_ptr< SteelDrive > steelDrive(new SteelDrive())
#define STEELDRIVE_MAXBUF
#define STEELDIVE_POSITION_THRESHOLD
#define STEELDRIVE_TEMPERATURE_FREQ
#define STEELDRIVE_CMD_LONG